Search in sources :

Example 1 with TopNRankingNode

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

the class PushdownFilterIntoWindow method apply.

@Override
public Result apply(FilterNode node, Captures captures, Context context) {
    Session session = context.getSession();
    TypeProvider types = context.getSymbolAllocator().getTypes();
    WindowNode windowNode = captures.get(childCapture);
    DomainTranslator.ExtractionResult extractionResult = DomainTranslator.getExtractionResult(plannerContext, session, node.getPredicate(), types);
    TupleDomain<Symbol> tupleDomain = extractionResult.getTupleDomain();
    Optional<RankingType> rankingType = toTopNRankingType(windowNode);
    Symbol rankingSymbol = getOnlyElement(windowNode.getWindowFunctions().keySet());
    OptionalInt upperBound = extractUpperBound(tupleDomain, rankingSymbol);
    if (upperBound.isEmpty()) {
        return Result.empty();
    }
    if (upperBound.getAsInt() <= 0) {
        return Result.ofPlanNode(new ValuesNode(node.getId(), node.getOutputSymbols(), ImmutableList.of()));
    }
    TopNRankingNode newSource = new TopNRankingNode(windowNode.getId(), windowNode.getSource(), windowNode.getSpecification(), rankingType.get(), rankingSymbol, upperBound.getAsInt(), false, Optional.empty());
    if (!allRowNumberValuesInDomain(tupleDomain, rankingSymbol, upperBound.getAsInt())) {
        return Result.ofPlanNode(new FilterNode(node.getId(), newSource, node.getPredicate()));
    }
    // Remove the row number domain because it is absorbed into the node
    TupleDomain<Symbol> newTupleDomain = tupleDomain.filter((symbol, domain) -> !symbol.equals(rankingSymbol));
    Expression newPredicate = ExpressionUtils.combineConjuncts(plannerContext.getMetadata(), extractionResult.getRemainingExpression(), new DomainTranslator(plannerContext).toPredicate(session, newTupleDomain));
    if (newPredicate.equals(BooleanLiteral.TRUE_LITERAL)) {
        return Result.ofPlanNode(newSource);
    }
    return Result.ofPlanNode(new FilterNode(node.getId(), newSource, newPredicate));
}
Also used : WindowNode(io.trino.sql.planner.plan.WindowNode) Util.toTopNRankingType(io.trino.sql.planner.iterative.rule.Util.toTopNRankingType) RankingType(io.trino.sql.planner.plan.TopNRankingNode.RankingType) ValuesNode(io.trino.sql.planner.plan.ValuesNode) Symbol(io.trino.sql.planner.Symbol) FilterNode(io.trino.sql.planner.plan.FilterNode) TypeProvider(io.trino.sql.planner.TypeProvider) OptionalInt(java.util.OptionalInt) TopNRankingNode(io.trino.sql.planner.plan.TopNRankingNode) Expression(io.trino.sql.tree.Expression) DomainTranslator(io.trino.sql.planner.DomainTranslator) Session(io.trino.Session)

Example 2 with TopNRankingNode

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

the class TopNRankingMatcher method detailMatches.

