Search in sources :

Example 1 with TRUE_LITERAL

use of io.trino.sql.tree.BooleanLiteral.TRUE_LITERAL 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 2 with TRUE_LITERAL

use of io.trino.sql.tree.BooleanLiteral.TRUE_LITERAL in project trino by trinodb.

the class DomainTranslator method toPredicate.

private Expression toPredicate(Session session, Domain domain, SymbolReference reference) {
    if (domain.getValues().isNone()) {
        return domain.isNullAllowed() ? new IsNullPredicate(reference) : FALSE_LITERAL;
    }
    if (domain.getValues().isAll()) {
        return domain.isNullAllowed() ? TRUE_LITERAL : new NotExpression(new IsNullPredicate(reference));
    }
    List<Expression> disjuncts = new ArrayList<>();
    disjuncts.addAll(domain.getValues().getValuesProcessor().transform(ranges -> extractDisjuncts(session, domain.getType(), ranges, reference), discreteValues -> extractDisjuncts(session, domain.getType(), discreteValues, reference), allOrNone -> {
        throw new IllegalStateException("Case should not be reachable");
    }));
    // Add nullability disjuncts
    if (domain.isNullAllowed()) {
        disjuncts.add(new IsNullPredicate(reference));
    }
    return combineDisjunctsWithDefault(plannerContext.getMetadata(), disjuncts, TRUE_LITERAL);
}
Also used : IsNullPredicate(io.trino.sql.tree.IsNullPredicate) TableProceduresPropertyManager(io.trino.metadata.TableProceduresPropertyManager) FAIL_ON_NULL(io.trino.spi.function.InvocationConvention.InvocationReturnConvention.FAIL_ON_NULL) ExpressionUtils.combineDisjunctsWithDefault(io.trino.sql.ExpressionUtils.combineDisjunctsWithDefault) InvocationConvention.simpleConvention(io.trino.spi.function.InvocationConvention.simpleConvention) PeekingIterator(com.google.common.collect.PeekingIterator) InterpretedFunctionInvoker(io.trino.sql.InterpretedFunctionInvoker) TypeUtils.isFloatingPointNaN(io.trino.spi.type.TypeUtils.isFloatingPointNaN) Preconditions.checkArgument(com.google.common.base.Preconditions.checkArgument) BooleanLiteral(io.trino.sql.tree.BooleanLiteral) ExpressionUtils.or(io.trino.sql.ExpressionUtils.or) Slices(io.airlift.slice.Slices) Map(java.util.Map) GREATER_THAN(io.trino.sql.tree.ComparisonExpression.Operator.GREATER_THAN) DiscreteValues(io.trino.spi.predicate.DiscreteValues) SqlParser(io.trino.sql.parser.SqlParser) FunctionCall(io.trino.sql.tree.FunctionCall) BetweenPredicate(io.trino.sql.tree.BetweenPredicate) SliceUtf8.getCodePointAt(io.airlift.slice.SliceUtf8.getCodePointAt) SATURATED_FLOOR_CAST(io.trino.spi.function.OperatorType.SATURATED_FLOOR_CAST) ImmutableSet(com.google.common.collect.ImmutableSet) ImmutableMap(com.google.common.collect.ImmutableMap) Range(io.trino.spi.predicate.Range) Ranges(io.trino.spi.predicate.Ranges) ResolvedFunction(io.trino.metadata.ResolvedFunction) Domain(io.trino.spi.predicate.Domain) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) FALSE_LITERAL(io.trino.sql.tree.BooleanLiteral.FALSE_LITERAL) Set(java.util.Set) TrinoException(io.trino.spi.TrinoException) ComparisonExpression(io.trino.sql.tree.ComparisonExpression) ValueSet(io.trino.spi.predicate.ValueSet) InPredicate(io.trino.sql.tree.InPredicate) Preconditions.checkState(com.google.common.base.Preconditions.checkState) LESS_THAN_OR_EQUAL(io.trino.sql.tree.ComparisonExpression.Operator.LESS_THAN_OR_EQUAL) SessionPropertyManager(io.trino.metadata.SessionPropertyManager) EQUAL(io.trino.sql.tree.ComparisonExpression.Operator.EQUAL) NOT_EQUAL(io.trino.sql.tree.ComparisonExpression.Operator.NOT_EQUAL) List(java.util.List) SymbolReference(io.trino.sql.tree.SymbolReference) Optional(java.util.Optional) Expression(io.trino.sql.tree.Expression) InListExpression(io.trino.sql.tree.InListExpression) ExpressionUtils.combineConjuncts(io.trino.sql.ExpressionUtils.combineConjuncts) NEVER_NULL(io.trino.spi.function.InvocationConvention.InvocationArgumentConvention.NEVER_NULL) Session(io.trino.Session) PlannerContext(io.trino.sql.PlannerContext) MethodHandle(java.lang.invoke.MethodHandle) Slice(io.airlift.slice.Slice) AllowAllAccessControl(io.trino.security.AllowAllAccessControl) NullableValue(io.trino.spi.predicate.NullableValue) DoubleType(io.trino.spi.type.DoubleType) LikePredicate(io.trino.sql.tree.LikePredicate) Type(io.trino.spi.type.Type) TypeCoercion(io.trino.type.TypeCoercion) BOOLEAN(io.trino.spi.type.BooleanType.BOOLEAN) Collectors.collectingAndThen(java.util.stream.Collectors.collectingAndThen) ArrayList(java.util.ArrayList) Cast(io.trino.sql.tree.Cast) VarcharType(io.trino.spi.type.VarcharType) ImmutableList(com.google.common.collect.ImmutableList) IsNotNullPredicate(io.trino.sql.tree.IsNotNullPredicate) NodeRef(io.trino.sql.tree.NodeRef) NotExpression(io.trino.sql.tree.NotExpression) Objects.requireNonNull(java.util.Objects.requireNonNull) NullLiteral(io.trino.sql.tree.NullLiteral) TableProceduresRegistry(io.trino.metadata.TableProceduresRegistry) Iterators.peekingIterator(com.google.common.collect.Iterators.peekingIterator) GREATER_THAN_OR_EQUAL(io.trino.sql.tree.ComparisonExpression.Operator.GREATER_THAN_OR_EQUAL) Nullable(javax.annotation.Nullable) AstVisitor(io.trino.sql.tree.AstVisitor) SliceUtf8.lengthOfCodePoint(io.airlift.slice.SliceUtf8.lengthOfCodePoint) StringLiteral(io.trino.sql.tree.StringLiteral) OperatorNotFoundException(io.trino.metadata.OperatorNotFoundException) Throwables(com.google.common.base.Throwables) Iterables.getOnlyElement(com.google.common.collect.Iterables.getOnlyElement) TRUE_LITERAL(io.trino.sql.tree.BooleanLiteral.TRUE_LITERAL) LESS_THAN(io.trino.sql.tree.ComparisonExpression.Operator.LESS_THAN) TupleDomain(io.trino.spi.predicate.TupleDomain) SliceUtf8.setCodePointAt(io.airlift.slice.SliceUtf8.setCodePointAt) GENERIC_INTERNAL_ERROR(io.trino.spi.StandardErrorCode.GENERIC_INTERNAL_ERROR) LikeFunctions(io.trino.type.LikeFunctions) Collectors.toList(java.util.stream.Collectors.toList) ExpressionUtils.and(io.trino.sql.ExpressionUtils.and) StatementAnalyzerFactory(io.trino.sql.analyzer.StatementAnalyzerFactory) TablePropertyManager(io.trino.metadata.TablePropertyManager) RealType(io.trino.spi.type.RealType) LogicalExpression(io.trino.sql.tree.LogicalExpression) SliceUtf8.countCodePoints(io.airlift.slice.SliceUtf8.countCodePoints) AnalyzePropertyManager(io.trino.metadata.AnalyzePropertyManager) SortedRangeSet(io.trino.spi.predicate.SortedRangeSet) ComparisonExpression(io.trino.sql.tree.ComparisonExpression) Expression(io.trino.sql.tree.Expression) InListExpression(io.trino.sql.tree.InListExpression) NotExpression(io.trino.sql.tree.NotExpression) LogicalExpression(io.trino.sql.tree.LogicalExpression) ArrayList(java.util.ArrayList) IsNullPredicate(io.trino.sql.tree.IsNullPredicate) NotExpression(io.trino.sql.tree.NotExpression)

