Search in sources :

Example 1 with Quantifier

use of com.apple.foundationdb.record.query.plan.temp.Quantifier in project fdb-record-layer by FoundationDB.

the class RecordQueryPlan method structuralEquals.

/**
 * Determine if two plans are structurally equal. This differs from the semantic equality defined in
 * {@link RelationalExpression}. For instance this method would return false
 * for two given plans {@code UNION(p1, p2)} and {@code UNION(p2, p1)} of two different sub-plans {@code p1} and
 * {@code p2}. In contrast to that these plans are considered semantically equal.
 * @param other object to compare this object with
 * @param equivalenceMap alias map to indicate aliases that should be considered as equal when {@code other} is
 *        compared to {@code this}. For instance {@code q1.x = 1} is only structurally equal with {@code q2.x = 1}
 *        if there is a mapping {@code q1 -> q2} in the alias map passed in
 * @return {@code true} if {@code this} is structurally equal to {@code other}, {@code false} otherwise
 */
@API(API.Status.EXPERIMENTAL)
default boolean structuralEquals(@Nullable final Object other, @Nonnull final AliasMap equivalenceMap) {
    if (this == other) {
        return true;
    }
    if (other == null || getClass() != other.getClass()) {
        return false;
    }
    final RelationalExpression otherExpression = (RelationalExpression) other;
    // We know this and otherExpression are of the same class. canCorrelate() needs to match as well.
    Verify.verify(canCorrelate() == otherExpression.canCorrelate());
    final List<Quantifier.Physical> quantifiers = Quantifiers.narrow(Quantifier.Physical.class, getQuantifiers());
    final List<Quantifier.Physical> otherQuantifiers = Quantifiers.narrow(Quantifier.Physical.class, otherExpression.getQuantifiers());
    if (quantifiers.size() != otherQuantifiers.size()) {
        return false;
    }
    final Iterable<AliasMap> boundCorrelatedReferencesIterable = enumerateUnboundCorrelatedTo(equivalenceMap, otherExpression);
    for (final AliasMap boundCorrelatedReferencesMap : boundCorrelatedReferencesIterable) {
        final AliasMap.Builder boundCorrelatedToBuilder = boundCorrelatedReferencesMap.derived();
        AliasMap boundCorrelatedToMap = AliasMap.emptyMap();
        int i;
        for (i = 0; i < quantifiers.size(); i++) {
            boundCorrelatedToMap = boundCorrelatedToBuilder.build();
            final Quantifier.Physical quantifier = quantifiers.get(i);
            final Quantifier.Physical otherQuantifier = otherQuantifiers.get(i);
            if (quantifier.structuralHashCode() != otherQuantifier.structuralHashCode()) {
                break;
            }
            if (!quantifier.structuralEquals(otherQuantifier)) {
                break;
            }
            if (canCorrelate()) {
                boundCorrelatedToBuilder.put(quantifier.getAlias(), otherQuantifier.getAlias());
            }
        }
        if (i == quantifiers.size() && (equalsWithoutChildren(otherExpression, boundCorrelatedToMap))) {
            return true;
        }
    }
    return false;
}
Also used : RelationalExpression(com.apple.foundationdb.record.query.plan.temp.RelationalExpression) Quantifier(com.apple.foundationdb.record.query.plan.temp.Quantifier) AliasMap(com.apple.foundationdb.record.query.plan.temp.AliasMap) API(com.apple.foundationdb.annotation.API)

Example 2 with Quantifier

use of com.apple.foundationdb.record.query.plan.temp.Quantifier in project fdb-record-layer by FoundationDB.

the class RecordQuerySetPlan method tryPushValues.