@Override
public MatchResult detailMatches(PlanNode node, StatsProvider stats, Session session, Metadata metadata, SymbolAliases symbolAliases) {
    checkState(shapeMatches(node), "Plan testing framework error: shapeMatches returned false in detailMatches in %s", this.getClass().getName());
    TopNRankingNode topNRankingNode = (TopNRankingNode) node;
    if (specification.isPresent()) {
        WindowNode.Specification expected = specification.get().getExpectedValue(symbolAliases);
        if (!expected.equals(topNRankingNode.getSpecification())) {
            return NO_MATCH;
        }
    }
    if (rankingSymbol.isPresent()) {
        Symbol expected = rankingSymbol.get().toSymbol(symbolAliases);
        if (!expected.equals(topNRankingNode.getRankingSymbol())) {
            return NO_MATCH;
        }
    }
    if (rankingType.isPresent()) {
        if (!rankingType.get().equals(topNRankingNode.getRankingType())) {
            return NO_MATCH;
        }
    }
    if (maxRankingPerPartition.isPresent()) {
        if (!maxRankingPerPartition.get().equals(topNRankingNode.getMaxRankingPerPartition())) {
            return NO_MATCH;
        }
    }
    if (partial.isPresent()) {
        if (!partial.get().equals(topNRankingNode.isPartial())) {
            return NO_MATCH;
        }
    }
    if (hashSymbol.isPresent()) {
        Optional<Symbol> expected = hashSymbol.get().map(alias -> alias.toSymbol(symbolAliases));
        if (!expected.equals(topNRankingNode.getHashSymbol())) {
            return NO_MATCH;
        }
    }
    return match();
}
Also used : WindowNode(io.trino.sql.planner.plan.WindowNode) TopNRankingNode(io.trino.sql.planner.plan.TopNRankingNode) Symbol(io.trino.sql.planner.Symbol)

Example 3 with TopNRankingNode

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

the class PushPredicateThroughProjectIntoWindow method apply.

@Override
public Result apply(FilterNode filter, Captures captures, Context context) {
    ProjectNode project = captures.get(PROJECT);
    WindowNode window = captures.get(WINDOW);
    Symbol rankingSymbol = getOnlyElement(window.getWindowFunctions().keySet());
    if (!project.getAssignments().getSymbols().contains(rankingSymbol)) {
        return Result.empty();
    }
    DomainTranslator.ExtractionResult extractionResult = DomainTranslator.getExtractionResult(plannerContext, context.getSession(), filter.getPredicate(), context.getSymbolAllocator().getTypes());
    TupleDomain<Symbol> tupleDomain = extractionResult.getTupleDomain();
    OptionalInt upperBound = extractUpperBound(tupleDomain, rankingSymbol);
    if (upperBound.isEmpty()) {
        return Result.empty();
    }
    if (upperBound.getAsInt() <= 0) {
        return Result.ofPlanNode(new ValuesNode(filter.getId(), filter.getOutputSymbols(), ImmutableList.of()));
    }
    RankingType rankingType = toTopNRankingType(window).orElseThrow();
    project = (ProjectNode) project.replaceChildren(ImmutableList.of(new TopNRankingNode(window.getId(), window.getSource(), window.getSpecification(), rankingType, rankingSymbol, upperBound.getAsInt(), false, Optional.empty())));
    if (!allRankingValuesInDomain(tupleDomain, rankingSymbol, upperBound.getAsInt())) {
        return Result.ofPlanNode(filter.replaceChildren(ImmutableList.of(project)));
    }
    // Remove the ranking domain because it is absorbed into the node
    TupleDomain<Symbol> newTupleDomain = tupleDomain.filter((symbol, domain) -> !symbol.equals(rankingSymbol));
    Expression newPredicate = ExpressionUtils.combineConjuncts(plannerContext.getMetadata(), extractionResult.getRemainingExpression(), new DomainTranslator(plannerContext).toPredicate(context.getSession(), newTupleDomain));
    if (newPredicate.equals(TRUE_LITERAL)) {
        return Result.ofPlanNode(project);
    }
    return Result.ofPlanNode(new FilterNode(filter.getId(), project, newPredicate));
}
Also used : WindowNode(io.trino.sql.planner.plan.WindowNode) ValuesNode(io.trino.sql.planner.plan.ValuesNode) Util.toTopNRankingType(io.trino.sql.planner.iterative.rule.Util.toTopNRankingType) RankingType(io.trino.sql.planner.plan.TopNRankingNode.RankingType) TopNRankingNode(io.trino.sql.planner.plan.TopNRankingNode) Expression(io.trino.sql.tree.Expression) Symbol(io.trino.sql.planner.Symbol) FilterNode(io.trino.sql.planner.plan.FilterNode) DomainTranslator(io.trino.sql.planner.DomainTranslator) ProjectNode(io.trino.sql.planner.plan.ProjectNode) OptionalInt(java.util.OptionalInt)

