use of io.crate.planner.operators.LogicalPlan in project crate by crate.
the class MoveFilterBeneathWindowAgg method apply.
@Override
public LogicalPlan apply(Filter filter, Captures captures, TableStats tableStats, TransactionContext txnCtx, NodeContext nodeCtx) {
WindowAgg windowAgg = captures.get(windowAggCapture);
WindowDefinition windowDefinition = windowAgg.windowDefinition();
List<WindowFunction> windowFunctions = windowAgg.windowFunctions();
Predicate<Symbol> containsWindowFunction = symbol -> symbol instanceof WindowFunction && windowFunctions.contains(symbol);
Symbol predicate = filter.query();
List<Symbol> filterParts = AndOperator.split(predicate);
ArrayList<Symbol> remainingFilterSymbols = new ArrayList<>();
ArrayList<Symbol> windowPartitionedBasedFilters = new ArrayList<>();
for (Symbol part : filterParts) {
if (SymbolVisitors.any(containsWindowFunction, part) == false && windowDefinition.partitions().containsAll(extractColumns(part))) {
windowPartitionedBasedFilters.add(part);
} else {
remainingFilterSymbols.add(part);
}
}
assert remainingFilterSymbols.size() > 0 || windowPartitionedBasedFilters.size() > 0 : "Splitting the filter symbol must result in at least one group";
/* SELECT ROW_NUMBER() OVER(PARTITION BY id)
* WHERE `x = 1`
*
* `x` is not the window partition column.
* We cannot push down the filter as it would change the window aggregation value
*
*/
if (windowPartitionedBasedFilters.isEmpty()) {
return null;
}
/* SELECT ROW_NUMBER() OVER(PARTITION BY id)
* WHERE `id = 1`
* remainingFilterSymbols: []
* windowPartitionedBasedFilters: [id = 1]
*
* Filter
* |
* WindowsAgg
*
* transforms to
*
* WindowAgg
* |
* Filter (id = 1)
*/
if (remainingFilterSymbols.isEmpty()) {
return transpose(filter, windowAgg);
}
/* WHERE `ROW_NUMBER() OVER(PARTITION BY id) = 2 AND id = 1`
* remainingFilterSymbols: [ROW_NUMBER() OVER(PARTITION BY id) = 2]
* windowPartitionedBasedFilters: [id = 1]
*
* Filter
* |
* WindowsAgg
*
* transforms to
*
* Filter (ROW_NUMBER() OVER(PARTITION BY id) = 2)
* |
* WindowAgg
* |
* Filter (id = 1)
*/
LogicalPlan newWindowAgg = windowAgg.replaceSources(List.of(new Filter(windowAgg.source(), AndOperator.join(windowPartitionedBasedFilters))));
return new Filter(newWindowAgg, AndOperator.join(remainingFilterSymbols));
}
use of io.crate.planner.operators.LogicalPlan in project crate by crate.
the class CopyToPlan method optimizeCollect.
private static LogicalPlan optimizeCollect(PlannerContext context, TableStats tableStats, LogicalPlan collect) {
OptimizeCollectWhereClauseAccess rewriteCollectToGet = new OptimizeCollectWhereClauseAccess();
Match<Collect> match = rewriteCollectToGet.pattern().accept(collect, Captures.empty());
if (match.isPresent()) {
LogicalPlan plan = rewriteCollectToGet.apply(match.value(), match.captures(), tableStats, context.transactionContext(), context.nodeContext());
return plan == null ? collect : plan;
}
return collect;
}
use of io.crate.planner.operators.LogicalPlan in project crate by crate.
the class CopyToPlan method planCopyToExecution.
@VisibleForTesting
static ExecutionPlan planCopyToExecution(AnalyzedCopyTo copyTo, PlannerContext context, TableStats tableStats, ProjectionBuilder projectionBuilder, Row params, SubQueryResults subQueryResults) {
var boundedCopyTo = bind(copyTo, context.transactionContext(), context.nodeContext(), params, subQueryResults);
WriterProjection.OutputFormat outputFormat = boundedCopyTo.outputFormat();
if (outputFormat == null) {
outputFormat = boundedCopyTo.columnsDefined() ? WriterProjection.OutputFormat.JSON_ARRAY : WriterProjection.OutputFormat.JSON_OBJECT;
}
WriterProjection projection = ProjectionBuilder.writerProjection(boundedCopyTo.outputs(), boundedCopyTo.uri(), boundedCopyTo.compressionType(), boundedCopyTo.overwrites(), boundedCopyTo.outputNames(), outputFormat, boundedCopyTo.withClauseOptions());
LogicalPlan collect = Collect.create(new DocTableRelation(boundedCopyTo.table()), boundedCopyTo.outputs(), boundedCopyTo.whereClause(), tableStats, context.params());
LogicalPlan source = optimizeCollect(context, tableStats, collect);
ExecutionPlan executionPlan = source.build(context, Set.of(), projectionBuilder, 0, 0, null, null, params, SubQueryResults.EMPTY);
executionPlan.addProjection(projection);
return Merge.ensureOnHandler(executionPlan, context, List.of(MergeCountProjection.INSTANCE));
}
use of io.crate.planner.operators.LogicalPlan in project crate by crate.
the class RewriteFilterOnOuterJoinToInnerJoin method apply.
@Override
public LogicalPlan apply(Filter filter, Captures captures, TableStats tableStats, TransactionContext txnCtx, NodeContext nodeCtx) {
var symbolEvaluator = new SymbolEvaluator(txnCtx, nodeCtx, SubQueryResults.EMPTY);
NestedLoopJoin nl = captures.get(nlCapture);
Symbol query = filter.query();
Map<Set<RelationName>, Symbol> splitQueries = QuerySplitter.split(query);
if (splitQueries.size() == 1 && splitQueries.keySet().iterator().next().size() > 1) {
return null;
}
LogicalPlan lhs = nl.sources().get(0);
LogicalPlan rhs = nl.sources().get(1);
Set<RelationName> leftName = lhs.getRelationNames();
Set<RelationName> rightName = rhs.getRelationNames();
Symbol leftQuery = splitQueries.remove(leftName);
Symbol rightQuery = splitQueries.remove(rightName);
final LogicalPlan newLhs;
final LogicalPlan newRhs;
final boolean newJoinIsInnerJoin;
switch(nl.joinType()) {
case LEFT:
/* LEFT OUTER JOIN -> NULL rows are generated for the RHS if the join-condition doesn't match
*
* cr> select t1.x as t1x, t2.x as t2x from t1 left join t2 on t1.x = t2.x;
* +-----+------+
* | t1x | t2x |
* +-----+------+
* | 3 | 3 |
* | 2 | 2 |
* | 1 | NULL |
* +-----+------+
*/
newLhs = getNewSource(leftQuery, lhs);
if (rightQuery == null) {
newRhs = rhs;
newJoinIsInnerJoin = false;
} else if (couldMatchOnNull(rightQuery, symbolEvaluator)) {
newRhs = rhs;
newJoinIsInnerJoin = false;
splitQueries.put(rightName, rightQuery);
} else {
newRhs = getNewSource(rightQuery, rhs);
newJoinIsInnerJoin = true;
}
break;
case RIGHT:
/* RIGHT OUTER JOIN -> NULL rows are generated for the LHS if the join-condition doesn't match
* cr> select t1.x as t1x, t2.x as t2x from t1 right join t2 on t1.x = t2.x;
* +------+-----+
* | t1x | t2x |
* +------+-----+
* | 3 | 3 |
* | 2 | 2 |
* | NULL | 4 |
* +------+-----+
*/
if (leftQuery == null) {
newLhs = lhs;
newJoinIsInnerJoin = false;
} else if (couldMatchOnNull(leftQuery, symbolEvaluator)) {
newLhs = lhs;
newJoinIsInnerJoin = false;
splitQueries.put(leftName, leftQuery);
} else {
newLhs = getNewSource(leftQuery, lhs);
newJoinIsInnerJoin = true;
}
newRhs = getNewSource(rightQuery, rhs);
break;
case FULL:
if (couldMatchOnNull(leftQuery, symbolEvaluator)) {
newLhs = lhs;
} else {
newLhs = getNewSource(leftQuery, lhs);
if (leftQuery != null) {
splitQueries.put(leftName, leftQuery);
}
}
if (couldMatchOnNull(rightQuery, symbolEvaluator)) {
newRhs = rhs;
} else {
newRhs = getNewSource(rightQuery, rhs);
}
/*
* Filters on each side must be put back into the Filter as each side can generate NULL's on outer joins
* which must be filtered out AFTER the join operation.
* In case the filter is only on one side, the join could be rewritten to a LEFT/RIGHT OUTER.
* TODO: Create a dedicated rule RewriteFilterOnOuterJoinToLeftOrRight
*
* cr> select t1.x as t1x, t2.x as t2x, t2.y as t2y from t1 full outer join t2 on t1.x = t2.x where t2y = 1;
* +------+------+------+
* | t1x | t2x | t2y |
* +------+------+------+
* | 3 | 3 | 1 |
* | 2 | 2 | 1 |
* | NULL | 4 | 1 |
* +------+------+------+
*/
if (leftQuery != null) {
splitQueries.put(leftName, leftQuery);
}
if (rightQuery != null) {
splitQueries.put(rightName, rightQuery);
}
newJoinIsInnerJoin = newLhs != lhs && newRhs != rhs;
break;
default:
throw new UnsupportedOperationException("The Rule to rewrite filter+outer-joins to inner joins must not be run on joins of type=" + nl.joinType());
}
if (newLhs == lhs && newRhs == rhs) {
return null;
}
NestedLoopJoin newJoin = new NestedLoopJoin(newLhs, newRhs, newJoinIsInnerJoin ? JoinType.INNER : nl.joinType(), nl.joinCondition(), nl.isFiltered(), nl.topMostLeftRelation(), nl.orderByWasPushedDown(), true);
assert newJoin.outputs().equals(nl.outputs()) : "Outputs after rewrite must be the same as before";
return splitQueries.isEmpty() ? newJoin : new Filter(newJoin, AndOperator.join(splitQueries.values()));
}
use of io.crate.planner.operators.LogicalPlan in project crate by crate.
the class MoveOrderBeneathUnion method apply.
@Override
public LogicalPlan apply(Order order, Captures captures, TableStats tableStats, TransactionContext txnCtx, NodeContext nodeCtx) {
Union union = captures.get(unionCapture);
List<LogicalPlan> unionSources = union.sources();
assert unionSources.size() == 2 : "A UNION must have exactly 2 unionSources";
Order lhsOrder = updateSources(order, unionSources.get(0));
Order rhsOrder = updateSources(order, unionSources.get(1));
return union.replaceSources(List.of(lhsOrder, rhsOrder));
}
Aggregations