Search in sources :

Example 6 with Symbol

use of io.trino.sql.planner.Symbol 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 7 with Symbol

use of io.trino.sql.planner.Symbol in project trino by trinodb.

the class ImplementFilteredAggregations method apply.

@Override
public Result apply(AggregationNode aggregationNode, Captures captures, Context context) {
    Assignments.Builder newAssignments = Assignments.builder();
    ImmutableMap.Builder<Symbol, Aggregation> aggregations = ImmutableMap.builder();
    ImmutableList.Builder<Expression> maskSymbols = ImmutableList.builder();
    boolean aggregateWithoutFilterOrMaskPresent = false;
    for (Map.Entry<Symbol, Aggregation> entry : aggregationNode.getAggregations().entrySet()) {
        Symbol output = entry.getKey();
        // strip the filters
        Aggregation aggregation = entry.getValue();
        Optional<Symbol> mask = aggregation.getMask();
        if (aggregation.getFilter().isPresent()) {
            Symbol filter = aggregation.getFilter().get();
            if (mask.isPresent()) {
                Symbol newMask = context.getSymbolAllocator().newSymbol("mask", BOOLEAN);
                Expression expression = and(mask.get().toSymbolReference(), filter.toSymbolReference());
                newAssignments.put(newMask, expression);
                mask = Optional.of(newMask);
                maskSymbols.add(newMask.toSymbolReference());
            } else {
                mask = Optional.of(filter);
                maskSymbols.add(filter.toSymbolReference());
            }
        } else if (mask.isPresent()) {
            maskSymbols.add(mask.get().toSymbolReference());
        } else {
            aggregateWithoutFilterOrMaskPresent = true;
        }
        aggregations.put(output, new Aggregation(aggregation.getResolvedFunction(), aggregation.getArguments(), aggregation.isDistinct(), Optional.empty(), aggregation.getOrderingScheme(), mask));
    }
    Expression predicate = TRUE_LITERAL;
    if (!aggregationNode.hasNonEmptyGroupingSet() && !aggregateWithoutFilterOrMaskPresent) {
        predicate = combineDisjunctsWithDefault(metadata, maskSymbols.build(), TRUE_LITERAL);
    }
    // identity projection for all existing inputs
    newAssignments.putIdentities(aggregationNode.getSource().getOutputSymbols());
    return Result.ofPlanNode(new AggregationNode(context.getIdAllocator().getNextId(), new FilterNode(context.getIdAllocator().getNextId(), new ProjectNode(context.getIdAllocator().getNextId(), aggregationNode.getSource(), newAssignments.build()), predicate), aggregations.buildOrThrow(), aggregationNode.getGroupingSets(), ImmutableList.of(), aggregationNode.getStep(), aggregationNode.getHashSymbol(), aggregationNode.getGroupIdSymbol()));
}
Also used : Symbol(io.trino.sql.planner.Symbol) ImmutableList(com.google.common.collect.ImmutableList) FilterNode(io.trino.sql.planner.plan.FilterNode) Assignments(io.trino.sql.planner.plan.Assignments) AggregationNode(io.trino.sql.planner.plan.AggregationNode) ImmutableMap(com.google.common.collect.ImmutableMap) Aggregation(io.trino.sql.planner.plan.AggregationNode.Aggregation) Expression(io.trino.sql.tree.Expression) ProjectNode(io.trino.sql.planner.plan.ProjectNode) ImmutableMap(com.google.common.collect.ImmutableMap) Map(java.util.Map)

Example 8 with Symbol

use of io.trino.sql.planner.Symbol in project trino by trinodb.

the class ImplementOffset method apply.

