use of com.apple.foundationdb.record.query.plan.temp.CorrelationIdentifier in project fdb-record-layer by FoundationDB.
the class RelationalExpressionWithChildren method getCorrelatedTo.
@Nonnull
@Override
@SuppressWarnings("squid:S2201")
default Set<CorrelationIdentifier> getCorrelatedTo() {
final ImmutableSet.Builder<CorrelationIdentifier> builder = ImmutableSet.builder();
final List<? extends Quantifier> quantifiers = getQuantifiers();
final Map<CorrelationIdentifier, ? extends Quantifier> aliasToQuantifierMap = quantifiers.stream().collect(Collectors.toMap(Quantifier::getAlias, Function.identity()));
// We should check if the graph is sound here, if it is not we should throw an exception. This method
// will properly return with an empty. There are other algorithms that may not be as defensive and we
// must protect ourselves from illegal graphs (and bugs).
final Optional<List<CorrelationIdentifier>> orderedOptional = TopologicalSort.anyTopologicalOrderPermutation(quantifiers.stream().map(Quantifier::getAlias).collect(Collectors.toSet()), alias -> Objects.requireNonNull(aliasToQuantifierMap.get(alias)).getCorrelatedTo());
orderedOptional.orElseThrow(() -> new IllegalArgumentException("correlations are cyclic"));
getCorrelatedToWithoutChildren().stream().filter(correlationIdentifier -> !aliasToQuantifierMap.containsKey(correlationIdentifier)).forEach(builder::add);
for (final Quantifier quantifier : quantifiers) {
quantifier.getCorrelatedTo().stream().filter(correlationIdentifier -> !canCorrelate() || !aliasToQuantifierMap.containsKey(correlationIdentifier)).forEach(builder::add);
}
return builder.build();
}
use of com.apple.foundationdb.record.query.plan.temp.CorrelationIdentifier in project fdb-record-layer by FoundationDB.
the class MergeProjectionAndFetchRule method onMatch.
@Override
public void onMatch(@Nonnull PlannerRuleCall call) {
final LogicalProjectionExpression projectionExpression = call.get(root);
// if the fetch is able to push all values we can eliminate the fetch as well
final RecordQueryFetchFromPartialRecordPlan fetchPlan = call.get(innerPlanMatcher);
final CorrelationIdentifier newInnerAlias = CorrelationIdentifier.uniqueID();
final List<? extends Value> resultValues = projectionExpression.getResultValues();
final boolean allPushable = resultValues.stream().allMatch(value -> fetchPlan.pushValue(value, newInnerAlias).isPresent());
if (allPushable) {
// all fields in the projection are already available underneath the fetch
// we don't need the projection nor the fetch
call.yield(call.ref(fetchPlan.getChild()));
}
}
use of com.apple.foundationdb.record.query.plan.temp.CorrelationIdentifier in project fdb-record-layer by FoundationDB.
the class PushDistinctThroughFetchRule method onMatch.
@Override
public void onMatch(@Nonnull PlannerRuleCall call) {
final PlannerBindings bindings = call.getBindings();
final RecordQueryFetchFromPartialRecordPlan fetchPlan = bindings.get(fetchPlanMatcher);
final RecordQueryPlan innerPlan = bindings.get(innerPlanMatcher);
final CorrelationIdentifier newInnerAlias = CorrelationIdentifier.uniqueID();
final Quantifier.Physical newInnerQuantifier = Quantifier.physical(GroupExpressionRef.of(innerPlan), newInnerAlias);
final RecordQueryUnorderedPrimaryKeyDistinctPlan pushedDistinctPlan = new RecordQueryUnorderedPrimaryKeyDistinctPlan(newInnerQuantifier);
final RecordQueryFetchFromPartialRecordPlan newFetchPlan = new RecordQueryFetchFromPartialRecordPlan(pushedDistinctPlan, fetchPlan.getPushValueFunction());
// case 2
call.yield(call.ref(newFetchPlan));
}
use of com.apple.foundationdb.record.query.plan.temp.CorrelationIdentifier in project fdb-record-layer by FoundationDB.
the class PushFilterThroughFetchRule method onMatch.
@Override
public void onMatch(@Nonnull PlannerRuleCall call) {
final PlannerBindings bindings = call.getBindings();
final RecordQueryPredicatesFilterPlan filterPlan = bindings.get(root);
final RecordQueryFetchFromPartialRecordPlan fetchPlan = bindings.get(fetchPlanMatcher);
final Quantifier.Physical quantifierOverFetch = bindings.get(quantifierOverFetchMatcher);
final RecordQueryPlan innerPlan = bindings.get(innerPlanMatcher);
final List<? extends QueryPredicate> queryPredicates = filterPlan.getPredicates();
final ImmutableList.Builder<QueryPredicate> pushedPredicatesBuilder = ImmutableList.builder();
final ImmutableList.Builder<QueryPredicate> residualPredicatesBuilder = ImmutableList.builder();
final CorrelationIdentifier newInnerAlias = CorrelationIdentifier.uniqueID();
for (final QueryPredicate queryPredicate : queryPredicates) {
final Optional<QueryPredicate> pushedPredicateOptional = queryPredicate.replaceLeavesMaybe(leafPredicate -> pushLeafPredicate(fetchPlan, newInnerAlias, leafPredicate));
if (pushedPredicateOptional.isPresent()) {
pushedPredicatesBuilder.add(pushedPredicateOptional.get());
} else {
residualPredicatesBuilder.add(queryPredicate);
}
}
final ImmutableList<QueryPredicate> pushedPredicates = pushedPredicatesBuilder.build();
final ImmutableList<QueryPredicate> residualPredicates = residualPredicatesBuilder.build();
Verify.verify(pushedPredicates.size() + residualPredicates.size() == queryPredicates.size());
// case 1
if (pushedPredicates.isEmpty()) {
return;
}
// for case 2 and case 3 we can at least build a FILTER(inner, pushedPredicates) as that is
// required both for case 2 nd 3
final Quantifier.Physical newInnerQuantifier = Quantifier.physical(GroupExpressionRef.of(innerPlan), newInnerAlias);
final RecordQueryPredicatesFilterPlan pushedFilterPlan = new RecordQueryPredicatesFilterPlan(newInnerQuantifier, pushedPredicates);
final RecordQueryFetchFromPartialRecordPlan newFetchPlan = new RecordQueryFetchFromPartialRecordPlan(pushedFilterPlan, fetchPlan.getPushValueFunction());
if (residualPredicates.isEmpty()) {
// case 2
call.yield(call.ref(newFetchPlan));
} else {
// case 3
// create yet another physical quantifier on top of the fetch
final Quantifier.Physical newQuantifierOverFetch = Quantifier.physical(GroupExpressionRef.of(newFetchPlan));
final AliasMap translationMap = AliasMap.of(quantifierOverFetch.getAlias(), newQuantifierOverFetch.getAlias());
// rebase all residual predicates to use that quantifier's alias
final ImmutableList<QueryPredicate> rebasedResidualPredicates = residualPredicates.stream().map(residualPredicate -> residualPredicate.rebase(translationMap)).collect(ImmutableList.toImmutableList());
call.yield(GroupExpressionRef.of(new RecordQueryPredicatesFilterPlan(newQuantifierOverFetch, rebasedResidualPredicates)));
}
}
use of com.apple.foundationdb.record.query.plan.temp.CorrelationIdentifier in project fdb-record-layer by FoundationDB.
the class OrderingProperty method deriveForInJoinFromOrderings.
@SuppressWarnings("java:S135")
public static Optional<Ordering> deriveForInJoinFromOrderings(@Nonnull final List<Optional<Ordering>> orderingOptionals, @Nonnull final RecordQueryInJoinPlan inJoinPlan) {
final Optional<Ordering> childOrderingOptional = Iterables.getOnlyElement(orderingOptionals);
if (childOrderingOptional.isPresent()) {
final var childOrdering = childOrderingOptional.get();
final var equalityBoundKeyMap = childOrdering.getEqualityBoundKeyMap();
final var inSource = inJoinPlan.getInSource();
final CorrelationIdentifier inAlias = inJoinPlan.getInAlias();
final SetMultimap<KeyExpression, Comparisons.Comparison> resultEqualityBoundKeyMap = HashMultimap.create(equalityBoundKeyMap);
KeyExpression inKeyExpression = null;
for (final var entry : equalityBoundKeyMap.entries()) {
// TODO we only look for the first entry that matches. That is enough for the in-to-join case,
// however, it is possible that more than one different key expressions are equality-bound
// by this in. That would constitute to more than one concurrent order which we cannot
// express at the moment (we need the PartialOrder approach for that).
final var comparison = entry.getValue();
final var correlatedTo = comparison.getCorrelatedTo();
if (correlatedTo.size() != 1) {
continue;
}
if (inAlias.equals(Iterables.getOnlyElement(correlatedTo))) {
inKeyExpression = entry.getKey();
resultEqualityBoundKeyMap.removeAll(inKeyExpression);
break;
}
}
if (inKeyExpression == null || !inSource.isSorted()) {
//
return Optional.of(new Ordering(resultEqualityBoundKeyMap, ImmutableList.of(), false));
}
//
// Prepend the existing order with the key expression we just found.
//
final var resultOrderingKeyPartsBuilder = ImmutableList.<KeyPart>builder();
resultOrderingKeyPartsBuilder.add(KeyPart.of(inKeyExpression, inSource.isReverse()));
resultOrderingKeyPartsBuilder.addAll(childOrdering.getOrderingKeyParts());
return Optional.of(new Ordering(resultEqualityBoundKeyMap, resultOrderingKeyPartsBuilder.build(), childOrdering.isDistinct()));
} else {
return Optional.empty();
}
}
Aggregations