Search in sources :

Example 1 with UnnestNode

use of io.trino.sql.planner.plan.UnnestNode in project trino by trinodb.

the class ExtractSpatialJoins method addPartitioningNodes.

private static PlanNode addPartitioningNodes(PlannerContext plannerContext, Context context, PlanNode node, Symbol partitionSymbol, KdbTree kdbTree, Expression geometry, Optional<Expression> radius) {
    Assignments.Builder projections = Assignments.builder();
    for (Symbol outputSymbol : node.getOutputSymbols()) {
        projections.putIdentity(outputSymbol);
    }
    TypeSignature typeSignature = new TypeSignature(KDB_TREE_TYPENAME);
    FunctionCallBuilder spatialPartitionsCall = FunctionCallBuilder.resolve(context.getSession(), plannerContext.getMetadata()).setName(QualifiedName.of("spatial_partitions")).addArgument(typeSignature, new Cast(new StringLiteral(KdbTreeUtils.toJson(kdbTree)), toSqlType(plannerContext.getTypeManager().getType(typeSignature)))).addArgument(GEOMETRY_TYPE_SIGNATURE, geometry);
    radius.ifPresent(value -> spatialPartitionsCall.addArgument(DOUBLE, value));
    FunctionCall partitioningFunction = spatialPartitionsCall.build();
    Symbol partitionsSymbol = context.getSymbolAllocator().newSymbol(partitioningFunction, new ArrayType(INTEGER));
    projections.put(partitionsSymbol, partitioningFunction);
    return new UnnestNode(context.getIdAllocator().getNextId(), new ProjectNode(context.getIdAllocator().getNextId(), node, projections.build()), node.getOutputSymbols(), ImmutableList.of(new UnnestNode.Mapping(partitionsSymbol, ImmutableList.of(partitionSymbol))), Optional.empty(), INNER, Optional.empty());
}
Also used : Cast(io.trino.sql.tree.Cast) ArrayType(io.trino.spi.type.ArrayType) TypeSignature(io.trino.spi.type.TypeSignature) StringLiteral(io.trino.sql.tree.StringLiteral) UnnestNode(io.trino.sql.planner.plan.UnnestNode) Symbol(io.trino.sql.planner.Symbol) Assignments(io.trino.sql.planner.plan.Assignments) ProjectNode(io.trino.sql.planner.plan.ProjectNode) FunctionCall(io.trino.sql.tree.FunctionCall) FunctionCallBuilder(io.trino.sql.planner.FunctionCallBuilder)

Example 2 with UnnestNode

use of io.trino.sql.planner.plan.UnnestNode in project trino by trinodb.

the class DecorrelateInnerUnnestWithGlobalAggregation method apply.