@Override
public Result apply(OffsetNode parent, Captures captures, Context context) {
    Symbol rowNumberSymbol = context.getSymbolAllocator().newSymbol("row_number", BIGINT);
    RowNumberNode rowNumberNode = new RowNumberNode(context.getIdAllocator().getNextId(), parent.getSource(), ImmutableList.of(), true, rowNumberSymbol, Optional.empty(), Optional.empty());
    FilterNode filterNode = new FilterNode(context.getIdAllocator().getNextId(), rowNumberNode, new ComparisonExpression(ComparisonExpression.Operator.GREATER_THAN, rowNumberSymbol.toSymbolReference(), new GenericLiteral("BIGINT", Long.toString(parent.getCount()))));
    ProjectNode projectNode = new ProjectNode(context.getIdAllocator().getNextId(), filterNode, Assignments.identity(parent.getOutputSymbols()));
    return Result.ofPlanNode(projectNode);
}
Also used : ComparisonExpression(io.trino.sql.tree.ComparisonExpression) Symbol(io.trino.sql.planner.Symbol) FilterNode(io.trino.sql.planner.plan.FilterNode) RowNumberNode(io.trino.sql.planner.plan.RowNumberNode) ProjectNode(io.trino.sql.planner.plan.ProjectNode) GenericLiteral(io.trino.sql.tree.GenericLiteral)

Example 9 with Symbol

use of io.trino.sql.planner.Symbol in project trino by trinodb.

the class InlineProjectIntoFilter method apply.

@Override
public Result apply(FilterNode node, Captures captures, Context context) {
    ProjectNode projectNode = captures.get(PROJECTION);
    List<Expression> filterConjuncts = extractConjuncts(node.getPredicate());
    Map<Boolean, List<Expression>> conjuncts = filterConjuncts.stream().collect(partitioningBy(SymbolReference.class::isInstance));
    List<Expression> simpleConjuncts = conjuncts.get(true);
    List<Expression> complexConjuncts = conjuncts.get(false);
    // Do not inline expression if the symbol is used multiple times in simple conjuncts.
    Set<Expression> simpleUniqueConjuncts = simpleConjuncts.stream().collect(Collectors.groupingBy(identity(), counting())).entrySet().stream().filter(entry -> entry.getValue() == 1).map(Map.Entry::getKey).collect(toImmutableSet());
    Set<Expression> complexConjunctSymbols = SymbolsExtractor.extractUnique(complexConjuncts).stream().map(Symbol::toSymbolReference).collect(toImmutableSet());
    // Do not inline expression if the symbol is used in complex conjuncts.
    Set<Expression> simpleConjunctsToInline = Sets.difference(simpleUniqueConjuncts, complexConjunctSymbols);
    if (simpleConjunctsToInline.isEmpty()) {
        return Result.empty();
    }
    ImmutableList.Builder<Expression> newConjuncts = ImmutableList.builder();
    Assignments.Builder newAssignments = Assignments.builder();
    Assignments.Builder postFilterAssignmentsBuilder = Assignments.builder();
    for (Expression conjunct : filterConjuncts) {
        if (simpleConjunctsToInline.contains(conjunct)) {
            Expression expression = projectNode.getAssignments().get(Symbol.from(conjunct));
            if (expression == null || expression instanceof SymbolReference) {
                // expression == null -> The symbol is not produced by the underlying projection (i.e. it is a correlation symbol).
                // expression instanceof SymbolReference -> Do not inline trivial projections.
                newConjuncts.add(conjunct);
            } else {
                newConjuncts.add(expression);
                newAssignments.putIdentities(SymbolsExtractor.extractUnique(expression));
                postFilterAssignmentsBuilder.put(Symbol.from(conjunct), TRUE_LITERAL);
            }
        } else {
            newConjuncts.add(conjunct);
        }
    }
    Assignments postFilterAssignments = postFilterAssignmentsBuilder.build();
    if (postFilterAssignments.isEmpty()) {
        return Result.empty();
    }
    Set<Symbol> postFilterSymbols = postFilterAssignments.getSymbols();
    // Remove inlined expressions from the underlying projection.
    newAssignments.putAll(projectNode.getAssignments().filter(symbol -> !postFilterSymbols.contains(symbol)));
    Map<Symbol, Expression> outputAssignments = new HashMap<>();
    outputAssignments.putAll(Assignments.identity(node.getOutputSymbols()).getMap());
    // Restore inlined symbols.
    outputAssignments.putAll(postFilterAssignments.getMap());
    return Result.ofPlanNode(new ProjectNode(context.getIdAllocator().getNextId(), new FilterNode(node.getId(), new ProjectNode(projectNode.getId(), projectNode.getSource(), newAssignments.build()), combineConjuncts(metadata, newConjuncts.build())), Assignments.builder().putAll(outputAssignments).build()));
}
Also used : Collectors.partitioningBy(java.util.stream.Collectors.partitioningBy) Patterns.filter(io.trino.sql.planner.plan.Patterns.filter) Collectors.counting(java.util.stream.Collectors.counting) HashMap(java.util.HashMap) Capture.newCapture(io.trino.matching.Capture.newCapture) FilterNode(io.trino.sql.planner.plan.FilterNode) ImmutableList(com.google.common.collect.ImmutableList) Map(java.util.Map) ImmutableSet.toImmutableSet(com.google.common.collect.ImmutableSet.toImmutableSet) Rule(io.trino.sql.planner.iterative.Rule) SymbolsExtractor(io.trino.sql.planner.SymbolsExtractor) ProjectNode(io.trino.sql.planner.plan.ProjectNode) Symbol(io.trino.sql.planner.Symbol) Assignments(io.trino.sql.planner.plan.Assignments) Set(java.util.Set) TRUE_LITERAL(io.trino.sql.tree.BooleanLiteral.TRUE_LITERAL) Collectors(java.util.stream.Collectors) Sets(com.google.common.collect.Sets) Capture(io.trino.matching.Capture) List(java.util.List) Pattern(io.trino.matching.Pattern) Patterns.source(io.trino.sql.planner.plan.Patterns.source) SymbolReference(io.trino.sql.tree.SymbolReference) Captures(io.trino.matching.Captures) Function.identity(java.util.function.Function.identity) Metadata(io.trino.metadata.Metadata) Expression(io.trino.sql.tree.Expression) ExpressionUtils.extractConjuncts(io.trino.sql.ExpressionUtils.extractConjuncts) Patterns.project(io.trino.sql.planner.plan.Patterns.project) ExpressionUtils.combineConjuncts(io.trino.sql.ExpressionUtils.combineConjuncts) HashMap(java.util.HashMap) ImmutableList(com.google.common.collect.ImmutableList) SymbolReference(io.trino.sql.tree.SymbolReference) Symbol(io.trino.sql.planner.Symbol) FilterNode(io.trino.sql.planner.plan.FilterNode) Assignments(io.trino.sql.planner.plan.Assignments) Expression(io.trino.sql.tree.Expression) ProjectNode(io.trino.sql.planner.plan.ProjectNode) ImmutableList(com.google.common.collect.ImmutableList) List(java.util.List) HashMap(java.util.HashMap) Map(java.util.Map)

