Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 package com.facebook.presto.sql.planner;
 
 
 import java.util.List;
 import java.util.Map;
 
 import static com.facebook.presto.metadata.FunctionRegistry.getMagicLiteralFunctionSignature;
 import static com.facebook.presto.spi.type.BigintType.BIGINT;
 import static com.facebook.presto.spi.type.DateType.DATE;
 import static com.facebook.presto.spi.type.TimestampType.TIMESTAMP;
 import static com.facebook.presto.sql.ExpressionUtils.and;
 import static com.facebook.presto.sql.ExpressionUtils.combineConjuncts;
 import static com.facebook.presto.sql.ExpressionUtils.combineDisjunctsWithDefault;
 import static com.facebook.presto.sql.ExpressionUtils.or;
 import static com.facebook.presto.sql.planner.LiteralInterpreter.toExpression;
 import static com.facebook.presto.sql.tree.BooleanLiteral.FALSE_LITERAL;
 import static com.facebook.presto.sql.tree.BooleanLiteral.TRUE_LITERAL;
 import static com.facebook.presto.sql.tree.ComparisonExpression.Type.EQUAL;
 import static com.facebook.presto.sql.tree.ComparisonExpression.Type.GREATER_THAN;
 import static com.facebook.presto.sql.tree.ComparisonExpression.Type.GREATER_THAN_OR_EQUAL;
 import static com.facebook.presto.sql.tree.ComparisonExpression.Type.LESS_THAN;
 import static com.facebook.presto.sql.tree.ComparisonExpression.Type.LESS_THAN_OR_EQUAL;
 import static com.facebook.presto.sql.tree.ComparisonExpression.Type.NOT_EQUAL;
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.collect.Iterables.getOnlyElement;
 import static com.google.common.primitives.Primitives.wrap;
 import static java.math.RoundingMode.CEILING;
 import static java.math.RoundingMode.FLOOR;
 
 public final class DomainTranslator
 {
     private static final String DATE_LITERAL = getMagicLiteralFunctionSignature().getName();
 
     private DomainTranslator()
     {
     }
 
     public static Expression toPredicate(TupleDomain<SymboltupleDomainMap<SymbolTypesymbolTypes)
     {
         if (tupleDomain.isNone()) {
             return ;
         }
         ImmutableList.Builder<ExpressionconjunctBuilder = ImmutableList.builder();
         for (Map.Entry<SymbolDomainentry : tupleDomain.getDomains().entrySet()) {
             Symbol symbol = entry.getKey();
             QualifiedNameReference reference = new QualifiedNameReference(symbol.toQualifiedName());
             Type type = symbolTypes.get(symbol);
             conjunctBuilder.add(toPredicate(entry.getValue(), referencetype));
         }
         return combineConjuncts(conjunctBuilder.build());
     }
 
    private static Expression toPredicate(Domain domainQualifiedNameReference referenceType type)
    {
        if (domain.getRanges().isNone()) {
            return domain.isNullAllowed() ? new IsNullPredicate(reference) : ;
        }
        if (domain.getRanges().isAll()) {
            return domain.isNullAllowed() ?  : new NotExpression(new IsNullPredicate(reference));
        }
        // Add disjuncts for ranges
        List<Expressiondisjuncts = new ArrayList<>();
        List<ExpressionsingleValues = new ArrayList<>();
        for (Range range : domain.getRanges()) {
            checkState(!range.isAll()); // Already checked
            if (range.isSingleValue()) {
                singleValues.add(toExpression(range.getLow().getValue(), type));
            }
            else if (isBetween(range)) {
                // Specialize the range with BETWEEN expression if possible b/c it is currently more efficient
                disjuncts.add(new BetweenPredicate(referencetoExpression(range.getLow().getValue(), type), toExpression(range.getHigh().getValue(), type)));
            }
            else {
                List<ExpressionrangeConjuncts = new ArrayList<>();
                if (!range.getLow().isLowerUnbounded()) {
                    switch (range.getLow().getBound()) {
                        case :
                            rangeConjuncts.add(new ComparisonExpression(referencetoExpression(range.getLow().getValue(), type)));
                            break;
                        case :
                            rangeConjuncts.add(new ComparisonExpression(referencetoExpression(range.getLow().getValue(),
                                    type)));
                            break;
                        case :
                            throw new IllegalStateException("Low Marker should never use BELOW bound: " + range);
                        default:
                            throw new AssertionError("Unhandled bound: " + range.getLow().getBound());
                    }
                }
                if (!range.getHigh().isUpperUnbounded()) {
                    switch (range.getHigh().getBound()) {
                        case :
                            throw new IllegalStateException("High Marker should never use ABOVE bound: " + range);
                        case :
                            rangeConjuncts.add(new ComparisonExpression(referencetoExpression(range.getHigh().getValue(), type)));
                            break;
                        case :
                            rangeConjuncts.add(new ComparisonExpression(referencetoExpression(range.getHigh().getValue(), type)));
                            break;
                        default:
                            throw new AssertionError("Unhandled bound: " + range.getHigh().getBound());
                    }
                }
                // If rangeConjuncts is null, then the range was ALL, which should already have been checked for
                checkState(!rangeConjuncts.isEmpty());
                disjuncts.add(combineConjuncts(rangeConjuncts));
            }
        }
        // Add back all of the possible single values either as an equality or an IN predicate
        if (singleValues.size() == 1) {
            disjuncts.add(new ComparisonExpression(referencegetOnlyElement(singleValues)));
        }
        else if (singleValues.size() > 1) {
            disjuncts.add(new InPredicate(referencenew InListExpression(singleValues)));
        }
        // Add nullability disjuncts
        checkState(!disjuncts.isEmpty());
        if (domain.isNullAllowed()) {
            disjuncts.add(new IsNullPredicate(reference));
        }
        return combineDisjunctsWithDefault(disjuncts);
    }
    private static boolean isBetween(Range range)
    {
        return !range.getLow().isLowerUnbounded() && range.getLow().getBound() == ..
                && !range.getHigh().isUpperUnbounded() && range.getHigh().getBound() == ..;
    }

    
Convert an Expression predicate into an ExtractionResult consisting of: 1) A successfully extracted TupleDomain 2) An Expression fragment which represents the part of the original Expression that will need to be re-evaluated after filtering with the TupleDomain.
    public static ExtractionResult fromPredicate(
            Metadata metadata,
            Session session,
            Expression predicate,
            Map<SymbolTypetypes)
    {
        return new Visitor(metadatasessiontypes).process(predicatefalse);
    }
    private static class Visitor
            extends AstVisitor<ExtractionResultBoolean>
    {
        private final Metadata metadata;
        private final ConnectorSession session;
        private final Map<SymbolTypetypes;
        private Visitor(Metadata metadataSession sessionMap<SymbolTypetypes)
        {
            this. = checkNotNull(metadata"metadata is null");
            this. = checkNotNull(session"session is null").toConnectorSession();
            this. = ImmutableMap.copyOf(checkNotNull(types"types is null"));
        }
        private Type checkedTypeLookup(Symbol symbol)
        {
            Type type = .get(symbol);
            checkArgument(type != null"Types is missing info for symbol: %s"symbol);
            return type;
        }
        private static SortedRangeSet complementIfNecessary(SortedRangeSet rangeboolean complement)
        {
            return complement ? range.complement() : range;
        }
        private static Domain complementIfNecessary(Domain domainboolean complement)
        {
            return complement ? domain.complement() : domain;
        }
        private static Expression complementIfNecessary(Expression expressionboolean complement)
        {
            return complement ? new NotExpression(expression) : expression;
        }
        @Override
        protected ExtractionResult visitExpression(Expression nodeBoolean complement)
        {
            // If we don't know how to process this node, the default response is to say that the TupleDomain is "all"
            return new ExtractionResult(TupleDomain.all(), complementIfNecessary(nodecomplement));
        }
        @Override
        protected ExtractionResult visitLogicalBinaryExpression(LogicalBinaryExpression nodeBoolean complement)
        {
            ExtractionResult leftResult = process(node.getLeft(), complement);
            ExtractionResult rightResult = process(node.getRight(), complement);
            LogicalBinaryExpression.Type type = complement ? flipLogicalBinaryType(node.getType()) : node.getType();
            switch (type) {
                case :
                    return new ExtractionResult(
                            leftResult.getTupleDomain().intersect(rightResult.getTupleDomain()),
                            combineConjuncts(leftResult.getRemainingExpression(), rightResult.getRemainingExpression()));
                case :
                    TupleDomain<SymbolcolumnUnionedTupleDomain = TupleDomain.columnWiseUnion(leftResult.getTupleDomain(), rightResult.getTupleDomain());
                    // In most cases, the columnUnionedTupleDomain is only a superset of the actual strict union
                    // and so we can return the current node as the remainingExpression so that all bounds will be double checked again at execution time.
                    Expression remainingExpression = complementIfNecessary(nodecomplement);
                    // However, there are a few cases where the column-wise union is actually equivalent to the strict union, so we if can detect
                    // some of these cases, we won't have to double check the bounds unnecessarily at execution time.
                    // We can only make inferences if the remaining expressions on both side are equal and deterministic
                    if (leftResult.getRemainingExpression().equals(rightResult.getRemainingExpression()) &&
                            DeterminismEvaluator.isDeterministic(leftResult.getRemainingExpression())) {
                        // The column-wise union is equivalent to the strict union if
                        // 1) If both TupleDomains consist of the same exact single column (e.g. left TupleDomain => (a > 0), right TupleDomain => (a < 10))
                        // 2) If one TupleDomain is a superset of the other (e.g. left TupleDomain => (a > 0, b > 0 && b < 10), right TupleDomain => (a > 5, b = 5))
                        boolean matchingSingleSymbolDomains = !leftResult.getTupleDomain().isNone()
                                && !rightResult.getTupleDomain().isNone()
                                && leftResult.getTupleDomain().getDomains().size() == 1
                                && rightResult.getTupleDomain().getDomains().size() == 1
                                && leftResult.getTupleDomain().getDomains().keySet().equals(rightResult.getTupleDomain().getDomains().keySet());
                        boolean oneSideIsSuperSet = leftResult.getTupleDomain().contains(rightResult.getTupleDomain()) || rightResult.getTupleDomain().contains(leftResult.getTupleDomain());
                        if (matchingSingleSymbolDomains || oneSideIsSuperSet) {
                            remainingExpression = leftResult.getRemainingExpression();
                        }
                    }
                    return new ExtractionResult(columnUnionedTupleDomainremainingExpression);
                default:
                    throw new AssertionError("Unknown type: " + node.getType());
            }
        }
        {
            switch (type) {
                case :
                    return ..;
                case :
                    return ..;
                default:
                    throw new AssertionError("Unknown type: " + type);
            }
        }
        @Override
        protected ExtractionResult visitNotExpression(NotExpression nodeBoolean complement)
        {
            return process(node.getValue(), !complement);
        }
        @Override
        protected ExtractionResult visitComparisonExpression(ComparisonExpression nodeBoolean complement)
        {
            if (isSimpleMagicLiteralComparison(node)) {
                node = normalizeSimpleComparison(node);
                node = convertMagicLiteralComparison(node);
            }
            else if (isSimpleComparison(node)) {
                node = normalizeSimpleComparison(node);
            }
            else {
                return super.visitComparisonExpression(nodecomplement);
            }
            Symbol symbol = Symbol.fromQualifiedName(((QualifiedNameReferencenode.getLeft()).getName());
            Type columnType = checkedTypeLookup(symbol);
            Object value = LiteralInterpreter.evaluate(node.getRight());
            // Handle the cases where implicit coercions can happen in comparisons
            // TODO: how to abstract this out
            if (value instanceof Double && columnType.equals()) {
                return process(coerceDoubleToLongComparison(node), complement);
            }
            if (value instanceof Long && columnType.equals(.)) {
                value = ((Longvalue).doubleValue();
            }
            verifyType(columnTypevalue);
            return createComparisonExtractionResult(node.getType(), symbolcolumnTypeobjectToComparable(value), complement);
        }
        private ExtractionResult createComparisonExtractionResult(ComparisonExpression.Type comparisonTypeSymbol columnType columnTypeComparable<?> valueboolean complement)
        {
            if (value == null) {
                switch (comparisonType) {
                    case :
                    case :
                    case :
                    case :
                    case :
                    case :
                        return new ExtractionResult(TupleDomain.none(), );
                    case :
                        Domain domain = complementIfNecessary(Domain.notNull(wrap(columnType.getJavaType())), complement);
                        return new ExtractionResult(
                                TupleDomain.withColumnDomains(ImmutableMap.of(columndomain)),
                                );
                    default:
                        throw new AssertionError("Unhandled type: " + comparisonType);
                }
            }
            Domain domain;
            switch (comparisonType) {
                case :
                    domain = Domain.create(complementIfNecessary(SortedRangeSet.of(Range.equal(value)), complement), false);
                    break;
                case :
                    domain = Domain.create(complementIfNecessary(SortedRangeSet.of(Range.greaterThan(value)), complement), false);
                    break;
                case :
                    domain = Domain.create(complementIfNecessary(SortedRangeSet.of(Range.greaterThanOrEqual(value)), complement), false);
                    break;
                case :
                    domain = Domain.create(complementIfNecessary(SortedRangeSet.of(Range.lessThan(value)), complement), false);
                    break;
                case :
                    domain = Domain.create(complementIfNecessary(SortedRangeSet.of(Range.lessThanOrEqual(value)), complement), false);
                    break;
                case :
                    domain = Domain.create(complementIfNecessary(SortedRangeSet.of(Range.lessThan(value), Range.greaterThan(value)), complement), false);
                    break;
                case :
                    // Need to potential complement the whole domain for IS_DISTINCT_FROM since it is null-aware
                    domain = complementIfNecessary(Domain.create(SortedRangeSet.of(Range.lessThan(value), Range.greaterThan(value)), true), complement);
                    break;
                default:
                    throw new AssertionError("Unhandled type: " + comparisonType);
            }
            return new ExtractionResult(
                    TupleDomain.withColumnDomains(ImmutableMap.of(columndomain)),
                    );
        }
        private static void verifyType(Type typeObject value)
        {
            checkState(value == null || wrap(type.getJavaType()).isInstance(value), "Value %s is not of expected type %s"valuetype);
        }
        private static Comparable<?> objectToComparable(Object value)
        {
            return (Comparable<?>) value;
        }
        @Override
        protected ExtractionResult visitInPredicate(InPredicate nodeBoolean complement)
        {
            if (!(node.getValue() instanceof QualifiedNameReference) || !(node.getValueList() instanceof InListExpression)) {
                return super.visitInPredicate(nodecomplement);
            }
            InListExpression valueList = (InListExpressionnode.getValueList();
            checkState(!valueList.getValues().isEmpty(), "InListExpression should never be empty");
            ImmutableList.Builder<Expressiondisjuncts = ImmutableList.builder();
            for (Expression expression : valueList.getValues()) {
                disjuncts.add(new ComparisonExpression(node.getValue(), expression));
            }
            return process(or(disjuncts.build()), complement);
        }
        @Override
        protected ExtractionResult visitBetweenPredicate(BetweenPredicate nodeBoolean complement)
        {
            // Re-write as two comparison expressions
            return process(and(
                    new ComparisonExpression(node.getValue(), node.getMin()),
                    new ComparisonExpression(node.getValue(), node.getMax())), complement);
        }
        @Override
        protected ExtractionResult visitIsNullPredicate(IsNullPredicate nodeBoolean complement)
        {
            if (!(node.getValue() instanceof QualifiedNameReference)) {
                return super.visitIsNullPredicate(nodecomplement);
            }
            Symbol symbol = Symbol.fromQualifiedName(((QualifiedNameReferencenode.getValue()).getName());
            Type columnType = checkedTypeLookup(symbol);
            Domain domain = complementIfNecessary(Domain.onlyNull(wrap(columnType.getJavaType())), complement);
            return new ExtractionResult(
                    TupleDomain.withColumnDomains(ImmutableMap.of(symboldomain)),
                    );
        }
        @Override
        protected ExtractionResult visitIsNotNullPredicate(IsNotNullPredicate nodeBoolean complement)
        {
            if (!(node.getValue() instanceof QualifiedNameReference)) {
                return super.visitIsNotNullPredicate(nodecomplement);
            }
            Symbol symbol = Symbol.fromQualifiedName(((QualifiedNameReferencenode.getValue()).getName());
            Type columnType = checkedTypeLookup(symbol);
            Domain domain = complementIfNecessary(Domain.notNull(wrap(columnType.getJavaType())), complement);
            return new ExtractionResult(
                    TupleDomain.withColumnDomains(ImmutableMap.of(symboldomain)),
                    );
        }
        @Override
        protected ExtractionResult visitBooleanLiteral(BooleanLiteral nodeBoolean complement)
        {
            boolean value = complement ? !node.getValue() : node.getValue();
            return new ExtractionResult(value ? TupleDomain.all() : TupleDomain.none(), );
        }
        @Override
        protected ExtractionResult visitNullLiteral(NullLiteral nodeBoolean complement)
        {
            return new ExtractionResult(TupleDomain.none(), );
        }
    }
    private static boolean isSimpleComparison(ComparisonExpression comparison)
    {
        return (comparison.getLeft() instanceof QualifiedNameReference && comparison.getRight() instanceof Literal) ||
                (comparison.getLeft() instanceof Literal && comparison.getRight() instanceof QualifiedNameReference);
    }

    
Normalize a simple comparison between a QualifiedNameReference and a Literal such that the QualifiedNameReference will always be on the left and the Literal on the right.
    {
        if (comparison.getLeft() instanceof QualifiedNameReference) {
            return comparison;
        }
        if (comparison.getRight() instanceof QualifiedNameReference) {
            return new ComparisonExpression(flipComparisonDirection(comparison.getType()), comparison.getRight(), comparison.getLeft());
        }
        throw new IllegalArgumentException("ComparisonExpression not a simple literal comparison: " + comparison);
    }
    {
        switch (type) {
            case :
                return ;
            case :
                return ;
            case :
                return ;
            case :
                return ;
            default:
                // The remaining types have no direction association
                return type;
        }
    }
    private static Expression coerceDoubleToLongComparison(ComparisonExpression comparison)
    {
        comparison = normalizeSimpleComparison(comparison);
        checkArgument(comparison.getLeft() instanceof QualifiedNameReference"Left must be a QualifiedNameReference");
        checkArgument(comparison.getRight() instanceof DoubleLiteral"Right must be a DoubleLiteral");
        QualifiedNameReference reference = (QualifiedNameReferencecomparison.getLeft();
        Double value = ((DoubleLiteralcomparison.getRight()).getValue();
        switch (comparison.getType()) {
            case :
            case :
                return new ComparisonExpression(comparison.getType(), referencetoExpression(DoubleMath.roundToLong(value), ));
            case :
            case :
                return new ComparisonExpression(comparison.getType(), referencetoExpression(DoubleMath.roundToLong(value), ));
            case :
                Long equalValue = DoubleMath.roundToLong(value);
                if (equalValue.doubleValue() != value) {
                    // Return something that is false for all non-null values
                    return and(new ComparisonExpression(referencenew LongLiteral("0")),
                            new ComparisonExpression(referencenew LongLiteral("0")));
                }
                return new ComparisonExpression(comparison.getType(), referencetoExpression(equalValue));
            case :
                Long notEqualValue = DoubleMath.roundToLong(value);
                if (notEqualValue.doubleValue() != value) {
                    // Return something that is true for all non-null values
                    return or(new ComparisonExpression(referencenew LongLiteral("0")),
                            new ComparisonExpression(referencenew LongLiteral("0")));
                }
                return new ComparisonExpression(comparison.getType(), referencetoExpression(notEqualValue));
            case :
                Long distinctValue = DoubleMath.roundToLong(value);
                if (distinctValue.doubleValue() != value) {
                    return ;
                }
                return new ComparisonExpression(comparison.getType(), referencetoExpression(distinctValue));
            default:
                throw new AssertionError("Unhandled type: " + comparison.getType());
        }
    }
    public static class ExtractionResult
    {
        private final TupleDomain<SymboltupleDomain;
        private final Expression remainingExpression;
        public ExtractionResult(TupleDomain<SymboltupleDomainExpression remainingExpression)
        {
            this. = checkNotNull(tupleDomain"tupleDomain is null");
            this. = checkNotNull(remainingExpression"remainingExpression is null");
        }
        public TupleDomain<SymbolgetTupleDomain()
        {
            return ;
        }
        public Expression getRemainingExpression()
        {
            return ;
        }
    }
    // TODO: remove this horrible hack
    private static boolean isSimpleMagicLiteralComparison(ComparisonExpression node)
    {
        FunctionCall call;
        if ((node.getLeft() instanceof QualifiedNameReference) && (node.getRight() instanceof FunctionCall)) {
            call = (FunctionCallnode.getRight();
        }
        else if ((node.getLeft() instanceof FunctionCall) && (node.getRight() instanceof QualifiedNameReference)) {
            call = (FunctionCallnode.getLeft();
        }
        else {
            return false;
        }
        if (call.getName().getPrefix().isPresent()) {
            return false;
        }
        String name = call.getName().getSuffix();
        return name.equals() || name.equals();
    }
    {
        // "magic literal" functions use the stack type value for the argument
        checkArgument(isSimpleMagicLiteralComparison(node), "not a simple magic literal comparison");
        FunctionCall call = (FunctionCallnode.getRight();
        Expression value = call.getArguments().get(0);
        return new ComparisonExpression(node.getType(), node.getLeft(), value);
    }
New to GrepCode? Check out our FAQ X