Example 4 with TopNRankingNode

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

the class PushDownDereferencesThroughTopNRanking method apply.

@Override
public Result apply(ProjectNode projectNode, Captures captures, Context context) {
    TopNRankingNode topNRankingNode = captures.get(CHILD);
    // Extract dereferences from project node assignments for pushdown
    Set<SubscriptExpression> dereferences = extractRowSubscripts(projectNode.getAssignments().getExpressions(), false, context.getSession(), typeAnalyzer, context.getSymbolAllocator().getTypes());
    // Exclude dereferences on symbols being used in partitionBy and orderBy
    WindowNode.Specification specification = topNRankingNode.getSpecification();
    dereferences = dereferences.stream().filter(expression -> {
        Symbol symbol = getBase(expression);
        return !specification.getPartitionBy().contains(symbol) && !specification.getOrderingScheme().map(OrderingScheme::getOrderBy).orElse(ImmutableList.of()).contains(symbol);
    }).collect(toImmutableSet());
    if (dereferences.isEmpty()) {
        return Result.empty();
    }
    // Create new symbols for dereference expressions
    Assignments dereferenceAssignments = Assignments.of(dereferences, context.getSession(), context.getSymbolAllocator(), typeAnalyzer);
    // Rewrite project node assignments using new symbols for dereference expressions
    Map<Expression, SymbolReference> mappings = HashBiMap.create(dereferenceAssignments.getMap()).inverse().entrySet().stream().collect(toImmutableMap(Map.Entry::getKey, entry -> entry.getValue().toSymbolReference()));
    Assignments newAssignments = projectNode.getAssignments().rewrite(expression -> replaceExpression(expression, mappings));
    return Result.ofPlanNode(new ProjectNode(context.getIdAllocator().getNextId(), topNRankingNode.replaceChildren(ImmutableList.of(new ProjectNode(context.getIdAllocator().getNextId(), topNRankingNode.getSource(), Assignments.builder().putIdentities(topNRankingNode.getSource().getOutputSymbols()).putAll(dereferenceAssignments).build()))), newAssignments));
}
Also used : Capture.newCapture(io.trino.matching.Capture.newCapture) DereferencePushdown.getBase(io.trino.sql.planner.iterative.rule.DereferencePushdown.getBase) SubscriptExpression(io.trino.sql.tree.SubscriptExpression) ImmutableList(com.google.common.collect.ImmutableList) Map(java.util.Map) Objects.requireNonNull(java.util.Objects.requireNonNull) ImmutableSet.toImmutableSet(com.google.common.collect.ImmutableSet.toImmutableSet) Rule(io.trino.sql.planner.iterative.Rule) ProjectNode(io.trino.sql.planner.plan.ProjectNode) Symbol(io.trino.sql.planner.Symbol) Assignments(io.trino.sql.planner.plan.Assignments) Set(java.util.Set) OrderingScheme(io.trino.sql.planner.OrderingScheme) Capture(io.trino.matching.Capture) DereferencePushdown.extractRowSubscripts(io.trino.sql.planner.iterative.rule.DereferencePushdown.extractRowSubscripts) HashBiMap(com.google.common.collect.HashBiMap) ImmutableMap.toImmutableMap(com.google.common.collect.ImmutableMap.toImmutableMap) Pattern(io.trino.matching.Pattern) TypeAnalyzer(io.trino.sql.planner.TypeAnalyzer) Patterns.source(io.trino.sql.planner.plan.Patterns.source) SymbolReference(io.trino.sql.tree.SymbolReference) Captures(io.trino.matching.Captures) Patterns.topNRanking(io.trino.sql.planner.plan.Patterns.topNRanking) TopNRankingNode(io.trino.sql.planner.plan.TopNRankingNode) ExpressionNodeInliner.replaceExpression(io.trino.sql.planner.ExpressionNodeInliner.replaceExpression) Expression(io.trino.sql.tree.Expression) Patterns.project(io.trino.sql.planner.plan.Patterns.project) WindowNode(io.trino.sql.planner.plan.WindowNode) WindowNode(io.trino.sql.planner.plan.WindowNode) OrderingScheme(io.trino.sql.planner.OrderingScheme) Symbol(io.trino.sql.planner.Symbol) SymbolReference(io.trino.sql.tree.SymbolReference) Assignments(io.trino.sql.planner.plan.Assignments) TopNRankingNode(io.trino.sql.planner.plan.TopNRankingNode) SubscriptExpression(io.trino.sql.tree.SubscriptExpression) ExpressionNodeInliner.replaceExpression(io.trino.sql.planner.ExpressionNodeInliner.replaceExpression) Expression(io.trino.sql.tree.Expression) SubscriptExpression(io.trino.sql.tree.SubscriptExpression) ProjectNode(io.trino.sql.planner.plan.ProjectNode) Map(java.util.Map) HashBiMap(com.google.common.collect.HashBiMap) ImmutableMap.toImmutableMap(com.google.common.collect.ImmutableMap.toImmutableMap)