@Nonnull
@SuppressWarnings("java:S135")
default Set<CorrelationIdentifier> tryPushValues(@Nonnull final List<TranslateValueFunction> dependentFunctions, @Nonnull final List<? extends Quantifier> quantifiers, @Nonnull final Iterable<? extends Value> values) {
    Verify.verify(!dependentFunctions.isEmpty());
    Verify.verify(dependentFunctions.size() == quantifiers.size());
    final Set<CorrelationIdentifier> candidatesAliases = quantifiers.stream().map(Quantifier::getAlias).collect(Collectors.toSet());
    final CorrelationIdentifier newBaseAlias = CorrelationIdentifier.uniqueID();
    final QuantifiedColumnValue newBaseColumnValue = QuantifiedColumnValue.of(newBaseAlias, 0);
    for (final Value value : values) {
        final AliasMap equivalencesMap = AliasMap.identitiesFor(ImmutableSet.of(newBaseAlias));
        @Nullable Value previousPushedValue = null;
        for (int i = 0; i < dependentFunctions.size(); i++) {
            final TranslateValueFunction dependentFunction = dependentFunctions.get(i);
            final Quantifier quantifier = quantifiers.get(i);
            if (!candidatesAliases.contains(quantifier.getAlias())) {
                continue;
            }
            final Optional<Value> pushedValueOptional = dependentFunction.translateValue(value, newBaseColumnValue);
            if (!pushedValueOptional.isPresent()) {
                candidatesAliases.remove(quantifier.getAlias());
                continue;
            }
            if (previousPushedValue == null) {
                previousPushedValue = pushedValueOptional.get();
            } else {
                if (!previousPushedValue.semanticEquals(pushedValueOptional.get(), equivalencesMap)) {
                    // something is really wrong as we cannot establish a proper genuine derivation path
                    return ImmutableSet.of();
                }
            }
        }
    }
    return ImmutableSet.copyOf(candidatesAliases);
}
Also used : QuantifiedColumnValue(com.apple.foundationdb.record.query.predicates.QuantifiedColumnValue) CorrelationIdentifier(com.apple.foundationdb.record.query.plan.temp.CorrelationIdentifier) Value(com.apple.foundationdb.record.query.predicates.Value) QuantifiedColumnValue(com.apple.foundationdb.record.query.predicates.QuantifiedColumnValue) AliasMap(com.apple.foundationdb.record.query.plan.temp.AliasMap) Quantifier(com.apple.foundationdb.record.query.plan.temp.Quantifier) Nullable(javax.annotation.Nullable) Nonnull(javax.annotation.Nonnull)

Example 3 with Quantifier

use of com.apple.foundationdb.record.query.plan.temp.Quantifier in project fdb-record-layer by FoundationDB.

the class InComparisonToExplodeRule method onMatch.

@Override
public void onMatch(@Nonnull PlannerRuleCall call) {
    final PlannerBindings bindings = call.getBindings();
    final SelectExpression selectExpression = bindings.get(root);
    // we don't need iteration stability
    final List<? extends ValuePredicate> inPredicatesList = bindings.getAll(inPredicateMatcher);
    if (inPredicatesList.isEmpty()) {
        return;
    }
    final Set<QueryPredicate> inPredicates = Sets.newIdentityHashSet();
    inPredicates.addAll(inPredicatesList);
    final ImmutableList.Builder<Quantifier> transformedQuantifiers = ImmutableList.builder();
    final ImmutableList.Builder<QueryPredicate> transformedPredicates = ImmutableList.builder();
    for (final QueryPredicate predicate : selectExpression.getPredicates()) {
        if (inPredicates.contains(predicate)) {
            final ValuePredicate valuePredicate = (ValuePredicate) predicate;
            final Comparisons.Comparison comparison = valuePredicate.getComparison();
            Verify.verify(comparison.getType() == Comparisons.Type.IN);
            final ExplodeExpression explodeExpression;
            if (comparison instanceof Comparisons.ListComparison) {
                explodeExpression = new ExplodeExpression(new LiteralValue<>(comparison.getComparand()));
            } else if (comparison instanceof Comparisons.ParameterComparison) {
                explodeExpression = new ExplodeExpression(QuantifiedColumnValue.of(CorrelationIdentifier.of(((Comparisons.ParameterComparison) comparison).getParameter()), 0));
            } else {
                throw new RecordCoreException("unknown in comparison " + comparison.getClass().getSimpleName());
            }
            final Quantifier.ForEach newQuantifier = Quantifier.forEach(GroupExpressionRef.of(explodeExpression));
            transformedPredicates.add(new ValuePredicate(((ValuePredicate) predicate).getValue(), new Comparisons.ParameterComparison(Comparisons.Type.EQUALS, Bindings.Internal.CORRELATION.bindingName(newQuantifier.getAlias().toString()), Bindings.Internal.CORRELATION)));
            transformedQuantifiers.add(newQuantifier);
        } else {
            transformedPredicates.add(predicate);
        }
    }
    transformedQuantifiers.addAll(bindings.getAll(innerQuantifierMatcher));
    call.yield(call.ref(new SelectExpression(selectExpression.getResultValues(), transformedQuantifiers.build(), transformedPredicates.build())));
}
Also used : QueryPredicate(com.apple.foundationdb.record.query.predicates.QueryPredicate) ImmutableList(com.google.common.collect.ImmutableList) LiteralValue(com.apple.foundationdb.record.query.predicates.LiteralValue) SelectExpression(com.apple.foundationdb.record.query.plan.temp.expressions.SelectExpression) ExplodeExpression(com.apple.foundationdb.record.query.plan.temp.expressions.ExplodeExpression) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) Comparisons(com.apple.foundationdb.record.query.expressions.Comparisons) ValuePredicate(com.apple.foundationdb.record.query.predicates.ValuePredicate) PlannerBindings(com.apple.foundationdb.record.query.plan.temp.matchers.PlannerBindings) Quantifier(com.apple.foundationdb.record.query.plan.temp.Quantifier) QuantifierMatchers.forEachQuantifier(com.apple.foundationdb.record.query.plan.temp.matchers.QuantifierMatchers.forEachQuantifier)

