Github user jihoonson commented on a diff in the pull request:
https://github.com/apache/tajo/pull/13#discussion_r13900969
--- Diff:
tajo-core/src/main/java/org/apache/tajo/engine/planner/LogicalPlanner.java ---
@@ -359,62 +415,241 @@ private EvalExprNode
buildPlanForNoneFromStatement(PlanContext context, Stack<Ex
return targets;
}
+ /**
+ * It checks if all targets of Projectable plan node can be evaluated
from the child node.
+ * It can avoid potential errors which possibly occur in physical
operators.
+ *
+ * @param block QueryBlock which includes the Projectable node
+ * @param projectable Projectable node to be valid
+ * @throws PlanningException
+ */
public static void verifyProjectedFields(QueryBlock block, Projectable
projectable) throws PlanningException {
- if (projectable instanceof ProjectionNode &&
block.hasNode(NodeType.GROUP_BY)) {
- for (Target target : projectable.getTargets()) {
- Set<Column> columns =
EvalTreeUtil.findUniqueColumns(target.getEvalTree());
- for (Column c : columns) {
- if (!projectable.getInSchema().contains(c)) {
- throw new PlanningException(c.getQualifiedName()
- + " must appear in the GROUP BY clause or be used in an
aggregate function at node ("
- + projectable.getPID() + ")" );
- }
- }
- }
- } else if (projectable instanceof GroupbyNode) {
+ if (projectable instanceof GroupbyNode) {
GroupbyNode groupbyNode = (GroupbyNode) projectable;
- // It checks if all column references within each target can be
evaluated with the input schema.
- int groupingColumnNum = groupbyNode.getGroupingColumns().length;
- for (int i = 0; i < groupingColumnNum; i++) {
- Set<Column> columns =
EvalTreeUtil.findUniqueColumns(groupbyNode.getTargets()[i].getEvalTree());
- if (!projectable.getInSchema().containsAll(columns)) {
- throw new PlanningException(String.format("Cannot get the
field(s) \"%s\" at node (%d)",
- TUtil.collectionToString(columns), projectable.getPID()));
+
+ if (!groupbyNode.isEmptyGrouping()) { // it should be targets
instead of
+ int groupingKeyNum = groupbyNode.getGroupingColumns().length;
+
+ for (int i = 0; i < groupingKeyNum; i++) {
+ Target target = groupbyNode.getTargets()[i];
+ if (groupbyNode.getTargets()[i].getEvalTree().getType() ==
EvalType.FIELD) {
+ FieldEval grpKeyEvalNode = target.getEvalTree();
+ if
(!groupbyNode.getInSchema().contains(grpKeyEvalNode.getColumnRef())) {
+ throwCannotEvaluateException(projectable,
grpKeyEvalNode.getName());
+ }
+ }
}
}
+
if (groupbyNode.hasAggFunctions()) {
- for (AggregationFunctionCallEval f :
groupbyNode.getAggFunctions()) {
- Set<Column> columns = EvalTreeUtil.findUniqueColumns(f);
- for (Column c : columns) {
- if (!projectable.getInSchema().contains(c)) {
- throw new PlanningException(String.format("Cannot get the
field \"%s\" at node (%d)",
- c, projectable.getPID()));
- }
+ verifyIfEvalNodesCanBeEvaluated(projectable,
groupbyNode.getAggFunctions());
+ }
+
+ } else if (projectable instanceof WindowAggNode) {
+ WindowAggNode windowAggNode = (WindowAggNode) projectable;
+
+ if (windowAggNode.hasPartitionKeys()) {
+ verifyIfColumnCanBeEvaluated(projectable.getInSchema(),
projectable, windowAggNode.getPartitionKeys());
+ }
+
+ if (windowAggNode.hasAggFunctions()) {
+ verifyIfEvalNodesCanBeEvaluated(projectable,
windowAggNode.getWindowFunctions());
+ }
+
+ if (windowAggNode.hasSortSpecs()) {
+ Column [] sortKeys =
PlannerUtil.sortSpecsToSchema(windowAggNode.getSortSpecs()).toArray();
+ verifyIfColumnCanBeEvaluated(projectable.getInSchema(),
projectable, sortKeys);
+ }
+
+ // verify targets except for function slots
+ for (int i = 0; i < windowAggNode.getTargets().length -
windowAggNode.getWindowFunctions().length; i++) {
+ Target target = windowAggNode.getTargets()[i];
+ Set<Column> columns =
EvalTreeUtil.findUniqueColumns(target.getEvalTree());
+ for (Column c : columns) {
+ if (!windowAggNode.getInSchema().contains(c)) {
+ throwCannotEvaluateException(projectable,
c.getQualifiedName());
}
}
}
+
} else if (projectable instanceof RelationNode) {
RelationNode relationNode = (RelationNode) projectable;
- for (Target target : projectable.getTargets()) {
- Set<Column> columns =
EvalTreeUtil.findUniqueColumns(target.getEvalTree());
- for (Column c : columns) {
- if (!relationNode.getTableSchema().contains(c)) {
- throw new PlanningException(String.format("Cannot get the
field \"%s\" at node (%d)",
- c, projectable.getPID()));
- }
+ verifyIfTargetsCanBeEvaluated(relationNode.getTableSchema(),
(Projectable) relationNode);
+
+ } else {
+ verifyIfTargetsCanBeEvaluated(projectable.getInSchema(),
projectable);
+ }
+ }
+
+ public static void verifyIfEvalNodesCanBeEvaluated(Projectable
projectable, EvalNode[] evalNodes)
+ throws PlanningException {
+ for (EvalNode e : evalNodes) {
+ Set<Column> columns = EvalTreeUtil.findUniqueColumns(e);
+ for (Column c : columns) {
+ if (!projectable.getInSchema().contains(c)) {
+ throwCannotEvaluateException(projectable, c.getQualifiedName());
+ }
+ }
+ }
+ }
+
+ public static void verifyIfTargetsCanBeEvaluated(Schema baseSchema,
Projectable projectable)
+ throws PlanningException {
+ for (Target target : projectable.getTargets()) {
+ Set<Column> columns =
EvalTreeUtil.findUniqueColumns(target.getEvalTree());
+ for (Column c : columns) {
+ if (!baseSchema.contains(c)) {
+ throwCannotEvaluateException(projectable, c.getQualifiedName());
}
}
+ }
+ }
+
+ public static void verifyIfColumnCanBeEvaluated(Schema baseSchema,
Projectable projectable, Column [] columns)
+ throws PlanningException {
+ for (Column c : columns) {
+ if (!baseSchema.contains(c)) {
+ throwCannotEvaluateException(projectable, c.getQualifiedName());
+ }
+ }
+ }
+
+ public static void throwCannotEvaluateException(Projectable projectable,
String columnName) throws PlanningException {
+ if (projectable instanceof UnaryNode && ((UnaryNode)
projectable).getChild().getType() == NodeType.GROUP_BY) {
+ throw new PlanningException(columnName
+ + " must appear in the GROUP BY clause or be used in an
aggregate function at node ("
+ + projectable.getPID() + ")");
} else {
- for (Target target : projectable.getTargets()) {
- Set<Column> columns =
EvalTreeUtil.findUniqueColumns(target.getEvalTree());
- for (Column c : columns) {
- if (!projectable.getInSchema().contains(c)) {
- throw new PlanningException(String.format("Cannot get the
field \"%s\" at node (%d)",
- c, projectable.getPID()));
+ throw new PlanningException(String.format("Cannot evaluate the field
\"%s\" at node (%d)",
+ columnName, projectable.getPID()));
+ }
+ }
+
+ private LogicalNode insertWindowAggNode(PlanContext context, LogicalNode
child, Stack<Expr> stack,
+ String [] referenceNames,
+
ExprNormalizer.WindowSpecReferences [] windowSpecReferenceses)
+ throws PlanningException {
+ LogicalPlan plan = context.plan;
+ QueryBlock block = context.queryBlock;
+ WindowAggNode windowAggNode =
context.plan.createNode(WindowAggNode.class);
+ if (child.getType() == NodeType.LIMIT) {
+ LimitNode limitNode = (LimitNode) child;
+ windowAggNode.setChild(limitNode.getChild());
+ windowAggNode.setInSchema(limitNode.getChild().getOutSchema());
+ limitNode.setChild(windowAggNode);
+ } else if (child.getType() == NodeType.SORT) {
+ SortNode sortNode = (SortNode) child;
+ windowAggNode.setChild(sortNode.getChild());
+ windowAggNode.setInSchema(sortNode.getChild().getOutSchema());
+ sortNode.setChild(windowAggNode);
+ } else {
+ windowAggNode.setChild(child);
+ windowAggNode.setInSchema(child.getOutSchema());
+ }
+
+ List<String> winFuncRefs = new ArrayList<String>();
+ List<WindowFunctionEval> winFuncs = new
ArrayList<WindowFunctionEval>();
+ List<WindowSpec> rawWindowSpecs = Lists.newArrayList();
+ for (Iterator<NamedExpr> it =
block.namedExprsMgr.getIteratorForUnevaluatedExprs(); it.hasNext();) {
+ NamedExpr rawTarget = it.next();
+ try {
+ EvalNode evalNode = exprAnnotator.createEvalNode(context.plan,
context.queryBlock, rawTarget.getExpr());
+ if (evalNode.getType() == EvalType.WINDOW_FUNCTION) {
+ winFuncRefs.add(rawTarget.getAlias());
+ winFuncs.add((WindowFunctionEval) evalNode);
+ block.namedExprsMgr.markAsEvaluated(rawTarget.getAlias(),
evalNode);
+
+ // TODO - Later, we also consider the possibility that a window
function contains only a window name.
+ rawWindowSpecs.add(((WindowFunctionExpr)
(rawTarget.getExpr())).getWindowSpec());
+ }
+ } catch (VerifyException ve) {
--- End diff --
Don't we need to handle this exception?
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at [email protected] or file a JIRA ticket
with INFRA.
---