Search in sources :

Example 1 with BASIC_COLUMN_EXTRACTOR

use of com.facebook.presto.spi.relation.DomainTranslator.BASIC_COLUMN_EXTRACTOR in project presto by prestodb.

the class PickTableLayout method pushPredicateIntoTableScan.

/**
 * For RowExpression {@param predicate}
 */
private static PlanNode pushPredicateIntoTableScan(TableScanNode node, RowExpression predicate, boolean pruneWithPredicateExpression, Session session, PlanNodeIdAllocator idAllocator, Metadata metadata, DomainTranslator domainTranslator) {
    // don't include non-deterministic predicates
    LogicalRowExpressions logicalRowExpressions = new LogicalRowExpressions(new RowExpressionDeterminismEvaluator(metadata.getFunctionAndTypeManager()), new FunctionResolution(metadata.getFunctionAndTypeManager()), metadata.getFunctionAndTypeManager());
    RowExpression deterministicPredicate = logicalRowExpressions.filterDeterministicConjuncts(predicate);
    DomainTranslator.ExtractionResult<VariableReferenceExpression> decomposedPredicate = domainTranslator.fromPredicate(session.toConnectorSession(), deterministicPredicate, BASIC_COLUMN_EXTRACTOR);
    TupleDomain<ColumnHandle> newDomain = decomposedPredicate.getTupleDomain().transform(variableName -> node.getAssignments().get(variableName)).intersect(node.getEnforcedConstraint());
    Map<ColumnHandle, VariableReferenceExpression> assignments = ImmutableBiMap.copyOf(node.getAssignments()).inverse();
    Constraint<ColumnHandle> constraint;
    if (pruneWithPredicateExpression) {
        LayoutConstraintEvaluatorForRowExpression evaluator = new LayoutConstraintEvaluatorForRowExpression(metadata, session, node.getAssignments(), logicalRowExpressions.combineConjuncts(deterministicPredicate, // which would be expensive to evaluate in the call to isCandidate below.
        domainTranslator.toPredicate(newDomain.simplify().transform(column -> assignments.getOrDefault(column, null)))));
        constraint = new Constraint<>(newDomain, evaluator::isCandidate);
    } else {
        // Currently, invoking the expression interpreter is very expensive.
        // TODO invoke the interpreter unconditionally when the interpreter becomes cheap enough.
        constraint = new Constraint<>(newDomain);
    }
    if (constraint.getSummary().isNone()) {
        return new ValuesNode(node.getSourceLocation(), idAllocator.getNextId(), node.getOutputVariables(), ImmutableList.of());
    }
    // Layouts will be returned in order of the connector's preference
    TableLayoutResult layout = metadata.getLayout(session, node.getTable(), constraint, Optional.of(node.getOutputVariables().stream().map(variable -> node.getAssignments().get(variable)).collect(toImmutableSet())));
    if (layout.getLayout().getPredicate().isNone()) {
        return new ValuesNode(node.getSourceLocation(), idAllocator.getNextId(), node.getOutputVariables(), ImmutableList.of());
    }
    TableScanNode tableScan = new TableScanNode(node.getSourceLocation(), node.getId(), layout.getLayout().getNewTableHandle(), node.getOutputVariables(), node.getAssignments(), layout.getLayout().getPredicate(), computeEnforced(newDomain, layout.getUnenforcedConstraint()));
    // The order of the arguments to combineConjuncts matters:
    // * Unenforced constraints go first because they can only be simple column references,
    // which are not prone to logic errors such as out-of-bound access, div-by-zero, etc.
    // * Conjuncts in non-deterministic expressions and non-TupleDomain-expressible expressions should
    // retain their original (maybe intermixed) order from the input predicate. However, this is not implemented yet.
    // * Short of implementing the previous bullet point, the current order of non-deterministic expressions
    // and non-TupleDomain-expressible expressions should be retained. Changing the order can lead
    // to failures of previously successful queries.
    RowExpression resultingPredicate = logicalRowExpressions.combineConjuncts(domainTranslator.toPredicate(layout.getUnenforcedConstraint().transform(assignments::get)), logicalRowExpressions.filterNonDeterministicConjuncts(predicate), decomposedPredicate.getRemainingExpression());
    if (!TRUE_CONSTANT.equals(resultingPredicate)) {
        return new FilterNode(node.getSourceLocation(), idAllocator.getNextId(), tableScan, resultingPredicate);
    }
    return tableScan;
}
Also used : RowExpressionDomainTranslator(com.facebook.presto.sql.relational.RowExpressionDomainTranslator) VariableReferenceExpression(com.facebook.presto.spi.relation.VariableReferenceExpression) Pattern(com.facebook.presto.matching.Pattern) TryFunction(com.facebook.presto.operator.scalar.TryFunction) ValuesNode(com.facebook.presto.spi.plan.ValuesNode) Preconditions.checkArgument(com.google.common.base.Preconditions.checkArgument) Capture(com.facebook.presto.matching.Capture) Map(java.util.Map) RowExpressionInterpreter(com.facebook.presto.sql.planner.RowExpressionInterpreter) ImmutableSet(com.google.common.collect.ImmutableSet) NullableValue(com.facebook.presto.common.predicate.NullableValue) ImmutableMap(com.google.common.collect.ImmutableMap) TableLayoutResult.computeEnforced(com.facebook.presto.metadata.TableLayoutResult.computeEnforced) DomainTranslator(com.facebook.presto.spi.relation.DomainTranslator) Set(java.util.Set) TRUE_CONSTANT(com.facebook.presto.expressions.LogicalRowExpressions.TRUE_CONSTANT) Objects(java.util.Objects) Capture.newCapture(com.facebook.presto.matching.Capture.newCapture) Optional(java.util.Optional) TableLayoutResult(com.facebook.presto.metadata.TableLayoutResult) Captures(com.facebook.presto.matching.Captures) RowExpressionDeterminismEvaluator(com.facebook.presto.sql.relational.RowExpressionDeterminismEvaluator) ConstantExpression(com.facebook.presto.spi.relation.ConstantExpression) Function(java.util.function.Function) Patterns.filter(com.facebook.presto.sql.planner.plan.Patterns.filter) ImmutableBiMap(com.google.common.collect.ImmutableBiMap) FilterNode(com.facebook.presto.spi.plan.FilterNode) SystemSessionProperties.isNewOptimizerEnabled(com.facebook.presto.SystemSessionProperties.isNewOptimizerEnabled) ImmutableList(com.google.common.collect.ImmutableList) LogicalRowExpressions(com.facebook.presto.expressions.LogicalRowExpressions) BASIC_COLUMN_EXTRACTOR(com.facebook.presto.spi.relation.DomainTranslator.BASIC_COLUMN_EXTRACTOR) Objects.requireNonNull(java.util.Objects.requireNonNull) ImmutableSet.toImmutableSet(com.google.common.collect.ImmutableSet.toImmutableSet) TableHandle(com.facebook.presto.spi.TableHandle) FunctionResolution(com.facebook.presto.sql.relational.FunctionResolution) VariablesExtractor(com.facebook.presto.sql.planner.VariablesExtractor) RowExpression(com.facebook.presto.spi.relation.RowExpression) VariableResolver(com.facebook.presto.sql.planner.VariableResolver) PlanNodeIdAllocator(com.facebook.presto.spi.plan.PlanNodeIdAllocator) Session(com.facebook.presto.Session) Rule(com.facebook.presto.sql.planner.iterative.Rule) Constraint(com.facebook.presto.spi.Constraint) TupleDomain(com.facebook.presto.common.predicate.TupleDomain) PreconditionRules.checkRulesAreFiredBeforeAddExchangesRule(com.facebook.presto.sql.planner.iterative.rule.PreconditionRules.checkRulesAreFiredBeforeAddExchangesRule) OPTIMIZED(com.facebook.presto.spi.relation.ExpressionOptimizer.Level.OPTIMIZED) Patterns.source(com.facebook.presto.sql.planner.plan.Patterns.source) PlanNode(com.facebook.presto.spi.plan.PlanNode) ColumnHandle(com.facebook.presto.spi.ColumnHandle) TableScanNode(com.facebook.presto.spi.plan.TableScanNode) Sets.intersection(com.google.common.collect.Sets.intersection) Patterns.tableScan(com.facebook.presto.sql.planner.plan.Patterns.tableScan) Metadata(com.facebook.presto.metadata.Metadata) RowExpressionDeterminismEvaluator(com.facebook.presto.sql.relational.RowExpressionDeterminismEvaluator) ColumnHandle(com.facebook.presto.spi.ColumnHandle) ValuesNode(com.facebook.presto.spi.plan.ValuesNode) LogicalRowExpressions(com.facebook.presto.expressions.LogicalRowExpressions) FilterNode(com.facebook.presto.spi.plan.FilterNode) RowExpression(com.facebook.presto.spi.relation.RowExpression) TableLayoutResult(com.facebook.presto.metadata.TableLayoutResult) FunctionResolution(com.facebook.presto.sql.relational.FunctionResolution) TableScanNode(com.facebook.presto.spi.plan.TableScanNode) VariableReferenceExpression(com.facebook.presto.spi.relation.VariableReferenceExpression) RowExpressionDomainTranslator(com.facebook.presto.sql.relational.RowExpressionDomainTranslator) DomainTranslator(com.facebook.presto.spi.relation.DomainTranslator)

