You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tajo.apache.org by hy...@apache.org on 2014/01/17 10:23:35 UTC
[05/12] TAJO-501: Rewrite the projection part of logical planning.
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/NamedExprsManager.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/NamedExprsManager.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/NamedExprsManager.java
new file mode 100644
index 0000000..05ba036
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/NamedExprsManager.java
@@ -0,0 +1,271 @@
+/**
+ * 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 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.FieldEval;
+import org.apache.tajo.util.TUtil;
+
+import java.util.*;
+
+import static java.util.Map.Entry;
+
+/**
+ * NamedExprsManager manages an expressions to be evaluated in a query block.
+ * NamedExprsManager uses a reference name to identify one expression or one
+ * EvalNode (annotated expression).
+ */
+public class NamedExprsManager {
+ /** Map; Reference name -> EvalNode */
+ private Map<String, EvalNode> nameToEvalMap = new LinkedHashMap<String, EvalNode>();
+ /** Map: EvalNode -> String */
+ private Map<EvalNode, String> evalToNameMap = new LinkedHashMap<EvalNode, String>();
+ /** Map; Reference name -> Expr */
+ private LinkedHashMap<String, Expr> nameToExprMap = new LinkedHashMap<String, Expr>();
+ /** Map; Expr -> Reference Name */
+ private LinkedHashMap<Expr, String> exprToNameMap = new LinkedHashMap<Expr, String>();
+ /** Map; Reference Name -> Boolean (if it is resolved or not) */
+ private LinkedHashMap<String, Boolean> resolvedFlags = new LinkedHashMap<String, Boolean>();
+
+ private BiMap<String, String> aliasedColumnMap = HashBiMap.create();
+
+ private LogicalPlan plan;
+
+ public NamedExprsManager(LogicalPlan plan) {
+ this.plan = plan;
+ }
+
+ /**
+ * Check whether the expression corresponding to a given name was resolved.
+ *
+ * @param name The name of a certain expression to be checked
+ * @return true if resolved. Otherwise, false.
+ */
+ public boolean isResolved(String name) {
+ String normalized = name.toLowerCase();
+ return resolvedFlags.containsKey(normalized) && resolvedFlags.get(normalized);
+ }
+
+ public boolean contains(String name) {
+ return nameToExprMap.containsKey(name);
+ }
+
+ public boolean contains(Expr expr) {
+ return exprToNameMap.containsKey(expr);
+ }
+
+ public String getName(Expr expr) {
+ return exprToNameMap.get(expr);
+ }
+
+ public NamedExpr getNamedExpr(String name) {
+ String normalized = name.toLowerCase();
+ return new NamedExpr(nameToExprMap.get(normalized), 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);
+ }
+
+ public String addExpr(Expr expr, String alias) {
+ if (exprToNameMap.containsKey(expr)) {
+ return exprToNameMap.get(expr);
+ } else {
+ String normalized = alias.toLowerCase();
+ nameToExprMap.put(normalized, expr);
+ exprToNameMap.put(expr, normalized);
+ resolvedFlags.put(normalized, false);
+ return normalized;
+ }
+ }
+
+ public String [] addReferences(Expr expr) throws PlanningException {
+ Set<ColumnReferenceExpr> foundSet = ExprFinder.finds(expr, OpType.Column);
+ String [] names = new String[foundSet.size()];
+ int i = 0;
+ for (ColumnReferenceExpr column : foundSet) {
+ addExpr(column);
+ names[i++] = column.getCanonicalName();
+ }
+ return names;
+ }
+
+ public String addExpr(Expr expr) {
+ String name;
+
+ // all columns are projected automatically. BTW, should we add column reference to this list?
+ if (expr.getType() == OpType.Column) {
+ name = ((ColumnReferenceExpr)expr).getCanonicalName();
+ if (nameToExprMap.containsKey(name)) { // if it is column and another one already exists, skip.
+ return name;
+ }
+ } else {
+ name = plan.newGeneratedFieldName(expr);
+ }
+ return addExpr(expr, name);
+ }
+
+ public String addNamedExpr(NamedExpr namedExpr) {
+ if (namedExpr.hasAlias()) {
+ return addExpr(namedExpr.getExpr(), namedExpr.getAlias());
+ } else {
+ return addExpr(namedExpr.getExpr());
+ }
+ }
+
+ public String [] addNamedExprArray(@Nullable Collection<NamedExpr> targets) {
+ if (targets != null || targets.size() > 0) {
+ String [] names = new String[targets.size()];
+ int i = 0;
+ for (NamedExpr target : targets) {
+ names[i++] = addNamedExpr(target);
+ }
+ return names;
+ } else {
+ return null;
+ }
+ }
+
+ public Collection<NamedExpr> getAllNamedExprs() {
+ List<NamedExpr> namedExprList = new ArrayList<NamedExpr>();
+ for (Entry<String, Expr> entry: nameToExprMap.entrySet()) {
+ namedExprList.add(new NamedExpr(entry.getValue(), entry.getKey()));
+ }
+ return namedExprList;
+ }
+
+ public void resolveExpr(String name, EvalNode evalNode) throws PlanningException {
+ String normalized = name.toLowerCase();
+ nameToEvalMap.put(normalized, evalNode);
+ evalToNameMap.put(evalNode, normalized);
+ resolvedFlags.put(normalized, true);
+
+ 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.
+ */
+ private String checkAndGetIfAliasedColumn(String name) {
+ Expr expr = nameToExprMap.get(name);
+ if (expr.getType() == OpType.Column) {
+ ColumnReferenceExpr column = (ColumnReferenceExpr) expr;
+ if (!column.getCanonicalName().equals(name)) {
+ return column.getCanonicalName();
+ }
+ }
+ return null;
+ }
+
+ public Target getTarget(Expr expr, boolean unresolved) {
+ String name = exprToNameMap.get(expr);
+ return getTarget(name, unresolved);
+ }
+
+ public Target getTarget(String name) {
+ return getTarget(name, false);
+ }
+
+ public Target getTarget(String name, boolean unresolved) {
+ String normalized = name;
+ if (!unresolved && resolvedFlags.containsKey(normalized) && resolvedFlags.get(normalized)) {
+ return new Target(new FieldEval(normalized, nameToEvalMap.get(normalized).getValueType()));
+ } else {
+ if (nameToEvalMap.containsKey(normalized)) {
+ return new Target(nameToEvalMap.get(normalized), name);
+ } else {
+ return null;
+ }
+ }
+ }
+
+ public String toString() {
+ return "unresolved=" + nameToExprMap.size() + ", resolved=" + nameToEvalMap.size()
+ + ", renamed=" + aliasedColumnMap.size();
+ }
+
+ /**
+ * It returns an iterator for unresolved NamedExprs.
+ */
+ public Iterator<NamedExpr> getUnresolvedExprs() {
+ return new UnresolvedIterator();
+ }
+
+ public class UnresolvedIterator implements Iterator<NamedExpr> {
+ private final Iterator<NamedExpr> iterator;
+
+ public UnresolvedIterator() {
+ List<NamedExpr> unresolvedList = TUtil.newList();
+ for (Entry<String,Expr> entry : nameToExprMap.entrySet()) {
+ if (!isResolved(entry.getKey())) {
+ unresolvedList.add(new NamedExpr(entry.getValue(), entry.getKey()));
+ }
+ }
+ if (unresolvedList.size() == 0) {
+ iterator = null;
+ } else {
+ iterator = unresolvedList.iterator();
+ }
+ }
+
+
+ @Override
+ public boolean hasNext() {
+ return iterator != null && iterator.hasNext();
+ }
+
+ @Override
+ public NamedExpr next() {
+ return iterator.next();
+ }
+
+ @Override
+ public void remove() {
+ }
+ }
+
+ public void reset() {
+ for (String name : resolvedFlags.keySet()) {
+ resolvedFlags.put(name, false);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PhysicalPlannerImpl.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PhysicalPlannerImpl.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PhysicalPlannerImpl.java
index d6d518c..d9689aa 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PhysicalPlannerImpl.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PhysicalPlannerImpl.java
@@ -26,6 +26,7 @@ import com.google.common.collect.ObjectArrays;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.fs.Path;
+import org.apache.tajo.algebra.Projection;
import org.apache.tajo.engine.planner.global.DataChannel;
import org.apache.tajo.storage.fragment.FileFragment;
import org.apache.tajo.storage.fragment.FragmentConvertor;
@@ -133,7 +134,8 @@ public class PhysicalPlannerImpl implements PhysicalPlanner {
case TABLE_SUBQUERY: {
TableSubQueryNode subQueryNode = (TableSubQueryNode) logicalNode;
leftExec = createPlanRecursive(ctx, subQueryNode.getSubQuery());
- return leftExec;
+ ProjectionExec projectionExec = new ProjectionExec(ctx, subQueryNode, leftExec);
+ return projectionExec;
}
case PARTITIONS_SCAN:
@@ -146,6 +148,11 @@ public class PhysicalPlannerImpl implements PhysicalPlanner {
leftExec = createPlanRecursive(ctx, grpNode.getChild());
return createGroupByPlan(ctx, grpNode, leftExec);
+ case HAVING:
+ HavingNode havingNode = (HavingNode) logicalNode;
+ leftExec = createPlanRecursive(ctx, havingNode.getChild());
+ return new HavingExec(ctx, havingNode, leftExec);
+
case SORT:
SortNode sortNode = (SortNode) logicalNode;
leftExec = createPlanRecursive(ctx, sortNode.getChild());
@@ -327,12 +334,18 @@ public class PhysicalPlannerImpl implements PhysicalPlanner {
PhysicalExec leftExec, PhysicalExec rightExec) throws IOException {
SortSpec[][] sortSpecs = PlannerUtil.getSortKeysFromJoinQual(
plan.getJoinQual(), leftExec.getSchema(), rightExec.getSchema());
- ExternalSortExec outerSort = new ExternalSortExec(context, sm,
- new SortNode(UNGENERATED_PID, sortSpecs[0], leftExec.getSchema(), leftExec.getSchema()),
- leftExec);
- ExternalSortExec innerSort = new ExternalSortExec(context, sm,
- new SortNode(UNGENERATED_PID, sortSpecs[1], rightExec.getSchema(), rightExec.getSchema()),
- rightExec);
+
+ SortNode leftSortNode = new SortNode(UNGENERATED_PID);
+ leftSortNode.setSortSpecs(sortSpecs[0]);
+ leftSortNode.setInSchema(leftExec.getSchema());
+ leftSortNode.setOutSchema(leftExec.getSchema());
+ ExternalSortExec outerSort = new ExternalSortExec(context, sm, leftSortNode, leftExec);
+
+ SortNode rightSortNode = new SortNode(UNGENERATED_PID);
+ rightSortNode.setSortSpecs(sortSpecs[1]);
+ rightSortNode.setInSchema(rightExec.getSchema());
+ rightSortNode.setOutSchema(rightExec.getSchema());
+ ExternalSortExec innerSort = new ExternalSortExec(context, sm, rightSortNode, rightExec);
LOG.info("Join (" + plan.getPID() +") chooses [Merge Join]");
return new MergeJoinExec(context, plan, outerSort, innerSort, sortSpecs[0], sortSpecs[1]);
@@ -399,10 +412,19 @@ public class PhysicalPlannerImpl implements PhysicalPlanner {
LOG.info("Right Outer Join (" + plan.getPID() +") chooses [Merge Join].");
SortSpec[][] sortSpecs2 = PlannerUtil.getSortKeysFromJoinQual(
plan.getJoinQual(), leftExec.getSchema(), rightExec.getSchema());
- ExternalSortExec outerSort2 = new ExternalSortExec(context, sm,
- new SortNode(UNGENERATED_PID,sortSpecs2[0], leftExec.getSchema(), leftExec.getSchema()), leftExec);
- ExternalSortExec innerSort2 = new ExternalSortExec(context, sm,
- new SortNode(UNGENERATED_PID,sortSpecs2[1], rightExec.getSchema(), rightExec.getSchema()), rightExec);
+
+ SortNode leftSortNode2 = new SortNode(UNGENERATED_PID);
+ leftSortNode2.setSortSpecs(sortSpecs2[0]);
+ leftSortNode2.setInSchema(leftExec.getSchema());
+ leftSortNode2.setOutSchema(leftExec.getSchema());
+ ExternalSortExec outerSort2 = new ExternalSortExec(context, sm, leftSortNode2, leftExec);
+
+ SortNode rightSortNode2 = new SortNode(UNGENERATED_PID);
+ rightSortNode2.setSortSpecs(sortSpecs2[1]);
+ rightSortNode2.setInSchema(rightExec.getSchema());
+ rightSortNode2.setOutSchema(rightExec.getSchema());
+ ExternalSortExec innerSort2 = new ExternalSortExec(context, sm, rightSortNode2, rightExec);
+
return new RightOuterMergeJoinExec(context, plan, outerSort2, innerSort2, sortSpecs2[0], sortSpecs2[1]);
}
@@ -481,10 +503,18 @@ public class PhysicalPlannerImpl implements PhysicalPlanner {
LOG.info("Full Outer Join (" + plan.getPID() +") chooses [Merge Join]");
SortSpec[][] sortSpecs3 = PlannerUtil.getSortKeysFromJoinQual(plan.getJoinQual(),
leftExec.getSchema(), rightExec.getSchema());
- ExternalSortExec outerSort3 = new ExternalSortExec(context, sm,
- new SortNode(UNGENERATED_PID,sortSpecs3[0], leftExec.getSchema(), leftExec.getSchema()), leftExec);
- ExternalSortExec innerSort3 = new ExternalSortExec(context, sm,
- new SortNode(UNGENERATED_PID,sortSpecs3[1], rightExec.getSchema(), rightExec.getSchema()), rightExec);
+
+ SortNode leftSortNode = new SortNode(UNGENERATED_PID);
+ leftSortNode.setSortSpecs(sortSpecs3[0]);
+ leftSortNode.setInSchema(leftExec.getSchema());
+ leftSortNode.setOutSchema(leftExec.getSchema());
+ ExternalSortExec outerSort3 = new ExternalSortExec(context, sm, leftSortNode, leftExec);
+
+ SortNode rightSortNode = new SortNode(UNGENERATED_PID);
+ rightSortNode.setSortSpecs(sortSpecs3[1]);
+ rightSortNode.setInSchema(rightExec.getSchema());
+ rightSortNode.setOutSchema(rightExec.getSchema());
+ ExternalSortExec innerSort3 = new ExternalSortExec(context, sm, rightSortNode, rightExec);
return new MergeFullOuterJoinExec(context, plan, outerSort3, innerSort3, sortSpecs3[0], sortSpecs3[1]);
}
@@ -706,7 +736,8 @@ public class PhysicalPlannerImpl implements PhysicalPlanner {
sortSpecs = ObjectArrays.concat(sortSpecs, enforcedSortSpecs, SortSpec.class);
}
- SortNode sortNode = new SortNode(-1, sortSpecs);
+ SortNode sortNode = new SortNode(-1);
+ sortNode.setSortSpecs(sortSpecs);
sortNode.setInSchema(subOp.getSchema());
sortNode.setOutSchema(subOp.getSchema());
// SortExec sortExec = new SortExec(sortNode, child);
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PlannerUtil.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PlannerUtil.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PlannerUtil.java
index 4e2441b..66358d5 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PlannerUtil.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PlannerUtil.java
@@ -22,7 +22,7 @@ import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.ObjectArrays;
import com.google.common.collect.Sets;
-import org.apache.tajo.algebra.JoinType;
+import org.apache.tajo.algebra.*;
import org.apache.tajo.annotation.Nullable;
import org.apache.tajo.catalog.Column;
import org.apache.tajo.catalog.Schema;
@@ -33,6 +33,7 @@ import org.apache.tajo.engine.eval.*;
import org.apache.tajo.engine.planner.logical.*;
import org.apache.tajo.engine.exception.InvalidQueryException;
import org.apache.tajo.storage.TupleComparator;
+import org.apache.tajo.util.TUtil;
import java.util.*;
@@ -139,12 +140,17 @@ public class PlannerUtil {
public static void replaceNode(LogicalPlan plan, LogicalNode startNode, LogicalNode oldNode, LogicalNode newNode) {
LogicalNodeReplaceVisitor replacer = new LogicalNodeReplaceVisitor(oldNode, newNode);
try {
- replacer.visit(null, plan, null, startNode, new Stack<LogicalNode>());
+ replacer.visit(new ReplacerContext(), plan, null, startNode, new Stack<LogicalNode>());
} catch (PlanningException e) {
e.printStackTrace();
}
}
- public static class LogicalNodeReplaceVisitor extends BasicLogicalPlanVisitor<Object, LogicalNode> {
+
+ static class ReplacerContext {
+ boolean updateSchemaFlag = false;
+ }
+
+ public static class LogicalNodeReplaceVisitor extends BasicLogicalPlanVisitor<ReplacerContext, LogicalNode> {
private LogicalNode target;
private LogicalNode tobeReplaced;
@@ -154,9 +160,9 @@ public class PlannerUtil {
}
@Override
- public LogicalNode visit(Object context, LogicalPlan plan, @Nullable LogicalPlan.QueryBlock block, LogicalNode node,
- Stack<LogicalNode> stack) throws PlanningException {
- super.visit(context, plan, null, node, stack);
+ public LogicalNode visit(ReplacerContext context, LogicalPlan plan, @Nullable LogicalPlan.QueryBlock block,
+ LogicalNode node, Stack<LogicalNode> stack) throws PlanningException {
+ LogicalNode child = super.visit(context, plan, null, node, stack);
if (node.deepEquals(target)) {
LogicalNode parent = stack.peek();
@@ -173,6 +179,18 @@ public class PlannerUtil {
UnaryNode unaryParent = (UnaryNode) parent;
unaryParent.setChild(tobeReplaced);
}
+
+ context.updateSchemaFlag = true;
+ }
+
+ if (context.updateSchemaFlag && !node.deepEquals(target)) {
+ if (node instanceof Projectable) {
+ node.setInSchema(child.getOutSchema());
+ context.updateSchemaFlag = false;
+ } else {
+ node.setInSchema(child.getOutSchema());
+ node.setOutSchema(child.getOutSchema());
+ }
}
return node;
}
@@ -241,10 +259,8 @@ public class PlannerUtil {
new Column(targetName, newTarget.getEvalTree().getValueType()))});
} else {
func.setFirstPhase();
- newTarget = new Target(func);
String targetName = "column_" + (targetId++);
- newTarget.setAlias(targetName);
-
+ newTarget = new Target(func, targetName);
AggregationFunctionCallEval secondFunc = null;
for (AggregationFunctionCallEval sf : secondStepFunctions) {
if (func.equals(sf)) {
@@ -264,14 +280,13 @@ public class PlannerUtil {
Schema targetSchema = PlannerUtil.targetToSchema(targetArray);
List<Target> newTarget = Lists.newArrayList();
for (Column column : groupBy.getGroupingColumns()) {
- if (!targetSchema.contains(column.getQualifiedName())) {
+ if (!targetSchema.containsByQualifiedName(column.getQualifiedName())) {
newTarget.add(new Target(new FieldEval(column)));
}
}
targetArray = ObjectArrays.concat(targetArray, newTarget.toArray(new Target[newTarget.size()]), Target.class);
child.setTargets(targetArray);
- child.setOutSchema(PlannerUtil.targetToSchema(targetArray));
// set the groupby chaining
groupBy.setChild(child);
groupBy.setInSchema(child.getOutSchema());
@@ -409,7 +424,7 @@ public class PlannerUtil {
} else {
for (Column col : columnRefs) {
- if (!node.getInSchema().contains(col.getQualifiedName())) {
+ if (!node.getInSchema().containsByQualifiedName(col.getQualifiedName())) {
return false;
}
}
@@ -506,6 +521,21 @@ public class PlannerUtil {
return targets;
}
+ public static Target[] schemaToTargetsWithGeneratedFields(Schema schema) {
+ List<Target> targets = TUtil.newList();
+
+ FieldEval eval;
+ Column column;
+ for (int i = 0; i < schema.getColumnNum(); i++) {
+ column = schema.getColumn(i);
+ if (column.getColumnName().charAt(0) != LogicalPlan.NONAMED_COLUMN_PREFIX) {
+ eval = new FieldEval(schema.getColumn(i));
+ targets.add(new Target(eval));
+ }
+ }
+ return targets.toArray(new Target[targets.size()]);
+ }
+
public static SortSpec[] schemaToSortSpecs(Schema schema) {
return schemaToSortSpecs(schema.toArray());
}
@@ -619,7 +649,7 @@ public class PlannerUtil {
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())) {
+ if (schemas[j].containsByQualifiedName(column.getQualifiedName())) {
pair[j] = column;
}
}
@@ -637,6 +667,10 @@ public class PlannerUtil {
}
}
+ 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) {
@@ -647,7 +681,9 @@ public class PlannerUtil {
} else {
name = t.getEvalTree().getName();
}
- schema.addColumn(name, type);
+ if (!schema.containsByQualifiedName(name)) {
+ schema.addColumn(name, type);
+ }
}
return schema;
@@ -668,7 +704,7 @@ public class PlannerUtil {
throw new InternalError(e.getMessage());
}
if (copy[i].getEvalTree().getType() == EvalType.FIELD) {
- FieldEval fieldEval = (FieldEval) copy[i].getEvalTree();
+ FieldEval fieldEval = copy[i].getEvalTree();
if (fieldEval.getColumnRef().hasQualifier()) {
fieldEval.getColumnRef().setName(fieldEval.getColumnName());
}
@@ -706,4 +742,51 @@ public class PlannerUtil {
return schema;
}
+ 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;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/Projector.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/Projector.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/Projector.java
index 12e4978..8d6db22 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/Projector.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/Projector.java
@@ -18,7 +18,6 @@
package org.apache.tajo.engine.planner;
-import org.apache.tajo.catalog.Column;
import org.apache.tajo.catalog.Schema;
import org.apache.tajo.engine.eval.EvalContext;
import org.apache.tajo.engine.eval.EvalNode;
@@ -29,59 +28,21 @@ public class Projector {
// for projection
private final int targetNum;
- private final int [] inMap;
- private final int [] outMap;
- private int [] evalOutMap; // target list?
- private EvalNode[] evals;
- private Tuple prevTuple;
+ private final EvalNode[] evals;
public Projector(Schema inSchema, Schema outSchema, Target [] targets) {
this.inSchema = inSchema;
-
- this.targetNum = targets != null ? targets.length : 0;
-
- inMap = new int[outSchema.getColumnNum() - targetNum];
- outMap = new int[outSchema.getColumnNum() - targetNum];
- int mapId = 0;
- Column col;
-
- if (targetNum > 0) {
- evalOutMap = new int[targetNum];
- evals = new EvalNode[targetNum];
- for (int i = 0; i < targetNum; i++) {
- // TODO - is it always correct?
- if (targets[i].hasAlias()) {
- evalOutMap[i] = outSchema.getColumnId(targets[i].getAlias());
- } else {
- evalOutMap[i] = outSchema.getColumnId(targets[i].getEvalTree().getName());
- }
- evals[i] = targets[i].getEvalTree();
- }
-
- outer:
- for (int targetId = 0; targetId < outSchema.getColumnNum(); targetId ++) {
- for (int j = 0; j < evalOutMap.length; j++) {
- if (evalOutMap[j] == targetId)
- continue outer;
- }
-
- col = inSchema.getColumnByFQN(outSchema.getColumn(targetId).getQualifiedName());
- outMap[mapId] = targetId;
- inMap[mapId] = inSchema.getColumnId(col.getQualifiedName());
- mapId++;
- }
- } else {
- for (int targetId = 0; targetId < outSchema.getColumnNum(); targetId ++) {
- col = inSchema.getColumnByFQN(outSchema.getColumn(targetId).getQualifiedName());
- outMap[mapId] = targetId;
- inMap[mapId] = inSchema.getColumnId(col.getQualifiedName());
- mapId++;
- }
+ if (targets == null) {
+ targets = PlannerUtil.schemaToTargets(outSchema);
+ }
+ this.targetNum = targets.length;
+ evals = new EvalNode[targetNum];
+ for (int i = 0; i < targetNum; i++) {
+ evals[i] = targets[i].getEvalTree();
}
}
public void eval(EvalContext[] evalContexts, Tuple in) {
- this.prevTuple = in;
if (targetNum > 0) {
for (int i = 0; i < evals.length; i++) {
evals[i].eval(evalContexts[i], inSchema, in);
@@ -90,17 +51,12 @@ public class Projector {
}
public void terminate(EvalContext [] evalContexts, Tuple out) {
- for (int i = 0; i < inMap.length; i++) {
- out.put(outMap[i], prevTuple.get(inMap[i]));
- }
- if (targetNum > 0) {
- for (int i = 0; i < evals.length; i++) {
- out.put(evalOutMap[i], evals[i].terminate(evalContexts[i]));
- }
+ for (int i = 0; i < targetNum; i++) {
+ out.put(i, evals[i].terminate(evalContexts[i]));
}
}
- public EvalContext [] renew() {
+ public EvalContext [] newContexts() {
EvalContext [] evalContexts = new EvalContext[targetNum];
for (int i = 0; i < targetNum; i++) {
evalContexts[i] = evals[i].newContext();
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/RangePartitionAlgorithm.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/RangePartitionAlgorithm.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/RangePartitionAlgorithm.java
index e25903f..35d7743 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/RangePartitionAlgorithm.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/RangePartitionAlgorithm.java
@@ -60,6 +60,9 @@ public abstract class RangePartitionAlgorithm {
BigDecimal columnCard;
switch (dataType.getType()) {
+ case BOOLEAN:
+ columnCard = new BigDecimal(2);
+ break;
case CHAR:
columnCard = new BigDecimal(end.asChar() - start.asChar());
break;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/SimpleAlgebraVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/SimpleAlgebraVisitor.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/SimpleAlgebraVisitor.java
new file mode 100644
index 0000000..dc7b7a2
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/SimpleAlgebraVisitor.java
@@ -0,0 +1,210 @@
+/**
+ * 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);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Insert or Update Section
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ 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);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Other Expressions
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public RESULT visitFunction(CONTEXT ctx, Stack<Expr> stack, FunctionExpr expr) throws PlanningException {
+ return super.visitFunction(ctx, stack, expr);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // General Set Section
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ @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);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Literal Section
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public RESULT visitDataType(CONTEXT ctx, Stack<Expr> stack, DataTypeExpr expr) throws PlanningException {
+ return super.visitDataType(ctx, stack, expr);
+ }
+
+ @Override
+ public RESULT visitCastExpr(CONTEXT ctx, Stack<Expr> stack, CastExpr expr) throws PlanningException {
+ return super.visitCastExpr(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/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/Target.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/Target.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/Target.java
index ac50c46..d83a394 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/Target.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/Target.java
@@ -22,6 +22,7 @@ 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;
@@ -34,14 +35,23 @@ public class Target implements Cloneable, GsonObject {
@Expose private Column column;
@Expose private String alias = null;
- public Target(EvalNode expr) {
- this.expr = expr;
- this.column = new Column(expr.getName(), expr.getValueType());
+ public Target(FieldEval fieldEval) {
+ this.expr = fieldEval;
+ this.column = fieldEval.getColumnRef();
}
public Target(final EvalNode eval, final String alias) {
- this(eval);
- setAlias(alias);
+ this.expr = eval;
+ // force lower case
+ String normalized = alias.toLowerCase();
+
+ // 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() {
@@ -73,7 +83,7 @@ public class Target implements Cloneable, GsonObject {
return (T) this.expr;
}
- public Column getColumnSchema() {
+ public Column getNamedColumn() {
return this.column;
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/TargetListManager.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/TargetListManager.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/TargetListManager.java
deleted file mode 100644
index 4e1427e..0000000
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/TargetListManager.java
+++ /dev/null
@@ -1,234 +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.Maps;
-import org.apache.tajo.algebra.Projection;
-import org.apache.tajo.catalog.Column;
-import org.apache.tajo.catalog.Schema;
-import org.apache.tajo.engine.eval.EvalNode;
-import org.apache.tajo.engine.eval.EvalTreeUtil;
-import org.apache.tajo.engine.eval.EvalType;
-import org.apache.tajo.engine.eval.FieldEval;
-
-import java.util.Collection;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * It manages a list of targets.
- */
-public class TargetListManager {
- private final LogicalPlan plan;
- private boolean [] resolvedFlags;
- private Projection projection;
- private Target[] targets;
- private Target[] unresolvedTargets;
- private Map<Column, Integer> targetColumnToId = Maps.newHashMap();
-
- public TargetListManager(LogicalPlan plan, Projection projection) {
- this.plan = plan;
- int targetNum = projection.size();
- if (projection.size() == 0) {
- resolvedFlags = new boolean[0];
- } else {
- resolvedFlags = new boolean[targetNum];
- }
- this.targets = new Target[targetNum];
- this.unresolvedTargets = new Target[targetNum];
- }
-
- public TargetListManager(LogicalPlan plan, Target[] unresolvedTargets) {
- this.plan = plan;
-
- this.targets = new Target[unresolvedTargets.length];
- this.unresolvedTargets = new Target[unresolvedTargets.length];
- for (int i = 0; i < unresolvedTargets.length; i++) {
- try {
- this.targets[i] = (Target) unresolvedTargets[i].clone();
- this.unresolvedTargets[i] = (Target) unresolvedTargets[i].clone();
- } catch (CloneNotSupportedException e) {
- e.printStackTrace();
- }
- }
- resolvedFlags = new boolean[unresolvedTargets.length];
- }
-
- public TargetListManager(LogicalPlan plan, String blockName) {
- this(plan, plan.getBlock(blockName).getTargetListManager().getUnresolvedTargets());
- }
-
- public Target getTarget(int id) {
- return targets[id];
- }
-
- public Target[] getTargets() {
- return this.targets;
- }
-
- public Target[] getUnresolvedTargets() {
- return this.unresolvedTargets;
- }
-
- public void fill(int id, Target target) {
- this.targets[id] = target;
- this.unresolvedTargets[id] = target;
-
- EvalNode evalNode = target.getEvalTree();
- if (evalNode.getType() == EvalType.FIELD) {
- if (target.hasAlias()) {
- FieldEval fieldEval = (FieldEval) evalNode;
- targetColumnToId.put(fieldEval.getColumnRef(), id);
- }
- }
- targetColumnToId.put(target.getColumnSchema(), id);
- }
-
- public int size() {
- return targets.length;
- }
-
- public void resolve(int id) {
- resolvedFlags[id] = true;
- }
-
- public void resolveAll() {
- for (int i = 0; i < resolvedFlags.length; i++) {
- resolvedFlags[i] = true;
- }
- }
-
- public boolean isResolved(int id) {
- return resolvedFlags[id];
- }
-
- /**
- * It checks whether only column reference is resolve or not.
- * Note that this method doesn't know if an expression is resolved.
- *
- * @param targetColumn A column to be checked
- * @return True if a column reference belong to a target list and is already resolved. Otherwise, false.
- */
- public boolean isResolve(Column targetColumn) throws PlanningException {
- Integer targetId = targetColumnToId.get(targetColumn);
- if (targetId == null) {
- return false;
- }
- return resolvedFlags[targetId];
- }
-
- public Column getResolvedColumn(Column targetColumn) throws PlanningException {
- Integer targetId = targetColumnToId.get(targetColumn);
- if (targetId == null) {
- throw new PlanningException("Unknown target column: " + targetColumn);
- }
- return getResolvedTargetToColumn(targetId);
- }
-
- public Target [] getUpdatedTarget(Set<Integer> exclude) throws PlanningException {
- Target [] updated = new Target[targets.length];
-
- for (int i = 0; i < targets.length; i++) {
- if (targets[i] == null) { // if it is not created
- continue;
- }
-
- if (!exclude.contains(i) && resolvedFlags[i]) { // if this target was evaluated, it becomes a column target.
- Column col = getResolvedTargetToColumn(i);
- updated[i] = new Target(new FieldEval(col));
- } else {
- try {
- updated[i] = (Target) targets[i].clone();
- } catch (CloneNotSupportedException e) {
- throw new PlanningException(e);
- }
- }
- }
- return updated;
- }
-
- public Target [] getUpdatedTarget() throws PlanningException {
- Target [] updated = new Target[targets.length];
-
- for (int i = 0; i < targets.length; i++) {
- if (targets[i] == null) { // if it is not created
- continue;
- }
-
- if (resolvedFlags[i]) { // if this target was evaluated, it becomes a column target.
- Column col = getResolvedTargetToColumn(i);
- updated[i] = new Target(new FieldEval(col));
- } else {
- try {
- updated[i] = (Target) targets[i].clone();
- } catch (CloneNotSupportedException e) {
- throw new PlanningException(e);
- }
- }
- }
- targets = updated;
- return updated;
- }
-
- public Schema getUpdatedSchema() {
- Schema schema = new Schema();
- for (int i = 0; i < resolvedFlags.length; i++) {
- if (resolvedFlags[i]) {
- Column col = getResolvedTargetToColumn(i);
- if (!schema.contains(col.getQualifiedName()))
- schema.addColumn(col);
- } else {
- Collection<Column> cols = getColumnRefs(i);
- for (Column col : cols) {
- if (!schema.contains(col.getQualifiedName())) {
- schema.addColumn(col);
- }
- }
- }
- }
- return schema;
- }
-
- public Collection<Column> getColumnRefs(int id) {
- return EvalTreeUtil.findDistinctRefColumns(targets[id].getEvalTree());
- }
-
- public Column getResolvedTargetToColumn(int id) {
- Target t = targets[id];
- String name;
- if (t.hasAlias() || t.getEvalTree().getType() == EvalType.FIELD) {
- name = t.getCanonicalName();
- } else { // if alias name is not given or target is an expression
- t.setAlias(plan.newNonameColumnName(t.getEvalTree().getName()));
- name = t.getCanonicalName();
- }
- return new Column(name, t.getEvalTree().getValueType());
- }
-
- public boolean isAllResolved() {
- for (boolean resolved : resolvedFlags) {
- if (!resolved) {
- return false;
- }
- }
-
- return true;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/global/GlobalPlanner.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/global/GlobalPlanner.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/global/GlobalPlanner.java
index d05ac46..58ad73c 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/global/GlobalPlanner.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/global/GlobalPlanner.java
@@ -50,8 +50,7 @@ public class GlobalPlanner {
private TajoConf conf;
private CatalogProtos.StoreType storeType;
- public GlobalPlanner(final TajoConf conf, final AbstractStorageManager sm)
- throws IOException {
+ public GlobalPlanner(final TajoConf conf, final AbstractStorageManager sm) throws IOException {
this.conf = conf;
this.storeType = CatalogProtos.StoreType.valueOf(conf.getVar(TajoConf.ConfVars.SHUFFLE_FILE_FORMAT).toUpperCase());
Preconditions.checkArgument(storeType != null);
@@ -249,8 +248,7 @@ public class GlobalPlanner {
}
private ExecutionBlock buildGroupBy(GlobalPlanContext context, ExecutionBlock childBlock,
- GroupbyNode groupbyNode)
- throws PlanningException {
+ GroupbyNode groupbyNode) throws PlanningException {
MasterPlan masterPlan = context.plan;
ExecutionBlock currentBlock;
@@ -259,7 +257,6 @@ public class GlobalPlanner {
return buildDistinctGroupBy(context, childBlock, groupbyNode);
} else {
GroupbyNode firstPhaseGroupBy = PlannerUtil.transformGroupbyTo2P(groupbyNode);
- firstPhaseGroupBy.setHavingCondition(null);
if (firstPhaseGroupBy.getChild().getType() == NodeType.TABLE_SUBQUERY &&
((TableSubQueryNode)firstPhaseGroupBy.getChild()).getSubQuery().getType() == NodeType.UNION) {
@@ -365,10 +362,20 @@ public class GlobalPlanner {
// if result table is not a partitioned table, directly store it
if(partitionDesc == null) {
- currentNode.setChild(childBlock.getPlan());
- currentNode.setInSchema(childBlock.getPlan().getOutSchema());
- childBlock.setPlan(currentNode);
- return childBlock;
+
+ if (childBlock.getPlan() == null) { // when the below is union
+ for (ExecutionBlock grandChildBlock : context.plan.getChilds(childBlock)) {
+ StoreTableNode copy = PlannerUtil.clone(context.plan.getLogicalPlan(), currentNode);
+ copy.setChild(grandChildBlock.getPlan());
+ grandChildBlock.setPlan(copy);
+ }
+ return childBlock;
+ } else {
+ currentNode.setChild(childBlock.getPlan());
+ currentNode.setInSchema(childBlock.getPlan().getOutSchema());
+ childBlock.setPlan(currentNode);
+ return childBlock;
+ }
}
// if result table is a partitioned table
@@ -419,9 +426,23 @@ public class GlobalPlanner {
ExecutionBlock execBlock = context.execBlockMap.remove(child.getPID());
- node.setChild(execBlock.getPlan());
- node.setInSchema(execBlock.getPlan().getOutSchema());
- execBlock.setPlan(node);
+ if (child.getType() == NodeType.TABLE_SUBQUERY &&
+ ((TableSubQueryNode)child).getSubQuery().getType() == NodeType.UNION) {
+ MasterPlan masterPlan = context.plan;
+ for (DataChannel dataChannel : masterPlan.getIncomingChannels(execBlock.getId())) {
+ ExecutionBlock subBlock = masterPlan.getExecBlock(dataChannel.getSrcId());
+
+ ProjectionNode copy = PlannerUtil.clone(plan, node);
+ copy.setChild(subBlock.getPlan());
+ subBlock.setPlan(copy);
+ }
+ execBlock.setPlan(null);
+ } else {
+ node.setChild(execBlock.getPlan());
+ node.setInSchema(execBlock.getPlan().getOutSchema());
+ execBlock.setPlan(node);
+ }
+
context.execBlockMap.put(node.getPID(), execBlock);
return node;
}
@@ -481,6 +502,20 @@ public class GlobalPlanner {
}
@Override
+ public LogicalNode visitHaving(GlobalPlanContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
+ HavingNode node, Stack<LogicalNode> stack) throws PlanningException {
+ LogicalNode child = super.visitHaving(context, plan, block, node, stack);
+
+ // Don't separate execution block. Having is pushed to the second grouping execution block.
+ ExecutionBlock childBlock = context.execBlockMap.remove(child.getPID());
+ node.setChild(childBlock.getPlan());
+ childBlock.setPlan(node);
+ context.execBlockMap.put(node.getPID(), childBlock);
+
+ return node;
+ }
+
+ @Override
public LogicalNode visitGroupBy(GlobalPlanContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
GroupbyNode node, Stack<LogicalNode> stack) throws PlanningException {
LogicalNode child = super.visitGroupBy(context, plan, block, node, stack);
@@ -553,9 +588,9 @@ public class GlobalPlanner {
}
for (ExecutionBlock childBlocks : unionBlocks) {
- UnionNode union = (UnionNode) childBlocks.getPlan();
- queryBlockBlocks.add(context.execBlockMap.get(union.getLeftChild().getPID()));
- queryBlockBlocks.add(context.execBlockMap.get(union.getRightChild().getPID()));
+ for (ExecutionBlock grandChildBlock : context.plan.getChilds(childBlocks)) {
+ queryBlockBlocks.add(grandChildBlock);
+ }
}
for (ExecutionBlock childBlocks : queryBlockBlocks) {
@@ -596,7 +631,20 @@ public class GlobalPlanner {
LogicalPlan.QueryBlock queryBlock,
TableSubQueryNode node, Stack<LogicalNode> stack) throws PlanningException {
LogicalNode child = super.visitTableSubQuery(context, plan, queryBlock, node, stack);
- return handleUnaryNode(context, child, node);
+
+ ExecutionBlock currentBlock = context.execBlockMap.remove(child.getPID());
+
+ if (child.getType() == NodeType.UNION) {
+ for (ExecutionBlock childBlock : context.plan.getChilds(currentBlock.getId())) {
+ TableSubQueryNode copy = PlannerUtil.clone(plan, node);
+ copy.setSubQuery(childBlock.getPlan());
+ childBlock.setPlan(copy);
+ }
+ } else {
+ currentBlock.setPlan(node);
+ }
+ context.execBlockMap.put(node.getPID(), currentBlock);
+ return node;
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/CreateTableNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/CreateTableNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/CreateTableNode.java
index d0c8373..3dc5655 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/CreateTableNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/CreateTableNode.java
@@ -38,15 +38,21 @@ public class CreateTableNode extends LogicalNode implements Cloneable {
@Expose private boolean external;
@Expose private PartitionDesc partitionDesc;
- public CreateTableNode(int pid, String tableName, Schema schema) {
+ public CreateTableNode(int pid) {
super(pid, NodeType.CREATE_TABLE);
- this.tableName = tableName;
- this.schema = schema;
+ }
+
+ public void setTableName(String name) {
+ this.tableName = name;
}
public final String getTableName() {
return this.tableName;
}
+
+ public void setSchema(Schema schema) {
+ this.schema = schema;
+ }
public Schema getSchema() {
return this.schema;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/DropTableNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/DropTableNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/DropTableNode.java
index 6510925..4dda7af 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/DropTableNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/DropTableNode.java
@@ -24,8 +24,11 @@ public class DropTableNode extends LogicalNode {
private String tableName;
private boolean purge;
- public DropTableNode(int pid, String tableName, boolean purge) {
+ public DropTableNode(int pid) {
super(pid, NodeType.DROP_TABLE);
+ }
+
+ public void set(String tableName, boolean purge) {
this.tableName = tableName;
this.purge = purge;
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/EvalExprNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/EvalExprNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/EvalExprNode.java
index 5bc41bf..ed63bbc 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/EvalExprNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/EvalExprNode.java
@@ -29,9 +29,8 @@ import org.apache.tajo.util.TUtil;
public class EvalExprNode extends LogicalNode implements Projectable {
@Expose private Target[] exprs;
- public EvalExprNode(int pid, Target[] exprs) {
+ public EvalExprNode(int pid) {
super(pid, NodeType.EXPRS);
- this.exprs = exprs;
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/GroupbyNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/GroupbyNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/GroupbyNode.java
index 352780a..41f1e88 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/GroupbyNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/GroupbyNode.java
@@ -20,33 +20,28 @@ package org.apache.tajo.engine.planner.logical;
import com.google.gson.annotations.Expose;
import org.apache.tajo.catalog.Column;
-import org.apache.tajo.catalog.Schema;
-import org.apache.tajo.engine.eval.EvalNode;
import org.apache.tajo.engine.planner.PlanString;
+import org.apache.tajo.engine.planner.PlannerUtil;
import org.apache.tajo.engine.planner.Target;
import org.apache.tajo.util.TUtil;
public class GroupbyNode extends UnaryNode implements Projectable, Cloneable {
@Expose private Column [] columns;
- @Expose private Schema havingSchema;
- @Expose private EvalNode havingCondition = null;
@Expose private Target [] targets;
@Expose private boolean hasDistinct = false;
-
- public GroupbyNode(int pid, final Column [] columns) {
- super(pid, NodeType.GROUP_BY);
- this.columns = columns;
- }
-
- public GroupbyNode(int pid, final Column [] columns, final EvalNode havingCondition) {
- this(pid, columns);
- this.havingCondition = havingCondition;
+
+ public GroupbyNode(int pid) {
+ super(pid, NodeType.GROUP_BY);
}
public final boolean isEmptyGrouping() {
return columns == null || columns.length == 0;
}
+ public void setGroupingColumns(Column [] groupingColumns) {
+ this.columns = groupingColumns;
+ }
+
public final Column [] getGroupingColumns() {
return this.columns;
}
@@ -58,26 +53,6 @@ public class GroupbyNode extends UnaryNode implements Projectable, Cloneable {
public void setDistinct(boolean distinct) {
hasDistinct = distinct;
}
-
- public final boolean hasHavingCondition() {
- return this.havingCondition != null;
- }
-
- public final EvalNode getHavingCondition() {
- return this.havingCondition;
- }
-
- public final void setHavingCondition(final EvalNode evalTree) {
- this.havingCondition = evalTree;
- }
-
- public final void setHavingSchema(Schema schema) {
- this.havingSchema = schema;
- }
-
- public Schema getHavingSchema() {
- return this.havingSchema;
- }
@Override
public boolean hasTargets() {
@@ -87,6 +62,7 @@ public class GroupbyNode extends UnaryNode implements Projectable, Cloneable {
@Override
public void setTargets(Target[] targets) {
this.targets = targets;
+ setOutSchema(PlannerUtil.targetToSchema(targets));
}
@Override
@@ -105,10 +81,7 @@ public class GroupbyNode extends UnaryNode implements Projectable, Cloneable {
if(i < columns.length - 1)
sb.append(",");
}
-
- if(hasHavingCondition()) {
- sb.append("], \"having qual\": \"").append(havingCondition).append("\"");
- }
+
if(hasTargets()) {
sb.append(", \"target\": [");
for (int i = 0; i < targets.length; i++) {
@@ -132,7 +105,6 @@ public class GroupbyNode extends UnaryNode implements Projectable, Cloneable {
GroupbyNode other = (GroupbyNode) obj;
boolean eq = super.equals(other);
eq = eq && TUtil.checkEquals(columns, other.columns);
- eq = eq && TUtil.checkEquals(havingCondition, other.havingCondition);
eq = eq && TUtil.checkEquals(targets, other.targets);
return eq;
} else {
@@ -149,8 +121,7 @@ public class GroupbyNode extends UnaryNode implements Projectable, Cloneable {
grp.columns[i] = (Column) columns[i].clone();
}
}
- grp.havingCondition = (EvalNode) (havingCondition != null
- ? havingCondition.clone() : null);
+
if (targets != null) {
grp.targets = new Target[targets.length];
for (int i = 0; i < targets.length; i++) {
@@ -183,7 +154,7 @@ public class GroupbyNode extends UnaryNode implements Projectable, Cloneable {
for (int i = 0; i < targets.length; i++) {
sb.append(targets[i]);
if( i < targets.length - 1) {
- sb.append(",");
+ sb.append(", ");
}
}
planStr.addExplan(sb.toString());
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/HavingNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/HavingNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/HavingNode.java
new file mode 100644
index 0000000..f4eafd0
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/HavingNode.java
@@ -0,0 +1,73 @@
+/**
+ * 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.logical;
+
+import com.google.gson.annotations.Expose;
+import org.apache.tajo.engine.eval.EvalNode;
+import org.apache.tajo.engine.planner.PlanString;
+
+public class HavingNode extends UnaryNode implements Cloneable {
+ @Expose private EvalNode qual;
+
+ public HavingNode(int pid) {
+ super(pid, NodeType.HAVING);
+ }
+
+ public EvalNode getQual() {
+ return this.qual;
+ }
+
+ public void setQual(EvalNode qual) {
+ this.qual = qual;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof HavingNode) {
+ HavingNode other = (HavingNode) obj;
+ return super.equals(other)
+ && this.qual.equals(other.qual);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ HavingNode selNode = (HavingNode) super.clone();
+ selNode.qual = (EvalNode) this.qual.clone();
+
+ return selNode;
+ }
+
+ @Override
+ public PlanString getPlanString() {
+ return new PlanString("Having: ").appendTitle(qual.toString());
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("\"Having\": {\"qual\": \"").append(qual.toString()).append("\",");
+ sb.append("\n \"out schema\": ").append(getOutSchema()).append(",");
+ sb.append("\n \"in schema\": ").append(getInSchema()).append("}");
+
+ return sb.toString()+"\n"
+ + getChild().toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/IndexScanNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/IndexScanNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/IndexScanNode.java
index 7272630..e82cc3e 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/IndexScanNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/IndexScanNode.java
@@ -35,7 +35,6 @@ public class IndexScanNode extends ScanNode {
super(pid, scanNode.getTableDesc());
setQual(scanNode.getQual());
setInSchema(scanNode.getInSchema());
- setOutSchema(scanNode.getOutSchema());
setTargets(scanNode.getTargets());
setType(NodeType.BST_INDEX_SCAN);
this.sortKeys = sortKeys;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/JoinNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/JoinNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/JoinNode.java
index 23a79df..2628c3b 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/JoinNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/JoinNode.java
@@ -25,6 +25,7 @@ import com.google.gson.annotations.Expose;
import org.apache.tajo.algebra.JoinType;
import org.apache.tajo.engine.eval.EvalNode;
import org.apache.tajo.engine.planner.PlanString;
+import org.apache.tajo.engine.planner.PlannerUtil;
import org.apache.tajo.engine.planner.Target;
import org.apache.tajo.util.TUtil;
@@ -87,6 +88,7 @@ public class JoinNode extends BinaryNode implements Projectable, Cloneable {
@Override
public void setTargets(Target[] targets) {
this.targets = targets;
+ this.setOutSchema(PlannerUtil.targetToSchema(targets));
}
@Override
@@ -97,8 +99,21 @@ public class JoinNode extends BinaryNode implements Projectable, Cloneable {
planStr.addExplan("Join Cond: " + joinQual.toString());
}
- planStr.addDetail("in schema: " + getInSchema());
+ if (hasTargets()) {
+ planStr.addExplan("target list: ");
+ boolean first = true;
+ for (Target target : targets) {
+ if (!first) {
+ planStr.appendExplain(", ");
+ }
+ planStr.appendExplain(target.toString());
+ first = false;
+ }
+ }
+
planStr.addDetail("out schema: " + getOutSchema());
+ planStr.addDetail("in schema: " + getInSchema());
+
return planStr;
}
@@ -108,14 +123,8 @@ public class JoinNode extends BinaryNode implements Projectable, Cloneable {
JoinNode other = (JoinNode) obj;
boolean eq = this.joinType.equals(other.joinType);
eq &= TUtil.checkEquals(this.targets, other.targets);
- if (this.joinQual != null && other.joinQual != null) {
- eq &= this.joinQual.equals(other.joinQual);
- } else if (this.joinQual == null && other.joinQual == null) {
-
- } else {
- eq = false;
- }
- return eq;
+ eq &= TUtil.checkEquals(joinQual, other.joinQual);
+ return eq && leftChild.equals(other.leftChild) && rightChild.equals(other.rightChild);
} else {
return false;
}
@@ -126,6 +135,12 @@ public class JoinNode extends BinaryNode implements Projectable, Cloneable {
JoinNode join = (JoinNode) super.clone();
join.joinType = this.joinType;
join.joinQual = this.joinQual == null ? null : (EvalNode) this.joinQual.clone();
+ if (hasTargets()) {
+ join.targets = new Target[targets.length];
+ for (int i = 0; i < targets.length; i++) {
+ join.targets[i] = (Target) targets[i].clone();
+ }
+ }
return join;
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/LimitNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/LimitNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/LimitNode.java
index b604fac..197a5bc 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/LimitNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/LimitNode.java
@@ -24,9 +24,12 @@ import org.apache.tajo.engine.planner.PlanString;
public final class LimitNode extends UnaryNode implements Cloneable {
@Expose private long fetchFirstNum;
- public LimitNode(int pid, long fetchFirstNum) {
+ public LimitNode(int pid) {
super(pid, NodeType.LIMIT);
- this.fetchFirstNum = fetchFirstNum;
+ }
+
+ public void setFetchFirst(long num) {
+ this.fetchFirstNum = num;
}
public long getFetchFirstNum() {
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/NodeType.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/NodeType.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/NodeType.java
index 4c0dd11..32b9bc6 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/NodeType.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/NodeType.java
@@ -32,6 +32,7 @@ public enum NodeType {
PROJECTION(ProjectionNode.class),
LIMIT(LimitNode.class),
SORT(SortNode.class),
+ HAVING(HavingNode.class),
GROUP_BY(GroupbyNode.class),
SELECTION(SelectionNode.class),
JOIN(JoinNode.class),
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/Projectable.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/Projectable.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/Projectable.java
index c2807fe..d72b31e 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/Projectable.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/Projectable.java
@@ -18,10 +18,17 @@
package org.apache.tajo.engine.planner.logical;
+import org.apache.tajo.catalog.Schema;
import org.apache.tajo.engine.planner.Target;
public interface Projectable {
boolean hasTargets();
+
void setTargets(Target[] targets);
+
Target [] getTargets();
+
+ public Schema getInSchema();
+
+ public Schema getOutSchema();
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/ProjectionNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/ProjectionNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/ProjectionNode.java
index 8ef2bda..1a219a6 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/ProjectionNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/ProjectionNode.java
@@ -20,6 +20,7 @@ package org.apache.tajo.engine.planner.logical;
import com.google.gson.annotations.Expose;
import org.apache.tajo.engine.planner.PlanString;
+import org.apache.tajo.engine.planner.PlannerUtil;
import org.apache.tajo.engine.planner.Target;
import org.apache.tajo.util.TUtil;
@@ -32,12 +33,8 @@ public class ProjectionNode extends UnaryNode implements Projectable {
@Expose private Target [] targets;
@Expose private boolean distinct = false;
- /**
- * @param targets they should be all evaluated ones.
- */
- public ProjectionNode(int pid, Target [] targets) {
+ public ProjectionNode(int pid) {
super(pid, NodeType.PROJECTION);
- this.targets = targets;
}
public boolean hasTargets() {
@@ -47,6 +44,7 @@ public class ProjectionNode extends UnaryNode implements Projectable {
@Override
public void setTargets(Target[] targets) {
this.targets = targets;
+ this.setOutSchema(PlannerUtil.targetToSchema(targets));
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/RelationNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/RelationNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/RelationNode.java
index 5ea61b4..8ed247e 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/RelationNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/RelationNode.java
@@ -20,6 +20,16 @@ package org.apache.tajo.engine.planner.logical;
import org.apache.tajo.catalog.Schema;
+/**
+ * It provides a logical view of a relation. Regarding a table, the main difference between a logical view and a
+ * physical view is as follows:
+ *
+ * <ul>
+ * <li>In logical view, each column in the table has qualified name by table alias name. In addition, the schema of
+ * logical view will includes partition columns if we use column-partitioned tables.</li>
+ * <li>In contrast, in physical view: each column in the table has qualified name by the original table.</li>
+ * </ul>
+ */
public abstract class RelationNode extends LogicalNode {
public RelationNode(int pid, NodeType nodeType) {
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/ScanNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/ScanNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/ScanNode.java
index cd9c1f1..165e1e8 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/ScanNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/ScanNode.java
@@ -90,6 +90,7 @@ public class ScanNode extends RelationNode implements Projectable {
@Override
public void setTargets(Target [] targets) {
this.targets = targets;
+ setOutSchema(PlannerUtil.targetToSchema(targets));
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/SelectionNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/SelectionNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/SelectionNode.java
index 699a561..b39ade3 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/SelectionNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/SelectionNode.java
@@ -24,11 +24,10 @@ import org.apache.tajo.engine.planner.PlanString;
public class SelectionNode extends UnaryNode implements Cloneable {
@Expose private EvalNode qual;
-
- public SelectionNode(int pid, EvalNode qual) {
- super(pid, NodeType.SELECTION);
- setQual(qual);
- }
+
+ public SelectionNode(int pid) {
+ super(pid, NodeType.SELECTION);
+ }
public EvalNode getQual() {
return this.qual;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/SortNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/SortNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/SortNode.java
index 46ceea8..00c8485 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/SortNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/SortNode.java
@@ -20,7 +20,6 @@ package org.apache.tajo.engine.planner.logical;
import com.google.common.base.Preconditions;
import com.google.gson.annotations.Expose;
-import org.apache.tajo.catalog.Schema;
import org.apache.tajo.catalog.SortSpec;
import org.apache.tajo.engine.planner.PlanString;
import org.apache.tajo.util.TUtil;
@@ -28,17 +27,13 @@ import org.apache.tajo.util.TUtil;
public final class SortNode extends UnaryNode implements Cloneable {
@Expose private SortSpec [] sortKeys;
- public SortNode(int pid, SortSpec[] sortKeys) {
+ public SortNode(int pid) {
super(pid, NodeType.SORT);
- Preconditions.checkArgument(sortKeys.length > 0,
- "At least one sort key must be specified");
- this.sortKeys = sortKeys;
}
- public SortNode(int pid, SortSpec[] sortKeys, Schema inSchema, Schema outSchema) {
- this(pid, sortKeys);
- this.setInSchema(inSchema);
- this.setOutSchema(outSchema);
+ public void setSortSpecs(SortSpec[] sortSpecs) {
+ Preconditions.checkArgument(sortSpecs.length > 0, "At least one sort key must be specified");
+ this.sortKeys = sortSpecs;
}
public SortSpec[] getSortKeys() {
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/TableSubQueryNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/TableSubQueryNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/TableSubQueryNode.java
index 335d12f..25e5d07 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/TableSubQueryNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/TableSubQueryNode.java
@@ -24,6 +24,7 @@ import org.apache.tajo.catalog.Schema;
import org.apache.tajo.engine.planner.PlanString;
import org.apache.tajo.engine.planner.PlannerUtil;
import org.apache.tajo.engine.planner.Target;
+import org.apache.tajo.util.TUtil;
public class TableSubQueryNode extends RelationNode implements Projectable {
@Expose private String tableName;
@@ -33,10 +34,13 @@ public class TableSubQueryNode extends RelationNode implements Projectable {
public TableSubQueryNode(int pid, String tableName, LogicalNode subQuery) {
super(pid, NodeType.TABLE_SUBQUERY);
this.tableName = PlannerUtil.normalizeTableName(tableName);
- this.subQuery = subQuery;
- setOutSchema((Schema) this.subQuery.getOutSchema().clone());
- getOutSchema().setQualifier(this.tableName);
- setInSchema((Schema) this.subQuery.getInSchema().clone());
+ if (subQuery != null) {
+ this.subQuery = subQuery;
+ setOutSchema((Schema) this.subQuery.getOutSchema().clone());
+ setInSchema((Schema) this.subQuery.getOutSchema().clone());
+ getInSchema().setQualifier(this.tableName);
+ getOutSchema().setQualifier(this.tableName);
+ }
}
public String getTableName() {
@@ -55,7 +59,10 @@ public class TableSubQueryNode extends RelationNode implements Projectable {
public void setSubQuery(LogicalNode node) {
this.subQuery = node;
- setInSchema(subQuery.getInSchema());
+ setInSchema((Schema) this.subQuery.getOutSchema().clone());
+ getInSchema().setQualifier(this.tableName);
+ setOutSchema((Schema) this.subQuery.getOutSchema().clone());
+ getOutSchema().setQualifier(this.tableName);
}
public LogicalNode getSubQuery() {
@@ -70,6 +77,7 @@ public class TableSubQueryNode extends RelationNode implements Projectable {
@Override
public void setTargets(Target[] targets) {
this.targets = targets;
+ setOutSchema(PlannerUtil.targetToSchema(targets));
}
@Override
@@ -81,6 +89,24 @@ public class TableSubQueryNode extends RelationNode implements Projectable {
public PlanString getPlanString() {
PlanString planStr = new PlanString("TablePrimarySubQuery");
planStr.appendTitle(" as ").appendTitle(tableName);
+
+ if (hasTargets()) {
+ StringBuilder sb = new StringBuilder("Targets: ");
+ for (int i = 0; i < targets.length; i++) {
+ sb.append(targets[i]);
+ if( i < targets.length - 1) {
+ sb.append(", ");
+ }
+ }
+ planStr.addExplan(sb.toString());
+ if (getOutSchema() != null) {
+ planStr.addExplan("out schema: " + getOutSchema().toString());
+ }
+ if (getInSchema() != null) {
+ planStr.addExplan("in schema: " + getInSchema().toString());
+ }
+ }
+
return planStr;
}
@@ -103,6 +129,13 @@ public class TableSubQueryNode extends RelationNode implements Projectable {
public Object clone() throws CloneNotSupportedException {
TableSubQueryNode newTableSubQueryNode = (TableSubQueryNode) super.clone();
newTableSubQueryNode.tableName = tableName;
+ newTableSubQueryNode.subQuery = (LogicalNode) subQuery.clone();
+ if (hasTargets()) {
+ newTableSubQueryNode.targets = new Target[targets.length];
+ for (int i = 0; i < targets.length; i++) {
+ newTableSubQueryNode.targets[i] = (Target) targets[i].clone();
+ }
+ }
return newTableSubQueryNode;
}
@@ -119,6 +152,14 @@ public class TableSubQueryNode extends RelationNode implements Projectable {
}
public String toString() {
- return "(" + getPID() + ") Table Subquery (alias = " + tableName + ")\n" + subQuery.toString();
+ StringBuilder sb = new StringBuilder();
+ sb.append("(").append(getPID()).append(") Table Subquery (alias=").append(tableName).append(")\n");
+ if (hasTargets()) {
+ sb.append(" targets: ").append(TUtil.arrayToString(targets)).append("\n");
+ }
+ sb.append(" out schema:").append(getOutSchema()).append("\n");
+ sb.append(" input schema:").append(getInSchema()).append("\n");
+ sb.append(subQuery.toString());
+ return sb.toString();
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/UnionNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/UnionNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/UnionNode.java
index d0e8b02..56ca146 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/UnionNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/UnionNode.java
@@ -25,19 +25,13 @@ import org.apache.tajo.engine.planner.PlanString;
public class UnionNode extends BinaryNode {
- public UnionNode(int pid, LogicalNode outer, LogicalNode inner) {
+ public UnionNode(int pid) {
super(pid, NodeType.UNION);
- setLeftChild(outer);
- setRightChild(inner);
}
-
@Override
public PlanString getPlanString() {
PlanString planStr = new PlanString("Union");
- planStr.appendTitle(" (L - " + ((TableSubQueryNode)getLeftChild()).getTableName());
- planStr.appendTitle(", R - " + ((TableSubQueryNode)getRightChild()).getTableName());
- planStr.appendTitle(")");
return planStr;
}