/** * Examine if the expr contains the column reference corresponding * to the target column */ public static boolean containColumnRef(EvalNode expr, Column target) { Set<Column> exprSet = findUniqueColumns(expr); return exprSet.contains(target); }
/** * It checks if evalNode can be evaluated at this @{link RelationNode}. */ public static boolean checkIfBeEvaluatedAtRelation(QueryBlock block, EvalNode evalNode, RelationNode node) { Set<Column> columnRefs = EvalTreeUtil.findUniqueColumns(evalNode); // aggregation functions cannot be evaluated in scan node if (EvalTreeUtil.findDistinctAggFunction(evalNode).size() > 0) { return false; } // aggregation functions cannot be evaluated in scan node if (EvalTreeUtil.findEvalsByType(evalNode, EvalType.WINDOW_FUNCTION).size() > 0) { return false; } if (columnRefs.size() > 0 && !node.getLogicalSchema().containsAll(columnRefs)) { return false; } // Why? - When a {case when} is used with outer join, case when must be evaluated at topmost outer join. if (containsOuterJoin(block)) { Collection<EvalNode> found = EvalTreeUtil.findOuterJoinSensitiveEvals(evalNode); if (found.size() > 0) { return false; } } return true; }
/** * Return all exprs to refer columns corresponding to the target. * * @param expr * @param target to be found * @return a list of exprs */ public static Collection<EvalNode> getContainExpr(EvalNode expr, Column target) { Set<EvalNode> exprSet = Sets.newHashSet(); getContainExpr(expr, target, exprSet); return exprSet; }
public static boolean checkIfCanBeConstant(EvalNode evalNode) { return findUniqueColumns(evalNode).size() == 0 && findDistinctAggFunction(evalNode).size() == 0; }
public static boolean checkIfBeEvaluatedAtGroupBy(EvalNode evalNode, GroupbyNode node) { Set<Column> columnRefs = EvalTreeUtil.findUniqueColumns(evalNode); if (columnRefs.size() > 0 && !node.getInSchema().containsAll(columnRefs)) { return false; } if (EvalTreeUtil.findEvalsByType(evalNode, EvalType.WINDOW_FUNCTION).size() > 0) { return false; } return true; }
for (Column evalColumn : EvalTreeUtil.findUniqueColumns(copy)) { if (aggrFunctionOutColumns.contains(evalColumn.getSimpleName())) { EvalTreeUtil.changeColumnRef(copy, evalColumn.getQualifiedName(), evalColumn.getSimpleName()); isEvalAggrFunction = true; break; if (groupByNode.getInSchema().containsAll(EvalTreeUtil.findUniqueColumns(copy))) { isEvalAggrFunction = true;
/** * Check whether the given predicate can be evaluated at the given join edge or not. The result depends on * the isOnPredicate flag which represents the given predicate is from the on clause of not. * * @param evalNode predicate * @param edge join edge * @param isOnPredicate flag to represent the candidates from the on clause of not * @return true if the predicate can be evaluated at the given join edge */ public static boolean checkIfEvaluatedAtEdge(EvalNode evalNode, JoinEdge edge, boolean isOnPredicate) { Set<Column> columnRefs = EvalTreeUtil.findUniqueColumns(evalNode); if (EvalTreeUtil.findDistinctAggFunction(evalNode).size() > 0) { return false; } if (EvalTreeUtil.findEvalsByType(evalNode, EvalType.WINDOW_FUNCTION).size() > 0) { return false; } if (columnRefs.size() > 0 && !edge.getSchema().containsAll(columnRefs)) { return false; } // Currently, join filters cannot be evaluated at joins if (PlannerUtil.isOuterJoinType(edge.getJoinType()) && !isOnPredicate) { return false; } return true; }
boolean isBothTermFields = isSingleColumn(binaryEval.getLeftExpr()) && isSingleColumn(binaryEval.getRightExpr()); Set<Column> leftColumns = EvalTreeUtil.findUniqueColumns(binaryEval.getLeftExpr()); Set<Column> rightColumns = EvalTreeUtil.findUniqueColumns(binaryEval.getRightExpr()); ensureColumnsOfDifferentTables = isJoinQualWithOnlyColumns(block, leftColumn, rightColumn); } else if (leftSchema != null && rightSchema != null) { ensureColumnsOfDifferentTables = isJoinQualwithSchemas(leftSchema, rightSchema, leftColumn, rightColumn); } else { ensureColumnsOfDifferentTables = isJoinQualWithOnlyColumns(null, leftColumn, rightColumn);
/** * If a given expression is join condition, it returns TRUE. Otherwise, it returns FALSE. * * If three conditions are satisfied, we can recognize the expression as a equi join condition. * <ol> * <li>An expression is an equal comparison expression.</li> * <li>Both terms in an expression are column references.</li> * <li>Both column references point come from different tables</li> * </ol> * * For theta join condition, we will use "an expression is a predicate including column references which come * from different two tables" instead of the first rule. * * @param expr EvalNode to be evaluated * @param includeThetaJoin If true, it will return equi as well as non-equi join conditions. * Otherwise, it only returns equi-join conditions. * @return True if it is join condition. */ public static boolean isJoinQual(EvalNode expr, boolean includeThetaJoin) { return isJoinQual(null, null, null, expr, includeThetaJoin); }
LinkedHashSet<Column> groupbyUniqColumns = EvalTreeUtil.findUniqueColumns(aggFunction); String groupbyMapKey = EvalTreeUtil.columnsToStr(groupbyUniqColumns); DistinctGroupbyNodeBuildInfo buildInfo = distinctNodeBuildInfos.get(groupbyMapKey); if (buildInfo == null) {
@Override public void visit(EvalNode node) { if (EvalTreeUtil.isJoinQual(null, schemas[0], schemas[1], node, includeThetaJoin)) { BinaryEval binaryEval = (BinaryEval) node; Column[] pair = new Column[2]; for (int i = 0; i <= 1; i++) { // access left, right sub expression Column column = EvalTreeUtil.findAllColumnRefs(binaryEval.getChild(i)).get(0); for (int j = 0; j < schemas.length; j++) { // check whether the column is for either outer or inner // 0 is outer, and 1 is inner if (schemas[j].contains(column.getQualifiedName())) { pair[j] = column; } } } if (pair[0] == null || pair[1] == null) { throw new IllegalStateException("Wrong join key: " + node); } pairs.add(pair); } }
private LogicalNode createCartesianProduct(PlanContext context, LogicalNode left, LogicalNode right) throws TajoException { LogicalPlan plan = context.plan; QueryBlock block = context.queryBlock; Schema merged = SchemaUtil.merge(left.getOutSchema(), right.getOutSchema()); JoinNode join = plan.createNode(JoinNode.class); join.init(JoinType.CROSS, left, right); join.setInSchema(merged); block.addJoinType(join.getJoinType()); EvalNode evalNode; List<String> newlyEvaluatedExprs = new ArrayList<>(); for (Iterator<NamedExpr> it = block.namedExprsMgr.getIteratorForUnevaluatedExprs(); it.hasNext();) { NamedExpr namedExpr = it.next(); try { evalNode = exprAnnotator.createEvalNode(context, namedExpr.getExpr(), NameResolvingMode.LEGACY); if (EvalTreeUtil.findDistinctAggFunction(evalNode).size() == 0 && EvalTreeUtil.findWindowFunction(evalNode).size() == 0) { block.namedExprsMgr.markAsEvaluated(namedExpr.getAlias(), evalNode); newlyEvaluatedExprs.add(namedExpr.getAlias()); } } catch (UndefinedColumnException ve) {} } List<Target> targets = new ArrayList<>(PlannerUtil.schemaToTargets(merged)); for (String newAddedExpr : newlyEvaluatedExprs) { targets.add(block.namedExprsMgr.getTarget(newAddedExpr, true)); } join.setTargets(targets); return join; }
private static void pushDownIfComplexTermInJoinCondition(Context ctx, EvalNode cnf, EvalNode term) throws TajoException { // 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) && term.getType() != EvalType.ROW_CONSTANT && term.getType() != EvalType.CONST) { String refName = ctx.addExpr(term); EvalTreeUtil.replace(cnf, term, new FieldEval(refName, term.getValueType())); } }
@Override public EvalNode visitValueListExpr(Context ctx, Stack<Expr> stack, ValueListExpr expr) throws TajoException { Datum[] values = new Datum[expr.getValues().length]; EvalNode [] evalNodes = new EvalNode[expr.getValues().length]; for (int i = 0; i < expr.getValues().length; i++) { evalNodes[i] = visit(ctx, stack, expr.getValues()[i]); if (!EvalTreeUtil.checkIfCanBeConstant(evalNodes[i])) { throw makeSyntaxError("Non constant values cannot be included in IN PREDICATE."); } values[i] = EvalTreeUtil.evaluateImmediately(null, evalNodes[i]); } return new RowConstantEval(values); }
@Test public final void testFindDistinctAggFunctions() throws TajoException { String query = "select sum(score) + max(age) from people"; Expr expr = analyzer.parse(query); LogicalPlan plan = planner.createPlan(defaultContext, expr); GroupbyNode groupByNode = plan.getRootBlock().getNode(NodeType.GROUP_BY); List aggEvals = groupByNode.getAggFunctions(); List<AggregationFunctionCallEval> list = new ArrayList<>(); for (Object aggEval : aggEvals) { list.addAll(EvalTreeUtil.findDistinctAggFunction((EvalNode) aggEval)); } assertEquals(2, list.size()); Set<String> result = Sets.newHashSet("max", "sum"); for (AggregationFunctionCallEval eval : list) { assertTrue(result.contains(eval.getName())); } }
for (Column evalColumn : EvalTreeUtil.findUniqueColumns(copy)) { if (aggrFunctionOutColumns.contains(evalColumn.getSimpleName())) { EvalTreeUtil.changeColumnRef(copy, evalColumn.getQualifiedName(), evalColumn.getSimpleName()); isEvalAggrFunction = true; break; if (groupByNode.getInSchema().containsAll(EvalTreeUtil.findUniqueColumns(copy))) { isEvalAggrFunction = true;
public static boolean checkIfCanBeConstant(EvalNode evalNode) { return findUniqueColumns(evalNode).size() == 0 && findDistinctAggFunction(evalNode).size() == 0; }
/** * Check whether the given predicate can be evaluated at the given join edge or not. The result depends on * the isOnPredicate flag which represents the given predicate is from the on clause of not. * * @param evalNode predicate * @param edge join edge * @param isOnPredicate flag to represent the candidates from the on clause of not * @return true if the predicate can be evaluated at the given join edge */ public static boolean checkIfEvaluatedAtEdge(EvalNode evalNode, JoinEdge edge, boolean isOnPredicate) { Set<Column> columnRefs = EvalTreeUtil.findUniqueColumns(evalNode); if (EvalTreeUtil.findDistinctAggFunction(evalNode).size() > 0) { return false; } if (EvalTreeUtil.findEvalsByType(evalNode, EvalType.WINDOW_FUNCTION).size() > 0) { return false; } if (columnRefs.size() > 0 && !edge.getSchema().containsAll(columnRefs)) { return false; } // Currently, join filters cannot be evaluated at joins if (PlannerUtil.isOuterJoinType(edge.getJoinType()) && !isOnPredicate) { return false; } return true; }
boolean isBothTermFields = isSingleColumn(binaryEval.getLeftExpr()) && isSingleColumn(binaryEval.getRightExpr()); Set<Column> leftColumns = EvalTreeUtil.findUniqueColumns(binaryEval.getLeftExpr()); Set<Column> rightColumns = EvalTreeUtil.findUniqueColumns(binaryEval.getRightExpr()); ensureColumnsOfDifferentTables = isJoinQualWithOnlyColumns(block, leftColumn, rightColumn); } else if (leftSchema != null && rightSchema != null) { ensureColumnsOfDifferentTables = isJoinQualwithSchemas(leftSchema, rightSchema, leftColumn, rightColumn); } else { ensureColumnsOfDifferentTables = isJoinQualWithOnlyColumns(null, leftColumn, rightColumn);
/** * If a given expression is join condition, it returns TRUE. Otherwise, it returns FALSE. * * If three conditions are satisfied, we can recognize the expression as a equi join condition. * <ol> * <li>An expression is an equal comparison expression.</li> * <li>Both terms in an expression are column references.</li> * <li>Both column references point come from different tables</li> * </ol> * * For theta join condition, we will use "an expression is a predicate including column references which come * from different two tables" instead of the first rule. * * @param expr EvalNode to be evaluated * @param includeThetaJoin If true, it will return equi as well as non-equi join conditions. * Otherwise, it only returns equi-join conditions. * @return True if it is join condition. */ public static boolean isJoinQual(EvalNode expr, boolean includeThetaJoin) { return isJoinQual(null, null, null, expr, includeThetaJoin); }