Example 2 with BASIC_COLUMN_EXTRACTOR

use of com.facebook.presto.spi.relation.DomainTranslator.BASIC_COLUMN_EXTRACTOR in project presto by prestodb.

the class MaterializedViewQueryOptimizer method visitQuerySpecification.

@Override
protected Node visitQuerySpecification(QuerySpecification node, Void context) {
    if (!node.getFrom().isPresent()) {
        throw new IllegalStateException("Query with no From clause is not rewritable by materialized view");
    }
    Relation relation = node.getFrom().get();
    if (relation instanceof AliasedRelation) {
        removablePrefix = Optional.of(((AliasedRelation) relation).getAlias());
        relation = ((AliasedRelation) relation).getRelation();
    }
    if (!(relation instanceof Table)) {
        throw new SemanticException(NOT_SUPPORTED, node, "Relation other than Table is not supported in query optimizer");
    }
    Table baseTable = (Table) relation;
    if (!removablePrefix.isPresent()) {
        removablePrefix = Optional.of(new Identifier(baseTable.getName().toString()));
    }
    if (node.getGroupBy().isPresent()) {
        ImmutableSet.Builder<Expression> expressionsInGroupByBuilder = ImmutableSet.builder();
        for (GroupingElement element : node.getGroupBy().get().getGroupingElements()) {
            element = removeGroupingElementPrefix(element, removablePrefix);
            Optional<Set<Expression>> groupByOfMaterializedView = materializedViewInfo.getGroupBy();
            if (groupByOfMaterializedView.isPresent()) {
                for (Expression expression : element.getExpressions()) {
                    if (!groupByOfMaterializedView.get().contains(expression) || !materializedViewInfo.getBaseToViewColumnMap().containsKey(expression)) {
                        throw new IllegalStateException(format("Grouping element %s is not present in materialized view groupBy field", element));
                    }
                }
            }
            expressionsInGroupByBuilder.addAll(element.getExpressions());
        }
        expressionsInGroupBy = Optional.of(expressionsInGroupByBuilder.build());
    }
    // TODO: Add HAVING validation to the validator https://github.com/prestodb/presto/issues/16406
    if (node.getHaving().isPresent()) {
        throw new SemanticException(NOT_SUPPORTED, node, "Having clause is not supported in query optimizer");
    }
    if (materializedViewInfo.getWhereClause().isPresent()) {
        if (!node.getWhere().isPresent()) {
            throw new IllegalStateException("Query with no where clause is not rewritable by materialized view with where clause");
        }
        QualifiedObjectName baseTableName = createQualifiedObjectName(session, baseTable, baseTable.getName());
        Optional<TableHandle> tableHandle = metadata.getTableHandle(session, baseTableName);
        if (!tableHandle.isPresent()) {
            throw new SemanticException(MISSING_TABLE, node, "Table does not exist");
        }
        ImmutableList.Builder<Field> fields = ImmutableList.builder();
        for (ColumnHandle columnHandle : metadata.getColumnHandles(session, tableHandle.get()).values()) {
            ColumnMetadata columnMetadata = metadata.getColumnMetadata(session, tableHandle.get(), columnHandle);
            fields.add(Field.newUnqualified(materializedViewInfo.getWhereClause().get().getLocation(), columnMetadata.getName(), columnMetadata.getType()));
        }
        Scope scope = Scope.builder().withRelationType(RelationId.anonymous(), new RelationType(fields.build())).build();
        // Given base query's filter condition and materialized view's filter condition, the goal is to check if MV's filters contain Base's filters (Base implies MV).
        // Let base query's filter condition be A, and MV's filter condition be B.
        // One way to evaluate A implies B is to evaluate logical expression A^~B and check if the output domain is none.
        // If the resulting domain is none, then A^~B is false. Thus A implies B.
        // For more information and examples: https://fb.quip.com/WwmxA40jLMxR
        // TODO: Implement method that utilizes external SAT solver libraries. https://github.com/prestodb/presto/issues/16536
        RowExpression materializedViewWhereCondition = convertToRowExpression(materializedViewInfo.getWhereClause().get(), scope);
        RowExpression baseQueryWhereCondition = convertToRowExpression(node.getWhere().get(), scope);
        RowExpression rewriteLogicExpression = and(baseQueryWhereCondition, call(baseQueryWhereCondition.getSourceLocation(), "not", new FunctionResolution(metadata.getFunctionAndTypeManager()).notFunction(), materializedViewWhereCondition.getType(), materializedViewWhereCondition));
        RowExpression disjunctiveNormalForm = logicalRowExpressions.convertToDisjunctiveNormalForm(rewriteLogicExpression);
        ExtractionResult<VariableReferenceExpression> result = domainTranslator.fromPredicate(session.toConnectorSession(), disjunctiveNormalForm, BASIC_COLUMN_EXTRACTOR);
        if (!result.getTupleDomain().equals(TupleDomain.none())) {
            throw new IllegalStateException("View filter condition does not contain base query's filter condition");
        }
    }
    return new QuerySpecification((Select) process(node.getSelect(), context), node.getFrom().map(from -> (Relation) process(from, context)), node.getWhere().map(where -> (Expression) process(where, context)), node.getGroupBy().map(groupBy -> (GroupBy) process(groupBy, context)), node.getHaving().map(having -> (Expression) process(having, context)), node.getOrderBy().map(orderBy -> (OrderBy) process(orderBy, context)), node.getOffset(), node.getLimit());
}
Also used : FunctionAndTypeManager(com.facebook.presto.metadata.FunctionAndTypeManager) WarningCollector(com.facebook.presto.spi.WarningCollector) RowExpressionDomainTranslator(com.facebook.presto.sql.relational.RowExpressionDomainTranslator) AliasedRelation(com.facebook.presto.sql.tree.AliasedRelation) SqlToRowExpressionTranslator(com.facebook.presto.sql.relational.SqlToRowExpressionTranslator) VariableReferenceExpression(com.facebook.presto.spi.relation.VariableReferenceExpression) ExpressionUtils.removeExpressionPrefix(com.facebook.presto.sql.ExpressionUtils.removeExpressionPrefix) SelectItem(com.facebook.presto.sql.tree.SelectItem) QualifiedObjectName(com.facebook.presto.common.QualifiedObjectName) ExpressionUtils.removeGroupingElementPrefix(com.facebook.presto.sql.ExpressionUtils.removeGroupingElementPrefix) FunctionCall(com.facebook.presto.sql.tree.FunctionCall) ImmutableSet(com.google.common.collect.ImmutableSet) Query(com.facebook.presto.sql.tree.Query) QueryBody(com.facebook.presto.sql.tree.QueryBody) QuerySpecification(com.facebook.presto.sql.tree.QuerySpecification) ImmutableMap(com.google.common.collect.ImmutableMap) Node(com.facebook.presto.sql.tree.Node) Set(java.util.Set) NOT_SUPPORTED(com.facebook.presto.sql.analyzer.SemanticErrorCode.NOT_SUPPORTED) GroupingElement(com.facebook.presto.sql.tree.GroupingElement) SortItem(com.facebook.presto.sql.tree.SortItem) String.format(java.lang.String.format) SqlParser(com.facebook.presto.sql.parser.SqlParser) LogicalBinaryExpression(com.facebook.presto.sql.tree.LogicalBinaryExpression) ColumnMetadata(com.facebook.presto.spi.ColumnMetadata) Optional(java.util.Optional) ExpressionUtils.removeSortItemPrefix(com.facebook.presto.sql.ExpressionUtils.removeSortItemPrefix) Select(com.facebook.presto.sql.tree.Select) ExtractionResult(com.facebook.presto.spi.relation.DomainTranslator.ExtractionResult) QualifiedName(com.facebook.presto.sql.tree.QualifiedName) ExpressionUtils.removeSingleColumnPrefix(com.facebook.presto.sql.ExpressionUtils.removeSingleColumnPrefix) Logger(com.facebook.airlift.log.Logger) Table(com.facebook.presto.sql.tree.Table) RowExpressionDeterminismEvaluator(com.facebook.presto.sql.relational.RowExpressionDeterminismEvaluator) Expressions.call(com.facebook.presto.sql.relational.Expressions.call) SingleColumn(com.facebook.presto.sql.tree.SingleColumn) Identifier(com.facebook.presto.sql.tree.Identifier) ImmutableList(com.google.common.collect.ImmutableList) LogicalRowExpressions(com.facebook.presto.expressions.LogicalRowExpressions) BASIC_COLUMN_EXTRACTOR(com.facebook.presto.spi.relation.DomainTranslator.BASIC_COLUMN_EXTRACTOR) Objects.requireNonNull(java.util.Objects.requireNonNull) TableHandle(com.facebook.presto.spi.TableHandle) FunctionResolution(com.facebook.presto.sql.relational.FunctionResolution) AllColumns(com.facebook.presto.sql.tree.AllColumns) SimpleGroupBy(com.facebook.presto.sql.tree.SimpleGroupBy) MaterializedViewInfo(com.facebook.presto.sql.analyzer.MaterializedViewInformationExtractor.MaterializedViewInfo) RowExpression(com.facebook.presto.spi.relation.RowExpression) GroupBy(com.facebook.presto.sql.tree.GroupBy) OrderBy(com.facebook.presto.sql.tree.OrderBy) Relation(com.facebook.presto.sql.tree.Relation) MISSING_TABLE(com.facebook.presto.sql.analyzer.SemanticErrorCode.MISSING_TABLE) Session(com.facebook.presto.Session) LogicalRowExpressions.and(com.facebook.presto.expressions.LogicalRowExpressions.and) AstVisitor(com.facebook.presto.sql.tree.AstVisitor) ComparisonExpression(com.facebook.presto.sql.tree.ComparisonExpression) TupleDomain(com.facebook.presto.common.predicate.TupleDomain) Expression(com.facebook.presto.sql.tree.Expression) ColumnHandle(com.facebook.presto.spi.ColumnHandle) MetadataUtil.createQualifiedObjectName(com.facebook.presto.metadata.MetadataUtil.createQualifiedObjectName) ArithmeticBinaryExpression(com.facebook.presto.sql.tree.ArithmeticBinaryExpression) Metadata(com.facebook.presto.metadata.Metadata) AccessControl(com.facebook.presto.security.AccessControl) ColumnMetadata(com.facebook.presto.spi.ColumnMetadata) ImmutableSet(com.google.common.collect.ImmutableSet) Set(java.util.Set) ImmutableList(com.google.common.collect.ImmutableList) FunctionResolution(com.facebook.presto.sql.relational.FunctionResolution) QuerySpecification(com.facebook.presto.sql.tree.QuerySpecification) AliasedRelation(com.facebook.presto.sql.tree.AliasedRelation) Relation(com.facebook.presto.sql.tree.Relation) Identifier(com.facebook.presto.sql.tree.Identifier) ImmutableSet(com.google.common.collect.ImmutableSet) OrderBy(com.facebook.presto.sql.tree.OrderBy) ColumnHandle(com.facebook.presto.spi.ColumnHandle) Table(com.facebook.presto.sql.tree.Table) SimpleGroupBy(com.facebook.presto.sql.tree.SimpleGroupBy) GroupBy(com.facebook.presto.sql.tree.GroupBy) RowExpression(com.facebook.presto.spi.relation.RowExpression) QualifiedObjectName(com.facebook.presto.common.QualifiedObjectName) MetadataUtil.createQualifiedObjectName(com.facebook.presto.metadata.MetadataUtil.createQualifiedObjectName) GroupingElement(com.facebook.presto.sql.tree.GroupingElement) VariableReferenceExpression(com.facebook.presto.spi.relation.VariableReferenceExpression) LogicalBinaryExpression(com.facebook.presto.sql.tree.LogicalBinaryExpression) RowExpression(com.facebook.presto.spi.relation.RowExpression) ComparisonExpression(com.facebook.presto.sql.tree.ComparisonExpression) Expression(com.facebook.presto.sql.tree.Expression) ArithmeticBinaryExpression(com.facebook.presto.sql.tree.ArithmeticBinaryExpression) VariableReferenceExpression(com.facebook.presto.spi.relation.VariableReferenceExpression) TableHandle(com.facebook.presto.spi.TableHandle) AliasedRelation(com.facebook.presto.sql.tree.AliasedRelation)