Example 5 with TopNRankingNode

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

the class PushdownLimitIntoWindow method apply.

@Override
public Result apply(LimitNode node, Captures captures, Context context) {
    WindowNode source = captures.get(childCapture);
    Optional<RankingType> rankingType = toTopNRankingType(source);
    int limit = toIntExact(node.getCount());
    TopNRankingNode topNRowNumberNode = new TopNRankingNode(source.getId(), source.getSource(), source.getSpecification(), rankingType.get(), getOnlyElement(source.getWindowFunctions().keySet()), limit, false, Optional.empty());
    if (rankingType.get() == ROW_NUMBER && source.getPartitionBy().isEmpty()) {
        return Result.ofPlanNode(topNRowNumberNode);
    }
    return Result.ofPlanNode(replaceChildren(node, ImmutableList.of(topNRowNumberNode)));
}
Also used : WindowNode(io.trino.sql.planner.plan.WindowNode) Util.toTopNRankingType(io.trino.sql.planner.iterative.rule.Util.toTopNRankingType) RankingType(io.trino.sql.planner.plan.TopNRankingNode.RankingType) TopNRankingNode(io.trino.sql.planner.plan.TopNRankingNode)

Aggregations

TopNRankingNode (io.trino.sql.planner.plan.TopNRankingNode)5 WindowNode (io.trino.sql.planner.plan.WindowNode)5 Symbol (io.trino.sql.planner.Symbol)4 Util.toTopNRankingType (io.trino.sql.planner.iterative.rule.Util.toTopNRankingType)3 RankingType (io.trino.sql.planner.plan.TopNRankingNode.RankingType)3 Expression (io.trino.sql.tree.Expression)3 DomainTranslator (io.trino.sql.planner.DomainTranslator)2 FilterNode (io.trino.sql.planner.plan.FilterNode)2 ProjectNode (io.trino.sql.planner.plan.ProjectNode)2 ValuesNode (io.trino.sql.planner.plan.ValuesNode)2 OptionalInt (java.util.OptionalInt)2 HashBiMap (com.google.common.collect.HashBiMap)1 ImmutableList (com.google.common.collect.ImmutableList)1 ImmutableMap.toImmutableMap (com.google.common.collect.ImmutableMap.toImmutableMap)1 ImmutableSet.toImmutableSet (com.google.common.collect.ImmutableSet.toImmutableSet)1 Session (io.trino.Session)1 Capture (io.trino.matching.Capture)1 Capture.newCapture (io.trino.matching.Capture.newCapture)1 Captures (io.trino.matching.Captures)1 Pattern (io.trino.matching.Pattern)1