@Override
public Result apply(CorrelatedJoinNode correlatedJoinNode, Captures captures, Context context) {
    // find global aggregation in subquery
    List<PlanNode> globalAggregations = PlanNodeSearcher.searchFrom(correlatedJoinNode.getSubquery(), context.getLookup()).where(DecorrelateInnerUnnestWithGlobalAggregation::isGlobalAggregation).recurseOnlyWhen(node -> node instanceof ProjectNode || isGlobalAggregation(node)).findAll();
    if (globalAggregations.isEmpty()) {
        return Result.empty();
    }
    // if there are multiple global aggregations, the one that is closest to the source is the "reducing" aggregation, because it reduces multiple input rows to single output row
    AggregationNode reducingAggregation = (AggregationNode) globalAggregations.get(globalAggregations.size() - 1);
    // find unnest in subquery
    Optional<UnnestNode> subqueryUnnest = PlanNodeSearcher.searchFrom(reducingAggregation.getSource(), context.getLookup()).where(node -> isSupportedUnnest(node, correlatedJoinNode.getCorrelation(), context.getLookup())).recurseOnlyWhen(node -> node instanceof ProjectNode || isGroupedAggregation(node)).findFirst();
    if (subqueryUnnest.isEmpty()) {
        return Result.empty();
    }
    UnnestNode unnestNode = subqueryUnnest.get();
    // assign unique id to input rows to restore semantics of aggregations after rewrite
    PlanNode input = new AssignUniqueId(context.getIdAllocator().getNextId(), correlatedJoinNode.getInput(), context.getSymbolAllocator().newSymbol("unique", BIGINT));
    // 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());
    }
    // rewrite correlated join to UnnestNode
    Symbol ordinalitySymbol = unnestNode.getOrdinalitySymbol().orElseGet(() -> context.getSymbolAllocator().newSymbol("ordinality", BIGINT));
    UnnestNode rewrittenUnnest = new UnnestNode(context.getIdAllocator().getNextId(), input, input.getOutputSymbols(), unnestNode.getMappings(), Optional.of(ordinalitySymbol), LEFT, Optional.empty());
    // append mask symbol based on ordinality to distinguish between the unnested rows and synthetic null rows
    Symbol mask = context.getSymbolAllocator().newSymbol("mask", BOOLEAN);
    ProjectNode sourceWithMask = new ProjectNode(context.getIdAllocator().getNextId(), rewrittenUnnest, Assignments.builder().putIdentities(rewrittenUnnest.getOutputSymbols()).put(mask, new IsNotNullPredicate(ordinalitySymbol.toSymbolReference())).build());
    // restore all projections, grouped aggregations and global aggregations from the subquery
    PlanNode result = rewriteNodeSequence(context.getLookup().resolve(correlatedJoinNode.getSubquery()), input.getOutputSymbols(), mask, sourceWithMask, reducingAggregation.getId(), unnestNode.getId(), context.getSymbolAllocator(), context.getIdAllocator(), context.getLookup());
    // restrict outputs
    return Result.ofPlanNode(restrictOutputs(context.getIdAllocator(), result, ImmutableSet.copyOf(correlatedJoinNode.getOutputSymbols())).orElse(result));
}
Also used : CorrelatedJoin.correlation(io.trino.sql.planner.plan.Patterns.CorrelatedJoin.correlation) QueryCardinalityUtil.isScalar(io.trino.sql.planner.optimizations.QueryCardinalityUtil.isScalar) INNER(io.trino.sql.planner.plan.JoinNode.Type.INNER) SymbolAllocator(io.trino.sql.planner.SymbolAllocator) BOOLEAN(io.trino.spi.type.BooleanType.BOOLEAN) SINGLE(io.trino.sql.planner.plan.AggregationNode.Step.SINGLE) CorrelatedJoinNode(io.trino.sql.planner.plan.CorrelatedJoinNode) PlanNode(io.trino.sql.planner.plan.PlanNode) AggregationDecorrelation.rewriteWithMasks(io.trino.sql.planner.iterative.rule.AggregationDecorrelation.rewriteWithMasks) CorrelatedJoin.filter(io.trino.sql.planner.plan.Patterns.CorrelatedJoin.filter) LEFT(io.trino.sql.planner.plan.JoinNode.Type.LEFT) ImmutableList(com.google.common.collect.ImmutableList) PlanNodeSearcher(io.trino.sql.planner.optimizations.PlanNodeSearcher) PlanNodeId(io.trino.sql.planner.plan.PlanNodeId) IsNotNullPredicate(io.trino.sql.tree.IsNotNullPredicate) Map(java.util.Map) AggregationNode(io.trino.sql.planner.plan.AggregationNode) Rule(io.trino.sql.planner.iterative.Rule) SymbolsExtractor(io.trino.sql.planner.SymbolsExtractor) Pattern.nonEmpty(io.trino.matching.Pattern.nonEmpty) AssignUniqueId(io.trino.sql.planner.plan.AssignUniqueId) ProjectNode(io.trino.sql.planner.plan.ProjectNode) Symbol(io.trino.sql.planner.Symbol) ImmutableSet(com.google.common.collect.ImmutableSet) ImmutableMap(com.google.common.collect.ImmutableMap) Lookup(io.trino.sql.planner.iterative.Lookup) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) Assignments(io.trino.sql.planner.plan.Assignments) Set(java.util.Set) Iterables.getOnlyElement(com.google.common.collect.Iterables.getOnlyElement) TRUE_LITERAL(io.trino.sql.tree.BooleanLiteral.TRUE_LITERAL) Streams(com.google.common.collect.Streams) UnnestNode(io.trino.sql.planner.plan.UnnestNode) AggregationNode.singleGroupingSet(io.trino.sql.planner.plan.AggregationNode.singleGroupingSet) List(java.util.List) Pattern(io.trino.matching.Pattern) BIGINT(io.trino.spi.type.BigintType.BIGINT) ExpressionUtils.and(io.trino.sql.ExpressionUtils.and) Captures(io.trino.matching.Captures) Util.restrictOutputs(io.trino.sql.planner.iterative.rule.Util.restrictOutputs) Mapping(io.trino.sql.planner.plan.UnnestNode.Mapping) Optional(java.util.Optional) Expression(io.trino.sql.tree.Expression) PlanNodeIdAllocator(io.trino.sql.planner.PlanNodeIdAllocator) Patterns.correlatedJoin(io.trino.sql.planner.plan.Patterns.correlatedJoin) PlanNode(io.trino.sql.planner.plan.PlanNode) AssignUniqueId(io.trino.sql.planner.plan.AssignUniqueId) UnnestNode(io.trino.sql.planner.plan.UnnestNode) Symbol(io.trino.sql.planner.Symbol) ProjectNode(io.trino.sql.planner.plan.ProjectNode) AggregationNode(io.trino.sql.planner.plan.AggregationNode) IsNotNullPredicate(io.trino.sql.tree.IsNotNullPredicate)