Example 3 with TRUE_LITERAL

use of io.trino.sql.tree.BooleanLiteral.TRUE_LITERAL in project trino by trinodb.

the class PushPredicateIntoTableScan method pushFilterIntoTableScan.

public static Optional<PlanNode> pushFilterIntoTableScan(FilterNode filterNode, TableScanNode node, boolean pruneWithPredicateExpression, Session session, SymbolAllocator symbolAllocator, PlannerContext plannerContext, TypeAnalyzer typeAnalyzer, StatsProvider statsProvider, DomainTranslator domainTranslator) {
    if (!isAllowPushdownIntoConnectors(session)) {
        return Optional.empty();
    }
    SplitExpression splitExpression = splitExpression(plannerContext, filterNode.getPredicate());
    DomainTranslator.ExtractionResult decomposedPredicate = DomainTranslator.getExtractionResult(plannerContext, session, splitExpression.getDeterministicPredicate(), symbolAllocator.getTypes());
    TupleDomain<ColumnHandle> newDomain = decomposedPredicate.getTupleDomain().transformKeys(node.getAssignments()::get).intersect(node.getEnforcedConstraint());
    Map<NodeRef<Expression>, Type> remainingExpressionTypes = typeAnalyzer.getTypes(session, symbolAllocator.getTypes(), decomposedPredicate.getRemainingExpression());
    Optional<ConnectorExpression> connectorExpression = new ConnectorExpressionTranslator.SqlToConnectorExpressionTranslator(session, remainingExpressionTypes, plannerContext).process(decomposedPredicate.getRemainingExpression());
    Map<String, ColumnHandle> connectorExpressionAssignments = connectorExpression.map(ignored -> node.getAssignments().entrySet().stream().collect(toImmutableMap(entry -> entry.getKey().getName(), Map.Entry::getValue))).orElse(ImmutableMap.of());
    Map<ColumnHandle, Symbol> assignments = ImmutableBiMap.copyOf(node.getAssignments()).inverse();
    Constraint constraint;
    // use evaluator only when there is some predicate which could not be translated into tuple domain
    if (pruneWithPredicateExpression && !TRUE_LITERAL.equals(decomposedPredicate.getRemainingExpression())) {
        LayoutConstraintEvaluator evaluator = new LayoutConstraintEvaluator(plannerContext, typeAnalyzer, session, symbolAllocator.getTypes(), node.getAssignments(), combineConjuncts(plannerContext.getMetadata(), splitExpression.getDeterministicPredicate(), // which would be expensive to evaluate in the call to isCandidate below.
        domainTranslator.toPredicate(session, newDomain.simplify().transformKeys(assignments::get))));
        constraint = new Constraint(newDomain, connectorExpression.orElse(TRUE), connectorExpressionAssignments, evaluator::isCandidate, evaluator.getArguments());
    } else {
        // Currently, invoking the expression interpreter is very expensive.
        // TODO invoke the interpreter unconditionally when the interpreter becomes cheap enough.
        constraint = new Constraint(newDomain, connectorExpression.orElse(TRUE), connectorExpressionAssignments);
    }
    // check if new domain is wider than domain already provided by table scan
    if (constraint.predicate().isEmpty() && // TODO do we need to track enforced ConnectorExpression in TableScanNode?
    TRUE.equals(connectorExpression.orElse(TRUE)) && newDomain.contains(node.getEnforcedConstraint())) {
        Expression resultingPredicate = createResultingPredicate(plannerContext, session, symbolAllocator, typeAnalyzer, splitExpression.getDynamicFilter(), TRUE_LITERAL, splitExpression.getNonDeterministicPredicate(), decomposedPredicate.getRemainingExpression());
        if (!TRUE_LITERAL.equals(resultingPredicate)) {
            return Optional.of(new FilterNode(filterNode.getId(), node, resultingPredicate));
        }
        return Optional.of(node);
    }
    if (newDomain.isNone()) {
        // to turn the subtree into a Values node
        return Optional.of(new ValuesNode(node.getId(), node.getOutputSymbols(), ImmutableList.of()));
    }
    Optional<ConstraintApplicationResult<TableHandle>> result = plannerContext.getMetadata().applyFilter(session, node.getTable(), constraint);
    if (result.isEmpty()) {
        return Optional.empty();
    }
    TableHandle newTable = result.get().getHandle();
    TableProperties newTableProperties = plannerContext.getMetadata().getTableProperties(session, newTable);
    Optional<TablePartitioning> newTablePartitioning = newTableProperties.getTablePartitioning();
    if (newTableProperties.getPredicate().isNone()) {
        return Optional.of(new ValuesNode(node.getId(), node.getOutputSymbols(), ImmutableList.of()));
    }
    TupleDomain<ColumnHandle> remainingFilter = result.get().getRemainingFilter();
    Optional<ConnectorExpression> remainingConnectorExpression = result.get().getRemainingExpression();
    boolean precalculateStatistics = result.get().isPrecalculateStatistics();
    verifyTablePartitioning(session, plannerContext.getMetadata(), node, newTablePartitioning);
    TableScanNode tableScan = new TableScanNode(node.getId(), newTable, node.getOutputSymbols(), node.getAssignments(), computeEnforced(newDomain, remainingFilter), // TODO (https://github.com/trinodb/trino/issues/8144) distinguish between predicate pushed down and remaining
    deriveTableStatisticsForPushdown(statsProvider, session, precalculateStatistics, filterNode), node.isUpdateTarget(), node.getUseConnectorNodePartitioning());
    Expression remainingDecomposedPredicate;
    if (remainingConnectorExpression.isEmpty() || remainingConnectorExpression.equals(connectorExpression)) {
        remainingDecomposedPredicate = decomposedPredicate.getRemainingExpression();
    } else {
        Map<String, Symbol> variableMappings = assignments.values().stream().collect(toImmutableMap(Symbol::getName, Function.identity()));
        Expression translatedExpression = ConnectorExpressionTranslator.translate(session, remainingConnectorExpression.get(), plannerContext, variableMappings, new LiteralEncoder(plannerContext));
        if (connectorExpression.isEmpty()) {
            remainingDecomposedPredicate = ExpressionUtils.combineConjuncts(plannerContext.getMetadata(), translatedExpression, decomposedPredicate.getRemainingExpression());
        } else {
            remainingDecomposedPredicate = translatedExpression;
        }
    }
    Expression resultingPredicate = createResultingPredicate(plannerContext, session, symbolAllocator, typeAnalyzer, splitExpression.getDynamicFilter(), domainTranslator.toPredicate(session, remainingFilter.transformKeys(assignments::get)), splitExpression.getNonDeterministicPredicate(), remainingDecomposedPredicate);
    if (!TRUE_LITERAL.equals(resultingPredicate)) {
        return Optional.of(new FilterNode(filterNode.getId(), tableScan, resultingPredicate));
    }
    return Optional.of(tableScan);
}
Also used : LayoutConstraintEvaluator(io.trino.sql.planner.LayoutConstraintEvaluator) SymbolAllocator(io.trino.sql.planner.SymbolAllocator) FilterNode(io.trino.sql.planner.plan.FilterNode) PlanNode(io.trino.sql.planner.plan.PlanNode) Preconditions.checkArgument(com.google.common.base.Preconditions.checkArgument) DeterminismEvaluator.isDeterministic(io.trino.sql.planner.DeterminismEvaluator.isDeterministic) Map(java.util.Map) TableScanNode(io.trino.sql.planner.plan.TableScanNode) Rules.deriveTableStatisticsForPushdown(io.trino.sql.planner.iterative.rule.Rules.deriveTableStatisticsForPushdown) TRUE(io.trino.spi.expression.Constant.TRUE) ImmutableMap(com.google.common.collect.ImmutableMap) Domain(io.trino.spi.predicate.Domain) ConnectorExpressionTranslator(io.trino.sql.planner.ConnectorExpressionTranslator) Patterns.tableScan(io.trino.sql.planner.plan.Patterns.tableScan) StatsProvider(io.trino.cost.StatsProvider) Objects(java.util.Objects) List(java.util.List) ImmutableMap.toImmutableMap(com.google.common.collect.ImmutableMap.toImmutableMap) Pattern(io.trino.matching.Pattern) SystemSessionProperties.isAllowPushdownIntoConnectors(io.trino.SystemSessionProperties.isAllowPushdownIntoConnectors) Optional(java.util.Optional) Expression(io.trino.sql.tree.Expression) ExpressionUtils.extractConjuncts(io.trino.sql.ExpressionUtils.extractConjuncts) ValuesNode(io.trino.sql.planner.plan.ValuesNode) ExpressionUtils.combineConjuncts(io.trino.sql.ExpressionUtils.combineConjuncts) Session(io.trino.Session) PlannerContext(io.trino.sql.PlannerContext) Constraint(io.trino.spi.connector.Constraint) LiteralEncoder(io.trino.sql.planner.LiteralEncoder) Type(io.trino.spi.type.Type) Patterns.filter(io.trino.sql.planner.plan.Patterns.filter) TableProperties(io.trino.metadata.TableProperties) Function(java.util.function.Function) Capture.newCapture(io.trino.matching.Capture.newCapture) ArrayList(java.util.ArrayList) ImmutableBiMap(com.google.common.collect.ImmutableBiMap) ImmutableList(com.google.common.collect.ImmutableList) Verify.verify(com.google.common.base.Verify.verify) NodeRef(io.trino.sql.tree.NodeRef) Objects.requireNonNull(java.util.Objects.requireNonNull) ColumnHandle(io.trino.spi.connector.ColumnHandle) Rule(io.trino.sql.planner.iterative.Rule) DomainTranslator(io.trino.sql.planner.DomainTranslator) TablePartitioning(io.trino.metadata.TableProperties.TablePartitioning) ExpressionUtils(io.trino.sql.ExpressionUtils) Symbol(io.trino.sql.planner.Symbol) ConstraintApplicationResult(io.trino.spi.connector.ConstraintApplicationResult) TRUE_LITERAL(io.trino.sql.tree.BooleanLiteral.TRUE_LITERAL) TupleDomain(io.trino.spi.predicate.TupleDomain) Capture(io.trino.matching.Capture) TableHandle(io.trino.metadata.TableHandle) ConnectorExpression(io.trino.spi.expression.ConnectorExpression) TypeAnalyzer(io.trino.sql.planner.TypeAnalyzer) Patterns.source(io.trino.sql.planner.plan.Patterns.source) DynamicFilters.isDynamicFilter(io.trino.sql.DynamicFilters.isDynamicFilter) Captures(io.trino.matching.Captures) Metadata(io.trino.metadata.Metadata) ValuesNode(io.trino.sql.planner.plan.ValuesNode) Constraint(io.trino.spi.connector.Constraint) ConnectorExpression(io.trino.spi.expression.ConnectorExpression) Symbol(io.trino.sql.planner.Symbol) FilterNode(io.trino.sql.planner.plan.FilterNode) NodeRef(io.trino.sql.tree.NodeRef) TablePartitioning(io.trino.metadata.TableProperties.TablePartitioning) LiteralEncoder(io.trino.sql.planner.LiteralEncoder) DomainTranslator(io.trino.sql.planner.DomainTranslator) ConstraintApplicationResult(io.trino.spi.connector.ConstraintApplicationResult) ColumnHandle(io.trino.spi.connector.ColumnHandle) Type(io.trino.spi.type.Type) TableScanNode(io.trino.sql.planner.plan.TableScanNode) Expression(io.trino.sql.tree.Expression) ConnectorExpression(io.trino.spi.expression.ConnectorExpression) ConnectorExpressionTranslator(io.trino.sql.planner.ConnectorExpressionTranslator) TableHandle(io.trino.metadata.TableHandle) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) ImmutableMap.toImmutableMap(com.google.common.collect.ImmutableMap.toImmutableMap) ImmutableBiMap(com.google.common.collect.ImmutableBiMap) TableProperties(io.trino.metadata.TableProperties) LayoutConstraintEvaluator(io.trino.sql.planner.LayoutConstraintEvaluator)