Example 10 with Symbol

use of io.trino.sql.planner.Symbol in project trino by trinodb.

the class InlineProjections method extractInliningTargets.

private static Set<Symbol> extractInliningTargets(PlannerContext plannerContext, ProjectNode parent, ProjectNode child, Session session, TypeAnalyzer typeAnalyzer, TypeProvider types) {
    // candidates for inlining are
    // 1. references to simple constants or symbol references
    // 2. references to complex expressions that
    // a. are not inputs to try() expressions
    // b. appear only once across all expressions
    // c. are not identity projections
    // which come from the child, as opposed to an enclosing scope.
    Set<Symbol> childOutputSet = ImmutableSet.copyOf(child.getOutputSymbols());
    Map<Symbol, Long> dependencies = parent.getAssignments().getExpressions().stream().flatMap(expression -> SymbolsExtractor.extractAll(expression).stream()).filter(childOutputSet::contains).collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
    // find references to simple constants or symbol references
    Set<Symbol> basicReferences = dependencies.keySet().stream().filter(input -> isEffectivelyLiteral(plannerContext, session, child.getAssignments().get(input)) || child.getAssignments().get(input) instanceof SymbolReference).filter(// skip identities, otherwise, this rule will keep firing forever
    input -> !child.getAssignments().isIdentity(input)).collect(toSet());
    // exclude any complex inputs to TRY expressions. Inlining them would potentially
    // change the semantics of those expressions
    Set<Symbol> tryArguments = parent.getAssignments().getExpressions().stream().flatMap(expression -> extractTryArguments(expression).stream()).collect(toSet());
    Set<Symbol> singletons = dependencies.entrySet().stream().filter(// reference appears just once across all expressions in parent project node
    entry -> entry.getValue() == 1).filter(// they are not inputs to TRY. Otherwise, inlining might change semantics
    entry -> !tryArguments.contains(entry.getKey())).filter(// skip identities, otherwise, this rule will keep firing forever
    entry -> !child.getAssignments().isIdentity(entry.getKey())).filter(entry -> {
        // skip dereferences, otherwise, inlining can cause conflicts with PushdownDereferences
        Expression assignment = child.getAssignments().get(entry.getKey());
        if (assignment instanceof SubscriptExpression) {
            if (typeAnalyzer.getType(session, types, ((SubscriptExpression) assignment).getBase()) instanceof RowType) {
                return false;
            }
        }
        return true;
    }).map(Map.Entry::getKey).collect(toSet());
    return Sets.union(singletons, basicReferences);
}
Also used : Function(java.util.function.Function) Capture.newCapture(io.trino.matching.Capture.newCapture) PlanNode(io.trino.sql.planner.plan.PlanNode) SubscriptExpression(io.trino.sql.tree.SubscriptExpression) ExpressionSymbolInliner.inlineSymbols(io.trino.sql.planner.ExpressionSymbolInliner.inlineSymbols) ImmutableList(com.google.common.collect.ImmutableList) Map(java.util.Map) Objects.requireNonNull(java.util.Objects.requireNonNull) Rule(io.trino.sql.planner.iterative.Rule) SymbolsExtractor(io.trino.sql.planner.SymbolsExtractor) TryExpression(io.trino.sql.tree.TryExpression) ProjectNode(io.trino.sql.planner.plan.ProjectNode) Collectors.toSet(java.util.stream.Collectors.toSet) Symbol(io.trino.sql.planner.Symbol) RowType(io.trino.spi.type.RowType) ImmutableSet(com.google.common.collect.ImmutableSet) Assignments(io.trino.sql.planner.plan.Assignments) Set(java.util.Set) Collectors(java.util.stream.Collectors) Sets(com.google.common.collect.Sets) Capture(io.trino.matching.Capture) ExpressionUtils.isEffectivelyLiteral(io.trino.sql.ExpressionUtils.isEffectivelyLiteral) Pattern(io.trino.matching.Pattern) TypeAnalyzer(io.trino.sql.planner.TypeAnalyzer) AstUtils(io.trino.sql.util.AstUtils) Patterns.source(io.trino.sql.planner.plan.Patterns.source) SymbolReference(io.trino.sql.tree.SymbolReference) Captures(io.trino.matching.Captures) TypeProvider(io.trino.sql.planner.TypeProvider) Optional(java.util.Optional) Expression(io.trino.sql.tree.Expression) Patterns.project(io.trino.sql.planner.plan.Patterns.project) Session(io.trino.Session) PlannerContext(io.trino.sql.PlannerContext) SubscriptExpression(io.trino.sql.tree.SubscriptExpression) TryExpression(io.trino.sql.tree.TryExpression) Expression(io.trino.sql.tree.Expression) Symbol(io.trino.sql.planner.Symbol) SymbolReference(io.trino.sql.tree.SymbolReference) SubscriptExpression(io.trino.sql.tree.SubscriptExpression) RowType(io.trino.spi.type.RowType) Map(java.util.Map)

