use of io.trino.sql.planner.plan.LimitNode in project trino by trinodb.
the class PushLimitThroughOuterJoin method apply.
@Override
public Result apply(LimitNode parent, Captures captures, Context context) {
JoinNode joinNode = captures.get(CHILD);
PlanNode left = joinNode.getLeft();
PlanNode right = joinNode.getRight();
if (joinNode.getType() == LEFT && !isAtMost(left, context.getLookup(), parent.getCount())) {
if (!ImmutableSet.copyOf(left.getOutputSymbols()).containsAll(parent.getPreSortedInputs())) {
return Result.empty();
}
return Result.ofPlanNode(parent.replaceChildren(ImmutableList.of(joinNode.replaceChildren(ImmutableList.of(new LimitNode(context.getIdAllocator().getNextId(), left, parent.getCount(), Optional.empty(), true, parent.getPreSortedInputs()), right)))));
}
if (joinNode.getType() == RIGHT && !isAtMost(right, context.getLookup(), parent.getCount())) {
if (!ImmutableSet.copyOf(right.getOutputSymbols()).containsAll(parent.getPreSortedInputs())) {
return Result.empty();
}
return Result.ofPlanNode(parent.replaceChildren(ImmutableList.of(joinNode.replaceChildren(ImmutableList.of(left, new LimitNode(context.getIdAllocator().getNextId(), right, parent.getCount(), Optional.empty(), true, parent.getPreSortedInputs()))))));
}
return Result.empty();
}
use of io.trino.sql.planner.plan.LimitNode in project trino by trinodb.
the class PushLimitThroughProject method apply.
@Override
public Result apply(LimitNode parent, Captures captures, Context context) {
ProjectNode projectNode = captures.get(CHILD);
// Do not push down if the projection is made up of symbol references and exclusive dereferences. This prevents
// undoing of PushDownDereferencesThroughLimit. We still push limit in the case of overlapping dereferences since
// it enables PushDownDereferencesThroughLimit rule to push optimal dereferences.
Set<Expression> projections = ImmutableSet.copyOf(projectNode.getAssignments().getExpressions());
if (!extractRowSubscripts(projections, false, context.getSession(), typeAnalyzer, context.getSymbolAllocator().getTypes()).isEmpty() && exclusiveDereferences(projections, context.getSession(), typeAnalyzer, context.getSymbolAllocator().getTypes())) {
return Result.empty();
}
// for a LimitNode without ties and pre-sorted inputs, simply reorder the nodes
if (!parent.isWithTies() && !parent.requiresPreSortedInputs()) {
return Result.ofPlanNode(transpose(parent, projectNode));
}
// for a LimitNode with ties, the tiesResolvingScheme must be rewritten in terms of symbols before projection
SymbolMapper.Builder symbolMapper = SymbolMapper.builder();
Set<Symbol> symbolsForRewrite = ImmutableSet.<Symbol>builder().addAll(parent.getPreSortedInputs()).addAll(parent.getTiesResolvingScheme().map(OrderingScheme::getOrderBy).orElse(ImmutableList.of())).build();
for (Symbol symbol : symbolsForRewrite) {
Expression expression = projectNode.getAssignments().get(symbol);
// if a symbol results from some computation, the translation fails
if (!(expression instanceof SymbolReference)) {
return Result.empty();
}
symbolMapper.put(symbol, Symbol.from(expression));
}
LimitNode mappedLimitNode = symbolMapper.build().map(parent, projectNode.getSource());
return Result.ofPlanNode(projectNode.replaceChildren(ImmutableList.of(mappedLimitNode)));
}
use of io.trino.sql.planner.plan.LimitNode in project trino by trinodb.
the class TransformExistsApplyToCorrelatedJoin method rewriteToNonDefaultAggregation.
private Optional<PlanNode> rewriteToNonDefaultAggregation(ApplyNode applyNode, Context context) {
checkState(applyNode.getSubquery().getOutputSymbols().isEmpty(), "Expected subquery output symbols to be pruned");
Symbol subqueryTrue = context.getSymbolAllocator().newSymbol("subqueryTrue", BOOLEAN);
PlanNode subquery = new ProjectNode(context.getIdAllocator().getNextId(), new LimitNode(context.getIdAllocator().getNextId(), applyNode.getSubquery(), 1L, false), Assignments.of(subqueryTrue, TRUE_LITERAL));
PlanNodeDecorrelator decorrelator = new PlanNodeDecorrelator(plannerContext, context.getSymbolAllocator(), context.getLookup());
if (decorrelator.decorrelateFilters(subquery, applyNode.getCorrelation()).isEmpty()) {
return Optional.empty();
}
Symbol exists = getOnlyElement(applyNode.getSubqueryAssignments().getSymbols());
Assignments.Builder assignments = Assignments.builder().putIdentities(applyNode.getInput().getOutputSymbols()).put(exists, new CoalesceExpression(ImmutableList.of(subqueryTrue.toSymbolReference(), BooleanLiteral.FALSE_LITERAL)));
return Optional.of(new ProjectNode(context.getIdAllocator().getNextId(), new CorrelatedJoinNode(applyNode.getId(), applyNode.getInput(), subquery, applyNode.getCorrelation(), LEFT, TRUE_LITERAL, applyNode.getOriginSubquery()), assignments.build()));
}
use of io.trino.sql.planner.plan.LimitNode in project trino by trinodb.
the class LogicalPlanner method createTableCreationPlan.
private RelationPlan createTableCreationPlan(Analysis analysis, Query query) {
Analysis.Create create = analysis.getCreate().orElseThrow();
QualifiedObjectName destination = create.getDestination().orElseThrow();
RelationPlan plan = createRelationPlan(analysis, query);
if (!create.isCreateTableAsSelectWithData()) {
PlanNode root = new LimitNode(idAllocator.getNextId(), plan.getRoot(), 0L, false);
plan = new RelationPlan(root, plan.getScope(), plan.getFieldMappings(), Optional.empty());
}
ConnectorTableMetadata tableMetadata = create.getMetadata().orElseThrow();
Optional<TableLayout> newTableLayout = create.getLayout();
List<String> columnNames = tableMetadata.getColumns().stream().filter(// todo this filter is redundant
column -> !column.isHidden()).map(ColumnMetadata::getName).collect(toImmutableList());
TableStatisticsMetadata statisticsMetadata = metadata.getStatisticsCollectionMetadataForWrite(session, destination.getCatalogName(), tableMetadata);
return createTableWriterPlan(analysis, plan.getRoot(), visibleFields(plan), new CreateReference(destination.getCatalogName(), tableMetadata, newTableLayout), columnNames, tableMetadata.getColumns(), newTableLayout, statisticsMetadata);
}
use of io.trino.sql.planner.plan.LimitNode in project trino by trinodb.
the class DecorrelateUnnest method apply.
@Override
public Result apply(CorrelatedJoinNode correlatedJoinNode, Captures captures, Context context) {
// determine shape of the subquery
PlanNode searchRoot = correlatedJoinNode.getSubquery();
// 1. find EnforceSingleRowNode in the subquery
Optional<EnforceSingleRowNode> enforceSingleRow = PlanNodeSearcher.searchFrom(searchRoot, context.getLookup()).where(EnforceSingleRowNode.class::isInstance).recurseOnlyWhen(planNode -> false).findFirst();
if (enforceSingleRow.isPresent()) {
searchRoot = enforceSingleRow.get().getSource();
}
// 2. find correlated UnnestNode in the subquery
Optional<UnnestNode> subqueryUnnest = PlanNodeSearcher.searchFrom(searchRoot, context.getLookup()).where(node -> isSupportedUnnest(node, correlatedJoinNode.getCorrelation(), context.getLookup())).recurseOnlyWhen(node -> node instanceof ProjectNode || (node instanceof LimitNode && ((LimitNode) node).getCount() > 0) || (node instanceof TopNNode && ((TopNNode) node).getCount() > 0)).findFirst();
if (subqueryUnnest.isEmpty()) {
return Result.empty();
}
UnnestNode unnestNode = subqueryUnnest.get();
// assign unique id to input rows
Symbol uniqueSymbol = context.getSymbolAllocator().newSymbol("unique", BIGINT);
PlanNode input = new AssignUniqueId(context.getIdAllocator().getNextId(), correlatedJoinNode.getInput(), uniqueSymbol);
// pre-project unnest symbols if they were pre-projected in subquery
// The correlated UnnestNode either unnests correlation symbols directly, or unnests symbols produced by a projection that uses only correlation symbols.
// Here, any underlying projection that was a source of the correlated UnnestNode, is appended as a source of the rewritten UnnestNode.
// If the projection is not necessary for UnnestNode (i.e. it does not produce any unnest symbols), it should be pruned afterwards.
PlanNode unnestSource = context.getLookup().resolve(unnestNode.getSource());
if (unnestSource instanceof ProjectNode) {
ProjectNode sourceProjection = (ProjectNode) unnestSource;
input = new ProjectNode(sourceProjection.getId(), input, Assignments.builder().putIdentities(input.getOutputSymbols()).putAll(sourceProjection.getAssignments()).build());
}
// determine join type for rewritten UnnestNode
Type unnestJoinType = LEFT;
if (enforceSingleRow.isEmpty() && correlatedJoinNode.getType() == CorrelatedJoinNode.Type.INNER && unnestNode.getJoinType() == INNER) {
unnestJoinType = INNER;
}
// make sure that the rewritten node is with ordinality, which might be necessary to restore inner unnest semantics after rewrite.
Symbol ordinalitySymbol = unnestNode.getOrdinalitySymbol().orElseGet(() -> context.getSymbolAllocator().newSymbol("ordinality", BIGINT));
// rewrite correlated join to UnnestNode.
UnnestNode rewrittenUnnest = new UnnestNode(context.getIdAllocator().getNextId(), input, input.getOutputSymbols(), unnestNode.getMappings(), Optional.of(ordinalitySymbol), unnestJoinType, Optional.empty());
// restore all nodes from the subquery
PlanNode rewrittenPlan = Rewriter.rewriteNodeSequence(correlatedJoinNode.getSubquery(), input.getOutputSymbols(), ordinalitySymbol, uniqueSymbol, rewrittenUnnest, context.getSession(), metadata, context.getLookup(), context.getIdAllocator(), context.getSymbolAllocator());
// between unnested rows and synthetic rows added by left unnest.
if (unnestNode.getJoinType() == INNER && rewrittenUnnest.getJoinType() == LEFT) {
Assignments.Builder assignments = Assignments.builder().putIdentities(correlatedJoinNode.getInput().getOutputSymbols());
for (Symbol subquerySymbol : correlatedJoinNode.getSubquery().getOutputSymbols()) {
assignments.put(subquerySymbol, new IfExpression(new IsNullPredicate(ordinalitySymbol.toSymbolReference()), new Cast(new NullLiteral(), toSqlType(context.getSymbolAllocator().getTypes().get(subquerySymbol))), subquerySymbol.toSymbolReference()));
}
rewrittenPlan = new ProjectNode(context.getIdAllocator().getNextId(), rewrittenPlan, assignments.build());
}
// restrict outputs
return Result.ofPlanNode(restrictOutputs(context.getIdAllocator(), rewrittenPlan, ImmutableSet.copyOf(correlatedJoinNode.getOutputSymbols())).orElse(rewrittenPlan));
}
Aggregations