Example 4 with TRUE_LITERAL

use of io.trino.sql.tree.BooleanLiteral.TRUE_LITERAL in project trino by trinodb.

the class SimplifyFilterPredicate method simplifyFilterExpression.

private Optional<Expression> simplifyFilterExpression(Expression expression) {
    if (expression instanceof IfExpression) {
        IfExpression ifExpression = (IfExpression) expression;
        Expression condition = ifExpression.getCondition();
        Expression trueValue = ifExpression.getTrueValue();
        Optional<Expression> falseValue = ifExpression.getFalseValue();
        if (trueValue.equals(TRUE_LITERAL) && (falseValue.isEmpty() || isNotTrue(falseValue.get()))) {
            return Optional.of(condition);
        }
        if (isNotTrue(trueValue) && falseValue.isPresent() && falseValue.get().equals(TRUE_LITERAL)) {
            return Optional.of(isFalseOrNullPredicate(condition));
        }
        if (falseValue.isPresent() && falseValue.get().equals(trueValue) && isDeterministic(trueValue, metadata)) {
            return Optional.of(trueValue);
        }
        if (isNotTrue(trueValue) && (falseValue.isEmpty() || isNotTrue(falseValue.get()))) {
            return Optional.of(FALSE_LITERAL);
        }
        if (condition.equals(TRUE_LITERAL)) {
            return Optional.of(trueValue);
        }
        if (isNotTrue(condition)) {
            return Optional.of(falseValue.orElse(FALSE_LITERAL));
        }
        return Optional.empty();
    }
    if (expression instanceof NullIfExpression) {
        NullIfExpression nullIfExpression = (NullIfExpression) expression;
        return Optional.of(LogicalExpression.and(nullIfExpression.getFirst(), isFalseOrNullPredicate(nullIfExpression.getSecond())));
    }
    if (expression instanceof SearchedCaseExpression) {
        SearchedCaseExpression caseExpression = (SearchedCaseExpression) expression;
        Optional<Expression> defaultValue = caseExpression.getDefaultValue();
        List<Expression> operands = caseExpression.getWhenClauses().stream().map(WhenClause::getOperand).collect(toImmutableList());
        List<Expression> results = caseExpression.getWhenClauses().stream().map(WhenClause::getResult).collect(toImmutableList());
        long trueResultsCount = results.stream().filter(result -> result.equals(TRUE_LITERAL)).count();
        long notTrueResultsCount = results.stream().filter(SimplifyFilterPredicate::isNotTrue).count();
        // all results true
        if (trueResultsCount == results.size() && defaultValue.isPresent() && defaultValue.get().equals(TRUE_LITERAL)) {
            return Optional.of(TRUE_LITERAL);
        }
        // all results not true
        if (notTrueResultsCount == results.size() && (defaultValue.isEmpty() || isNotTrue(defaultValue.get()))) {
            return Optional.of(FALSE_LITERAL);
        }
        // one result true, and remaining results not true
        if (trueResultsCount == 1 && notTrueResultsCount == results.size() - 1 && (defaultValue.isEmpty() || isNotTrue(defaultValue.get()))) {
            ImmutableList.Builder<Expression> builder = ImmutableList.builder();
            for (WhenClause whenClause : caseExpression.getWhenClauses()) {
                Expression operand = whenClause.getOperand();
                Expression result = whenClause.getResult();
                if (isNotTrue(result)) {
                    builder.add(isFalseOrNullPredicate(operand));
                } else {
                    builder.add(operand);
                    return Optional.of(combineConjuncts(metadata, builder.build()));
                }
            }
        }
        // all results not true, and default true
        if (notTrueResultsCount == results.size() && defaultValue.isPresent() && defaultValue.get().equals(TRUE_LITERAL)) {
            ImmutableList.Builder<Expression> builder = ImmutableList.builder();
            operands.stream().forEach(operand -> builder.add(isFalseOrNullPredicate(operand)));
            return Optional.of(combineConjuncts(metadata, builder.build()));
        }
        // skip clauses with not true conditions
        List<WhenClause> whenClauses = new ArrayList<>();
        for (WhenClause whenClause : caseExpression.getWhenClauses()) {
            Expression operand = whenClause.getOperand();
            if (operand.equals(TRUE_LITERAL)) {
                if (whenClauses.isEmpty()) {
                    return Optional.of(whenClause.getResult());
                }
                return Optional.of(new SearchedCaseExpression(whenClauses, Optional.of(whenClause.getResult())));
            }
            if (!isNotTrue(operand)) {
                whenClauses.add(whenClause);
            }
        }
        if (whenClauses.isEmpty()) {
            return Optional.of(defaultValue.orElse(FALSE_LITERAL));
        }
        if (whenClauses.size() < caseExpression.getWhenClauses().size()) {
            return Optional.of(new SearchedCaseExpression(whenClauses, defaultValue));
        }
        return Optional.empty();
    }
    if (expression instanceof SimpleCaseExpression) {
        SimpleCaseExpression caseExpression = (SimpleCaseExpression) expression;
        Optional<Expression> defaultValue = caseExpression.getDefaultValue();
        if (caseExpression.getOperand() instanceof NullLiteral) {
            return Optional.of(defaultValue.orElse(FALSE_LITERAL));
        }
        List<Expression> results = caseExpression.getWhenClauses().stream().map(WhenClause::getResult).collect(toImmutableList());
        if (results.stream().allMatch(result -> result.equals(TRUE_LITERAL)) && defaultValue.isPresent() && defaultValue.get().equals(TRUE_LITERAL)) {
            return Optional.of(TRUE_LITERAL);
        }
        if (results.stream().allMatch(SimplifyFilterPredicate::isNotTrue) && (defaultValue.isEmpty() || isNotTrue(defaultValue.get()))) {
            return Optional.of(FALSE_LITERAL);
        }
        return Optional.empty();
    }
    return Optional.empty();
}
Also used : IsNullPredicate(io.trino.sql.tree.IsNullPredicate) SimpleCaseExpression(io.trino.sql.tree.SimpleCaseExpression) Patterns.filter(io.trino.sql.planner.plan.Patterns.filter) NullIfExpression(io.trino.sql.tree.NullIfExpression) FilterNode(io.trino.sql.planner.plan.FilterNode) ArrayList(java.util.ArrayList) Cast(io.trino.sql.tree.Cast) ImmutableList(com.google.common.collect.ImmutableList) SearchedCaseExpression(io.trino.sql.tree.SearchedCaseExpression) DeterminismEvaluator.isDeterministic(io.trino.sql.planner.DeterminismEvaluator.isDeterministic) NotExpression(io.trino.sql.tree.NotExpression) NullLiteral(io.trino.sql.tree.NullLiteral) Rule(io.trino.sql.planner.iterative.Rule) WhenClause(io.trino.sql.tree.WhenClause) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) FALSE_LITERAL(io.trino.sql.tree.BooleanLiteral.FALSE_LITERAL) TRUE_LITERAL(io.trino.sql.tree.BooleanLiteral.TRUE_LITERAL) List(java.util.List) Pattern(io.trino.matching.Pattern) IfExpression(io.trino.sql.tree.IfExpression) Captures(io.trino.matching.Captures) LogicalExpression(io.trino.sql.tree.LogicalExpression) Metadata(io.trino.metadata.Metadata) Optional(java.util.Optional) Expression(io.trino.sql.tree.Expression) ExpressionUtils.extractConjuncts(io.trino.sql.ExpressionUtils.extractConjuncts) ExpressionUtils.combineConjuncts(io.trino.sql.ExpressionUtils.combineConjuncts) NullIfExpression(io.trino.sql.tree.NullIfExpression) IfExpression(io.trino.sql.tree.IfExpression) ImmutableList(com.google.common.collect.ImmutableList) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) ArrayList(java.util.ArrayList) SimpleCaseExpression(io.trino.sql.tree.SimpleCaseExpression) WhenClause(io.trino.sql.tree.WhenClause) SearchedCaseExpression(io.trino.sql.tree.SearchedCaseExpression) SimpleCaseExpression(io.trino.sql.tree.SimpleCaseExpression) NullIfExpression(io.trino.sql.tree.NullIfExpression) SearchedCaseExpression(io.trino.sql.tree.SearchedCaseExpression) NotExpression(io.trino.sql.tree.NotExpression) IfExpression(io.trino.sql.tree.IfExpression) LogicalExpression(io.trino.sql.tree.LogicalExpression) Expression(io.trino.sql.tree.Expression) NullIfExpression(io.trino.sql.tree.NullIfExpression) NullLiteral(io.trino.sql.tree.NullLiteral)