Aggregations

Symbol (io.trino.sql.planner.Symbol)366 Test (org.testng.annotations.Test)171 ImmutableList (com.google.common.collect.ImmutableList)124 ImmutableMap (com.google.common.collect.ImmutableMap)106 Optional (java.util.Optional)96 PlanNode (io.trino.sql.planner.plan.PlanNode)85 Expression (io.trino.sql.tree.Expression)85 Map (java.util.Map)66 Assignments (io.trino.sql.planner.plan.Assignments)65 JoinNode (io.trino.sql.planner.plan.JoinNode)64 ProjectNode (io.trino.sql.planner.plan.ProjectNode)61 PlanMatchPattern.values (io.trino.sql.planner.assertions.PlanMatchPattern.values)56 SymbolReference (io.trino.sql.tree.SymbolReference)55 BIGINT (io.trino.spi.type.BigintType.BIGINT)52 Type (io.trino.spi.type.Type)51 Session (io.trino.Session)46 List (java.util.List)46 RuleTester (io.trino.sql.planner.iterative.rule.test.RuleTester)43 RuleTester.defaultRuleTester (io.trino.sql.planner.iterative.rule.test.RuleTester.defaultRuleTester)43 PlanNodeId (io.trino.sql.planner.plan.PlanNodeId)43