Aggregations

Session (com.facebook.presto.Session)2 TupleDomain (com.facebook.presto.common.predicate.TupleDomain)2 LogicalRowExpressions (com.facebook.presto.expressions.LogicalRowExpressions)2 Metadata (com.facebook.presto.metadata.Metadata)2 ColumnHandle (com.facebook.presto.spi.ColumnHandle)2 TableHandle (com.facebook.presto.spi.TableHandle)2 BASIC_COLUMN_EXTRACTOR (com.facebook.presto.spi.relation.DomainTranslator.BASIC_COLUMN_EXTRACTOR)2 RowExpression (com.facebook.presto.spi.relation.RowExpression)2 VariableReferenceExpression (com.facebook.presto.spi.relation.VariableReferenceExpression)2 FunctionResolution (com.facebook.presto.sql.relational.FunctionResolution)2 RowExpressionDeterminismEvaluator (com.facebook.presto.sql.relational.RowExpressionDeterminismEvaluator)2 RowExpressionDomainTranslator (com.facebook.presto.sql.relational.RowExpressionDomainTranslator)2 ImmutableList (com.google.common.collect.ImmutableList)2 ImmutableMap (com.google.common.collect.ImmutableMap)2 ImmutableSet (com.google.common.collect.ImmutableSet)2 Objects.requireNonNull (java.util.Objects.requireNonNull)2 Optional (java.util.Optional)2 Set (java.util.Set)2 Logger (com.facebook.airlift.log.Logger)1 SystemSessionProperties.isNewOptimizerEnabled (com.facebook.presto.SystemSessionProperties.isNewOptimizerEnabled)1