Example 3 with UnnestNode

use of io.trino.sql.planner.plan.UnnestNode in project trino by trinodb.

the class DecorrelateLeftUnnestWithGlobalAggregation method isSupportedUnnest.

/**
 * This rule supports decorrelation of UnnestNode meeting certain conditions:
 * - the UnnestNode should be based on correlation symbols, that is: either unnest correlation symbols directly,
 * or unnest symbols produced by a projection that uses only correlation symbols.
 * - the UnnestNode should not have any replicate symbols,
 * - the UnnestNode should be of type LEFT,
 * - the UnnestNode should not have a filter.
 */
private static boolean isSupportedUnnest(PlanNode node, List<Symbol> correlation, Lookup lookup) {
    if (!(node instanceof UnnestNode)) {
        return false;
    }
    UnnestNode unnestNode = (UnnestNode) node;
    List<Symbol> unnestSymbols = unnestNode.getMappings().stream().map(UnnestNode.Mapping::getInput).collect(toImmutableList());
    PlanNode unnestSource = lookup.resolve(unnestNode.getSource());
    boolean basedOnCorrelation = ImmutableSet.copyOf(correlation).containsAll(unnestSymbols) || unnestSource instanceof ProjectNode && ImmutableSet.copyOf(correlation).containsAll(SymbolsExtractor.extractUnique(((ProjectNode) unnestSource).getAssignments().getExpressions()));
    return isScalar(unnestNode.getSource(), lookup) && unnestNode.getReplicateSymbols().isEmpty() && basedOnCorrelation && unnestNode.getJoinType() == LEFT && (unnestNode.getFilter().isEmpty() || unnestNode.getFilter().get().equals(TRUE_LITERAL));
}
Also used : PlanNode(io.trino.sql.planner.plan.PlanNode) UnnestNode(io.trino.sql.planner.plan.UnnestNode) Symbol(io.trino.sql.planner.Symbol) ProjectNode(io.trino.sql.planner.plan.ProjectNode)

Example 4 with UnnestNode

use of io.trino.sql.planner.plan.UnnestNode in project trino by trinodb.

the class DecorrelateUnnest method isSupportedUnnest.

/**
 * This rule supports decorrelation of UnnestNode meeting certain conditions:
 * - the UnnestNode should be based on correlation symbols, that is: either unnest correlation symbols directly,
 * or unnest symbols produced by a projection that uses only correlation symbols.
 * - the UnnestNode should not have any replicate symbols,
 * - the UnnestNode should be of type INNER or LEFT,
 * - the UnnestNode should not have a filter.
 */