Example 5 with TRUE_LITERAL

use of io.trino.sql.tree.BooleanLiteral.TRUE_LITERAL in project trino by trinodb.

the class TransformFilteringSemiJoinToInnerJoin method apply.

@Override
public Result apply(FilterNode filterNode, Captures captures, Context context) {
    SemiJoinNode semiJoin = captures.get(SEMI_JOIN);
    // Do not transform semi-join in context of DELETE
    if (PlanNodeSearcher.searchFrom(semiJoin.getSource(), context.getLookup()).where(node -> node instanceof TableScanNode && ((TableScanNode) node).isUpdateTarget()).matches()) {
        return Result.empty();
    }
    Symbol semiJoinSymbol = semiJoin.getSemiJoinOutput();
    Predicate<Expression> isSemiJoinSymbol = expression -> expression.equals(semiJoinSymbol.toSymbolReference());
    List<Expression> conjuncts = extractConjuncts(filterNode.getPredicate());
    if (conjuncts.stream().noneMatch(isSemiJoinSymbol)) {
        return Result.empty();
    }
    Expression filteredPredicate = and(conjuncts.stream().filter(not(isSemiJoinSymbol)).collect(toImmutableList()));
    Expression simplifiedPredicate = inlineSymbols(symbol -> {
        if (symbol.equals(semiJoinSymbol)) {
            return TRUE_LITERAL;
        }
        return symbol.toSymbolReference();
    }, filteredPredicate);
    Optional<Expression> joinFilter = simplifiedPredicate.equals(TRUE_LITERAL) ? Optional.empty() : Optional.of(simplifiedPredicate);
    PlanNode filteringSourceDistinct = new AggregationNode(context.getIdAllocator().getNextId(), semiJoin.getFilteringSource(), ImmutableMap.of(), singleGroupingSet(ImmutableList.of(semiJoin.getFilteringSourceJoinSymbol())), ImmutableList.of(), SINGLE, Optional.empty(), Optional.empty());
    JoinNode innerJoin = new JoinNode(semiJoin.getId(), INNER, semiJoin.getSource(), filteringSourceDistinct, ImmutableList.of(new EquiJoinClause(semiJoin.getSourceJoinSymbol(), semiJoin.getFilteringSourceJoinSymbol())), semiJoin.getSource().getOutputSymbols(), ImmutableList.of(), false, joinFilter, Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), semiJoin.getDynamicFilterId().map(id -> ImmutableMap.of(id, semiJoin.getFilteringSourceJoinSymbol())).orElse(ImmutableMap.of()), Optional.empty());
    ProjectNode project = new ProjectNode(context.getIdAllocator().getNextId(), innerJoin, Assignments.builder().putIdentities(innerJoin.getOutputSymbols()).put(semiJoinSymbol, TRUE_LITERAL).build());
    return Result.ofPlanNode(project);
}
Also used : INNER(io.trino.sql.planner.plan.JoinNode.Type.INNER) Patterns.filter(io.trino.sql.planner.plan.Patterns.filter) SINGLE(io.trino.sql.planner.plan.AggregationNode.Step.SINGLE) SystemSessionProperties.isRewriteFilteringSemiJoinToInnerJoin(io.trino.SystemSessionProperties.isRewriteFilteringSemiJoinToInnerJoin) Capture.newCapture(io.trino.matching.Capture.newCapture) FilterNode(io.trino.sql.planner.plan.FilterNode) PlanNode(io.trino.sql.planner.plan.PlanNode) ExpressionSymbolInliner.inlineSymbols(io.trino.sql.planner.ExpressionSymbolInliner.inlineSymbols) ImmutableList(com.google.common.collect.ImmutableList) PlanNodeSearcher(io.trino.sql.planner.optimizations.PlanNodeSearcher) EquiJoinClause(io.trino.sql.planner.plan.JoinNode.EquiJoinClause) AggregationNode(io.trino.sql.planner.plan.AggregationNode) Rule(io.trino.sql.planner.iterative.Rule) JoinNode(io.trino.sql.planner.plan.JoinNode) ProjectNode(io.trino.sql.planner.plan.ProjectNode) TableScanNode(io.trino.sql.planner.plan.TableScanNode) Symbol(io.trino.sql.planner.Symbol) ImmutableMap(com.google.common.collect.ImmutableMap) Predicate(java.util.function.Predicate) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) Assignments(io.trino.sql.planner.plan.Assignments) Patterns.semiJoin(io.trino.sql.planner.plan.Patterns.semiJoin) SemiJoinNode(io.trino.sql.planner.plan.SemiJoinNode) TRUE_LITERAL(io.trino.sql.tree.BooleanLiteral.TRUE_LITERAL) Capture(io.trino.matching.Capture) AggregationNode.singleGroupingSet(io.trino.sql.planner.plan.AggregationNode.singleGroupingSet) List(java.util.List) Pattern(io.trino.matching.Pattern) ExpressionUtils.and(io.trino.sql.ExpressionUtils.and) Patterns.source(io.trino.sql.planner.plan.Patterns.source) Captures(io.trino.matching.Captures) Optional(java.util.Optional) Expression(io.trino.sql.tree.Expression) ExpressionUtils.extractConjuncts(io.trino.sql.ExpressionUtils.extractConjuncts) Predicate.not(java.util.function.Predicate.not) Session(io.trino.Session) Symbol(io.trino.sql.planner.Symbol) JoinNode(io.trino.sql.planner.plan.JoinNode) SemiJoinNode(io.trino.sql.planner.plan.SemiJoinNode) EquiJoinClause(io.trino.sql.planner.plan.JoinNode.EquiJoinClause) AggregationNode(io.trino.sql.planner.plan.AggregationNode) SemiJoinNode(io.trino.sql.planner.plan.SemiJoinNode) PlanNode(io.trino.sql.planner.plan.PlanNode) TableScanNode(io.trino.sql.planner.plan.TableScanNode) Expression(io.trino.sql.tree.Expression) ProjectNode(io.trino.sql.planner.plan.ProjectNode)

