From 98a9cfa4778c1bbd035157865e28f57c10622cee Mon Sep 17 00:00:00 2001 From: Hyunsik Choi Date: Tue, 7 Oct 2014 10:09:20 -0700 Subject: [PATCH] TAJO-1099: LogicalPlanner::convertDataType causes NPE in some cases. --- .../engine/eval/SimpleEvalNodeVisitor.java | 3 ++ .../optimizer/eval/EvalTreeOptimizer.java | 2 ++ .../planner/LogicalPlanPreprocessor.java | 34 +++++++++++-------- .../tajo/engine/planner/TypeDeterminant.java | 17 ++++++++++ .../engine/planner/logical/EvalExprNode.java | 2 ++ 5 files changed, 44 insertions(+), 14 deletions(-) diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/eval/SimpleEvalNodeVisitor.java b/tajo-core/src/main/java/org/apache/tajo/engine/eval/SimpleEvalNodeVisitor.java index 15b628bb01..7e7594a7a9 100644 --- a/tajo-core/src/main/java/org/apache/tajo/engine/eval/SimpleEvalNodeVisitor.java +++ b/tajo-core/src/main/java/org/apache/tajo/engine/eval/SimpleEvalNodeVisitor.java @@ -18,6 +18,7 @@ package org.apache.tajo.engine.eval; +import com.google.common.base.Preconditions; import org.apache.tajo.exception.UnsupportedException; import java.util.Stack; @@ -29,6 +30,8 @@ public abstract class SimpleEvalNodeVisitor { public EvalNode visit(CONTEXT context, EvalNode evalNode, Stack stack) { + Preconditions.checkNotNull(evalNode); + EvalNode result; if (evalNode instanceof UnaryEval) { diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/optimizer/eval/EvalTreeOptimizer.java b/tajo-core/src/main/java/org/apache/tajo/engine/optimizer/eval/EvalTreeOptimizer.java index f5b4c06770..3ed272e269 100644 --- a/tajo-core/src/main/java/org/apache/tajo/engine/optimizer/eval/EvalTreeOptimizer.java +++ b/tajo-core/src/main/java/org/apache/tajo/engine/optimizer/eval/EvalTreeOptimizer.java @@ -18,6 +18,7 @@ package org.apache.tajo.engine.optimizer.eval; +import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -65,6 +66,7 @@ public int compare(EvalTreeOptimizationRule o1, EvalTreeOptimizationRule o2) { } public EvalNode optimize(LogicalPlanner.PlanContext context, EvalNode node) { + Preconditions.checkNotNull(node); EvalNode optimized = node; for (EvalTreeOptimizationRule rule : rules) { 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 index 96758d6031..5897ba6fdd 100644 --- 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 @@ -162,7 +162,9 @@ public LogicalNode visitProjection(LogicalPlanner.PlanContext ctx, Stack s throws PlanningException { // If Non-from statement, it immediately returns. if (!expr.hasChild()) { - return ctx.plan.createNode(EvalExprNode.class); + EvalExprNode exprNode = ctx.plan.createNode(EvalExprNode.class); + exprNode.setTargets(buildTargets(ctx, expr.getNamedExprs())); + return exprNode; } stack.push(expr); // <--- push @@ -200,20 +202,8 @@ public LogicalNode visitProjection(LogicalPlanner.PlanContext ctx, Stack s } } - Target [] targets; - targets = new Target[projectTargetExprs.length]; + Target [] targets = buildTargets(ctx, expr.getNamedExprs()); - for (int i = 0; i < expr.getNamedExprs().length; i++) { - NamedExpr namedExpr = expr.getNamedExprs()[i]; - TajoDataTypes.DataType dataType = typeDeterminant.determineDataType(ctx, namedExpr.getExpr()); - - if (namedExpr.hasAlias()) { - targets[i] = new Target(new FieldEval(new Column(namedExpr.getAlias(), dataType))); - } else { - String generatedName = ctx.plan.generateUniqueColumnName(namedExpr.getExpr()); - targets[i] = new Target(new FieldEval(new Column(generatedName, dataType))); - } - } stack.pop(); // <--- Pop ProjectionNode projectionNode = ctx.plan.createNode(ProjectionNode.class); @@ -224,6 +214,22 @@ public LogicalNode visitProjection(LogicalPlanner.PlanContext ctx, Stack s 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 stack, Limit expr) throws PlanningException { diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/TypeDeterminant.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/TypeDeterminant.java index 275e056b60..94a8d4a6da 100644 --- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/TypeDeterminant.java +++ b/tajo-core/src/main/java/org/apache/tajo/engine/planner/TypeDeterminant.java @@ -18,6 +18,7 @@ package org.apache.tajo.engine.planner; +import com.google.common.base.Preconditions; import org.apache.tajo.algebra.*; import org.apache.tajo.catalog.CatalogService; import org.apache.tajo.catalog.CatalogUtil; @@ -77,6 +78,10 @@ public DataType visitBinaryOperator(LogicalPlanner.PlanContext ctx, Stack } public DataType computeBinaryType(OpType type, DataType lhsDataType, DataType rhsDataType) throws PlanningException { + Preconditions.checkNotNull(type); + Preconditions.checkNotNull(lhsDataType); + Preconditions.checkNotNull(rhsDataType); + if(OpType.isLogicalType(type) || OpType.isComparisonType(type)) { return BOOL_TYPE; } else if (OpType.isArithmeticType(type)) { @@ -301,4 +306,16 @@ public DataType visitTimeLiteral(LogicalPlanner.PlanContext ctx, Stack sta throws PlanningException { return CatalogUtil.newSimpleDataType(TajoDataTypes.Type.TIME); } + + @Override + public DataType visitDateLiteral(LogicalPlanner.PlanContext ctx, Stack stack, DateLiteral expr) + throws PlanningException { + return CatalogUtil.newSimpleDataType(TajoDataTypes.Type.DATE); + } + + @Override + public DataType visitIntervalLiteral(LogicalPlanner.PlanContext ctx, Stack stack, IntervalLiteral expr) + throws PlanningException { + return CatalogUtil.newSimpleDataType(TajoDataTypes.Type.INTERVAL); + } } diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/planner/logical/EvalExprNode.java b/tajo-core/src/main/java/org/apache/tajo/engine/planner/logical/EvalExprNode.java index 6ea3f4055e..45ab611f5b 100644 --- a/tajo-core/src/main/java/org/apache/tajo/engine/planner/logical/EvalExprNode.java +++ b/tajo-core/src/main/java/org/apache/tajo/engine/planner/logical/EvalExprNode.java @@ -23,6 +23,7 @@ import com.google.gson.annotations.Expose; import org.apache.tajo.engine.planner.PlanString; +import org.apache.tajo.engine.planner.PlannerUtil; import org.apache.tajo.engine.planner.Target; import org.apache.tajo.util.TUtil; @@ -41,6 +42,7 @@ public boolean hasTargets() { @Override public void setTargets(Target[] targets) { this.exprs = targets; + setOutSchema(PlannerUtil.targetToSchema(targets)); } @Override