private static boolean isSupportedUnnest(PlanNode node, List<Symbol> correlation, Lookup lookup) {
    if (!(node instanceof UnnestNode)) {
        return false;
    }
    UnnestNode unnestNode = (UnnestNode) node;
    List<Symbol> unnestSymbols = unnestNode.getMappings().stream().map(UnnestNode.Mapping::getInput).collect(toImmutableList());
    PlanNode unnestSource = lookup.resolve(unnestNode.getSource());
    boolean basedOnCorrelation = ImmutableSet.copyOf(correlation).containsAll(unnestSymbols) || unnestSource instanceof ProjectNode && ImmutableSet.copyOf(correlation).containsAll(SymbolsExtractor.extractUnique(((ProjectNode) unnestSource).getAssignments().getExpressions()));
    return isScalar(unnestNode.getSource(), lookup) && unnestNode.getReplicateSymbols().isEmpty() && basedOnCorrelation && (unnestNode.getJoinType() == INNER || unnestNode.getJoinType() == LEFT) && (unnestNode.getFilter().isEmpty() || unnestNode.getFilter().get().equals(TRUE_LITERAL));
}
Also used : PlanNode(io.trino.sql.planner.plan.PlanNode) UnnestNode(io.trino.sql.planner.plan.UnnestNode) Symbol(io.trino.sql.planner.Symbol) ProjectNode(io.trino.sql.planner.plan.ProjectNode)

Example 5 with UnnestNode

use of io.trino.sql.planner.plan.UnnestNode in project trino by trinodb.

the class RelationPlanner method planUnnest.

private RelationPlan planUnnest(PlanBuilder subPlan, Unnest node, List<Symbol> replicatedColumns, Optional<Expression> filter, Join.Type type, Scope outputScope) {
    subPlan = subPlan.appendProjections(node.getExpressions(), symbolAllocator, idAllocator);
    Map<Field, Symbol> allocations = analysis.getOutputDescriptor(node).getVisibleFields().stream().collect(toImmutableMap(Function.identity(), symbolAllocator::newSymbol));
    UnnestAnalysis unnestAnalysis = analysis.getUnnest(node);
    ImmutableList.Builder<UnnestNode.Mapping> mappings = ImmutableList.builder();
    for (Expression expression : node.getExpressions()) {
        Symbol input = subPlan.translate(expression);
        List<Symbol> outputs = unnestAnalysis.getMappings().get(NodeRef.of(expression)).stream().map(allocations::get).collect(toImmutableList());
        mappings.add(new UnnestNode.Mapping(input, outputs));
    }
    UnnestNode unnestNode = new UnnestNode(idAllocator.getNextId(), subPlan.getRoot(), replicatedColumns, mappings.build(), unnestAnalysis.getOrdinalityField().map(allocations::get), JoinNode.Type.typeConvert(type), filter);
    // Currently, it works out because, by construction, the order of the output symbols in the UnnestNode will match the order of the fields in the Join node.
    return new RelationPlan(unnestNode, outputScope, unnestNode.getOutputSymbols(), outerContext);
}
Also used : Field(io.trino.sql.analyzer.Field) ComparisonExpression(io.trino.sql.tree.ComparisonExpression) CoalesceExpression(io.trino.sql.tree.CoalesceExpression) Expression(io.trino.sql.tree.Expression) SubqueryExpression(io.trino.sql.tree.SubqueryExpression) UnnestNode(io.trino.sql.planner.plan.UnnestNode) UnnestAnalysis(io.trino.sql.analyzer.Analysis.UnnestAnalysis) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) ImmutableList(com.google.common.collect.ImmutableList)

Aggregations

UnnestNode (io.trino.sql.planner.plan.UnnestNode)12 Symbol (io.trino.sql.planner.Symbol)11 PlanNode (io.trino.sql.planner.plan.PlanNode)8 ProjectNode (io.trino.sql.planner.plan.ProjectNode)8 ImmutableList.toImmutableList (com.google.common.collect.ImmutableList.toImmutableList)6 ImmutableList (com.google.common.collect.ImmutableList)5 Assignments (io.trino.sql.planner.plan.Assignments)5 Expression (io.trino.sql.tree.Expression)5 List (java.util.List)5 Optional (java.util.Optional)5 ImmutableSet (com.google.common.collect.ImmutableSet)4 Captures (io.trino.matching.Captures)4 Pattern (io.trino.matching.Pattern)4 Rule (io.trino.sql.planner.iterative.Rule)4 Iterables.getOnlyElement (com.google.common.collect.Iterables.getOnlyElement)3 Session (io.trino.Session)3 Pattern.nonEmpty (io.trino.matching.Pattern.nonEmpty)3 Metadata (io.trino.metadata.Metadata)3 BIGINT (io.trino.spi.type.BigintType.BIGINT)3 SymbolsExtractor (io.trino.sql.planner.SymbolsExtractor)3