You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tajo.apache.org by hj...@apache.org on 2014/10/26 20:27:32 UTC
[26/35] TAJO-1125: Separate logical plan and optimizer into a maven
module.
http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-core/src/main/java/org/apache/tajo/engine/planner/LogicalPlan.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/LogicalPlan.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/LogicalPlan.java
deleted file mode 100644
index 1cbe87a..0000000
--- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/LogicalPlan.java
+++ /dev/null
@@ -1,682 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.tajo.engine.planner;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import org.apache.commons.lang.ObjectUtils;
-import org.apache.tajo.algebra.*;
-import org.apache.tajo.annotation.NotThreadSafe;
-import org.apache.tajo.catalog.Column;
-import org.apache.tajo.catalog.Schema;
-import org.apache.tajo.engine.eval.ConstEval;
-import org.apache.tajo.engine.eval.EvalNode;
-import org.apache.tajo.engine.planner.graph.DirectedGraphCursor;
-import org.apache.tajo.engine.planner.graph.SimpleDirectedGraph;
-import org.apache.tajo.engine.planner.logical.LogicalNode;
-import org.apache.tajo.engine.planner.logical.LogicalRootNode;
-import org.apache.tajo.engine.planner.logical.NodeType;
-import org.apache.tajo.engine.planner.logical.RelationNode;
-import org.apache.tajo.engine.planner.nameresolver.NameResolvingMode;
-import org.apache.tajo.engine.planner.nameresolver.NameResolver;
-import org.apache.tajo.util.TUtil;
-
-import java.lang.reflect.Constructor;
-import java.util.*;
-
-/**
- * This represents and keeps every information about a query plan for a query.
- */
-@NotThreadSafe
-public class LogicalPlan {
- /** the prefix character for virtual tables */
- public static final char VIRTUAL_TABLE_PREFIX='#';
- public static final char NONAMED_COLUMN_PREFIX='?';
-
- /** it indicates the root block */
- public static final String ROOT_BLOCK = VIRTUAL_TABLE_PREFIX + "ROOT";
- public static final String NONAME_BLOCK_PREFIX = VIRTUAL_TABLE_PREFIX + "QB_";
- private static final int NO_SEQUENCE_PID = -1;
- private int nextPid = 0;
- private Integer noNameBlockId = 0;
- private Integer noNameColumnId = 0;
-
- /** a map from between a block name to a block plan */
- private Map<String, QueryBlock> queryBlocks = new LinkedHashMap<String, QueryBlock>();
- private Map<Integer, LogicalNode> nodeMap = new HashMap<Integer, LogicalNode>();
- private Map<Integer, QueryBlock> queryBlockByPID = new HashMap<Integer, QueryBlock>();
- private Map<String, String> exprToBlockNameMap = TUtil.newHashMap();
- private SimpleDirectedGraph<String, BlockEdge> queryBlockGraph = new SimpleDirectedGraph<String, BlockEdge>();
-
- /** planning and optimization log */
- private List<String> planingHistory = Lists.newArrayList();
- LogicalPlanner planner;
-
- private boolean isExplain;
-
- public LogicalPlan(LogicalPlanner planner) {
- this.planner = planner;
- }
-
- /**
- * Create a LogicalNode instance for a type. Each a LogicalNode instance is given an unique plan node id (PID).
- *
- * @param theClass The class to be created
- * @return a LogicalNode instance identified by an unique plan node id (PID).
- */
- public <T extends LogicalNode> T createNode(Class<T> theClass) {
- try {
- Constructor<T> ctor = theClass.getConstructor(int.class);
- return ctor.newInstance(newPID());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Create a LogicalNode instance for a type. Each a LogicalNode instance is not given an unique plan node id (PID).
- * This method must be only used after all query planning and optimization phases.
- *
- * @param theClass The class to be created
- * @return a LogicalNode instance
- */
- public static <T extends LogicalNode> T createNodeWithoutPID(Class<T> theClass) {
- try {
- Constructor<T> ctor = theClass.getConstructor(int.class);
- return ctor.newInstance(NO_SEQUENCE_PID);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- public void setExplain() {
- isExplain = true;
- }
-
- public boolean isExplain() {
- return isExplain;
- }
-
- /**
- * Create a new {@link QueryBlock} and Get
- *
- * @param blockName the query block name
- * @return a created query block
- */
- public QueryBlock newAndGetBlock(String blockName) {
- QueryBlock block = new QueryBlock(blockName);
- queryBlocks.put(blockName, block);
- return block;
- }
-
- public int newPID() {
- return nextPid++;
- }
-
- public QueryBlock newQueryBlock() {
- return newAndGetBlock(NONAME_BLOCK_PREFIX + (noNameBlockId++));
- }
-
- public void resetGeneratedId() {
- noNameColumnId = 0;
- }
-
- /**
- * It generates an unique column name from EvalNode. It is usually used for an expression or predicate without
- * a specified name (i.e., alias).
- */
- public String generateUniqueColumnName(EvalNode evalNode) {
- String prefix = evalNode.getName();
- return attachSeqIdToGeneratedColumnName(prefix).toLowerCase();
- }
-
- /**
- * It generates an unique column name from Expr. It is usually used for an expression or predicate without
- * a specified name (i.e., alias).
- */
- public String generateUniqueColumnName(Expr expr) {
- String generatedName;
- if (expr.getType() == OpType.Column) {
- generatedName = ((ColumnReferenceExpr) expr).getCanonicalName();
- } else { // if a generated column name
- generatedName = attachSeqIdToGeneratedColumnName(getGeneratedPrefixFromExpr(expr));
- }
- return generatedName;
- }
-
- /**
- * It attaches a generated column name with a sequence id. It always keeps generated names unique.
- */
- private String attachSeqIdToGeneratedColumnName(String prefix) {
- int sequence = noNameColumnId++;
- return NONAMED_COLUMN_PREFIX + prefix.toLowerCase() + (sequence > 0 ? "_" + sequence : "");
- }
-
- /**
- * It generates a column reference prefix name. It is usually used for an expression or predicate without
- * a specified name (i.e., alias). For example, a predicate in WHERE does not have any alias name.
- * It just returns a prefix name. In other words, it always returns the same prefix for the same type of expressions.
- * So, you must add some suffix to the returned name in order to distinguish reference names.
- */
- private static String getGeneratedPrefixFromExpr(Expr expr) {
- String prefix;
-
- switch (expr.getType()) {
- case Column:
- prefix = ((ColumnReferenceExpr) expr).getCanonicalName();
- break;
- case CountRowsFunction:
- prefix = "count";
- break;
- case GeneralSetFunction:
- GeneralSetFunctionExpr setFunction = (GeneralSetFunctionExpr) expr;
- prefix = setFunction.getSignature();
- break;
- case Function:
- FunctionExpr function = (FunctionExpr) expr;
- prefix = function.getSignature();
- break;
- case Literal:
- LiteralValue literal = (LiteralValue) expr;
- switch (literal.getValueType()) {
- case Boolean:
- prefix = "bool";
- break;
- case String:
- prefix = "text";
- break;
- case Unsigned_Integer:
- case Unsigned_Large_Integer:
- prefix = "number";
- break;
- case Unsigned_Float:
- prefix = "real";
- break;
- default:
- throw new IllegalStateException(literal.getValueType() + " is not implemented");
- }
- break;
- case DateLiteral:
- prefix = "date";
- break;
- case TimeLiteral:
- prefix = "time";
- break;
- case TimestampLiteral:
- prefix = "timestamp";
- break;
- default:
- prefix = expr.getType().name();
- }
- return prefix;
- }
-
- public QueryBlock getRootBlock() {
- return queryBlocks.get(ROOT_BLOCK);
- }
-
- public QueryBlock getBlock(String blockName) {
- return queryBlocks.get(blockName);
- }
-
- public QueryBlock getBlock(LogicalNode node) {
- return queryBlockByPID.get(node.getPID());
- }
-
- public void removeBlock(QueryBlock block) {
- queryBlocks.remove(block.getName());
- List<Integer> tobeRemoved = new ArrayList<Integer>();
- for (Map.Entry<Integer, QueryBlock> entry : queryBlockByPID.entrySet()) {
- tobeRemoved.add(entry.getKey());
- }
- for (Integer rn : tobeRemoved) {
- queryBlockByPID.remove(rn);
- }
- }
-
- public void disconnectBlocks(QueryBlock srcBlock, QueryBlock targetBlock) {
- queryBlockGraph.removeEdge(srcBlock.getName(), targetBlock.getName());
- }
-
- public void connectBlocks(QueryBlock srcBlock, QueryBlock targetBlock, BlockType type) {
- queryBlockGraph.addEdge(srcBlock.getName(), targetBlock.getName(), new BlockEdge(srcBlock, targetBlock, type));
- }
-
- public QueryBlock getParentBlock(QueryBlock block) {
- return queryBlocks.get(queryBlockGraph.getParent(block.getName(), 0));
- }
-
- public List<QueryBlock> getChildBlocks(QueryBlock block) {
- List<QueryBlock> childBlocks = TUtil.newList();
- for (String blockName : queryBlockGraph.getChilds(block.getName())) {
- childBlocks.add(queryBlocks.get(blockName));
- }
- return childBlocks;
- }
-
- public void mapExprToBlock(Expr expr, String blockName) {
- exprToBlockNameMap.put(ObjectUtils.identityToString(expr), blockName);
- }
-
- public QueryBlock getBlockByExpr(Expr expr) {
- return getBlock(exprToBlockNameMap.get(ObjectUtils.identityToString(expr)));
- }
-
- public String getBlockNameByExpr(Expr expr) {
- return exprToBlockNameMap.get(ObjectUtils.identityToString(expr));
- }
-
- public Collection<QueryBlock> getQueryBlocks() {
- return queryBlocks.values();
- }
-
- public SimpleDirectedGraph<String, BlockEdge> getQueryBlockGraph() {
- return queryBlockGraph;
- }
-
- public Column resolveColumn(QueryBlock block, ColumnReferenceExpr columnRef) throws PlanningException {
- return NameResolver.resolve(this, block, columnRef, NameResolvingMode.LEGACY);
- }
-
- public String getQueryGraphAsString() {
- StringBuilder sb = new StringBuilder();
-
- sb.append("\n-----------------------------\n");
- sb.append("Query Block Graph\n");
- sb.append("-----------------------------\n");
- sb.append(queryBlockGraph.toStringGraph(getRootBlock().getName()));
- sb.append("-----------------------------\n");
- sb.append("Optimization Log:\n");
- if (!planingHistory.isEmpty()) {
- sb.append("[LogicalPlan]\n");
- for (String eachHistory: planingHistory) {
- sb.append("\t> ").append(eachHistory).append("\n");
- }
- }
- DirectedGraphCursor<String, BlockEdge> cursor =
- new DirectedGraphCursor<String, BlockEdge>(queryBlockGraph, getRootBlock().getName());
- while(cursor.hasNext()) {
- QueryBlock block = getBlock(cursor.nextBlock());
- if (block.getPlanHistory().size() > 0) {
- sb.append("[").append(block.getName()).append("]\n");
- for (String log : block.getPlanHistory()) {
- sb.append("\t> ").append(log).append("\n");
- }
- }
- }
- sb.append("-----------------------------\n");
- sb.append("\n");
-
- sb.append(getLogicalPlanAsString());
-
- return sb.toString();
- }
-
- public String getLogicalPlanAsString() {
- ExplainLogicalPlanVisitor explain = new ExplainLogicalPlanVisitor();
-
- StringBuilder explains = new StringBuilder();
- try {
- ExplainLogicalPlanVisitor.Context explainContext = explain.getBlockPlanStrings(this, getRootBlock().getRoot());
- while(!explainContext.explains.empty()) {
- explains.append(
- ExplainLogicalPlanVisitor.printDepthString(explainContext.getMaxDepth(), explainContext.explains.pop()));
- }
- } catch (PlanningException e) {
- throw new RuntimeException(e);
- }
-
- return explains.toString();
- }
-
- public void addHistory(String string) {
- planingHistory.add(string);
- }
-
- public List<String> getHistory() {
- return planingHistory;
- }
-
- @Override
- public String toString() {
- return getQueryGraphAsString();
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // Query Block
- ///////////////////////////////////////////////////////////////////////////
-
- public static enum BlockType {
- TableSubQuery,
- ScalarSubQuery
- }
-
- public static class BlockEdge {
- private String childName;
- private String parentName;
- private BlockType blockType;
-
-
- public BlockEdge(String childName, String parentName, BlockType blockType) {
- this.childName = childName;
- this.parentName = parentName;
- this.blockType = blockType;
- }
-
- public BlockEdge(QueryBlock child, QueryBlock parent, BlockType blockType) {
- this(child.getName(), parent.getName(), blockType);
- }
-
- public String getParentName() {
- return parentName;
- }
-
- public String getChildName() {
- return childName;
- }
-
- public BlockType getBlockType() {
- return blockType;
- }
- }
-
- public class QueryBlock {
- private final String blockName;
- private LogicalNode rootNode;
- private NodeType rootType;
-
- // transient states
- private final Map<String, RelationNode> canonicalNameToRelationMap = TUtil.newHashMap();
- private final Map<String, List<String>> relationAliasMap = TUtil.newHashMap();
- private final Map<String, String> columnAliasMap = TUtil.newHashMap();
- private final Map<OpType, List<Expr>> operatorToExprMap = TUtil.newHashMap();
- private final List<RelationNode> relationList = TUtil.newList();
- private boolean hasWindowFunction = false;
- private final Map<String, ConstEval> constantPoolByRef = Maps.newHashMap();
- private final Map<Expr, String> constantPool = Maps.newHashMap();
-
- /**
- * It's a map between nodetype and node. node types can be duplicated. So, latest node type is only kept.
- */
- private final Map<NodeType, LogicalNode> nodeTypeToNodeMap = TUtil.newHashMap();
- private final Map<String, LogicalNode> exprToNodeMap = TUtil.newHashMap();
- final NamedExprsManager namedExprsMgr;
-
- private LogicalNode currentNode;
- private LogicalNode latestNode;
- private final Set<JoinType> includedJoinTypes = TUtil.newHashSet();
- /**
- * Set true value if this query block has either implicit or explicit aggregation.
- */
- private boolean aggregationRequired = false;
- private Schema schema;
-
- /** It contains a planning log for this block */
- private final List<String> planingHistory = Lists.newArrayList();
- /** It is for debugging or unit tests */
- private Target [] rawTargets;
-
- public QueryBlock(String blockName) {
- this.blockName = blockName;
- this.namedExprsMgr = new NamedExprsManager(LogicalPlan.this, this);
- }
-
- public String getName() {
- return blockName;
- }
-
- public void refresh() {
- setRoot(rootNode);
- }
-
- public void setRoot(LogicalNode blockRoot) {
- this.rootNode = blockRoot;
- if (blockRoot instanceof LogicalRootNode) {
- LogicalRootNode rootNode = (LogicalRootNode) blockRoot;
- rootType = rootNode.getChild().getType();
- }
- }
-
- public <NODE extends LogicalNode> NODE getRoot() {
- return (NODE) rootNode;
- }
-
- public NodeType getRootType() {
- return rootType;
- }
-
- public Target [] getRawTargets() {
- return rawTargets;
- }
-
- public void setRawTargets(Target[] rawTargets) {
- this.rawTargets = rawTargets;
- }
-
- public boolean existsRelation(String name) {
- return canonicalNameToRelationMap.containsKey(name);
- }
-
- public boolean isAlreadyRenamedTableName(String name) {
- return relationAliasMap.containsKey(name);
- }
-
- public RelationNode getRelation(String name) {
- if (canonicalNameToRelationMap.containsKey(name)) {
- return canonicalNameToRelationMap.get(name);
- }
-
- if (relationAliasMap.containsKey(name)) {
- return canonicalNameToRelationMap.get(relationAliasMap.get(name).get(0));
- }
-
- return null;
- }
-
- public void addRelation(RelationNode relation) {
- if (relation.hasAlias()) {
- TUtil.putToNestedList(relationAliasMap, relation.getTableName(), relation.getCanonicalName());
- }
- canonicalNameToRelationMap.put(relation.getCanonicalName(), relation);
- relationList.add(relation);
- }
-
- public Collection<RelationNode> getRelations() {
- return Collections.unmodifiableList(relationList);
- }
-
- public boolean hasTableExpression() {
- return this.canonicalNameToRelationMap.size() > 0;
- }
-
- public void addConstReference(String refName, Expr expr, ConstEval value) {
- constantPoolByRef.put(refName, value);
- constantPool.put(expr, refName);
- }
-
- public boolean isConstReference(String refName) {
- return constantPoolByRef.containsKey(refName);
- }
-
- public boolean isRegisteredConst(Expr expr) {
- return constantPool.containsKey(expr);
- }
-
- public String getConstReference(Expr expr) {
- return constantPool.get(expr);
- }
-
- public ConstEval getConstByReference(String refName) {
- return constantPoolByRef.get(refName);
- }
-
- public void addColumnAlias(String original, String alias) {
- columnAliasMap.put(alias, original);
- }
-
- public boolean isAliasedName(String alias) {
- return columnAliasMap.containsKey(alias);
- }
-
- public String getOriginalName(String alias) {
- return columnAliasMap.get(alias);
- }
-
- public void setSchema(Schema schema) {
- this.schema = schema;
- }
-
- public Schema getSchema() {
- return schema;
- }
-
- public NamedExprsManager getNamedExprsManager() {
- return namedExprsMgr;
- }
-
- public void updateCurrentNode(Expr expr) throws PlanningException {
-
- if (expr.getType() != OpType.RelationList) { // skip relation list because it is a virtual expr.
- this.currentNode = exprToNodeMap.get(ObjectUtils.identityToString(expr));
- if (currentNode == null) {
- throw new PlanningException("Unregistered Algebra Expression: " + expr.getType());
- }
- }
- }
-
- @SuppressWarnings("unchecked")
- public <T extends LogicalNode> T getCurrentNode() {
- return (T) this.currentNode;
- }
-
- public void updateLatestNode(LogicalNode node) {
- this.latestNode = node;
- }
-
- public <T extends LogicalNode> T getLatestNode() {
- return (T) this.latestNode;
- }
-
- public void setAlgebraicExpr(Expr expr) {
- TUtil.putToNestedList(operatorToExprMap, expr.getType(), expr);
- }
-
- public boolean hasAlgebraicExpr(OpType opType) {
- return operatorToExprMap.containsKey(opType);
- }
-
- public <T extends Expr> List<T> getAlgebraicExpr(OpType opType) {
- return (List<T>) operatorToExprMap.get(opType);
- }
-
- public <T extends Expr> T getSingletonExpr(OpType opType) {
- if (hasAlgebraicExpr(opType)) {
- return (T) operatorToExprMap.get(opType).get(0);
- } else {
- return null;
- }
- }
-
- public boolean hasNode(NodeType nodeType) {
- return nodeTypeToNodeMap.containsKey(nodeType);
- }
-
- public void registerNode(LogicalNode node) {
- // id -> node
- nodeMap.put(node.getPID(), node);
-
- // So, this is only for filter, groupby, sort, limit, projection, which exists once at a query block.
- nodeTypeToNodeMap.put(node.getType(), node);
-
- queryBlockByPID.put(node.getPID(), this);
- }
-
- public void unregisterNode(LogicalNode node) {
- nodeMap.remove(node.getPID());
- nodeTypeToNodeMap.remove(node.getType());
- queryBlockByPID.remove(node.getPID());
- }
-
- @SuppressWarnings("unchecked")
- public <T extends LogicalNode> T getNode(NodeType nodeType) {
- return (T) nodeTypeToNodeMap.get(nodeType);
- }
-
- // expr -> node
- public void registerExprWithNode(Expr expr, LogicalNode node) {
- exprToNodeMap.put(ObjectUtils.identityToString(expr), node);
- }
-
- public <T extends LogicalNode> T getNodeFromExpr(Expr expr) {
- return (T) exprToNodeMap.get(ObjectUtils.identityToString(expr));
- }
-
- public void setHasWindowFunction() {
- hasWindowFunction = true;
- }
-
- public boolean hasWindowSpecs() {
- return hasWindowFunction;
- }
-
- /**
- * This flag can be changed as a plan is generated.
- *
- * True value means that this query should have aggregation phase. If aggregation plan is added to this block,
- * it becomes false because it doesn't need aggregation phase anymore. It is usually used to add aggregation
- * phase from SELECT statement without group-by clause.
- *
- * @return True if aggregation is needed but this query hasn't had aggregation phase.
- */
- public boolean isAggregationRequired() {
- return this.aggregationRequired;
- }
-
- /**
- * Unset aggregation required flag. It has to be called after an aggregation phase is added to this block.
- */
- public void unsetAggregationRequire() {
- this.aggregationRequired = false;
- }
-
- public void setAggregationRequire() {
- aggregationRequired = true;
- }
-
- public boolean containsJoinType(JoinType joinType) {
- return includedJoinTypes.contains(joinType);
- }
-
- public void addJoinType(JoinType joinType) {
- includedJoinTypes.add(joinType);
- }
-
- public List<String> getPlanHistory() {
- return planingHistory;
- }
-
- public void addPlanHistory(String history) {
- this.planingHistory.add(history);
- }
-
- public String toString() {
- return blockName;
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-core/src/main/java/org/apache/tajo/engine/planner/LogicalPlanPreprocessor.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/LogicalPlanPreprocessor.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/LogicalPlanPreprocessor.java
deleted file mode 100644
index 9338979..0000000
--- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/LogicalPlanPreprocessor.java
+++ /dev/null
@@ -1,501 +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 org.apache.tajo.catalog.*;
-import org.apache.tajo.common.TajoDataTypes;
-import org.apache.tajo.engine.eval.ConstEval;
-import org.apache.tajo.engine.eval.EvalNode;
-import org.apache.tajo.engine.eval.FieldEval;
-import org.apache.tajo.engine.exception.NoSuchColumnException;
-import org.apache.tajo.engine.planner.LogicalPlan.QueryBlock;
-import org.apache.tajo.engine.planner.logical.*;
-import org.apache.tajo.engine.planner.nameresolver.NameResolver;
-import org.apache.tajo.engine.planner.nameresolver.NameResolvingMode;
-import org.apache.tajo.engine.utils.SchemaUtil;
-import org.apache.tajo.util.TUtil;
-
-import java.util.*;
-
-/**
- * It finds all relations for each block and builds base schema information.
- */
-public class LogicalPlanPreprocessor extends BaseAlgebraVisitor<LogicalPlanner.PlanContext, LogicalNode> {
- private TypeDeterminant typeDeterminant;
- private ExprAnnotator annotator;
-
- /** Catalog service */
- private CatalogService catalog;
-
- LogicalPlanPreprocessor(CatalogService catalog, ExprAnnotator annotator) {
- this.catalog = catalog;
- this.annotator = annotator;
- this.typeDeterminant = new TypeDeterminant(catalog);
- }
-
- @Override
- public void preHook(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, Expr expr) throws PlanningException {
- ctx.queryBlock.setAlgebraicExpr(expr);
- ctx.plan.mapExprToBlock(expr, ctx.queryBlock.getName());
- }
-
- @Override
- public LogicalNode postHook(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, Expr expr, LogicalNode result)
- throws PlanningException {
- // If non-from statement, result can be null. It avoids that case.
- if (result != null) {
- // setNode method registers each node to corresponding block and plan.
- ctx.queryBlock.registerNode(result);
- // It makes a map between an expr and a logical node.
- ctx.queryBlock.registerExprWithNode(expr, result);
- }
- return result;
- }
-
- /**
- * Get all columns of the relations correspondent to the asterisk expression.
- * @param ctx
- * @param asteriskExpr
- * @return array of columns
- * @throws PlanningException
- */
- public static Column[] getColumns(LogicalPlanner.PlanContext ctx, QualifiedAsteriskExpr asteriskExpr)
- throws PlanningException {
- RelationNode relationOp = null;
- QueryBlock block = ctx.queryBlock;
- Collection<QueryBlock> queryBlocks = ctx.plan.getQueryBlocks();
- if (asteriskExpr.hasQualifier()) {
- String qualifier;
-
- if (CatalogUtil.isFQTableName(asteriskExpr.getQualifier())) {
- qualifier = asteriskExpr.getQualifier();
- } else {
- qualifier = CatalogUtil.buildFQName(ctx.queryContext.getCurrentDatabase(), asteriskExpr.getQualifier());
- }
-
- relationOp = block.getRelation(qualifier);
-
- // if a column name is outside of this query block
- if (relationOp == null) {
- // TODO - nested query can only refer outer query block? or not?
- for (QueryBlock eachBlock : queryBlocks) {
- if (eachBlock.existsRelation(qualifier)) {
- relationOp = eachBlock.getRelation(qualifier);
- }
- }
- }
-
- // If we cannot find any relation against a qualified column name
- if (relationOp == null) {
- throw new NoSuchColumnException(CatalogUtil.buildFQName(qualifier, "*"));
- }
-
- Schema schema = relationOp.getTableSchema();
- Column[] resolvedColumns = new Column[schema.size()];
- return schema.getColumns().toArray(resolvedColumns);
- } else { // if a column reference is not qualified
- // columns of every relation should be resolved.
- Iterator<RelationNode> iterator = block.getRelations().iterator();
- Schema schema;
- List<Column> resolvedColumns = TUtil.newList();
-
- while (iterator.hasNext()) {
- relationOp = iterator.next();
- schema = relationOp.getTableSchema();
- resolvedColumns.addAll(schema.getColumns());
- }
-
- if (resolvedColumns.size() == 0) {
- throw new NoSuchColumnException(asteriskExpr.toString());
- }
-
- return resolvedColumns.toArray(new Column[resolvedColumns.size()]);
- }
- }
-
- /**
- * Resolve an asterisk expression to the real column reference expressions.
- * @param ctx context
- * @param asteriskExpr asterisk expression
- * @return a list of NamedExpr each of which has ColumnReferenceExprs as its child
- * @throws PlanningException
- */
- private static List<NamedExpr> resolveAsterisk(LogicalPlanner.PlanContext ctx, QualifiedAsteriskExpr asteriskExpr)
- throws PlanningException {
- Column[] columns = getColumns(ctx, asteriskExpr);
- List<NamedExpr> newTargetExprs = new ArrayList<NamedExpr>(columns.length);
- int i;
- for (i = 0; i < columns.length; i++) {
- newTargetExprs.add(new NamedExpr(new ColumnReferenceExpr(columns[i].getQualifier(), columns[i].getSimpleName())));
- }
- return newTargetExprs;
- }
-
- private static boolean hasAsterisk(NamedExpr [] namedExprs) {
- for (NamedExpr eachTarget : namedExprs) {
- if (eachTarget.getExpr().getType() == OpType.Asterisk) {
- return true;
- }
- }
- return false;
- }
-
- private static NamedExpr [] voidResolveAsteriskNamedExpr(LogicalPlanner.PlanContext context,
- NamedExpr [] namedExprs) throws PlanningException {
- List<NamedExpr> rewrittenTargets = TUtil.newList();
- for (NamedExpr originTarget : namedExprs) {
- if (originTarget.getExpr().getType() == OpType.Asterisk) {
- // rewrite targets
- rewrittenTargets.addAll(resolveAsterisk(context, (QualifiedAsteriskExpr) originTarget.getExpr()));
- } else {
- rewrittenTargets.add(originTarget);
- }
- }
- return rewrittenTargets.toArray(new NamedExpr[rewrittenTargets.size()]);
- }
-
- @Override
- public LogicalNode visitProjection(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, Projection expr)
- throws PlanningException {
- // If Non-from statement, it immediately returns.
- if (!expr.hasChild()) {
- EvalExprNode exprNode = ctx.plan.createNode(EvalExprNode.class);
- exprNode.setTargets(buildTargets(ctx, expr.getNamedExprs()));
- return exprNode;
- }
-
- stack.push(expr); // <--- push
- LogicalNode child = visit(ctx, stack, expr.getChild());
-
- // Resolve the asterisk expression
- if (hasAsterisk(expr.getNamedExprs())) {
- expr.setNamedExprs(voidResolveAsteriskNamedExpr(ctx, expr.getNamedExprs()));
- }
-
- NamedExpr[] projectTargetExprs = expr.getNamedExprs();
- for (int i = 0; i < expr.getNamedExprs().length; i++) {
- NamedExpr namedExpr = projectTargetExprs[i];
-
- // 1) Normalize all field names occured in each expr into full qualified names
- NameRefInSelectListNormalizer.normalize(ctx, namedExpr.getExpr());
-
- // 2) Register explicit column aliases to block
- if (namedExpr.getExpr().getType() == OpType.Column && namedExpr.hasAlias()) {
- ctx.queryBlock.addColumnAlias(((ColumnReferenceExpr)namedExpr.getExpr()).getCanonicalName(),
- namedExpr.getAlias());
- } else if (OpType.isLiteralType(namedExpr.getExpr().getType()) && namedExpr.hasAlias()) {
- Expr constExpr = namedExpr.getExpr();
- ConstEval constEval = (ConstEval) annotator.createEvalNode(ctx, constExpr, NameResolvingMode.RELS_ONLY);
- ctx.queryBlock.addConstReference(namedExpr.getAlias(), constExpr, constEval);
- }
- }
-
- Target [] targets = buildTargets(ctx, expr.getNamedExprs());
-
- stack.pop(); // <--- Pop
-
- ProjectionNode projectionNode = ctx.plan.createNode(ProjectionNode.class);
- projectionNode.setInSchema(child.getOutSchema());
- projectionNode.setOutSchema(PlannerUtil.targetToSchema(targets));
-
- ctx.queryBlock.setSchema(projectionNode.getOutSchema());
- return projectionNode;
- }
-
- private Target [] buildTargets(LogicalPlanner.PlanContext context, NamedExpr [] exprs) throws PlanningException {
- Target [] targets = new Target[exprs.length];
- for (int i = 0; i < exprs.length; i++) {
- NamedExpr namedExpr = exprs[i];
- TajoDataTypes.DataType dataType = typeDeterminant.determineDataType(context, namedExpr.getExpr());
-
- if (namedExpr.hasAlias()) {
- targets[i] = new Target(new FieldEval(new Column(namedExpr.getAlias(), dataType)));
- } else {
- String generatedName = context.plan.generateUniqueColumnName(namedExpr.getExpr());
- targets[i] = new Target(new FieldEval(new Column(generatedName, dataType)));
- }
- }
- return targets;
- }
-
- @Override
- public LogicalNode visitLimit(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, Limit expr)
- throws PlanningException {
- stack.push(expr);
- LogicalNode child = visit(ctx, stack, expr.getChild());
- stack.pop();
-
- LimitNode limitNode = ctx.plan.createNode(LimitNode.class);
- limitNode.setInSchema(child.getOutSchema());
- limitNode.setOutSchema(child.getOutSchema());
- return limitNode;
- }
-
- @Override
- public LogicalNode visitSort(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, Sort expr) throws PlanningException {
- stack.push(expr);
- LogicalNode child = visit(ctx, stack, expr.getChild());
- stack.pop();
-
- SortNode sortNode = ctx.plan.createNode(SortNode.class);
- sortNode.setInSchema(child.getOutSchema());
- sortNode.setOutSchema(child.getOutSchema());
- return sortNode;
- }
-
- @Override
- public LogicalNode visitHaving(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, Having expr)
- throws PlanningException {
- stack.push(expr);
- LogicalNode child = visit(ctx, stack, expr.getChild());
- stack.pop();
-
- HavingNode havingNode = ctx.plan.createNode(HavingNode.class);
- havingNode.setInSchema(child.getOutSchema());
- havingNode.setOutSchema(child.getOutSchema());
- return havingNode;
- }
-
- @Override
- public LogicalNode visitGroupBy(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, Aggregation expr)
- throws PlanningException {
- stack.push(expr); // <--- push
- LogicalNode child = visit(ctx, stack, expr.getChild());
-
- Projection projection = ctx.queryBlock.getSingletonExpr(OpType.Projection);
- int finalTargetNum = projection.getNamedExprs().length;
- Target [] targets = new Target[finalTargetNum];
-
- if (hasAsterisk(projection.getNamedExprs())) {
- projection.setNamedExprs(voidResolveAsteriskNamedExpr(ctx, projection.getNamedExprs()));
- }
-
- for (int i = 0; i < finalTargetNum; i++) {
- NamedExpr namedExpr = projection.getNamedExprs()[i];
- EvalNode evalNode = annotator.createEvalNode(ctx, namedExpr.getExpr(), NameResolvingMode.SUBEXPRS_AND_RELS);
-
- if (namedExpr.hasAlias()) {
- targets[i] = new Target(evalNode, namedExpr.getAlias());
- } else {
- targets[i] = new Target(evalNode, "?name_" + i);
- }
- }
- stack.pop();
-
- GroupbyNode groupByNode = ctx.plan.createNode(GroupbyNode.class);
- groupByNode.setInSchema(child.getOutSchema());
- groupByNode.setOutSchema(PlannerUtil.targetToSchema(targets));
- return groupByNode;
- }
-
- @Override
- public LogicalNode visitUnion(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, SetOperation expr)
- throws PlanningException {
- LogicalPlan.QueryBlock leftBlock = ctx.plan.newQueryBlock();
- LogicalPlanner.PlanContext leftContext = new LogicalPlanner.PlanContext(ctx, leftBlock);
- LogicalNode leftChild = visit(leftContext, new Stack<Expr>(), expr.getLeft());
- leftBlock.setRoot(leftChild);
- ctx.queryBlock.registerExprWithNode(expr.getLeft(), leftChild);
-
- LogicalPlan.QueryBlock rightBlock = ctx.plan.newQueryBlock();
- LogicalPlanner.PlanContext rightContext = new LogicalPlanner.PlanContext(ctx, rightBlock);
- LogicalNode rightChild = visit(rightContext, new Stack<Expr>(), expr.getRight());
- rightBlock.setRoot(rightChild);
- ctx.queryBlock.registerExprWithNode(expr.getRight(), rightChild);
-
- UnionNode unionNode = new UnionNode(ctx.plan.newPID());
- unionNode.setLeftChild(leftChild);
- unionNode.setRightChild(rightChild);
- unionNode.setInSchema(leftChild.getOutSchema());
- unionNode.setOutSchema(leftChild.getOutSchema());
-
- return unionNode;
- }
-
- public LogicalNode visitFilter(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, Selection expr)
- throws PlanningException {
- stack.push(expr);
- LogicalNode child = visit(ctx, stack, expr.getChild());
- stack.pop();
-
- SelectionNode selectionNode = ctx.plan.createNode(SelectionNode.class);
- selectionNode.setInSchema(child.getOutSchema());
- selectionNode.setOutSchema(child.getOutSchema());
- return selectionNode;
- }
-
- @Override
- public LogicalNode visitJoin(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, Join expr) throws PlanningException {
- stack.push(expr);
- LogicalNode left = visit(ctx, stack, expr.getLeft());
- LogicalNode right = visit(ctx, stack, expr.getRight());
- stack.pop();
- JoinNode joinNode = ctx.plan.createNode(JoinNode.class);
- joinNode.setJoinType(expr.getJoinType());
- Schema merged = SchemaUtil.merge(left.getOutSchema(), right.getOutSchema());
- joinNode.setInSchema(merged);
- joinNode.setOutSchema(merged);
-
- ctx.queryBlock.addJoinType(expr.getJoinType());
- return joinNode;
- }
-
- @Override
- public LogicalNode visitRelation(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, Relation expr)
- throws PlanningException {
- Relation relation = expr;
-
- String actualRelationName;
- if (CatalogUtil.isFQTableName(expr.getName())) {
- actualRelationName = relation.getName();
- } else {
- actualRelationName = CatalogUtil.buildFQName(ctx.queryContext.getCurrentDatabase(), relation.getName());
- }
-
- TableDesc desc = catalog.getTableDesc(actualRelationName);
- ScanNode scanNode = ctx.plan.createNode(ScanNode.class);
- if (relation.hasAlias()) {
- scanNode.init(desc, relation.getAlias());
- } else {
- scanNode.init(desc);
- }
- ctx.queryBlock.addRelation(scanNode);
-
- return scanNode;
- }
-
- @Override
- public LogicalNode visitTableSubQuery(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, TablePrimarySubQuery expr)
- throws PlanningException {
-
- LogicalPlanner.PlanContext newContext;
- // Note: TableSubQuery always has a table name.
- // SELECT .... FROM (SELECT ...) TB_NAME <-
- QueryBlock queryBlock = ctx.plan.newQueryBlock();
- newContext = new LogicalPlanner.PlanContext(ctx, queryBlock);
- LogicalNode child = super.visitTableSubQuery(newContext, stack, expr);
- queryBlock.setRoot(child);
-
- // a table subquery should be dealt as a relation.
- TableSubQueryNode node = ctx.plan.createNode(TableSubQueryNode.class);
- node.init(CatalogUtil.buildFQName(ctx.queryContext.getCurrentDatabase(), expr.getName()), child);
- ctx.queryBlock.addRelation(node);
- return node;
- }
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
- // Data Definition Language Section
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- @Override
- public LogicalNode visitCreateDatabase(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, CreateDatabase expr)
- throws PlanningException {
- CreateDatabaseNode createDatabaseNode = ctx.plan.createNode(CreateDatabaseNode.class);
- return createDatabaseNode;
- }
-
- @Override
- public LogicalNode visitDropDatabase(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, DropDatabase expr)
- throws PlanningException {
- DropDatabaseNode dropDatabaseNode = ctx.plan.createNode(DropDatabaseNode.class);
- return dropDatabaseNode;
- }
-
- @Override
- public LogicalNode visitCreateTable(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, CreateTable expr)
- throws PlanningException {
-
- CreateTableNode createTableNode = ctx.plan.createNode(CreateTableNode.class);
-
- if (expr.hasSubQuery()) {
- stack.push(expr);
- visit(ctx, stack, expr.getSubQuery());
- stack.pop();
- }
-
- return createTableNode;
- }
-
- @Override
- public LogicalNode visitDropTable(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, DropTable expr)
- throws PlanningException {
- DropTableNode dropTable = ctx.plan.createNode(DropTableNode.class);
- return dropTable;
- }
-
- @Override
- public LogicalNode visitAlterTablespace(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, AlterTablespace expr)
- throws PlanningException {
- AlterTablespaceNode alterTablespace = ctx.plan.createNode(AlterTablespaceNode.class);
- return alterTablespace;
- }
-
- @Override
- public LogicalNode visitAlterTable(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, AlterTable expr)
- throws PlanningException {
- AlterTableNode alterTableNode = ctx.plan.createNode(AlterTableNode.class);
- return alterTableNode;
- }
-
- @Override
- public LogicalNode visitTruncateTable(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, TruncateTable expr)
- throws PlanningException {
- TruncateTableNode truncateTableNode = ctx.plan.createNode(TruncateTableNode.class);
- return truncateTableNode;
- }
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
- // Insert or Update Section
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- public LogicalNode visitInsert(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, Insert expr)
- throws PlanningException {
- LogicalNode child = super.visitInsert(ctx, stack, expr);
-
- InsertNode insertNode = new InsertNode(ctx.plan.newPID());
- insertNode.setInSchema(child.getOutSchema());
- insertNode.setOutSchema(child.getOutSchema());
- return insertNode;
- }
-
- static class NameRefInSelectListNormalizer extends SimpleAlgebraVisitor<LogicalPlanner.PlanContext, Object> {
- private static final NameRefInSelectListNormalizer instance;
-
- static {
- instance = new NameRefInSelectListNormalizer();
- }
-
- public static void normalize(LogicalPlanner.PlanContext context, Expr expr) throws PlanningException {
- NameRefInSelectListNormalizer normalizer = new NameRefInSelectListNormalizer();
- normalizer.visit(context,new Stack<Expr>(), expr);
- }
-
- @Override
- public Expr visitColumnReference(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, ColumnReferenceExpr expr)
- throws PlanningException {
-
- String normalized = NameResolver.resolve(ctx.plan, ctx.queryBlock, expr,
- NameResolvingMode.RELS_ONLY).getQualifiedName();
- expr.setName(normalized);
-
- return expr;
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-core/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVerifier.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVerifier.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVerifier.java
deleted file mode 100644
index c9932fa..0000000
--- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVerifier.java
+++ /dev/null
@@ -1,263 +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 org.apache.tajo.catalog.CatalogService;
-import org.apache.tajo.catalog.Column;
-import org.apache.tajo.catalog.Schema;
-import org.apache.tajo.conf.TajoConf;
-import org.apache.tajo.engine.planner.logical.*;
-import org.apache.tajo.engine.query.QueryContext;
-
-import java.util.Stack;
-
-public class LogicalPlanVerifier extends BasicLogicalPlanVisitor<LogicalPlanVerifier.Context, LogicalNode> {
- private TajoConf conf;
- private CatalogService catalog;
-
- public LogicalPlanVerifier(TajoConf conf, CatalogService catalog) {
- this.conf = conf;
- this.catalog = catalog;
- }
-
- public static class Context {
- QueryContext queryContext;
- VerificationState state;
-
- public Context(QueryContext queryContext, VerificationState state) {
- this.queryContext = this.queryContext;
- this.state = state;
- }
- }
-
- public VerificationState verify(QueryContext queryContext, VerificationState state, LogicalPlan plan) throws PlanningException {
- Context context = new Context(queryContext, state);
- visit(context, plan, plan.getRootBlock());
- return context.state;
- }
-
- /**
- * It checks if an output schema of a projectable node and target's output data types are equivalent to each other.
- */
- private static void verifyProjectableOutputSchema(Projectable node) throws PlanningException {
-
- Schema outputSchema = node.getOutSchema();
- Schema targetSchema = PlannerUtil.targetToSchema(node.getTargets());
-
- if (outputSchema.size() != node.getTargets().length) {
- throw new PlanningException(String.format("Output schema and Target's schema are mismatched at Node (%d)",
- + node.getPID()));
- }
-
- for (int i = 0; i < outputSchema.size(); i++) {
- if (!outputSchema.getColumn(i).getDataType().equals(targetSchema.getColumn(i).getDataType())) {
- Column targetColumn = targetSchema.getColumn(i);
- Column insertColumn = outputSchema.getColumn(i);
- throw new PlanningException("ERROR: " +
- insertColumn.getSimpleName() + " is of type " + insertColumn.getDataType().getType().name() +
- ", but target column '" + targetColumn.getSimpleName() + "' is of type " +
- targetColumn.getDataType().getType().name());
- }
- }
- }
-
- @Override
- public LogicalNode visitProjection(Context state, LogicalPlan plan, LogicalPlan.QueryBlock block,
- ProjectionNode node, Stack<LogicalNode> stack) throws PlanningException {
- super.visitProjection(state, plan, block, node, stack);
-
- for (Target target : node.getTargets()) {
- ExprsVerifier.verify(state.state, node, target.getEvalTree());
- }
-
- verifyProjectableOutputSchema(node);
-
- return node;
- }
-
- @Override
- public LogicalNode visitLimit(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block,
- LimitNode node, Stack<LogicalNode> stack) throws PlanningException {
- super.visitLimit(context, plan, block, node, stack);
-
- if (node.getFetchFirstNum() < 0) {
- context.state.addVerification("LIMIT must not be negative");
- }
-
- return node;
- }
-
- @Override
- public LogicalNode visitGroupBy(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block,
- GroupbyNode node, Stack<LogicalNode> stack) throws PlanningException {
- super.visitGroupBy(context, plan, block, node, stack);
-
- verifyProjectableOutputSchema(node);
- return node;
- }
-
- @Override
- public LogicalNode visitFilter(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block,
- SelectionNode node, Stack<LogicalNode> stack) throws PlanningException {
- visit(context, plan, block, node.getChild(), stack);
- ExprsVerifier.verify(context.state, node, node.getQual());
- return node;
- }
-
- @Override
- public LogicalNode visitJoin(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block, JoinNode node,
- Stack<LogicalNode> stack) throws PlanningException {
- visit(context, plan, block, node.getLeftChild(), stack);
- visit(context, plan, block, node.getRightChild(), stack);
-
- if (node.hasJoinQual()) {
- ExprsVerifier.verify(context.state, node, node.getJoinQual());
- }
-
- verifyProjectableOutputSchema(node);
-
- return node;
- }
-
- private void verifySetStatement(VerificationState state, BinaryNode setNode) {
- Preconditions.checkArgument(setNode.getType() == NodeType.UNION || setNode.getType() == NodeType.INTERSECT ||
- setNode.getType() == NodeType.EXCEPT);
- Schema left = setNode.getLeftChild().getOutSchema();
- Schema right = setNode.getRightChild().getOutSchema();
- NodeType type = setNode.getType();
-
- if (left.size() != right.size()) {
- state.addVerification("each " + type.name() + " query must have the same number of columns");
- return;
- }
-
- Column[] leftColumns = left.toArray();
- Column[] rightColumns = right.toArray();
-
- for (int i = 0; i < leftColumns.length; i++) {
- if (!leftColumns[i].getDataType().equals(rightColumns[i].getDataType())) {
- state.addVerification(type + " types " + leftColumns[i].getDataType().getType() + " and "
- + rightColumns[i].getDataType().getType() + " cannot be matched");
- }
- }
- }
-
- @Override
- public LogicalNode visitUnion(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block,
- UnionNode node, Stack<LogicalNode> stack) throws PlanningException {
- super.visitUnion(context, plan, block, node, stack);
- verifySetStatement(context.state, node);
- return node;
- }
-
- @Override
- public LogicalNode visitExcept(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block,
- ExceptNode node, Stack<LogicalNode> stack) throws PlanningException {
- super.visitExcept(context, plan, block, node, stack);
- verifySetStatement(context.state, node);
- return node;
- }
-
- @Override
- public LogicalNode visitIntersect(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block,
- IntersectNode node, Stack<LogicalNode> stack) throws PlanningException {
- super.visitIntersect(context, plan, block, node, stack);
- verifySetStatement(context.state, node);
- return node;
- }
-
- @Override
- public LogicalNode visitTableSubQuery(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block,
- TableSubQueryNode node, Stack<LogicalNode> stack) throws PlanningException {
- super.visitTableSubQuery(context, plan, block, node, stack);
- if (node.hasTargets()) {
- for (Target target : node.getTargets()) {
- ExprsVerifier.verify(context.state, node, target.getEvalTree());
- }
- }
-
- verifyProjectableOutputSchema(node);
- return node;
- }
-
- @Override
- public LogicalNode visitScan(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block, ScanNode node,
- Stack<LogicalNode> stack) throws PlanningException {
- if (node.hasTargets()) {
- for (Target target : node.getTargets()) {
- ExprsVerifier.verify(context.state, node, target.getEvalTree());
- }
- }
-
- if (node.hasQual()) {
- ExprsVerifier.verify(context.state, node, node.getQual());
- }
-
- verifyProjectableOutputSchema(node);
-
- return node;
- }
-
- @Override
- public LogicalNode visitStoreTable(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block,
- StoreTableNode node, Stack<LogicalNode> stack) throws PlanningException {
- super.visitStoreTable(context, plan, block, node, stack);
- return node;
- }
-
- @Override
- public LogicalNode visitInsert(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block,
- InsertNode node, Stack<LogicalNode> stack) throws PlanningException {
- super.visitInsert(context, plan, block, node, stack);
- return node;
- }
-
- /**
- * This ensures that corresponding columns in both tables are equivalent to each other.
- */
- private static void ensureDomains(VerificationState state, Schema targetTableScheme, Schema schema)
- throws PlanningException {
- for (int i = 0; i < schema.size(); i++) {
- if (!schema.getColumn(i).getDataType().equals(targetTableScheme.getColumn(i).getDataType())) {
- Column targetColumn = targetTableScheme.getColumn(i);
- Column insertColumn = schema.getColumn(i);
- state.addVerification("ERROR: " +
- insertColumn.getSimpleName() + " is of type " + insertColumn.getDataType().getType().name() +
- ", but target column '" + targetColumn.getSimpleName() + "' is of type " +
- targetColumn.getDataType().getType().name());
- }
- }
- }
-
- @Override
- public LogicalNode visitCreateTable(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block,
- CreateTableNode node, Stack<LogicalNode> stack) throws PlanningException {
- super.visitCreateTable(context, plan, block, node, stack);
- // here, we don't need check table existence because this check is performed in PreLogicalPlanVerifier.
- return node;
- }
-
- @Override
- public LogicalNode visitDropTable(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block,
- DropTableNode node, Stack<LogicalNode> stack) {
- // here, we don't need check table existence because this check is performed in PreLogicalPlanVerifier.
- return node;
- }
-}
http://git-wip-us.apache.org/repos/asf/tajo/blob/b143f991/tajo-core/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVisitor.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVisitor.java
deleted file mode 100644
index 0a36610..0000000
--- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVisitor.java
+++ /dev/null
@@ -1,98 +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.*;
-
-import java.util.Stack;
-
-public interface LogicalPlanVisitor<CONTEXT, RESULT> {
- RESULT visitRoot(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, LogicalRootNode node,
- Stack<LogicalNode> stack) throws PlanningException;
-
- RESULT visitProjection(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, ProjectionNode node,
- Stack<LogicalNode> stack) throws PlanningException;
-
- RESULT visitLimit(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, LimitNode node,
- Stack<LogicalNode> stack) throws PlanningException;
-
- RESULT visitSort(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, SortNode node,
- Stack<LogicalNode> stack) throws PlanningException;
-
- RESULT visitHaving(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, HavingNode node,
- Stack<LogicalNode> stack) throws PlanningException;
-
- RESULT visitGroupBy(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, GroupbyNode node,
- Stack<LogicalNode> stack) throws PlanningException;
- RESULT visitWindowAgg(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, WindowAggNode node,
- Stack<LogicalNode> stack) throws PlanningException;
- RESULT visitDistinct(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, DistinctGroupbyNode node,
- Stack<LogicalNode> stack) throws PlanningException;
-
- RESULT visitFilter(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, SelectionNode node,
- Stack<LogicalNode> stack) throws PlanningException;
-
- RESULT visitJoin(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, JoinNode node,
- Stack<LogicalNode> stack) throws PlanningException;
-
- RESULT visitUnion(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, UnionNode node,
- Stack<LogicalNode> stack) throws PlanningException;
-
- RESULT visitExcept(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, ExceptNode node,
- Stack<LogicalNode> stack) throws PlanningException;
-
- RESULT visitIntersect(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, IntersectNode node,
- Stack<LogicalNode> stack) throws PlanningException;
-
- RESULT visitTableSubQuery(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, TableSubQueryNode node,
- Stack<LogicalNode> stack) throws PlanningException;
-
- RESULT visitScan(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, ScanNode node,
- Stack<LogicalNode> stack) throws PlanningException;
-
- RESULT visitPartitionedTableScan(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block,
- PartitionedTableScanNode node, Stack<LogicalNode> stack) throws PlanningException;
-
- RESULT visitStoreTable(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, StoreTableNode node,
- Stack<LogicalNode> stack) throws PlanningException;
-
- RESULT visitInsert(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, InsertNode node,
- Stack<LogicalNode> stack) throws PlanningException;
-
- RESULT visitCreateDatabase(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, CreateDatabaseNode node,
- Stack<LogicalNode> stack) throws PlanningException;
-
- RESULT visitDropDatabase(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, DropDatabaseNode node,
- Stack<LogicalNode> stack) throws PlanningException;
-
- RESULT visitCreateTable(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, CreateTableNode node,
- Stack<LogicalNode> stack) throws PlanningException;
-
- RESULT visitDropTable(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, DropTableNode node,
- Stack<LogicalNode> stack) throws PlanningException;
-
- RESULT visitAlterTablespace(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, AlterTablespaceNode node,
- Stack<LogicalNode> stack) throws PlanningException;
-
- RESULT visitAlterTable(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, AlterTableNode node,
- Stack<LogicalNode> stack) throws PlanningException;
-
- RESULT visitTruncateTable(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, TruncateTableNode node,
- Stack<LogicalNode> stack) throws PlanningException;
-}