Example 4 with Quantifier

use of com.apple.foundationdb.record.query.plan.temp.Quantifier in project fdb-record-layer by FoundationDB.

the class RelationalExpressionWithChildren method computeMappedQuantifiers.

@Nonnull
default Set<Quantifier> computeMappedQuantifiers(@Nonnull final PartialMatch partialMatch) {
    final var matchInfo = partialMatch.getMatchInfo();
    final var mappedForEachQuantifiers = new LinkedIdentitySet<Quantifier>();
    for (final Quantifier quantifier : getQuantifiers()) {
        if (matchInfo.getChildPartialMatch(quantifier.getAlias()).isPresent()) {
            mappedForEachQuantifiers.add(quantifier);
        }
    }
    return mappedForEachQuantifiers;
}
Also used : Quantifier(com.apple.foundationdb.record.query.plan.temp.Quantifier) LinkedIdentitySet(com.apple.foundationdb.record.query.plan.temp.LinkedIdentitySet) Nonnull(javax.annotation.Nonnull)

Example 5 with Quantifier

use of com.apple.foundationdb.record.query.plan.temp.Quantifier in project fdb-record-layer by FoundationDB.

the class SelectExpression method compensate.

@Override
@SuppressWarnings({ "java:S135", "java:S1066" })
public Compensation compensate(@Nonnull final PartialMatch partialMatch, @Nonnull final Map<CorrelationIdentifier, ComparisonRange> boundParameterPrefixMap) {
    final Map<QueryPredicate, QueryPredicate> toBeReappliedPredicatesMap = Maps.newIdentityHashMap();
    final MatchInfo matchInfo = partialMatch.getMatchInfo();
    final PredicateMap predicateMap = matchInfo.getPredicateMap();
    // 
    // The partial match we are called with here has child matches that have compensations on their own.
    // Given a pair of these matches that we reach along two for each quantifiers (forming a join) we have to
    // apply both compensations. The compensation class has a union method to combine two compensations in an
    // optimal way. We need to fold over all those compensations to form one child compensation. The tree that
    // is formed by partial matches therefore collapses into a chain of compensations.
    // 
    final List<? extends Quantifier> quantifiers = getQuantifiers();
    final Compensation childCompensation = quantifiers.stream().filter(quantifier -> quantifier instanceof Quantifier.ForEach).flatMap(quantifier -> matchInfo.getChildPartialMatch(quantifier).map(childPartialMatch -> childPartialMatch.compensate(boundParameterPrefixMap)).map(Stream::of).orElse(Stream.empty())).reduce(Compensation.noCompensation(), Compensation::union);
    // 
    // The fact that we matched the partial match handed in must mean that the child compensation is not impossible.
    // 
    Verify.verify(!childCompensation.isImpossible());
    // 
    for (final QueryPredicate predicate : getPredicates()) {
        final Optional<PredicateMapping> predicateMappingOptional = predicateMap.getMappingOptional(predicate);
        Verify.verify(predicateMappingOptional.isPresent());
        final PredicateMapping predicateMapping = predicateMappingOptional.get();
        final Optional<QueryPredicate> reappliedPredicateOptional = predicateMapping.reapplyPredicateFunction().reapplyPredicateMaybe(matchInfo, boundParameterPrefixMap);
        reappliedPredicateOptional.ifPresent(reappliedPredicate -> toBeReappliedPredicatesMap.put(predicate, reappliedPredicate));
    }
    return Compensation.ofChildCompensationAndPredicateMap(childCompensation, toBeReappliedPredicatesMap, computeMappedQuantifiers(partialMatch), computeUnmatchedForEachQuantifiers(partialMatch));
}
Also used : ValuePredicate(com.apple.foundationdb.record.query.predicates.ValuePredicate) RelationalExpressionWithPredicates(com.apple.foundationdb.record.query.plan.temp.RelationalExpressionWithPredicates) Quantifier(com.apple.foundationdb.record.query.plan.temp.Quantifier) PredicateWithValue(com.apple.foundationdb.record.query.predicates.PredicateWithValue) ValueComparisonRangePredicate(com.apple.foundationdb.record.query.predicates.ValueComparisonRangePredicate) Function(java.util.function.Function) PredicateMap(com.apple.foundationdb.record.query.plan.temp.PredicateMap) Multimaps(com.google.common.collect.Multimaps) PartialMatch(com.apple.foundationdb.record.query.plan.temp.PartialMatch) HashMultimap(com.google.common.collect.HashMultimap) ImmutableList(com.google.common.collect.ImmutableList) ComparisonRange(com.apple.foundationdb.record.query.plan.temp.ComparisonRange) IterableHelpers(com.apple.foundationdb.record.query.plan.temp.IterableHelpers) Map(java.util.Map) Compensation(com.apple.foundationdb.record.query.plan.temp.Compensation) IdentityBiMap(com.apple.foundationdb.record.query.plan.temp.IdentityBiMap) Placeholder(com.apple.foundationdb.record.query.predicates.ValueComparisonRangePredicate.Placeholder) AliasMap(com.apple.foundationdb.record.query.plan.temp.AliasMap) Nonnull(javax.annotation.Nonnull) PredicateMapping(com.apple.foundationdb.record.query.plan.temp.PredicateMultiMap.PredicateMapping) Verify(com.google.common.base.Verify) ImmutableSet(com.google.common.collect.ImmutableSet) Equivalence(com.google.common.base.Equivalence) ImmutableMap(com.google.common.collect.ImmutableMap) Collection(java.util.Collection) Set(java.util.Set) InternalPlannerGraphRewritable(com.apple.foundationdb.record.query.plan.temp.explain.InternalPlannerGraphRewritable) QueryPredicate(com.apple.foundationdb.record.query.predicates.QueryPredicate) EnumeratingIterable(com.apple.foundationdb.record.query.combinatorics.EnumeratingIterable) Streams(com.google.common.collect.Streams) AndPredicate(com.apple.foundationdb.record.query.predicates.AndPredicate) Maps(com.google.common.collect.Maps) Collectors(java.util.stream.Collectors) Sets(com.google.common.collect.Sets) RelationalExpression(com.apple.foundationdb.record.query.plan.temp.RelationalExpression) Objects(java.util.Objects) Value(com.apple.foundationdb.record.query.predicates.Value) Comparisons(com.apple.foundationdb.record.query.expressions.Comparisons) List(java.util.List) Stream(java.util.stream.Stream) Sargable(com.apple.foundationdb.record.query.predicates.ValueComparisonRangePredicate.Sargable) CorrelationIdentifier(com.apple.foundationdb.record.query.plan.temp.CorrelationIdentifier) CrossProduct(com.apple.foundationdb.record.query.combinatorics.CrossProduct) MatchInfo(com.apple.foundationdb.record.query.plan.temp.MatchInfo) Optional(java.util.Optional) API(com.apple.foundationdb.annotation.API) PlannerGraph(com.apple.foundationdb.record.query.plan.temp.explain.PlannerGraph) QueryPredicate(com.apple.foundationdb.record.query.predicates.QueryPredicate) MatchInfo(com.apple.foundationdb.record.query.plan.temp.MatchInfo) Compensation(com.apple.foundationdb.record.query.plan.temp.Compensation) PredicateMap(com.apple.foundationdb.record.query.plan.temp.PredicateMap) Quantifier(com.apple.foundationdb.record.query.plan.temp.Quantifier) PredicateMapping(com.apple.foundationdb.record.query.plan.temp.PredicateMultiMap.PredicateMapping)

