use of io.prestosql.spi.plan.JoinNode in project hetu-core by openlookeng.
the class PushAggregationThroughOuterJoin method apply.
@Override
public Result apply(AggregationNode aggregation, Captures captures, Context context) {
JoinNode join = captures.get(JOIN);
if (join.getFilter().isPresent() || !(join.getType() == JoinNode.Type.LEFT || join.getType() == JoinNode.Type.RIGHT) || !groupsOnAllColumns(aggregation, getOuterTable(join).getOutputSymbols()) || !isDistinct(context.getLookup().resolve(getOuterTable(join)), context.getLookup()::resolve)) {
return Result.empty();
}
List<Symbol> groupingKeys = join.getCriteria().stream().map(join.getType() == JoinNode.Type.RIGHT ? JoinNode.EquiJoinClause::getLeft : JoinNode.EquiJoinClause::getRight).collect(toImmutableList());
AggregationNode rewrittenAggregation = new AggregationNode(aggregation.getId(), getInnerTable(join), aggregation.getAggregations(), singleGroupingSet(groupingKeys), ImmutableList.of(), aggregation.getStep(), aggregation.getHashSymbol(), aggregation.getGroupIdSymbol(), aggregation.getAggregationType(), aggregation.getFinalizeSymbol());
JoinNode rewrittenJoin;
if (join.getType() == JoinNode.Type.LEFT) {
rewrittenJoin = new JoinNode(join.getId(), join.getType(), join.getLeft(), rewrittenAggregation, join.getCriteria(), ImmutableList.<Symbol>builder().addAll(join.getLeft().getOutputSymbols()).addAll(rewrittenAggregation.getAggregations().keySet()).build(), join.getFilter(), join.getLeftHashSymbol(), join.getRightHashSymbol(), join.getDistributionType(), join.isSpillable(), join.getDynamicFilters());
} else {
rewrittenJoin = new JoinNode(join.getId(), join.getType(), rewrittenAggregation, join.getRight(), join.getCriteria(), ImmutableList.<Symbol>builder().addAll(rewrittenAggregation.getAggregations().keySet()).addAll(join.getRight().getOutputSymbols()).build(), join.getFilter(), join.getLeftHashSymbol(), join.getRightHashSymbol(), join.getDistributionType(), join.isSpillable(), join.getDynamicFilters());
}
Optional<PlanNode> resultNode = coalesceWithNullAggregation(rewrittenAggregation, rewrittenJoin, context.getSymbolAllocator(), context.getIdAllocator(), context.getLookup());
if (!resultNode.isPresent()) {
return Result.empty();
}
return Result.ofPlanNode(resultNode.get());
}
use of io.prestosql.spi.plan.JoinNode in project hetu-core by openlookeng.
the class TablePushdown method updateOuterTableAndInnerTablePath.
/**
* @param originalOuterJoinNode the original JoinNode captured by the rule
* @param stack the stack which has all nodes from outer join to the TableScanNode of the table to be pushed down
* @param lookup captured from the context
* @return the final updated plan tree after all rearrangements
*/
private PlanNode updateOuterTableAndInnerTablePath(JoinNode originalOuterJoinNode, Stack<NodeWithTreeDirection> stack, Lookup lookup) {
if (verifyIfJoinNodeInPath(stack)) {
Stack<NodeWithTreeDirection> intermediateOuterTableStack = new Stack<>();
// First pop the stack till we reach a join node and push into another intermediateOuterTableStack.
while (!(stack.peek().getNode() instanceof JoinNode)) {
intermediateOuterTableStack.push(stack.pop());
}
JoinNode originalInnerJoinNode = (JoinNode) stack.peek().getNode();
PlanNode childOfInnerJoin = intermediateOuterTableStack.peek().getNode();
List<Symbol> outerJoinOutputSymbols = originalOuterJoinNode.getOutputSymbols();
// update the outputSymbol for the new outer Join node to same as previous outer join
List<Symbol> newOuterOutputSymbols = ImmutableList.<Symbol>builder().addAll(outerJoinOutputSymbols).build();
List<Symbol> newInnerOutputSymbols;
/*
* Based on which direction the outer table is from the original Outer JoinNode(orig-OJ), do the following-
* Get the output symbols from opposite direction source of orig-OJ
* Get the output symbols from the child of the original Inner JoinNode(orig-IJ), which will be moved.
* Add them to a List in appropriate order. This list is the output symbols for new-IJ (created from orig-OJ)
* */
if (outerTableDirection == DIRECTION.LEFT) {
newInnerOutputSymbols = ImmutableList.<Symbol>builder().addAll(childOfInnerJoin.getOutputSymbols()).addAll(originalOuterJoinNode.getRight().getOutputSymbols()).build();
} else {
newInnerOutputSymbols = ImmutableList.<Symbol>builder().addAll(originalOuterJoinNode.getLeft().getOutputSymbols()).addAll(childOfInnerJoin.getOutputSymbols()).build();
}
/*
* this sets new outer join's join criteria
* As the earlier inner is new outer, it's join criteria must borrow from both the earlier join criterias
* hence choose the unchanged ones, as these were the ones which were forwarded to earlier outerjoin
* For the original join node's unchanged child-
* this join criteria must be present here also as it was used earlier
* */
List<JoinNode.EquiJoinClause> newInnerJoinCriteria = getNewInnerJoinCriteria(originalInnerJoinNode, originalOuterJoinNode);
List<JoinNode.EquiJoinClause> newOuterJoinCriteria = getNewOuterJoinCriteria(originalInnerJoinNode, originalOuterJoinNode);
JoinNode newOuterJoinNode;
JoinNode newInnerJoinNode;
/*
* Create the final new inner JoinNode based on the requirement of a JoinFilter or not
* */
if (needNewInnerJoinFilter(originalOuterJoinNode, childOfInnerJoin)) {
newInnerJoinNode = new JoinNode(originalOuterJoinNode.getId(), originalOuterJoinNode.getType(), childOfInnerJoin, resolveNodeFromGroupReference(originalOuterJoinNode, 1, lookup), newInnerJoinCriteria, newInnerOutputSymbols, originalOuterJoinNode.getFilter(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), originalOuterJoinNode.getDynamicFilters());
} else {
newInnerJoinNode = new JoinNode(originalOuterJoinNode.getId(), originalOuterJoinNode.getType(), childOfInnerJoin, resolveNodeFromGroupReference(originalOuterJoinNode, 1, lookup), newInnerJoinCriteria, newInnerOutputSymbols, Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), originalOuterJoinNode.getDynamicFilters());
}
/*
* Create the new outer JoinNode based on the direction of the subquery table
* */
if (innerTableDirection == DIRECTION.LEFT) {
newOuterJoinNode = new JoinNode(originalInnerJoinNode.getId(), originalInnerJoinNode.getType(), newInnerJoinNode, originalInnerJoinNode.getRight(), newOuterJoinCriteria, newOuterOutputSymbols, originalOuterJoinNode.getFilter(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), originalInnerJoinNode.getDynamicFilters());
} else {
newOuterJoinNode = new JoinNode(originalInnerJoinNode.getId(), originalInnerJoinNode.getType(), originalInnerJoinNode.getLeft(), newInnerJoinNode, newOuterJoinCriteria, newOuterOutputSymbols, originalOuterJoinNode.getFilter(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), originalInnerJoinNode.getDynamicFilters());
}
return updateInnerTable(newOuterJoinNode, newInnerJoinNode, innerTablePathStack, true);
} else {
/*
* The outer table has a direct path to the JoinNode under consideration
* We don't change the tree at all, instead just returning the current node.
* */
return updateInnerTable(originalOuterJoinNode, originalOuterJoinNode, innerTablePathStack, false);
}
}
use of io.prestosql.spi.plan.JoinNode in project hetu-core by openlookeng.
the class TablePushdown method getNewOuterJoinCriteria.
/**
* @param innerJoinNode the original InnerJoinNode which joined the two outer tables
* @param originalJoinNode the original JoinNode captured by the rule
* @return the new join criteria for the newly created outer join nodes
*/
private List<JoinNode.EquiJoinClause> getNewOuterJoinCriteria(JoinNode innerJoinNode, JoinNode originalJoinNode) {
Symbol joinSymbolOfInnerJoinFixedSource;
Symbol joinSymbolOfOuterJoinFixedSource;
JoinNode.EquiJoinClause newJoinClause;
if (outerTableDirection == DIRECTION.LEFT) {
joinSymbolOfOuterJoinFixedSource = originalJoinNode.getCriteria().get(0).getRight();
} else {
joinSymbolOfOuterJoinFixedSource = originalJoinNode.getCriteria().get(0).getLeft();
}
if (innerTableDirection == DIRECTION.LEFT) {
joinSymbolOfInnerJoinFixedSource = innerJoinNode.getCriteria().get(0).getRight();
newJoinClause = new JoinNode.EquiJoinClause(joinSymbolOfOuterJoinFixedSource, joinSymbolOfInnerJoinFixedSource);
} else {
joinSymbolOfInnerJoinFixedSource = innerJoinNode.getCriteria().get(0).getLeft();
newJoinClause = new JoinNode.EquiJoinClause(joinSymbolOfInnerJoinFixedSource, joinSymbolOfOuterJoinFixedSource);
}
return ImmutableList.of(newJoinClause);
}
use of io.prestosql.spi.plan.JoinNode in project hetu-core by openlookeng.
the class TablePushdown method getNewInnerJoinCriteria.
/**
* @param innerJoinNode the original InnerJoinNode which joined the two outer tables
* @param originalOuterJoin the original JoinNode captured by the rule
* @return the new join criteria for the newly created inner join nodes
*/
private List<JoinNode.EquiJoinClause> getNewInnerJoinCriteria(JoinNode innerJoinNode, JoinNode originalOuterJoin) {
Symbol joinSymbolOfInnerJoinTransferSource;
Symbol joinSymbolOfOuterJoinFixedSource;
JoinNode.EquiJoinClause newJoinClause;
if (innerTableDirection == DIRECTION.LEFT) {
joinSymbolOfInnerJoinTransferSource = innerJoinNode.getCriteria().get(0).getLeft();
} else {
joinSymbolOfInnerJoinTransferSource = innerJoinNode.getCriteria().get(0).getRight();
}
if (outerTableDirection == DIRECTION.LEFT) {
joinSymbolOfOuterJoinFixedSource = originalOuterJoin.getCriteria().get(0).getRight();
newJoinClause = new JoinNode.EquiJoinClause(joinSymbolOfInnerJoinTransferSource, joinSymbolOfOuterJoinFixedSource);
} else {
joinSymbolOfOuterJoinFixedSource = originalOuterJoin.getCriteria().get(0).getLeft();
newJoinClause = new JoinNode.EquiJoinClause(joinSymbolOfOuterJoinFixedSource, joinSymbolOfOuterJoinFixedSource);
}
return ImmutableList.of(newJoinClause);
}
use of io.prestosql.spi.plan.JoinNode in project hetu-core by openlookeng.
the class TransformCorrelatedInPredicateToJoin method buildInPredicateEquivalent.
private PlanNode buildInPredicateEquivalent(ApplyNode apply, InPredicate inPredicate, Symbol inPredicateOutputSymbol, Decorrelated decorrelated, PlanNodeIdAllocator idAllocator, PlanSymbolAllocator planSymbolAllocator) {
Expression correlationCondition = and(decorrelated.getCorrelatedPredicates());
PlanNode decorrelatedBuildSource = decorrelated.getDecorrelatedNode();
AssignUniqueId probeSide = new AssignUniqueId(idAllocator.getNextId(), apply.getInput(), planSymbolAllocator.newSymbol("unique", BIGINT));
Symbol buildSideKnownNonNull = planSymbolAllocator.newSymbol("buildSideKnownNonNull", BIGINT);
ProjectNode buildSide = new ProjectNode(idAllocator.getNextId(), decorrelatedBuildSource, Assignments.builder().putAll(identityAsSymbolReferences(decorrelatedBuildSource.getOutputSymbols())).put(buildSideKnownNonNull, castToRowExpression(bigint(0))).build());
Symbol probeSideSymbol = SymbolUtils.from(inPredicate.getValue());
Symbol buildSideSymbol = SymbolUtils.from(inPredicate.getValueList());
Expression joinExpression = and(or(new IsNullPredicate(toSymbolReference(probeSideSymbol)), new ComparisonExpression(ComparisonExpression.Operator.EQUAL, toSymbolReference(probeSideSymbol), toSymbolReference(buildSideSymbol)), new IsNullPredicate(toSymbolReference(buildSideSymbol))), correlationCondition);
JoinNode leftOuterJoin = leftOuterJoin(idAllocator, probeSide, buildSide, joinExpression);
Symbol matchConditionSymbol = planSymbolAllocator.newSymbol("matchConditionSymbol", BOOLEAN);
Expression matchCondition = and(isNotNull(probeSideSymbol), isNotNull(buildSideSymbol));
Symbol nullMatchConditionSymbol = planSymbolAllocator.newSymbol("nullMatchConditionSymbol", BOOLEAN);
Expression nullMatchCondition = and(isNotNull(buildSideKnownNonNull), not(matchCondition));
ProjectNode preProjection = new ProjectNode(idAllocator.getNextId(), leftOuterJoin, Assignments.builder().putAll(AssignmentUtils.identityAsSymbolReferences(leftOuterJoin.getOutputSymbols())).put(matchConditionSymbol, castToRowExpression(matchCondition)).put(nullMatchConditionSymbol, castToRowExpression(nullMatchCondition)).build());
Symbol countMatchesSymbol = planSymbolAllocator.newSymbol("countMatches", BIGINT);
Symbol countNullMatchesSymbol = planSymbolAllocator.newSymbol("countNullMatches", BIGINT);
AggregationNode aggregation = new AggregationNode(idAllocator.getNextId(), preProjection, ImmutableMap.<Symbol, AggregationNode.Aggregation>builder().put(countMatchesSymbol, countWithFilter(matchConditionSymbol)).put(countNullMatchesSymbol, countWithFilter(nullMatchConditionSymbol)).build(), singleGroupingSet(probeSide.getOutputSymbols()), ImmutableList.of(), AggregationNode.Step.SINGLE, Optional.empty(), Optional.empty(), AggregationNode.AggregationType.HASH, Optional.empty());
// TODO since we care only about "some count > 0", we could have specialized node instead of leftOuterJoin that does the job without materializing join results
SearchedCaseExpression inPredicateEquivalent = new SearchedCaseExpression(ImmutableList.of(new WhenClause(isGreaterThan(countMatchesSymbol, 0), booleanConstant(true)), new WhenClause(isGreaterThan(countNullMatchesSymbol, 0), booleanConstant(null))), Optional.of(booleanConstant(false)));
return new ProjectNode(idAllocator.getNextId(), aggregation, Assignments.builder().putAll(identityAsSymbolReferences(apply.getInput().getOutputSymbols())).put(inPredicateOutputSymbol, castToRowExpression(inPredicateEquivalent)).build());
}
Aggregations