From 4965cd6a36e13accc4541b7aae8a3582988c42e3 Mon Sep 17 00:00:00 2001 From: Hyunsik Choi Date: Mon, 23 Jun 2014 17:54:00 +0900 Subject: [PATCH 1/3] TAJO-884: complex join conditions should be supported in ON clause. --- .../apache/tajo/engine/eval/EvalTreeUtil.java | 9 +- .../tajo/engine/planner/ExprAnnotator.java | 2 +- .../tajo/engine/planner/ExprNormalizer.java | 44 +++++++- .../tajo/engine/planner/LogicalPlan.java | 36 +++--- .../tajo/engine/planner/LogicalPlanner.java | 7 +- .../planner/logical/join/JoinGraph.java | 25 ++++- .../rewrite/ProjectionPushDownRule.java | 104 ++++++++++++++---- .../tajo/engine/query/TestCreateTable.java | 2 +- .../tajo/engine/query/TestJoinQuery.java | 43 ++++++++ .../testLeftOuterJoinWithConstantExpr3.sql | 2 +- .../queries/TestJoinQuery/table1_int4_ddl.sql | 3 + .../queries/TestJoinQuery/table1_int8_ddl.sql | 3 + .../testComplexJoinCondition1.sql | 1 + .../testComplexJoinCondition2.sql | 1 + .../testComplexJoinCondition3.sql | 1 + .../testComplexJoinCondition4.sql | 1 + .../testDifferentTypesJoinCondition.sql | 1 + .../testLeftOuterJoinWithConstantExpr3.sql | 2 +- .../testComplexJoinCondition1.result | 27 +++++ .../testComplexJoinCondition2.result | 27 +++++ .../testComplexJoinCondition3.result | 27 +++++ .../testComplexJoinCondition4.result | 29 +++++ .../testDifferentTypesJoinCondition.result | 7 ++ 23 files changed, 347 insertions(+), 57 deletions(-) create mode 100644 tajo-core/src/test/resources/queries/TestJoinQuery/table1_int4_ddl.sql create mode 100644 tajo-core/src/test/resources/queries/TestJoinQuery/table1_int8_ddl.sql create mode 100644 tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition1.sql create mode 100644 tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition2.sql create mode 100644 tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition3.sql create mode 100644 tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition4.sql create mode 100644 tajo-core/src/test/resources/queries/TestJoinQuery/testDifferentTypesJoinCondition.sql create mode 100644 tajo-core/src/test/resources/results/TestJoinQuery/testComplexJoinCondition1.result create mode 100644 tajo-core/src/test/resources/results/TestJoinQuery/testComplexJoinCondition2.result create mode 100644 tajo-core/src/test/resources/results/TestJoinQuery/testComplexJoinCondition3.result create mode 100644 tajo-core/src/test/resources/results/TestJoinQuery/testComplexJoinCondition4.result create mode 100644 tajo-core/src/test/resources/results/TestJoinQuery/testDifferentTypesJoinCondition.result diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java index 8982bd54a1..1ecd328e87 100644 --- a/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java +++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java @@ -248,14 +248,17 @@ public static boolean isJoinQual(EvalNode expr, boolean includeThetaJoin) { } BinaryEval binaryEval = (BinaryEval) expr; - boolean isBothTermFields = - binaryEval.getLeftExpr().getType() == EvalType.FIELD && - binaryEval.getRightExpr().getType() == EvalType.FIELD; + boolean isBothTermFields = isSingleColumn(binaryEval.getLeftExpr()) && isSingleColumn(binaryEval.getRightExpr()); + return joinComparator && isBothTermFields; } else { return false; } } + + static boolean isSingleColumn(EvalNode evalNode) { + return EvalTreeUtil.findUniqueColumns(evalNode).size() == 1; + } public static class ChangeColumnRefVisitor implements EvalNodeVisitor { private final String findColumn; diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java index 3a53cd2b24..e143823c75 100644 --- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java +++ b/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java @@ -152,7 +152,7 @@ static DataType getWidestType(DataType...types) throws PlanningException { private static EvalNode convertType(EvalNode evalNode, DataType toType) { // if original and toType is the same, we don't need type conversion. - if (evalNode.getValueType() == toType) { + if (evalNode.getValueType().equals(toType)) { return evalNode; } // the conversion to null is not allowed. diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprNormalizer.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprNormalizer.java index b87665a67d..75b2b9580a 100644 --- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprNormalizer.java +++ b/tajo-core/src/main/java/org/apache/tajo/engine/planner/ExprNormalizer.java @@ -20,6 +20,7 @@ import org.apache.tajo.algebra.*; import org.apache.tajo.catalog.CatalogUtil; +import org.apache.tajo.engine.exception.NoSuchColumnException; import java.util.ArrayList; import java.util.List; @@ -80,15 +81,21 @@ class ExprNormalizer extends SimpleAlgebraVisitor aggExprs = new ArrayList(); // aggregation functions List scalarExprs = new ArrayList(); // scalar expressions which can be referred - private ExprNormalizedResult(LogicalPlanner.PlanContext context) { + private ExprNormalizedResult(LogicalPlanner.PlanContext context, boolean tryBinaryCommonTermsElimination) { this.plan = context.plan; this.block = context.queryBlock; + this.tryBinaryCommonTermsElimination = tryBinaryCommonTermsElimination; + } + + public boolean isBinaryCommonTermsElimination() { + return tryBinaryCommonTermsElimination; } @Override @@ -98,7 +105,11 @@ public String toString() { } public ExprNormalizedResult normalize(LogicalPlanner.PlanContext context, Expr expr) throws PlanningException { - ExprNormalizedResult exprNormalizedResult = new ExprNormalizedResult(context); + return normalize(context, expr, false); + } + public ExprNormalizedResult normalize(LogicalPlanner.PlanContext context, Expr expr, boolean subexprElimination) + throws PlanningException { + ExprNormalizedResult exprNormalizedResult = new ExprNormalizedResult(context, subexprElimination); Stack stack = new Stack(); stack.push(expr); visit(exprNormalizedResult, new Stack(), expr); @@ -152,9 +163,27 @@ public Expr visitUnaryOperator(ExprNormalizedResult ctx, Stack stack, Unar return expr; } + private boolean isBinaryCommonTermsElimination(ExprNormalizedResult ctx, Expr expr) { + return ctx.isBinaryCommonTermsElimination() && expr.getType() != OpType.Column + && ctx.block.namedExprsMgr.contains(expr); + } + @Override public Expr visitBinaryOperator(ExprNormalizedResult ctx, Stack stack, BinaryOperator expr) throws PlanningException { - super.visitBinaryOperator(ctx, stack, expr); + stack.push(expr); + + visit(ctx, new Stack(), expr.getLeft()); + if (isBinaryCommonTermsElimination(ctx, expr.getLeft())) { + String refName = ctx.block.namedExprsMgr.addExpr(expr.getLeft()); + expr.setLeft(new ColumnReferenceExpr(refName)); + } + + visit(ctx, new Stack(), expr.getRight()); + if (isBinaryCommonTermsElimination(ctx, expr.getRight())) { + String refName = ctx.block.namedExprsMgr.addExpr(expr.getRight()); + expr.setRight(new ColumnReferenceExpr(refName)); + } + stack.pop(); //////////////////////// // For Left Term @@ -249,9 +278,12 @@ public Expr visitColumnReference(ExprNormalizedResult ctx, Stack stack, Co throws PlanningException { // if a column reference is not qualified, it finds and sets the qualified column name. if (!(expr.hasQualifier() && CatalogUtil.isFQTableName(expr.getQualifier()))) { - if (!ctx.block.namedExprsMgr.contains(expr.getCanonicalName())) { - String normalized = ctx.plan.getNormalizedColumnName(ctx.block, expr); - expr.setName(normalized); + if (!ctx.block.namedExprsMgr.contains(expr.getCanonicalName()) && expr.getType() == OpType.Column) { + try { + String normalized = ctx.plan.getNormalizedColumnName(ctx.block, expr); + expr.setName(normalized); + } catch (NoSuchColumnException nsc) { + } } } return expr; 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 index 0508bacad4..92df760233 100644 --- 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 @@ -26,6 +26,7 @@ import org.apache.tajo.catalog.Column; import org.apache.tajo.catalog.Schema; import org.apache.tajo.engine.eval.EvalNode; +import org.apache.tajo.engine.exception.AmbiguousFieldException; import org.apache.tajo.engine.exception.NoSuchColumnException; import org.apache.tajo.engine.exception.VerifyException; import org.apache.tajo.engine.planner.graph.DirectedGraphCursor; @@ -384,6 +385,21 @@ private Column resolveColumnWithQualifier(QueryBlock block, ColumnReferenceExpr private Column resolveColumnWithoutQualifier(QueryBlock block, ColumnReferenceExpr columnRef)throws PlanningException { + + List candidates = TUtil.newList(); + + // It tries to find a full qualified column name from all relations in the current block. + for (RelationNode rel : block.getRelations()) { + Column found = rel.getTableSchema().getColumn(columnRef.getName()); + if (found != null) { + candidates.add(found); + } + } + + if (!candidates.isEmpty()) { + return ensureUniqueColumn(candidates); + } + // Trying to find the column within the current block if (block.currentNode != null && block.currentNode.getInSchema() != null) { Column found = block.currentNode.getInSchema().getColumn(columnRef.getCanonicalName()); @@ -399,7 +415,7 @@ private Column resolveColumnWithoutQualifier(QueryBlock block, } } - List candidates = TUtil.newList(); + // Trying to find columns from aliased references. if (block.namedExprsMgr.isAliased(columnRef.getCanonicalName())) { String originalName = block.namedExprsMgr.getAlias(columnRef.getCanonicalName()); @@ -412,22 +428,10 @@ private Column resolveColumnWithoutQualifier(QueryBlock block, return ensureUniqueColumn(candidates); } - // Trying to find columns from other relations in the current block - for (RelationNode rel : block.getRelations()) { - Column found = rel.getTableSchema().getColumn(columnRef.getName()); - if (found != null) { - candidates.add(found); - } - } - - if (!candidates.isEmpty()) { - return ensureUniqueColumn(candidates); - } - // This is an exception case. It means that there are some bugs in other parts. LogicalNode blockRootNode = block.getRoot(); if (blockRootNode != null && blockRootNode.getOutSchema().getColumn(columnRef.getCanonicalName()) != null) { - throw new VerifyException("ERROR: no such a column name "+ columnRef.getCanonicalName()); + throw new NoSuchColumnException("ERROR: no such a column name "+ columnRef.getCanonicalName()); } // Trying to find columns from other relations in other blocks @@ -456,7 +460,7 @@ private Column resolveColumnWithoutQualifier(QueryBlock block, return ensureUniqueColumn(candidates); } - throw new VerifyException("ERROR: no such a column name "+ columnRef.getCanonicalName()); + throw new NoSuchColumnException("ERROR: no such a column name "+ columnRef.getCanonicalName()); } private static Column ensureUniqueColumn(List candidates) @@ -474,7 +478,7 @@ private static Column ensureUniqueColumn(List candidates) } sb.append(column); } - throw new VerifyException("Ambiguous Column Name: " + sb.toString()); + throw new AmbiguousFieldException("Ambiguous Column Name: " + sb.toString()); } else { return null; } diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/LogicalPlanner.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/LogicalPlanner.java index 6474444d0e..0b55196587 100644 --- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/LogicalPlanner.java +++ b/tajo-core/src/main/java/org/apache/tajo/engine/planner/LogicalPlanner.java @@ -767,7 +767,7 @@ public LogicalNode visitJoin(PlanContext context, Stack stack, Join join) QueryBlock block = context.queryBlock; if (join.hasQual()) { - ExprNormalizedResult normalizedResult = normalizer.normalize(context, join.getQual()); + ExprNormalizedResult normalizedResult = normalizer.normalize(context, join.getQual(), true); block.namedExprsMgr.addExpr(normalizedResult.baseExpr); if (normalizedResult.aggExprs.size() > 0 || normalizedResult.scalarExprs.size() > 0) { throw new VerifyException("Filter condition cannot include aggregation function"); @@ -1207,13 +1207,10 @@ private InsertNode buildInsertIntoTablePlan(PlanContext context, InsertNode inse // See PreLogicalPlanVerifier.visitInsert. // It guarantees that the equivalence between the numbers of target and projected columns. - ScanNode scanNode = context.plan.createNode(ScanNode.class); - scanNode.init(desc); - context.queryBlock.addRelation(scanNode); String [] targets = expr.getTargetColumns(); Schema targetColumns = new Schema(); for (int i = 0; i < targets.length; i++) { - Column targetColumn = context.plan.resolveColumn(context.queryBlock, new ColumnReferenceExpr(targets[i])); + Column targetColumn = desc.getLogicalSchema().getColumn(targets[i]); targetColumns.addColumn(targetColumn); } insertNode.setTargetSchema(targetColumns); diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/logical/join/JoinGraph.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/logical/join/JoinGraph.java index d384f51eb5..d54cdff378 100644 --- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/logical/join/JoinGraph.java +++ b/tajo-core/src/main/java/org/apache/tajo/engine/planner/logical/join/JoinGraph.java @@ -31,6 +31,7 @@ import org.apache.tajo.engine.planner.PlanningException; import org.apache.tajo.engine.planner.graph.SimpleUndirectedGraph; import org.apache.tajo.engine.planner.logical.JoinNode; +import org.apache.tajo.engine.planner.logical.RelationNode; import java.util.Collection; import java.util.Set; @@ -58,7 +59,17 @@ public class JoinGraph extends SimpleUndirectedGraph { String qualifier = CatalogUtil.extractQualifier(columnName); relationNames[0] = qualifier; } else { - throw new PlanningException("Cannot expect a referenced relation: " + leftExpr); + // search for a relation which evaluates a right term included in a join condition + for (RelationNode rel : block.getRelations()) { + if (rel.getOutSchema().contains(leftExpr)) { + String qualifier = rel.getCanonicalName(); + relationNames[0] = qualifier; + } + } + + if (relationNames[0] == null) { // if not found + throw new PlanningException("Cannot expect a referenced relation: " + leftExpr); + } } } @@ -70,7 +81,17 @@ public class JoinGraph extends SimpleUndirectedGraph { String qualifier = CatalogUtil.extractQualifier(columnName); relationNames[1] = qualifier; } else { - throw new PlanningException("Cannot expect a referenced relation: " + rightExpr); + // search for a relation which evaluates a right term included in a join condition + for (RelationNode rel : block.getRelations()) { + if (rel.getOutSchema().contains(rightExpr)) { + String qualifier = rel.getCanonicalName(); + relationNames[1] = qualifier; + } + } + + if (relationNames[1] == null) { // if not found + throw new PlanningException("Cannot expect a referenced relation: " + rightExpr); + } } } diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/rewrite/ProjectionPushDownRule.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/rewrite/ProjectionPushDownRule.java index 8e91dca9ed..dbd36d6469 100644 --- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/rewrite/ProjectionPushDownRule.java +++ b/tajo-core/src/main/java/org/apache/tajo/engine/planner/rewrite/ProjectionPushDownRule.java @@ -135,8 +135,10 @@ public static class TargetListManager { private BiMap idToEvalBiMap; /** Map: Id -> Names */ private LinkedHashMap> idToNamesMap; - /** Map: Name -> Boolean */ - private LinkedHashMap evaluationStateMap; + /** Map: Id -> Boolean */ + private LinkedHashMap evaluationStateMap; + /** Map: alias name -> Id */ + private LinkedHashMap aliasMap; private LogicalPlan plan; @@ -146,12 +148,35 @@ public TargetListManager(LogicalPlan plan) { idToEvalBiMap = HashBiMap.create(); idToNamesMap = Maps.newLinkedHashMap(); evaluationStateMap = Maps.newLinkedHashMap(); + aliasMap = Maps.newLinkedHashMap(); } private int getNextSeqId() { return seqId++; } + /** + * If some expression is duplicated, we call an alias indicating the duplicated expression 'native alias'. + * This method checks whether a reference is native alias or not. + * + * @param name The reference name + * @return True if the reference is native alias. Otherwise, it will return False. + */ + public boolean isNativeAlias(String name) { + return aliasMap.containsKey(name); + } + + /** + * This method retrieves the name indicating actual expression that an given alias indicate. + * + * @param name an alias name + * @return Real reference name + */ + public String getRealReferenceName(String name) { + int refId = aliasMap.get(name); + return getPrimaryName(refId); + } + /** * Add an expression with a specified name, which is usually an alias. * Later, you can refer this expression by the specified name. @@ -163,12 +188,19 @@ private String add(String specifiedName, EvalNode evalNode) throws PlanningExcep if (nameToIdBiMap.containsKey(specifiedName)) { int refId = nameToIdBiMap.get(specifiedName); EvalNode found = idToEvalBiMap.get(refId); - if (found != null && !evalNode.equals(found)) { - if (found.getType() != EvalType.FIELD && evalNode.getType() != EvalType.FIELD) { - throw new PlanningException("Duplicate alias: " + evalNode); - } - if (found.getType() == EvalType.FIELD) { - idToEvalBiMap.forcePut(refId, evalNode); + if (found != null) { + if (evalNode.equals(found)) { // if input expression already exists + return specifiedName; + } else { + // The case where if existing reference name and a given reference name are the same to each other and + // existing EvalNode and a given EvalNode is the different + if (found.getType() != EvalType.FIELD && evalNode.getType() != EvalType.FIELD) { + throw new PlanningException("Duplicate alias: " + evalNode); + } + + if (found.getType() == EvalType.FIELD) { + idToEvalBiMap.forcePut(refId, evalNode); + } } } } @@ -176,18 +208,19 @@ private String add(String specifiedName, EvalNode evalNode) throws PlanningExcep int refId; if (idToEvalBiMap.inverse().containsKey(evalNode)) { refId = idToEvalBiMap.inverse().get(evalNode); + aliasMap.put(specifiedName, refId); + } else { refId = getNextSeqId(); idToEvalBiMap.put(refId, evalNode); + TUtil.putToNestedList(idToNamesMap, refId, specifiedName); + for (Column column : EvalTreeUtil.findUniqueColumns(evalNode)) { + add(new FieldEval(column)); + } + evaluationStateMap.put(refId, false); } nameToIdBiMap.put(specifiedName, refId); - TUtil.putToNestedList(idToNamesMap, refId, specifiedName); - evaluationStateMap.put(specifiedName, false); - - for (Column column : EvalTreeUtil.findUniqueColumns(evalNode)) { - add(new FieldEval(column)); - } return specifiedName; } @@ -287,7 +320,8 @@ public boolean isEvaluated(String name) { if (!nameToIdBiMap.containsKey(name)) { throw new RuntimeException("No Such target name: " + name); } - return evaluationStateMap.get(name); + int refId = nameToIdBiMap.get(name); + return evaluationStateMap.get(refId); } public void markAsEvaluated(Target target) { @@ -296,7 +330,7 @@ public void markAsEvaluated(Target target) { if (!idToNamesMap.containsKey(refId)) { throw new RuntimeException("No such eval: " + evalNode); } - evaluationStateMap.put(target.getCanonicalName(), true); + evaluationStateMap.put(refId, true); } public Iterator getFilteredTargets(Set required) { @@ -305,6 +339,7 @@ public Iterator getFilteredTargets(Set required) { class FilteredTargetIterator implements Iterator { List filtered = TUtil.newList(); + Iterator iterator; public FilteredTargetIterator(Set required) { for (String name : nameToIdBiMap.keySet()) { @@ -312,16 +347,17 @@ public FilteredTargetIterator(Set required) { filtered.add(getTarget(name)); } } + iterator = filtered.iterator(); } @Override public boolean hasNext() { - return false; + return iterator.hasNext(); } @Override public Target next() { - return null; + return iterator.next(); } @Override @@ -412,8 +448,15 @@ public LogicalNode visitProjection(Context context, LogicalPlan plan, LogicalPla for (String referenceName : referenceNames) { Target target = context.targetListMgr.getTarget(referenceName); - if (context.targetListMgr.isEvaluated(referenceName)) { - finalTargets.add(new Target(new FieldEval(target.getNamedColumn()))); + if (target.getEvalTree().getType() == EvalType.CONST) { + finalTargets.add(target); + } else if (context.targetListMgr.isEvaluated(referenceName)) { + if (context.targetListMgr.isNativeAlias(referenceName)) { + String realRefName = context.targetListMgr.getRealReferenceName(referenceName); + finalTargets.add(new Target(new FieldEval(realRefName, target.getDataType()), referenceName)); + } else { + finalTargets.add(new Target(new FieldEval(target.getNamedColumn()))); + } } else if (LogicalPlanner.checkIfBeEvaluatedAtThis(target.getEvalTree(), node)) { finalTargets.add(target); context.targetListMgr.markAsEvaluated(target); @@ -687,12 +730,31 @@ public LogicalNode visitFilter(Context context, LogicalPlan plan, LogicalPlan.Qu return node; } + private static void pushDownIfComplexTermInJoinCondition(Context ctx, EvalNode cnf, EvalNode term) + throws PlanningException { + if (term.getType() != EvalType.FIELD) { + String refName = ctx.targetListMgr.add(term); + EvalTreeUtil.replace(cnf, term, new FieldEval(refName, term.getValueType())); + } + } + public LogicalNode visitJoin(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block, JoinNode node, Stack stack) throws PlanningException { Context newContext = new Context(context); String joinQualReference = null; if (node.hasJoinQual()) { + for (EvalNode eachQual : AlgebraicUtil.toConjunctiveNormalFormArray(node.getJoinQual())) { + if (eachQual instanceof BinaryEval) { + BinaryEval binaryQual = (BinaryEval) eachQual; + + for (int i = 0; i < 2; i++) { + EvalNode term = binaryQual.getExpr(i); + pushDownIfComplexTermInJoinCondition(newContext, eachQual, term); + } + } + } + joinQualReference = newContext.addExpr(node.getJoinQual()); newContext.addNecessaryReferences(node.getJoinQual()); } @@ -874,7 +936,7 @@ public LogicalNode visitScan(Context context, LogicalPlan plan, LogicalPlan.Quer newContext.addExpr(target); } - for (Iterator it = getFilteredTarget(targets, context.requiredSet); it.hasNext();) { + for (Iterator it = context.targetListMgr.getFilteredTargets(newContext.requiredSet); it.hasNext();) { Target target = it.next(); if (LogicalPlanner.checkIfBeEvaluatedAtRelation(block, target.getEvalTree(), node)) { diff --git a/tajo-core/src/test/java/org/apache/tajo/engine/query/TestCreateTable.java b/tajo-core/src/test/java/org/apache/tajo/engine/query/TestCreateTable.java index adc44e32a3..3d90a7964e 100644 --- a/tajo-core/src/test/java/org/apache/tajo/engine/query/TestCreateTable.java +++ b/tajo-core/src/test/java/org/apache/tajo/engine/query/TestCreateTable.java @@ -499,7 +499,7 @@ public final void testCreateTableLike1() throws Exception { // Table created using CTAS executeString("CREATE TABLE table3 (c1 int, c2 varchar) PARTITION BY COLUMN (c3 int);").close(); - executeString("CREATE TABLE table4 AS SELECT c1*c1, c2, c2,c3 from table3;").close(); + executeString("CREATE TABLE table4 AS SELECT c1*c1, c2, c2 as c2_a,c3 from table3;").close(); executeString("CREATE TABLE table2 LIKE table4"); testMsg = "testCreateTableLike1: Table using CTAS test failed"; assertTrue(testMsg, isClonedTable("table4","table2")); diff --git a/tajo-core/src/test/java/org/apache/tajo/engine/query/TestJoinQuery.java b/tajo-core/src/test/java/org/apache/tajo/engine/query/TestJoinQuery.java index b1aca5611f..499aa6de3d 100644 --- a/tajo-core/src/test/java/org/apache/tajo/engine/query/TestJoinQuery.java +++ b/tajo-core/src/test/java/org/apache/tajo/engine/query/TestJoinQuery.java @@ -376,4 +376,47 @@ public final void testJoinAsterisk() throws Exception { assertResultSet(res); cleanupQuery(res); } + + @Test + public void testDifferentTypesJoinCondition() throws Exception { + // select * from table3 t3 join table4 t4 on t3.id = t4.id; + executeDDL("table1_int8_ddl.sql", "table1", "table3"); + executeDDL("table1_int4_ddl.sql", "table1", "table4"); + ResultSet res = executeQuery(); + assertResultSet(res); + cleanupQuery(res); + } + + @Test + public void testComplexJoinCondition1() throws Exception { + // select n1.n_nationkey, n1.n_name, n2.n_name from nation n1 join nation n2 on n1.n_name = upper(n2.n_name); + ResultSet res = executeQuery(); + assertResultSet(res); + cleanupQuery(res); + } + + @Test + public void testComplexJoinCondition2() throws Exception { + // select n1.n_nationkey, n1.n_name, upper(n2.n_name) name from nation n1 join nation n2 + // on n1.n_name = upper(n2.n_name); + + ResultSet res = executeQuery(); + assertResultSet(res); + cleanupQuery(res); + } + + @Test + public void testComplexJoinCondition3() throws Exception { + // select n1.n_nationkey, n1.n_name, n2.n_name from nation n1 join nation n2 on lower(n1.n_name) = lower(n2.n_name); + ResultSet res = executeQuery(); + assertResultSet(res); + cleanupQuery(res); + } + + @Test + public void testComplexJoinCondition4() throws Exception { + ResultSet res = executeQuery(); + assertResultSet(res); + cleanupQuery(res); + } } diff --git a/tajo-core/src/test/resources/queries/TestJoinBroadcast/testLeftOuterJoinWithConstantExpr3.sql b/tajo-core/src/test/resources/queries/TestJoinBroadcast/testLeftOuterJoinWithConstantExpr3.sql index 90be13bf47..f79b18b5cf 100644 --- a/tajo-core/src/test/resources/queries/TestJoinBroadcast/testLeftOuterJoinWithConstantExpr3.sql +++ b/tajo-core/src/test/resources/queries/TestJoinBroadcast/testLeftOuterJoinWithConstantExpr3.sql @@ -14,4 +14,4 @@ left outer join ( b on a.c_custkey = b.c_custkey order by - c_custkey; \ No newline at end of file + a.c_custkey; \ No newline at end of file diff --git a/tajo-core/src/test/resources/queries/TestJoinQuery/table1_int4_ddl.sql b/tajo-core/src/test/resources/queries/TestJoinQuery/table1_int4_ddl.sql new file mode 100644 index 0000000000..0d35ceece1 --- /dev/null +++ b/tajo-core/src/test/resources/queries/TestJoinQuery/table1_int4_ddl.sql @@ -0,0 +1,3 @@ +create external table ${0} (id int, name text, score float, type text) using csv +with ('csvfile.delimiter'='|', 'csvfile.null'='NULL') location ${table.path}; + diff --git a/tajo-core/src/test/resources/queries/TestJoinQuery/table1_int8_ddl.sql b/tajo-core/src/test/resources/queries/TestJoinQuery/table1_int8_ddl.sql new file mode 100644 index 0000000000..3a7a44aefa --- /dev/null +++ b/tajo-core/src/test/resources/queries/TestJoinQuery/table1_int8_ddl.sql @@ -0,0 +1,3 @@ +create external table ${0} (id bigint, name text, score float, type text) using csv +with ('csvfile.delimiter'='|', 'csvfile.null'='NULL') location ${table.path}; + diff --git a/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition1.sql b/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition1.sql new file mode 100644 index 0000000000..5dbc2d6c98 --- /dev/null +++ b/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition1.sql @@ -0,0 +1 @@ +select n1.n_nationkey, n1.n_name, n2.n_name from nation n1 join nation n2 on n1.n_name = upper(n2.n_name); \ No newline at end of file diff --git a/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition2.sql b/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition2.sql new file mode 100644 index 0000000000..b83e82d9c2 --- /dev/null +++ b/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition2.sql @@ -0,0 +1 @@ +select n1.n_nationkey, n1.n_name, upper(n2.n_name) as name from nation n1 join nation n2 on n1.n_name = upper(n2.n_name); \ No newline at end of file diff --git a/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition3.sql b/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition3.sql new file mode 100644 index 0000000000..cffbfb4947 --- /dev/null +++ b/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition3.sql @@ -0,0 +1 @@ +select n1.n_nationkey, n1.n_name, n2.n_name from nation n1 join nation n2 on lower(n1.n_name) = lower(n2.n_name); \ No newline at end of file diff --git a/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition4.sql b/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition4.sql new file mode 100644 index 0000000000..ea500831ee --- /dev/null +++ b/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition4.sql @@ -0,0 +1 @@ +select n1.n_nationkey, substr(n1.n_name, 1, 4) name1, substr(n2.n_name, 1, 4) name2 from nation n1 join nation n2 on substr(n1.n_name, 1, 4) = substr(n2.n_name, 1, 4); \ No newline at end of file diff --git a/tajo-core/src/test/resources/queries/TestJoinQuery/testDifferentTypesJoinCondition.sql b/tajo-core/src/test/resources/queries/TestJoinQuery/testDifferentTypesJoinCondition.sql new file mode 100644 index 0000000000..340df908b2 --- /dev/null +++ b/tajo-core/src/test/resources/queries/TestJoinQuery/testDifferentTypesJoinCondition.sql @@ -0,0 +1 @@ +select * from table3 t3 join table4 t4 on t3.id = t4.id; \ No newline at end of file diff --git a/tajo-core/src/test/resources/queries/TestJoinQuery/testLeftOuterJoinWithConstantExpr3.sql b/tajo-core/src/test/resources/queries/TestJoinQuery/testLeftOuterJoinWithConstantExpr3.sql index 90be13bf47..f79b18b5cf 100644 --- a/tajo-core/src/test/resources/queries/TestJoinQuery/testLeftOuterJoinWithConstantExpr3.sql +++ b/tajo-core/src/test/resources/queries/TestJoinQuery/testLeftOuterJoinWithConstantExpr3.sql @@ -14,4 +14,4 @@ left outer join ( b on a.c_custkey = b.c_custkey order by - c_custkey; \ No newline at end of file + a.c_custkey; \ No newline at end of file diff --git a/tajo-core/src/test/resources/results/TestJoinQuery/testComplexJoinCondition1.result b/tajo-core/src/test/resources/results/TestJoinQuery/testComplexJoinCondition1.result new file mode 100644 index 0000000000..e0691a77f8 --- /dev/null +++ b/tajo-core/src/test/resources/results/TestJoinQuery/testComplexJoinCondition1.result @@ -0,0 +1,27 @@ +n_nationkey,n_name,n_name +------------------------------- +0,ALGERIA,ALGERIA +1,ARGENTINA,ARGENTINA +2,BRAZIL,BRAZIL +3,CANADA,CANADA +4,EGYPT,EGYPT +5,ETHIOPIA,ETHIOPIA +6,FRANCE,FRANCE +7,GERMANY,GERMANY +8,INDIA,INDIA +9,INDONESIA,INDONESIA +10,IRAN,IRAN +11,IRAQ,IRAQ +12,JAPAN,JAPAN +13,JORDAN,JORDAN +14,KENYA,KENYA +15,MOROCCO,MOROCCO +16,MOZAMBIQUE,MOZAMBIQUE +17,PERU,PERU +18,CHINA,CHINA +19,ROMANIA,ROMANIA +20,SAUDI ARABIA,SAUDI ARABIA +21,VIETNAM,VIETNAM +22,RUSSIA,RUSSIA +23,UNITED KINGDOM,UNITED KINGDOM +24,UNITED STATES,UNITED STATES \ No newline at end of file diff --git a/tajo-core/src/test/resources/results/TestJoinQuery/testComplexJoinCondition2.result b/tajo-core/src/test/resources/results/TestJoinQuery/testComplexJoinCondition2.result new file mode 100644 index 0000000000..63289e1d0c --- /dev/null +++ b/tajo-core/src/test/resources/results/TestJoinQuery/testComplexJoinCondition2.result @@ -0,0 +1,27 @@ +n_nationkey,n_name,name +------------------------------- +0,ALGERIA,ALGERIA +1,ARGENTINA,ARGENTINA +2,BRAZIL,BRAZIL +3,CANADA,CANADA +4,EGYPT,EGYPT +5,ETHIOPIA,ETHIOPIA +6,FRANCE,FRANCE +7,GERMANY,GERMANY +8,INDIA,INDIA +9,INDONESIA,INDONESIA +10,IRAN,IRAN +11,IRAQ,IRAQ +12,JAPAN,JAPAN +13,JORDAN,JORDAN +14,KENYA,KENYA +15,MOROCCO,MOROCCO +16,MOZAMBIQUE,MOZAMBIQUE +17,PERU,PERU +18,CHINA,CHINA +19,ROMANIA,ROMANIA +20,SAUDI ARABIA,SAUDI ARABIA +21,VIETNAM,VIETNAM +22,RUSSIA,RUSSIA +23,UNITED KINGDOM,UNITED KINGDOM +24,UNITED STATES,UNITED STATES \ No newline at end of file diff --git a/tajo-core/src/test/resources/results/TestJoinQuery/testComplexJoinCondition3.result b/tajo-core/src/test/resources/results/TestJoinQuery/testComplexJoinCondition3.result new file mode 100644 index 0000000000..e0691a77f8 --- /dev/null +++ b/tajo-core/src/test/resources/results/TestJoinQuery/testComplexJoinCondition3.result @@ -0,0 +1,27 @@ +n_nationkey,n_name,n_name +------------------------------- +0,ALGERIA,ALGERIA +1,ARGENTINA,ARGENTINA +2,BRAZIL,BRAZIL +3,CANADA,CANADA +4,EGYPT,EGYPT +5,ETHIOPIA,ETHIOPIA +6,FRANCE,FRANCE +7,GERMANY,GERMANY +8,INDIA,INDIA +9,INDONESIA,INDONESIA +10,IRAN,IRAN +11,IRAQ,IRAQ +12,JAPAN,JAPAN +13,JORDAN,JORDAN +14,KENYA,KENYA +15,MOROCCO,MOROCCO +16,MOZAMBIQUE,MOZAMBIQUE +17,PERU,PERU +18,CHINA,CHINA +19,ROMANIA,ROMANIA +20,SAUDI ARABIA,SAUDI ARABIA +21,VIETNAM,VIETNAM +22,RUSSIA,RUSSIA +23,UNITED KINGDOM,UNITED KINGDOM +24,UNITED STATES,UNITED STATES \ No newline at end of file diff --git a/tajo-core/src/test/resources/results/TestJoinQuery/testComplexJoinCondition4.result b/tajo-core/src/test/resources/results/TestJoinQuery/testComplexJoinCondition4.result new file mode 100644 index 0000000000..689eb624d3 --- /dev/null +++ b/tajo-core/src/test/resources/results/TestJoinQuery/testComplexJoinCondition4.result @@ -0,0 +1,29 @@ +n_nationkey,name1,name2 +------------------------------- +0,ALGE,ALGE +1,ARGE,ARGE +2,BRAZ,BRAZ +3,CANA,CANA +4,EGYP,EGYP +5,ETHI,ETHI +6,FRAN,FRAN +7,GERM,GERM +8,INDI,INDI +9,INDO,INDO +10,IRAN,IRAN +11,IRAQ,IRAQ +12,JAPA,JAPA +13,JORD,JORD +14,KENY,KENY +15,MORO,MORO +16,MOZA,MOZA +17,PERU,PERU +18,CHIN,CHIN +19,ROMA,ROMA +20,SAUD,SAUD +21,VIET,VIET +22,RUSS,RUSS +23,UNIT,UNIT +24,UNIT,UNIT +23,UNIT,UNIT +24,UNIT,UNIT \ No newline at end of file diff --git a/tajo-core/src/test/resources/results/TestJoinQuery/testDifferentTypesJoinCondition.result b/tajo-core/src/test/resources/results/TestJoinQuery/testDifferentTypesJoinCondition.result new file mode 100644 index 0000000000..d5b7510b4c --- /dev/null +++ b/tajo-core/src/test/resources/results/TestJoinQuery/testDifferentTypesJoinCondition.result @@ -0,0 +1,7 @@ +id,name,score,type,id,name,score,type +------------------------------- +1,ooo,1.1,a,1,ooo,1.1,a +2,ppp,2.3,b,2,ppp,2.3,b +3,qqq,3.4,c,3,qqq,3.4,c +4,rrr,4.5,d,4,rrr,4.5,d +5,xxx,5.6,e,5,xxx,5.6,e \ No newline at end of file From a76682b906ae3be54332e2224d91308448f96f15 Mon Sep 17 00:00:00 2001 From: Hyunsik Choi Date: Tue, 24 Jun 2014 18:57:54 +0900 Subject: [PATCH 2/3] Fixed some unit test failures after rebase. --- .../planner/rewrite/ProjectionPushDownRule.java | 8 ++++++-- .../java/org/apache/tajo/master/GlobalEngine.java | 11 ++++++----- .../org/apache/tajo/engine/query/TestJoinQuery.java | 11 ++++++++--- .../TestJoinQuery/testComplexJoinCondition1.sql | 7 ++++++- .../TestJoinQuery/testComplexJoinCondition2.sql | 7 ++++++- .../TestJoinQuery/testComplexJoinCondition3.sql | 7 ++++++- .../TestJoinQuery/testComplexJoinCondition4.sql | 7 ++++++- .../TestJoinQuery/testComplexJoinCondition4.result | 2 +- 8 files changed, 45 insertions(+), 15 deletions(-) diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/rewrite/ProjectionPushDownRule.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/rewrite/ProjectionPushDownRule.java index dbd36d6469..827daeec5f 100644 --- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/rewrite/ProjectionPushDownRule.java +++ b/tajo-core/src/main/java/org/apache/tajo/engine/planner/rewrite/ProjectionPushDownRule.java @@ -732,8 +732,12 @@ public LogicalNode visitFilter(Context context, LogicalPlan plan, LogicalPlan.Qu private static void pushDownIfComplexTermInJoinCondition(Context ctx, EvalNode cnf, EvalNode term) throws PlanningException { - if (term.getType() != EvalType.FIELD) { - String refName = ctx.targetListMgr.add(term); + + // If one of both terms in a binary operator is a complex expression, the binary operator will require + // multiple phases. In this case, join cannot evaluate a binary operator. + // So, we should prevent dividing the binary operator into more subexpressions. + if (term.getType() != EvalType.FIELD && !(term instanceof BinaryEval)) { + String refName = ctx.addExpr(term); EvalTreeUtil.replace(cnf, term, new FieldEval(refName, term.getValueType())); } } diff --git a/tajo-core/src/main/java/org/apache/tajo/master/GlobalEngine.java b/tajo-core/src/main/java/org/apache/tajo/master/GlobalEngine.java index db82dfa332..df2364337d 100644 --- a/tajo-core/src/main/java/org/apache/tajo/master/GlobalEngine.java +++ b/tajo-core/src/main/java/org/apache/tajo/master/GlobalEngine.java @@ -478,11 +478,12 @@ private LogicalPlan createLogicalPlan(Session session, Expr expression) throws P } LogicalPlan plan = planner.createPlan(session, expression); - if (LOG.isDebugEnabled()) { - LOG.debug("============================================="); - LOG.debug("Non Optimized Query: \n" + plan.toString()); - LOG.debug("============================================="); - } +// if (LOG.isDebugEnabled()) { +// LOG.debug("============================================="); +// LOG.debug("Non Optimized Query: \n" + plan.toString()); +// LOG.debug("============================================="); +// } + LOG.info("Non Optimized Query: \n" + plan.toString()); optimizer.optimize(session, plan); LOG.info("============================================="); LOG.info("Optimized Query: \n" + plan.toString()); diff --git a/tajo-core/src/test/java/org/apache/tajo/engine/query/TestJoinQuery.java b/tajo-core/src/test/java/org/apache/tajo/engine/query/TestJoinQuery.java index 231376ce32..3ca8186c27 100644 --- a/tajo-core/src/test/java/org/apache/tajo/engine/query/TestJoinQuery.java +++ b/tajo-core/src/test/java/org/apache/tajo/engine/query/TestJoinQuery.java @@ -855,9 +855,14 @@ public void testDifferentTypesJoinCondition() throws Exception { // select * from table3 t3 join table4 t4 on t3.id = t4.id; executeDDL("table1_int8_ddl.sql", "table1", "table3"); executeDDL("table1_int4_ddl.sql", "table1", "table4"); - ResultSet res = executeQuery(); - assertResultSet(res); - cleanupQuery(res); + try { + ResultSet res = executeQuery(); + assertResultSet(res); + cleanupQuery(res); + } finally { + executeString("DROP TABLE table3"); + executeString("DROP TABLE table4"); + } } @Test diff --git a/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition1.sql b/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition1.sql index 5dbc2d6c98..b61ad3812c 100644 --- a/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition1.sql +++ b/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition1.sql @@ -1 +1,6 @@ -select n1.n_nationkey, n1.n_name, n2.n_name from nation n1 join nation n2 on n1.n_name = upper(n2.n_name); \ No newline at end of file +select + n1.n_nationkey, + n1.n_name, + n2.n_name +from nation n1 join nation n2 on n1.n_name = upper(n2.n_name) +order by n1.n_nationkey; \ No newline at end of file diff --git a/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition2.sql b/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition2.sql index b83e82d9c2..33effbbcf6 100644 --- a/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition2.sql +++ b/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition2.sql @@ -1 +1,6 @@ -select n1.n_nationkey, n1.n_name, upper(n2.n_name) as name from nation n1 join nation n2 on n1.n_name = upper(n2.n_name); \ No newline at end of file +select + n1.n_nationkey, + n1.n_name, + upper(n2.n_name) as name +from nation n1 join nation n2 on n1.n_name = upper(n2.n_name) +order by n1.n_nationkey; \ No newline at end of file diff --git a/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition3.sql b/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition3.sql index cffbfb4947..567426940f 100644 --- a/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition3.sql +++ b/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition3.sql @@ -1 +1,6 @@ -select n1.n_nationkey, n1.n_name, n2.n_name from nation n1 join nation n2 on lower(n1.n_name) = lower(n2.n_name); \ No newline at end of file +select + n1.n_nationkey, + n1.n_name, + n2.n_name +from nation n1 join nation n2 on lower(n1.n_name) = lower(n2.n_name) +order by n1.n_nationkey; \ No newline at end of file diff --git a/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition4.sql b/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition4.sql index ea500831ee..45d8adfc4d 100644 --- a/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition4.sql +++ b/tajo-core/src/test/resources/queries/TestJoinQuery/testComplexJoinCondition4.sql @@ -1 +1,6 @@ -select n1.n_nationkey, substr(n1.n_name, 1, 4) name1, substr(n2.n_name, 1, 4) name2 from nation n1 join nation n2 on substr(n1.n_name, 1, 4) = substr(n2.n_name, 1, 4); \ No newline at end of file +select + n1.n_nationkey, + substr(n1.n_name, 1, 4) name1, + substr(n2.n_name, 1, 4) name2 +from nation n1 join nation n2 on substr(n1.n_name, 1, 4) = substr(n2.n_name, 1, 4) +order by n1.n_nationkey; \ No newline at end of file diff --git a/tajo-core/src/test/resources/results/TestJoinQuery/testComplexJoinCondition4.result b/tajo-core/src/test/resources/results/TestJoinQuery/testComplexJoinCondition4.result index 689eb624d3..325375d49c 100644 --- a/tajo-core/src/test/resources/results/TestJoinQuery/testComplexJoinCondition4.result +++ b/tajo-core/src/test/resources/results/TestJoinQuery/testComplexJoinCondition4.result @@ -24,6 +24,6 @@ n_nationkey,name1,name2 21,VIET,VIET 22,RUSS,RUSS 23,UNIT,UNIT -24,UNIT,UNIT 23,UNIT,UNIT +24,UNIT,UNIT 24,UNIT,UNIT \ No newline at end of file From 47033e5a5d8d76fbb69a53a99b6c63973a4c535d Mon Sep 17 00:00:00 2001 From: Hyunsik Choi Date: Wed, 25 Jun 2014 11:41:52 +0900 Subject: [PATCH 3/3] Recover plan output log. --- .../java/org/apache/tajo/master/GlobalEngine.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tajo-core/src/main/java/org/apache/tajo/master/GlobalEngine.java b/tajo-core/src/main/java/org/apache/tajo/master/GlobalEngine.java index df2364337d..db82dfa332 100644 --- a/tajo-core/src/main/java/org/apache/tajo/master/GlobalEngine.java +++ b/tajo-core/src/main/java/org/apache/tajo/master/GlobalEngine.java @@ -478,12 +478,11 @@ private LogicalPlan createLogicalPlan(Session session, Expr expression) throws P } LogicalPlan plan = planner.createPlan(session, expression); -// if (LOG.isDebugEnabled()) { -// LOG.debug("============================================="); -// LOG.debug("Non Optimized Query: \n" + plan.toString()); -// LOG.debug("============================================="); -// } - LOG.info("Non Optimized Query: \n" + plan.toString()); + if (LOG.isDebugEnabled()) { + LOG.debug("============================================="); + LOG.debug("Non Optimized Query: \n" + plan.toString()); + LOG.debug("============================================="); + } optimizer.optimize(session, plan); LOG.info("============================================="); LOG.info("Optimized Query: \n" + plan.toString());