Aggregations

Quantifier (com.apple.foundationdb.record.query.plan.temp.Quantifier)23 Nonnull (javax.annotation.Nonnull)13 API (com.apple.foundationdb.annotation.API)10 ImmutableList (com.google.common.collect.ImmutableList)10 List (java.util.List)9 RelationalExpression (com.apple.foundationdb.record.query.plan.temp.RelationalExpression)8 CorrelationIdentifier (com.apple.foundationdb.record.query.plan.temp.CorrelationIdentifier)7 AliasMap (com.apple.foundationdb.record.query.plan.temp.AliasMap)6 BindingMatcher (com.apple.foundationdb.record.query.plan.temp.matchers.BindingMatcher)6 QueryPredicate (com.apple.foundationdb.record.query.predicates.QueryPredicate)6 Value (com.apple.foundationdb.record.query.predicates.Value)6 GroupExpressionRef (com.apple.foundationdb.record.query.plan.temp.GroupExpressionRef)5 PlannerRule (com.apple.foundationdb.record.query.plan.temp.PlannerRule)5 PlannerRuleCall (com.apple.foundationdb.record.query.plan.temp.PlannerRuleCall)5 ImmutableSet (com.google.common.collect.ImmutableSet)5 Collection (java.util.Collection)5 Set (java.util.Set)5 RecordQueryPlan (com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan)4 MatchInfo (com.apple.foundationdb.record.query.plan.temp.MatchInfo)4 PartialMatch (com.apple.foundationdb.record.query.plan.temp.PartialMatch)4