Aggregations

ImmutableList (com.google.common.collect.ImmutableList)13 TRUE_LITERAL (io.trino.sql.tree.BooleanLiteral.TRUE_LITERAL)13 Optional (java.util.Optional)10 Symbol (io.trino.sql.planner.Symbol)9 ImmutableMap (com.google.common.collect.ImmutableMap)8 PlanMatchPattern.values (io.trino.sql.planner.assertions.PlanMatchPattern.values)7 Test (org.testng.annotations.Test)7 ComparisonExpression (io.trino.sql.tree.ComparisonExpression)6 BaseRuleTest (io.trino.sql.planner.iterative.rule.test.BaseRuleTest)5 JoinNode (io.trino.sql.planner.plan.JoinNode)5 Expression (io.trino.sql.tree.Expression)5 List (java.util.List)5 ImmutableList.toImmutableList (com.google.common.collect.ImmutableList.toImmutableList)4 Session (io.trino.Session)4 Captures (io.trino.matching.Captures)4 Pattern (io.trino.matching.Pattern)4 ExpressionUtils.combineConjuncts (io.trino.sql.ExpressionUtils.combineConjuncts)4 ExpressionUtils.extractConjuncts (io.trino.sql.ExpressionUtils.extractConjuncts)4 PlanMatchPattern.filter (io.trino.sql.planner.assertions.PlanMatchPattern.filter)4 PlanMatchPattern.join (io.trino.sql.planner.assertions.PlanMatchPattern.join)4