diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/RecordQueryPlannerConfiguration.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/RecordQueryPlannerConfiguration.java
index 89cbad12e3..fdf47e7560 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/RecordQueryPlannerConfiguration.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/RecordQueryPlannerConfiguration.java
@@ -24,6 +24,7 @@
import com.apple.foundationdb.record.IndexFetchMethod;
import com.apple.foundationdb.record.RecordPlannerConfigurationProto;
import com.apple.foundationdb.record.query.RecordQuery;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.CascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.PlannerRule;
import com.apple.foundationdb.record.query.plan.cascades.PlanningRuleSet;
@@ -622,9 +623,9 @@ public Builder setAllowNonIndexSort(final boolean allowNonIndexSort) {
*/
@CanIgnoreReturnValue
@Nonnull
- public Builder setDisabledTransformationRules(@Nonnull final Set>> disabledTransformationRules) {
+ public Builder setDisabledTransformationRules(@Nonnull final Set>> disabledTransformationRules) {
protoBuilder.clearDisabledTransformationRules();
- for (Class extends CascadesRule>> rule : disabledTransformationRules) {
+ for (Class extends AbstractCascadesRule>> rule : disabledTransformationRules) {
protoBuilder.addDisabledTransformationRules(rule.getSimpleName());
}
return this;
@@ -664,7 +665,7 @@ public Builder setDisabledTransformationRuleNames(@Nonnull final Set dis
@Nonnull
public Builder disableRewritingRules() {
for (CascadesRule> rule : RewritingRuleSet.OPTIONAL_RULES) {
- disableTransformationRule((Class extends CascadesRule>>) rule.getClass());
+ disableTransformationRule((Class extends AbstractCascadesRule>>) rule.getClass());
}
return this;
}
@@ -676,7 +677,7 @@ public Builder disableRewritingRules() {
*/
@CanIgnoreReturnValue
@Nonnull
- public Builder disableTransformationRule(@Nonnull Class extends CascadesRule>> ruleClass) {
+ public Builder disableTransformationRule(@Nonnull Class extends AbstractCascadesRule>> ruleClass) {
protoBuilder.addDisabledTransformationRules(ruleClass.getSimpleName());
return this;
}
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AbstractCascadesRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AbstractCascadesRule.java
new file mode 100644
index 0000000000..b8d636d87d
--- /dev/null
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AbstractCascadesRule.java
@@ -0,0 +1,106 @@
+/*
+ * AbstractCascadesRule.java
+ *
+ * This source file is part of the FoundationDB open source project
+ *
+ * Copyright 2015-2018 Apple Inc. and the FoundationDB project authors
+ *
+ * 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.apple.foundationdb.record.query.plan.cascades;
+
+import com.apple.foundationdb.annotation.API;
+import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression;
+import com.apple.foundationdb.record.query.plan.cascades.matching.structure.BindingMatcher;
+import com.google.common.collect.ImmutableSet;
+
+import javax.annotation.Nonnull;
+import java.util.Collection;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * Classes that inherit from AbstractCascadesRule
form the base of the Cascades planning system. During the planning
+ * process, rules are matched to a current {@link RelationalExpression} and then provide zero or more logically equivalent
+ * expressions.
+ *
+ * The rule matching occurs in two stages: first, the planner examines the {@link #matcher} of the rule,
+ * which is a {@link BindingMatcher} expression that expresses the operators that the rule applies to and the hierarchical
+ * structure that they take on in the expression tree. If the rule matches the binding, its {@link #onMatch(PlannerRuleCall)}
+ * method is called, with a parameter that provides the planner's {@link PlanContext} and access to the map of bindings,
+ * among other things. This method can inspect the operators bound during the structural matching and implement other
+ * logic.
+ *
+ * The onMatch()
method returns logically equivalent expressions to the planner by calling the
+ * yield methods on its rule call, with a new {@link RelationalExpression}s. These methods can be called more than once,
+ * or zero times if no alternative expressions are found.
+ *
+ * A rule should not attempt to modify any of the bound objects that the rule call provides. Nearly all such objects are
+ * immutable, and the mutable ones are hidden behind interfaces that do not expose mutation methods. In particular,
+ * a rule should never cast an {@link Reference} in an attempt to access it.
+ *
+ * A AbstractCascadesRule
should not store state between successive calls to {@link #onMatch(PlannerRuleCall)},
+ * since it may be reused an arbitrary number of times and may be reinstantiated at any time. To simplify cleanup,
+ * any state that needs to be shared within a rule call should be encapsulated in a helper object (such as a static
+ * inner class) or documented carefully.
+ * @param a parent planner expression type of all possible root planner expressions that this rule could match
+ * @see com.apple.foundationdb.record.query.plan.cascades
+ * @see PlannerRuleCall
+ */
+@API(API.Status.EXPERIMENTAL)
+public abstract class AbstractCascadesRule implements CascadesRule {
+ @Nonnull
+ private final BindingMatcher matcher;
+
+ @Nonnull
+ private final Set> requirementDependencies;
+
+ public AbstractCascadesRule(@Nonnull BindingMatcher matcher) {
+ this.matcher = matcher;
+ this.requirementDependencies = ImmutableSet.of();
+ }
+
+ public AbstractCascadesRule(@Nonnull BindingMatcher matcher, Collection> requirementDependencies) {
+ this.matcher = matcher;
+ this.requirementDependencies = ImmutableSet.copyOf(requirementDependencies);
+ }
+
+ /**
+ * Returns the class of the operator at the root of the binding expression, if this rule uses a non-trivial binding.
+ * Used primarily for indexing rules for more efficient rule search.
+ * @return the class of the root of this rule's binding, or Optional.empty()
if the rule matches anything
+ * @see PlanningRuleSet
+ */
+ @Nonnull
+ @Override
+ public Optional> getRootOperator() {
+ return Optional.of(matcher.getRootClass());
+ }
+
+ @Nonnull
+ public Set> getConstraintDependencies() {
+ return requirementDependencies;
+ }
+
+ @Nonnull
+ @Override
+ public BindingMatcher getMatcher() {
+ return matcher;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName();
+ }
+}
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/CascadesPlanner.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/CascadesPlanner.java
index fb9f7b51a0..92e65a4270 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/CascadesPlanner.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/CascadesPlanner.java
@@ -50,6 +50,7 @@
import com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan;
import com.google.common.base.Suppliers;
import com.google.common.base.Verify;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -58,10 +59,10 @@
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
+import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -79,7 +80,7 @@
*
*
*
- * Like many optimization frameworks, Cascades is driven by sets of {@link CascadesRule}s that can be defined for
+ * Like many optimization frameworks, Cascades is driven by sets of {@link AbstractCascadesRule}s that can be defined for
* {@link RelationalExpression}s, {@link PartialMatch}es and {@link MatchPartition}s, each of which describes a
* particular transformation and encapsulates the logic for determining its applicability and applying it. The planner
* searches through its {@link PlanningRuleSet} to find a matching rule and then executes that rule, creating zero or
@@ -92,7 +93,7 @@
* of the current planner expression, the current partial match, or the current match partition.
*
*
- * A {@link CascadesRule#onMatch(CascadesRuleCall)} method that is run for each successful match, producing zero
+ * A {@link AbstractCascadesRule#onMatch(PlannerRuleCall)} method that is run for each successful match, producing zero
* or more new expressions and/or zero or more new partial matches.
*
*
@@ -197,7 +198,7 @@
*
* @see Reference
* @see RelationalExpression
- * @see CascadesRule
+ * @see AbstractCascadesRule
* @see CascadesCostModel
*/
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@@ -519,7 +520,7 @@ public interface Task {
@Nonnull
PlannerPhase getPlannerPhase();
- void execute();
+ boolean execute();
Debugger.Event toTaskEvent(Location location);
}
@@ -551,13 +552,14 @@ public PlannerPhase getPlannerPhase() {
}
@Override
- public void execute() {
+ public boolean execute() {
if (plannerPhase.hasNextPhase()) {
// if there is another phase push it first so it gets executed at the very end
taskStack.push(new InitiatePlannerPhase(plannerPhase.getNextPhase()));
}
taskStack.push(new OptimizeGroup(plannerPhase, currentRoot));
taskStack.push(new ExploreGroup(plannerPhase, currentRoot));
+ return true;
}
@Override
@@ -605,7 +607,7 @@ public PlannerPhase getPlannerPhase() {
}
@Override
- public void execute() {
+ public boolean execute() {
RelationalExpression bestFinalExpression = null;
final var costModel = plannerPhase.createCostModel(configuration);
for (final var finalExpression : group.getFinalExpressions()) {
@@ -646,6 +648,7 @@ public void execute() {
} else {
group.pruneWith(bestFinalExpression);
}
+ return true;
}
@Override
@@ -688,13 +691,13 @@ public PlannerPhase getPlannerPhase() {
}
@Override
- public void execute() {
+ public boolean execute() {
final var targetPlannerStage = plannerPhase.getTargetPlannerStage();
final var groupPlannerStage = group.getPlannerStage();
if (targetPlannerStage != groupPlannerStage) {
if (targetPlannerStage.precedes(groupPlannerStage)) {
// group is further along in the planning process, do not re-explore
- return;
+ return false;
} else {
//
// targetPlannerStage succeeds groupPlannerStage
@@ -728,6 +731,7 @@ public void execute() {
} else {
group.commitExploration();
}
+ return true;
}
@Override
@@ -796,7 +800,7 @@ public AbstractExploreExpression(@Nonnull final PlannerPhase plannerPhase,
}
@Override
- public void execute() {
+ public boolean execute() {
final var ruleSet = getPlannerPhase().getRuleSet();
// push all rules that need to run after all exploration for a (group, expression) pair is done.
@@ -824,15 +828,26 @@ public void execute() {
.filter(rule -> rule instanceof PreOrderRule &&
shouldPushRule(rule))
.forEach(this::pushTransformTask);
+ return true;
}
protected abstract boolean shouldPushRule(@Nonnull CascadesRule> rule);
private void pushTransformTask(@Nonnull CascadesRule extends RelationalExpression> rule) {
- taskStack.push(new TransformExpression(getPlannerPhase(), getGroup(), getExpression(), rule));
+ if (rule instanceof ConditionalCascadesRule, ?>) {
+ taskStack.push(new ConditionalTransformExpression(getPlannerPhase(), getGroup(), getExpression(),
+ getRules((ConditionalCascadesRule, ?>)rule)));
+ } else {
+ taskStack.push(new TransformExpression(getPlannerPhase(), getGroup(), getExpression(), rule));
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private List> getRules(ConditionalCascadesRule, ?> rule) {
+ return (List>)rule.getRules();
}
- private void pushTransformMatchPartition(CascadesRule extends MatchPartition> rule) {
+ private void pushTransformMatchPartition(AbstractCascadesRule extends MatchPartition> rule) {
taskStack.push(new TransformMatchPartition(getPlannerPhase(), getGroup(), getExpression(), rule));
}
@@ -982,45 +997,53 @@ protected boolean shouldExecute() {
*/
@Override
@SuppressWarnings("java:S1117")
- public void execute() {
+ public boolean execute() {
if (!shouldExecute()) {
- return;
+ return false;
}
final PlannerBindings initialBindings = getInitialBindings();
- final AtomicInteger numMatches = new AtomicInteger(0);
-
- rule.getMatcher()
- .bindMatches(getConfiguration(), initialBindings, getBindable())
- .map(bindings -> new CascadesRuleCall(plannerPhase, planContext, rule, group,
- traversal, taskStack, bindings, evaluationContext))
- .forEach(ruleCall -> {
- int ruleMatchesCount = numMatches.incrementAndGet();
- if (isMaxNumMatchesPerRuleCallExceeded(configuration, ruleMatchesCount)) {
- throw new RecordQueryPlanComplexityException("Maximum number of matches per rule call has been exceeded")
- .addLogInfo(LogMessageKeys.RULE, ruleCall)
- .addLogInfo(LogMessageKeys.RULE_MATCHES_COUNT, ruleMatchesCount)
- .addLogInfo(LogMessageKeys.MAX_RULE_MATCHES_COUNT,
- configuration.getMaxNumMatchesPerRuleCall());
- }
- // we notify the debugger (if installed) that the transform task is succeeding and
- // about begin and end of the rule call event
- Debugger.withDebugger(debugger -> debugger.onEvent(toTaskEvent(Location.MATCH_PRE)));
- Debugger.withDebugger(debugger ->
- debugger.onEvent(new Debugger.TransformRuleCallEvent(plannerPhase, currentRoot,
- taskStack, Location.BEGIN, group, getBindable(), rule, ruleCall)));
- try {
- executeRuleCall(ruleCall);
- } finally {
- Debugger.withDebugger(debugger ->
- debugger.onEvent(new Debugger.TransformRuleCallEvent(plannerPhase, currentRoot,
- taskStack, Location.END, group, getBindable(), rule, ruleCall)));
- }
- });
- }
-
- protected void executeRuleCall(@Nonnull CascadesRuleCall ruleCall) {
+ int numMatches = 0;
+ boolean hasMadeProgress = false;
+
+ final Iterable boundMatches =
+ () -> rule.getMatcher()
+ .bindMatches(getConfiguration(), initialBindings, getBindable()).iterator();
+
+ for (final var bindings : boundMatches) {
+ final var ruleCall =
+ new CascadesRuleCall(plannerPhase, planContext, rule, group,
+ traversal, taskStack, bindings, evaluationContext);
+ numMatches ++;
+
+ if (isMaxNumMatchesPerRuleCallExceeded(configuration, numMatches)) {
+ throw new RecordQueryPlanComplexityException("Maximum number of matches per rule call has been exceeded")
+ .addLogInfo(LogMessageKeys.RULE, ruleCall)
+ .addLogInfo(LogMessageKeys.RULE_MATCHES_COUNT, numMatches)
+ .addLogInfo(LogMessageKeys.MAX_RULE_MATCHES_COUNT,
+ configuration.getMaxNumMatchesPerRuleCall());
+ }
+ // we notify the debugger (if installed) that the transform task is succeeding and
+ // about begin and end of the rule call event
+ Debugger.withDebugger(debugger -> debugger.onEvent(toTaskEvent(Location.MATCH_PRE)));
+ Debugger.withDebugger(debugger ->
+ debugger.onEvent(new Debugger.TransformRuleCallEvent(plannerPhase, currentRoot,
+ taskStack, Location.BEGIN, group, getBindable(), rule, ruleCall)));
+ try {
+ hasMadeProgress |= executeRuleCall(ruleCall);
+ } finally {
+ Debugger.withDebugger(debugger ->
+ debugger.onEvent(new Debugger.TransformRuleCallEvent(plannerPhase, currentRoot,
+ taskStack, Location.END, group, getBindable(), rule, ruleCall)));
+ }
+ }
+ return hasMadeProgress;
+ }
+
+ protected boolean executeRuleCall(@Nonnull CascadesRuleCall ruleCall) {
+ boolean hasMadeProgress = false;
+
ruleCall.run();
//
@@ -1037,6 +1060,7 @@ protected void executeRuleCall(@Nonnull CascadesRuleCall ruleCall) {
debugger.onEvent(new Debugger.TransformRuleCallEvent(plannerPhase, currentRoot, taskStack,
Location.YIELD, group, getBindable(), rule, ruleCall)));
taskStack.push(new AdjustMatch(getPlannerPhase(), getGroup(), getExpression(), newPartialMatch));
+ hasMadeProgress = true;
}
for (final RelationalExpression newExpression : ruleCall.getNewFinalExpressions()) {
@@ -1044,6 +1068,7 @@ protected void executeRuleCall(@Nonnull CascadesRuleCall ruleCall) {
debugger.onEvent(new Debugger.TransformRuleCallEvent(plannerPhase, currentRoot, taskStack,
Location.YIELD, group, getBindable(), rule, ruleCall)));
exploreExpressionAndOptimizeInputs(plannerPhase, getGroup(), newExpression, true);
+ hasMadeProgress = true;
}
for (final RelationalExpression newExpression : ruleCall.getNewExploratoryExpressions()) {
@@ -1051,6 +1076,7 @@ protected void executeRuleCall(@Nonnull CascadesRuleCall ruleCall) {
debugger.onEvent(new Debugger.TransformRuleCallEvent(plannerPhase, currentRoot, taskStack,
Location.YIELD, group, getBindable(), rule, ruleCall)));
exploreExpression(plannerPhase, group, newExpression, true);
+ hasMadeProgress = true;
}
final var referencesWithPushedRequirements = ruleCall.getReferencesWithPushedConstraints();
@@ -1064,13 +1090,16 @@ protected void executeRuleCall(@Nonnull CascadesRuleCall ruleCall) {
//
if (!(rule instanceof PreOrderRule)) {
taskStack.push(this);
+ hasMadeProgress = true;
}
for (final Reference reference : referencesWithPushedRequirements) {
if (!reference.hasNeverBeenExplored()) {
taskStack.push(new ExploreGroup(plannerPhase, reference));
+ hasMadeProgress = true;
}
}
}
+ return hasMadeProgress;
}
@Override
@@ -1117,6 +1146,32 @@ protected PlannerBindings getInitialBindings() {
}
}
+ private class ConditionalTransformExpression extends TransformExpression {
+ @Nonnull
+ private final List> rules;
+
+ public ConditionalTransformExpression(@Nonnull final PlannerPhase plannerPhase,
+ @Nonnull final Reference group,
+ @Nonnull final RelationalExpression expression,
+ @Nonnull final List extends AbstractCascadesRule extends RelationalExpression>> rules) {
+ super(plannerPhase, group, expression, rules.get(0));
+ this.rules = ImmutableList.copyOf(rules);
+ }
+
+ @Override
+ public boolean execute() {
+ final boolean hasMadeProgress = super.execute();
+ if (!hasMadeProgress) {
+ final var remainingRules = rules.subList(1, rules.size());
+ if (!remainingRules.isEmpty()) {
+ taskStack.push(new ConditionalTransformExpression(getPlannerPhase(), getGroup(), getExpression(),
+ remainingRules));
+ }
+ }
+ return hasMadeProgress;
+ }
+ }
+
/**
* Class to transform a match partition using a rule.
*/
@@ -1127,7 +1182,7 @@ private class TransformMatchPartition extends AbstractTransform {
public TransformMatchPartition(@Nonnull final PlannerPhase plannerPhase,
@Nonnull final Reference group,
@Nonnull final RelationalExpression expression,
- @Nonnull final CascadesRule extends MatchPartition> rule) {
+ @Nonnull final AbstractCascadesRule extends MatchPartition> rule) {
super(plannerPhase, group, expression, rule);
this.matchPartitionSupplier = Suppliers.memoize(() -> MatchPartition.of(group, expression));
}
@@ -1150,7 +1205,7 @@ public TransformPartialMatch(@Nonnull final PlannerPhase plannerPhase,
@Nonnull final Reference group,
@Nonnull final RelationalExpression expression,
@Nonnull final PartialMatch partialMatch,
- @Nonnull final CascadesRule extends PartialMatch> rule) {
+ @Nonnull final AbstractCascadesRule extends PartialMatch> rule) {
super(plannerPhase, group, expression, rule);
this.partialMatch = partialMatch;
}
@@ -1185,12 +1240,13 @@ public AdjustMatch(@Nonnull final PlannerPhase plannerPhase,
}
@Override
- public void execute() {
+ public boolean execute() {
final var ruleSet = getPlannerPhase().getRuleSet();
ruleSet.getPartialMatchRules(rule -> configuration.isRuleEnabled(rule))
.forEach(rule ->
taskStack.push(new TransformPartialMatch(getPlannerPhase(), getGroup(), getExpression(),
partialMatch, rule)));
+ return true;
}
@Override
@@ -1240,14 +1296,15 @@ public PlannerPhase getPlannerPhase() {
}
@Override
- public void execute() {
+ public boolean execute() {
if (!group.containsExactly(expression)) {
- return;
+ return false;
}
for (final Quantifier quantifier : expression.getQuantifiers()) {
final Reference rangesOver = quantifier.getRangesOver();
taskStack.push(new OptimizeGroup(plannerPhase, rangesOver));
}
+ return true;
}
@Override
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/CascadesRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/CascadesRule.java
index 8aaabaff66..69013916b2 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/CascadesRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/CascadesRule.java
@@ -1,5 +1,5 @@
/*
- * CascadesRule.java
+ * AbstractCascadesRule.java
*
* This source file is part of the FoundationDB open source project
*
@@ -21,89 +21,18 @@
package com.apple.foundationdb.record.query.plan.cascades;
import com.apple.foundationdb.annotation.API;
-import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression;
-import com.apple.foundationdb.record.query.plan.cascades.matching.structure.BindingMatcher;
-import com.google.common.collect.ImmutableSet;
import javax.annotation.Nonnull;
-import java.util.Collection;
-import java.util.Optional;
import java.util.Set;
/**
- * Classes that inherit from CascadesRule
form the base of the Cascades planning system. During the planning
- * process, rules are matched to a current {@link RelationalExpression} and then provide zero or more logically equivalent
- * expressions.
- *
- * The rule matching occurs in two stages: first, the planner examines the {@link #matcher} of the rule,
- * which is a {@link BindingMatcher} expression that expresses the operators that the rule applies to and the hierarchical
- * structure that they take on in the expression tree. If the rule matches the binding, its {@link #onMatch(CascadesRuleCall)}
- * method is called, with a parameter that provides the planner's {@link PlanContext} and access to the map of bindings,
- * among other things. This method can inspect the operators bound during the structural matching and implement other
- * logic.
- *
- * The onMatch()
method returns logically equivalent expressions to the planner by calling the
- * yield methods on its rule call, with a new {@link RelationalExpression}s. These methods can be called more than once,
- * or zero times if no alternative expressions are found.
- *
- * A rule should not attempt to modify any of the bound objects that the rule call provides. Nearly all such objects are
- * immutable, and the mutable ones are hidden behind interfaces that do not expose mutation methods. In particular,
- * a rule should never cast an {@link Reference} in an attempt to access it.
- *
- * A CascadesRule
should not store state between successive calls to {@link #onMatch(CascadesRuleCall)},
- * since it may be reused an arbitrary number of times and may be reinstantiated at any time. To simplify cleanup,
- * any state that needs to be shared within a rule call should be encapsulated in a helper object (such as a static
- * inner class) or documented carefully.
+ * TODO.
* @param a parent planner expression type of all possible root planner expressions that this rule could match
* @see com.apple.foundationdb.record.query.plan.cascades
* @see PlannerRuleCall
*/
@API(API.Status.EXPERIMENTAL)
-public abstract class CascadesRule implements PlannerRule {
+public interface CascadesRule extends PlannerRule {
@Nonnull
- private final BindingMatcher matcher;
-
- @Nonnull
- private final Set> requirementDependencies;
-
- public CascadesRule(@Nonnull BindingMatcher matcher) {
- this.matcher = matcher;
- this.requirementDependencies = ImmutableSet.of();
- }
-
- public CascadesRule(@Nonnull BindingMatcher matcher, Collection> requirementDependencies) {
- this.matcher = matcher;
- this.requirementDependencies = ImmutableSet.copyOf(requirementDependencies);
- }
-
- /**
- * Returns the class of the operator at the root of the binding expression, if this rule uses a non-trivial binding.
- * Used primarily for indexing rules for more efficient rule search.
- * @return the class of the root of this rule's binding, or Optional.empty()
if the rule matches anything
- * @see PlanningRuleSet
- */
- @Nonnull
- @Override
- public Optional> getRootOperator() {
- return Optional.of(matcher.getRootClass());
- }
-
- @Nonnull
- public Set> getConstraintDependencies() {
- return requirementDependencies;
- }
-
- @Override
- public abstract void onMatch(@Nonnull CascadesRuleCall call);
-
- @Nonnull
- @Override
- public BindingMatcher getMatcher() {
- return matcher;
- }
-
- @Override
- public String toString() {
- return getClass().getSimpleName();
- }
+ Set> getConstraintDependencies();
}
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/CascadesRuleCall.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/CascadesRuleCall.java
index d79081a5cb..97835d7dd6 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/CascadesRuleCall.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/CascadesRuleCall.java
@@ -50,7 +50,7 @@
/**
* A rule call implementation for the {@link CascadesPlanner}. The life cycle of a rule call object starts with the
* planner's decision to call a rule and ends after yielded objects have been processed. The planner instantiates a new
- * instance of this class and passes it to {@link CascadesRule#onMatch(CascadesRuleCall)} when the rule is executed.
+ * instance of this class and passes it to {@link AbstractCascadesRule#onMatch(PlannerRuleCall)} when the rule is executed.
* During the execution of a rule, the rule implementation can invoke various yielding methods (most prominently
* {@link #yieldExploratoryExpression(RelationalExpression)}, {@link #yieldFinalExpression(RelationalExpression)},
* and {@link #yieldPartialMatch}) which modify the query graph if needed, and (if necessary) queue up those newly
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/CascadesRuleSet.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/CascadesRuleSet.java
index 3049512dec..1822b53edf 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/CascadesRuleSet.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/CascadesRuleSet.java
@@ -59,23 +59,23 @@ public Stream extends CascadesRule extends RelationalExpression>> getRules(@
}
@Nonnull
- public Stream> getPartialMatchRules() {
+ public Stream> getPartialMatchRules() {
return getPartialMatchRules(ignored -> true);
}
@Nonnull
- public Stream> getPartialMatchRules(@Nonnull final Predicate> rulePredicate) {
+ public Stream> getPartialMatchRules(@Nonnull final Predicate> rulePredicate) {
return Stream.empty();
}
@Nonnull
- public Stream> getMatchPartitionRules() {
+ public Stream> getMatchPartitionRules() {
return getMatchPartitionRules(ignored -> true);
}
@Nonnull
- public Stream> getMatchPartitionRules(@Nonnull final Predicate> rulePredicate) {
+ public Stream> getMatchPartitionRules(@Nonnull final Predicate> rulePredicate) {
return Stream.empty();
}
}
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/ConditionalCascadesRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/ConditionalCascadesRule.java
new file mode 100644
index 0000000000..8a1edef9a2
--- /dev/null
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/ConditionalCascadesRule.java
@@ -0,0 +1,146 @@
+/*
+ * ConditionalCascadesRule.java
+ *
+ * This source file is part of the FoundationDB open source project
+ *
+ * Copyright 2015-2025 Apple Inc. and the FoundationDB project authors
+ *
+ * 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.apple.foundationdb.record.query.plan.cascades;
+
+import com.apple.foundationdb.annotation.API;
+import com.apple.foundationdb.record.RecordCoreException;
+import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression;
+import com.apple.foundationdb.record.query.plan.cascades.matching.structure.BindingMatcher;
+import com.google.common.base.Verify;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+import javax.annotation.Nonnull;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * TODO.
+ * @param a parent planner expression type of all possible root planner expressions that this rule could match
+ * @param the kind of
+ */
+@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
+@API(API.Status.EXPERIMENTAL)
+public class ConditionalCascadesRule> extends AbstractCascadesRule {
+ @Nonnull
+ final List rules;
+ @Nonnull
+ Optional> rootOperatorOptional;
+
+ @SafeVarargs
+ @SuppressWarnings("varargs")
+ public ConditionalCascadesRule(@Nonnull final R... rules) {
+ this(ImmutableList.copyOf(rules));
+ }
+
+ public ConditionalCascadesRule(@Nonnull final List rules) {
+ super(bindingMatcher(rules), ImmutableSet.of());
+ this.rules = ImmutableList.copyOf(rules);
+ this.rootOperatorOptional = rootOperatorMaybe(rules);
+ }
+
+ @Nonnull
+ public List getRules() {
+ return rules;
+ }
+
+ @Nonnull
+ @Override
+ public Optional> getRootOperator() {
+ return rootOperatorOptional;
+ }
+
+ @Override
+ public void onMatch(@Nonnull final CascadesRuleCall call) {
+ throw new RecordCoreException("cannot call this method directly");
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + rules;
+ }
+
+ @Nonnull
+ private static > BindingMatcher bindingMatcher(@Nonnull final List rules) {
+ BindingMatcher bindingMatcher = null;
+ for (final var rule : rules) {
+ if (bindingMatcher == null) {
+ bindingMatcher = rule.getMatcher();
+ } else {
+ final var currentBindingMatcher = rule.getMatcher();
+ Verify.verify(currentBindingMatcher.getRootClass() == bindingMatcher.getRootClass());
+ }
+ }
+ return Objects.requireNonNull(bindingMatcher, "need to have at least one rule");
+ }
+
+ @Nonnull
+ @SuppressWarnings("OptionalAssignedToNull")
+ private static > Optional> rootOperatorMaybe(@Nonnull final List rules) {
+ Optional> rootOperatorOptional = null;
+ for (final var rule : rules) {
+ if (rootOperatorOptional == null) {
+ rootOperatorOptional = rule.getRootOperator();
+ } else {
+ final var currentRootOperatorOptional = rule.getRootOperator();
+ Verify.verify(rootOperatorOptional.isPresent() || currentRootOperatorOptional.isEmpty());
+ Verify.verify(rootOperatorOptional.isEmpty() ||
+ (currentRootOperatorOptional.isPresent() && rootOperatorOptional.get() == currentRootOperatorOptional.get()));
+ }
+ }
+ return Objects.requireNonNull(rootOperatorOptional, "need to have at least one rule");
+ }
+
+ public static class ConditionalExplorationCascadesRule extends ConditionalCascadesRule> implements ExplorationCascadesRule {
+ @SafeVarargs
+ @SuppressWarnings("varargs")
+ public ConditionalExplorationCascadesRule(@Nonnull final ExplorationCascadesRule... rules) {
+ super(rules);
+ }
+
+ public ConditionalExplorationCascadesRule(@Nonnull final List> rules) {
+ super(rules);
+ }
+
+ @Override
+ public void onMatch(@Nonnull final ExplorationCascadesRuleCall call) {
+ throw new RecordCoreException("cannot call this method directly");
+ }
+ }
+
+ public static class ConditionalImplementationCascadesRule extends ConditionalCascadesRule> implements ImplementationCascadesRule {
+ @SafeVarargs
+ @SuppressWarnings("varargs")
+ public ConditionalImplementationCascadesRule(@Nonnull final ImplementationCascadesRule... rules) {
+ super(rules);
+ }
+
+ public ConditionalImplementationCascadesRule(@Nonnull final List> rules) {
+ super(rules);
+ }
+
+ @Override
+ public void onMatch(@Nonnull final ImplementationCascadesRuleCall call) {
+ throw new RecordCoreException("cannot call this method directly");
+ }
+ }
+}
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/ExplorationCascadesRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/ExplorationCascadesRule.java
index d53aa8c9c5..87c5d7bf77 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/ExplorationCascadesRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/ExplorationCascadesRule.java
@@ -22,11 +22,8 @@
import com.apple.foundationdb.annotation.API;
import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression;
-import com.apple.foundationdb.record.query.plan.cascades.matching.structure.BindingMatcher;
-import com.google.common.collect.ImmutableSet;
import javax.annotation.Nonnull;
-import java.util.Collection;
/**
* Abstract class to be extended for all exploration rules. The main purpose of this class is to constrain the
@@ -49,23 +46,14 @@
* @param a parent planner expression type of all possible root planner expressions that this rule could match
*/
@API(API.Status.EXPERIMENTAL)
-public abstract class ExplorationCascadesRule extends CascadesRule {
- public ExplorationCascadesRule(@Nonnull BindingMatcher matcher) {
- this(matcher, ImmutableSet.of());
- }
-
- public ExplorationCascadesRule(@Nonnull final BindingMatcher matcher,
- @Nonnull final Collection> requirementDependencies) {
- super(matcher, requirementDependencies);
- }
-
+public interface ExplorationCascadesRule extends CascadesRule {
/**
* Note that this method is intentionally {@code final} to prevent reimplementation by subclasses. Subclassed should
* instead override the more constrained {@link #onMatch(ExplorationCascadesRuleCall)}.
* @param call the regular {@link CascadesRuleCall}
*/
@Override
- public final void onMatch(@Nonnull final CascadesRuleCall call) {
+ default void onMatch(@Nonnull final CascadesRuleCall call) {
// needs to be cast up to select the right overloaded method
onMatch((ExplorationCascadesRuleCall)call);
}
@@ -74,5 +62,5 @@ public final void onMatch(@Nonnull final CascadesRuleCall call) {
* Abstract method to be implemented by the specific rule.
* @param call the constrained rule call
*/
- public abstract void onMatch(@Nonnull ExplorationCascadesRuleCall call);
+ void onMatch(@Nonnull ExplorationCascadesRuleCall call);
}
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/ImplementationCascadesRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/ImplementationCascadesRule.java
index 9596029563..41a2543470 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/ImplementationCascadesRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/ImplementationCascadesRule.java
@@ -22,8 +22,6 @@
import com.apple.foundationdb.annotation.API;
import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression;
-import com.apple.foundationdb.record.query.plan.cascades.matching.structure.BindingMatcher;
-import com.google.common.collect.ImmutableSet;
import javax.annotation.Nonnull;
import java.util.Collection;
@@ -58,23 +56,14 @@
* @param a parent planner expression type of all possible root planner expressions that this rule could match
*/
@API(API.Status.EXPERIMENTAL)
-public abstract class ImplementationCascadesRule extends CascadesRule {
- public ImplementationCascadesRule(@Nonnull BindingMatcher matcher) {
- this(matcher, ImmutableSet.of());
- }
-
- public ImplementationCascadesRule(@Nonnull final BindingMatcher matcher,
- @Nonnull final Collection> requirementDependencies) {
- super(matcher, requirementDependencies);
- }
-
+public interface ImplementationCascadesRule extends CascadesRule {
/**
* Note that this method is intentionally final to prevent reimplementation by subclasses. Subclassed should instead
* override the more constrained {@link #onMatch(ImplementationCascadesRuleCall)}.
* @param call the regular {@link CascadesRuleCall}
*/
@Override
- public final void onMatch(@Nonnull final CascadesRuleCall call) {
+ default void onMatch(@Nonnull final CascadesRuleCall call) {
// needs to be cast up to select the right overloaded method
onMatch((ImplementationCascadesRuleCall)call);
}
@@ -83,5 +72,5 @@ public final void onMatch(@Nonnull final CascadesRuleCall call) {
* Abstract method to be implemented by the specific rule.
* @param call the constrained rule call
*/
- public abstract void onMatch(@Nonnull ImplementationCascadesRuleCall call);
+ void onMatch(@Nonnull ImplementationCascadesRuleCall call);
}
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PlanContext.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PlanContext.java
index bd85ed5e47..28480fea8b 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PlanContext.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PlanContext.java
@@ -27,9 +27,9 @@
import java.util.Set;
/**
- * A basic context object that stores all of the metadata about a record store, such as the available indexes.
+ * A basic context object that stores all metadata about a record store, such as the available indexes.
* It provides access to this information to the planner and the
- * {@link CascadesRule#onMatch(CascadesRuleCall)} method.
+ * {@link AbstractCascadesRule#onMatch(PlannerRuleCall)} method.
*/
@API(API.Status.EXPERIMENTAL)
public interface PlanContext {
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PlannerRuleCall.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PlannerRuleCall.java
index e252a3194f..2a79c12d26 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PlannerRuleCall.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PlannerRuleCall.java
@@ -31,7 +31,7 @@
* A PlannerRuleCall
is a context object that supports a single application of a rule to a particular
* expression. It stores and provides convenient access to various context related to the transformation, such as any
* bindings, access to the {@link PlanContext}, etc. A PlannerRuleCall
is passed to every rule's
- * {@link CascadesRule#onMatch(CascadesRuleCall)} method.
+ * {@link AbstractCascadesRule#onMatch(PlannerRuleCall)} method.
*/
@API(API.Status.EXPERIMENTAL)
public interface PlannerRuleCall {
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PlanningRuleSet.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PlanningRuleSet.java
index 23f92b270a..074a13e719 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PlanningRuleSet.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PlanningRuleSet.java
@@ -111,7 +111,7 @@ public class PlanningRuleSet extends CascadesRuleSet {
new PartitionSelectRule(),
new PartitionBinarySelectRule()
);
- private static final Set> MATCHING_RULES = ImmutableSet.of(
+ private static final Set> MATCHING_RULES = ImmutableSet.of(
new MatchLeafRule(),
new MatchIntermediateRule()
);
@@ -178,10 +178,10 @@ public class PlanningRuleSet extends CascadesRuleSet {
.addAll(MATCHING_RULES)
.addAll(EXPLORATION_RULES)
.build();
- private static final Set> PARTIAL_MATCH_RULES = ImmutableSet.of(
+ private static final Set> PARTIAL_MATCH_RULES = ImmutableSet.of(
new AdjustMatchRule()
);
- private static final Set> MATCH_PARTITION_RULES = ImmutableSet.of(
+ private static final Set> MATCH_PARTITION_RULES = ImmutableSet.of(
new DataAccessRule(),
new SelectDataAccessRule(),
new PredicateToLogicalUnionRule()
@@ -207,14 +207,14 @@ public class PlanningRuleSet extends CascadesRuleSet {
@Nonnull
@Override
- public Stream> getPartialMatchRules(@Nonnull final Predicate> rulePredicate) {
+ public Stream> getPartialMatchRules(@Nonnull final Predicate> rulePredicate) {
return PARTIAL_MATCH_RULES.stream()
.filter(rulePredicate);
}
@Nonnull
@Override
- public Stream> getMatchPartitionRules(@Nonnull final Predicate> rulePredicate) {
+ public Stream> getMatchPartitionRules(@Nonnull final Predicate> rulePredicate) {
return MATCH_PARTITION_RULES.stream()
.filter(rulePredicate);
}
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/RewritingRuleSet.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/RewritingRuleSet.java
index aa4036ccfc..d69329074b 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/RewritingRuleSet.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/RewritingRuleSet.java
@@ -22,7 +22,9 @@
import com.apple.foundationdb.annotation.API;
import com.apple.foundationdb.annotation.SpotBugsSuppressWarnings;
+import com.apple.foundationdb.record.query.plan.cascades.ConditionalCascadesRule.ConditionalExplorationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression;
+import com.apple.foundationdb.record.query.plan.cascades.expressions.SelectExpression;
import com.apple.foundationdb.record.query.plan.cascades.rules.DecorrelateValuesRule;
import com.apple.foundationdb.record.query.plan.cascades.rules.FinalizeExpressionsRule;
import com.apple.foundationdb.record.query.plan.cascades.rules.PredicatePushDownRule;
@@ -30,6 +32,7 @@
import com.apple.foundationdb.record.query.plan.cascades.rules.SelectMergeRule;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Streams;
import javax.annotation.Nonnull;
import java.util.Set;
@@ -40,18 +43,25 @@
@API(API.Status.EXPERIMENTAL)
@SuppressWarnings("java:S1452")
public class RewritingRuleSet extends CascadesRuleSet {
- private static final Set> EXPLORATION_RULES = ImmutableSet.of(
- new QueryPredicateSimplificationRule(),
- new PredicatePushDownRule(),
- new DecorrelateValuesRule()
- );
- private static final Set> PREORDER_RULES = ImmutableSet.of();
+ private static final ConditionalExplorationCascadesRule
+ decorrelateThenPushDownThenSimplification =
+ new ConditionalExplorationCascadesRule<>(new DecorrelateValuesRule(),
+ new PredicatePushDownRule(),
+ new QueryPredicateSimplificationRule());
+
+ private static final Set> EXPLORATION_RULES =
+ ImmutableSet.of(decorrelateThenPushDownThenSimplification);
+
+ private static final Set> PREORDER_RULES = ImmutableSet.of();
private static final Set> IMPLEMENTATION_RULES = ImmutableSet.of(
new SelectMergeRule(),
new FinalizeExpressionsRule()
);
+ private static final Set> CONDITIONAL_RULES =
+ ImmutableSet.of(decorrelateThenPushDownThenSimplification);
+
@Nonnull
private static final Set> ALL_EXPRESSION_RULES =
ImmutableSet.>builder()
@@ -62,8 +72,11 @@ public class RewritingRuleSet extends CascadesRuleSet {
@Nonnull
public static final Set> OPTIONAL_RULES =
- ALL_EXPRESSION_RULES.stream()
- .filter(rule -> !(rule instanceof FinalizeExpressionsRule))
+ Streams.concat(PREORDER_RULES.stream(), EXPLORATION_RULES.stream(), IMPLEMENTATION_RULES.stream(),
+ CONDITIONAL_RULES.stream()
+ .flatMap(conditionalCascadesRule -> conditionalCascadesRule.getRules().stream()))
+ .filter(rule -> !(rule instanceof FinalizeExpressionsRule) &&
+ !(rule instanceof ConditionalCascadesRule))
.collect(ImmutableSet.toImmutableSet());
@Nonnull
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/debug/State.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/debug/State.java
index a39eb38661..d3053a0231 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/debug/State.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/debug/State.java
@@ -22,6 +22,7 @@
import com.apple.foundationdb.record.RecordCoreException;
import com.apple.foundationdb.record.logging.KeyValueLogMessage;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.CascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.Quantifier;
import com.apple.foundationdb.record.query.plan.cascades.Reference;
@@ -308,7 +309,7 @@ public void addCurrentEvent(@Nonnull final Debugger.Event event) {
forEventClass.increaseOwnTimeInNs(ownTime);
if (event instanceof Debugger.TransformRuleCallEvent) {
final CascadesRule> rule = ((Debugger.TransformRuleCallEvent)event).getRule();
- final Class extends CascadesRule>> ruleClass = (Class extends CascadesRule>>)rule.getClass();
+ final Class extends CascadesRule>> ruleClass = (Class extends AbstractCascadesRule>>)rule.getClass();
final MutableStats forPlannerRuleClass = getEventStatsForPlannerRuleClass(ruleClass);
forPlannerRuleClass.increaseTotalTimeInNs(totalTime);
forPlannerRuleClass.increaseOwnTimeInNs(ownTime);
@@ -357,7 +358,7 @@ private void updateCounts(@Nonnull final Debugger.Event event) {
forEventClass.increaseCount(event.getLocation(), 1L);
if (event instanceof Debugger.EventWithRule) {
final CascadesRule> rule = ((Debugger.EventWithRule)event).getRule();
- final Class extends CascadesRule>> ruleClass = (Class extends CascadesRule>>)rule.getClass();
+ final Class extends CascadesRule>> ruleClass = (Class extends AbstractCascadesRule>>)rule.getClass();
final MutableStats forPlannerRuleClass = getEventStatsForPlannerRuleClass(ruleClass);
forPlannerRuleClass.increaseCount(event.getLocation(), 1L);
}
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java
index c98ed6dd73..51e0a11ca4 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java
@@ -23,8 +23,8 @@
import com.apple.foundationdb.annotation.API;
import com.apple.foundationdb.record.RecordCoreException;
import com.apple.foundationdb.record.query.combinatorics.ChooseK;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.CascadesPlanner;
-import com.apple.foundationdb.record.query.plan.cascades.CascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.CascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.ComparisonRange;
import com.apple.foundationdb.record.query.plan.cascades.Compensation;
@@ -99,7 +99,7 @@
*/
@API(API.Status.EXPERIMENTAL)
@SuppressWarnings({"java:S3776", "java:S4738", "OptionalUsedAsFieldOrParameterType"})
-public abstract class AbstractDataAccessRule extends CascadesRule {
+public abstract class AbstractDataAccessRule extends AbstractCascadesRule {
private static final Logger logger = LoggerFactory.getLogger(AbstractDataAccessRule.class);
private final BindingMatcher completeMatchMatcher;
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AdjustMatchRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AdjustMatchRule.java
index c7abf635ce..a0c09912f6 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AdjustMatchRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AdjustMatchRule.java
@@ -21,7 +21,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
import com.apple.foundationdb.annotation.API;
-import com.apple.foundationdb.record.query.plan.cascades.CascadesRule;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.CascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.Reference;
import com.apple.foundationdb.record.query.plan.cascades.MatchCandidate;
@@ -58,7 +58,7 @@
* provided properties guaranteed by the candidate side.
*/
@API(API.Status.EXPERIMENTAL)
-public class AdjustMatchRule extends CascadesRule {
+public class AdjustMatchRule extends AbstractCascadesRule {
private static final BindingMatcher rootMatcher = PartialMatchMatchers.incompleteMatch();
public AdjustMatchRule() {
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/DecorrelateValuesRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/DecorrelateValuesRule.java
index 8130eb7e31..08fbbf9c6b 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/DecorrelateValuesRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/DecorrelateValuesRule.java
@@ -20,6 +20,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier;
import com.apple.foundationdb.record.query.plan.cascades.ExplorationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ExplorationCascadesRuleCall;
@@ -134,7 +135,7 @@
* }
*/
@SuppressWarnings("PMD.TooManyStaticImports")
-public class DecorrelateValuesRule extends ExplorationCascadesRule {
+public class DecorrelateValuesRule extends AbstractCascadesRule implements ExplorationCascadesRule {
// TODO: This could use filtered expression partitions, but we have to make modifications to the test infrastructure to ensure there are final children
// We currently use a predicate over the expressions in the reference rather than a matcher here because we don't
// want to create multiple matches if there happens to be a reference containing multiple range(1) values. Doing
@@ -163,6 +164,7 @@ public class DecorrelateValuesRule extends ExplorationCascadesRule {
+public class FinalizeExpressionsRule extends AbstractCascadesRule implements ImplementationCascadesRule {
@Nonnull
private static final BindingMatcher> childPartitionsMatcher =
anyExpressionPartition();
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementDeleteRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementDeleteRule.java
index 8f7b072916..9ca9108bc3 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementDeleteRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementDeleteRule.java
@@ -21,6 +21,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
import com.apple.foundationdb.annotation.API;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.PlanPartition;
@@ -47,7 +48,7 @@
*/
@API(API.Status.EXPERIMENTAL)
@SuppressWarnings("PMD.TooManyStaticImports")
-public class ImplementDeleteRule extends ImplementationCascadesRule {
+public class ImplementDeleteRule extends AbstractCascadesRule implements ImplementationCascadesRule {
@Nonnull
private static final BindingMatcher innerPlanPartitionMatcher = anyPlanPartition();
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementDistinctRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementDistinctRule.java
index 58c5ce5428..5dbc39a929 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementDistinctRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementDistinctRule.java
@@ -21,6 +21,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
import com.apple.foundationdb.annotation.API;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.PlanPartition;
@@ -59,7 +60,7 @@
*/
@API(API.Status.EXPERIMENTAL)
@SuppressWarnings("PMD.TooManyStaticImports")
-public class ImplementDistinctRule extends ImplementationCascadesRule {
+public class ImplementDistinctRule extends AbstractCascadesRule implements ImplementationCascadesRule {
@Nonnull
private static final BindingMatcher innerPlanPartitionMatcher = anyPlanPartition();
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementDistinctUnionRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementDistinctUnionRule.java
index a3a685871c..f06112be76 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementDistinctUnionRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementDistinctUnionRule.java
@@ -22,6 +22,7 @@
import com.apple.foundationdb.annotation.API;
import com.apple.foundationdb.record.query.combinatorics.CrossProduct;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.Ordering;
@@ -71,7 +72,7 @@
*/
@API(API.Status.EXPERIMENTAL)
@SuppressWarnings("PMD.TooManyStaticImports")
-public class ImplementDistinctUnionRule extends ImplementationCascadesRule {
+public class ImplementDistinctUnionRule extends AbstractCascadesRule implements ImplementationCascadesRule {
@Nonnull
private static final CollectionMatcher unionLegPlanPartitionsMatcher = all(anyPlanPartition());
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementExplodeRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementExplodeRule.java
index 088f9831ad..046b7ee9ea 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementExplodeRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementExplodeRule.java
@@ -21,6 +21,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
import com.apple.foundationdb.annotation.API;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.expressions.ExplodeExpression;
@@ -36,7 +37,7 @@
*/
@API(API.Status.EXPERIMENTAL)
@SuppressWarnings("PMD.TooManyStaticImports")
-public class ImplementExplodeRule extends ImplementationCascadesRule {
+public class ImplementExplodeRule extends AbstractCascadesRule implements ImplementationCascadesRule {
private static final BindingMatcher root =
explodeExpression();
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementFilterRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementFilterRule.java
index ab1fa3dcf5..76f2e0c12d 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementFilterRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementFilterRule.java
@@ -21,6 +21,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
import com.apple.foundationdb.annotation.API;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.PlanPartition;
@@ -50,7 +51,7 @@
*/
@API(API.Status.EXPERIMENTAL)
@SuppressWarnings("PMD.TooManyStaticImports")
-public class ImplementFilterRule extends ImplementationCascadesRule {
+public class ImplementFilterRule extends AbstractCascadesRule implements ImplementationCascadesRule {
@Nonnull
private static final BindingMatcher innerPlanPartitionMatcher = anyPlanPartition();
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementInJoinRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementInJoinRule.java
index 5f66e07b62..a25771b20a 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementInJoinRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementInJoinRule.java
@@ -24,6 +24,7 @@
import com.apple.foundationdb.record.query.combinatorics.CrossProduct;
import com.apple.foundationdb.record.query.combinatorics.TopologicalSort;
import com.apple.foundationdb.record.query.expressions.Comparisons;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
@@ -86,7 +87,7 @@
*/
@API(API.Status.EXPERIMENTAL)
@SuppressWarnings({"PMD.TooManyStaticImports", "java:S4738", "java:S3776"})
-public class ImplementInJoinRule extends ImplementationCascadesRule {
+public class ImplementInJoinRule extends AbstractCascadesRule implements ImplementationCascadesRule {
private static final BindingMatcher explodeExpressionMatcher = explodeExpression();
private static final CollectionMatcher explodeQuantifiersMatcher = some(forEachQuantifier(explodeExpressionMatcher));
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementInUnionRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementInUnionRule.java
index f7d48a1a6a..b050508df4 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementInUnionRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementInUnionRule.java
@@ -22,6 +22,7 @@
import com.apple.foundationdb.annotation.API;
import com.apple.foundationdb.record.query.expressions.Comparisons;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
@@ -71,7 +72,7 @@
*/
@API(API.Status.EXPERIMENTAL)
@SuppressWarnings("PMD.TooManyStaticImports")
-public class ImplementInUnionRule extends ImplementationCascadesRule {
+public class ImplementInUnionRule extends AbstractCascadesRule implements ImplementationCascadesRule {
private static final BindingMatcher explodeExpressionMatcher = explodeExpression();
private static final CollectionMatcher explodeQuantifiersMatcher = some(forEachQuantifier(explodeExpressionMatcher));
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementInsertRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementInsertRule.java
index fceae5dc25..b43cdca44c 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementInsertRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementInsertRule.java
@@ -21,6 +21,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
import com.apple.foundationdb.annotation.API;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.PlanPartition;
@@ -43,7 +44,7 @@
*/
@API(API.Status.EXPERIMENTAL)
@SuppressWarnings("PMD.TooManyStaticImports")
-public class ImplementInsertRule extends ImplementationCascadesRule {
+public class ImplementInsertRule extends AbstractCascadesRule implements ImplementationCascadesRule {
@Nonnull
private static final BindingMatcher innerPlanPartitionMatcher = anyPlanPartition();
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementIntersectionRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementIntersectionRule.java
index 7122182d60..78a02ffee5 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementIntersectionRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementIntersectionRule.java
@@ -21,6 +21,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
import com.apple.foundationdb.annotation.API;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.PlanPartition;
@@ -57,7 +58,7 @@
*/
@API(API.Status.EXPERIMENTAL)
@SuppressWarnings("PMD.TooManyStaticImports")
-public class ImplementIntersectionRule extends ImplementationCascadesRule {
+public class ImplementIntersectionRule extends AbstractCascadesRule implements ImplementationCascadesRule {
@Nonnull
private static final BindingMatcher intersectionLegPlanPartitionMatcher = anyPlanPartition();
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementNestedLoopJoinRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementNestedLoopJoinRule.java
index 7d1e65a68e..95a5b12860 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementNestedLoopJoinRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementNestedLoopJoinRule.java
@@ -22,6 +22,7 @@
import com.apple.foundationdb.annotation.API;
import com.apple.foundationdb.record.logging.KeyValueLogMessage;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.PlanPartition;
@@ -61,7 +62,7 @@
*/
@API(API.Status.EXPERIMENTAL)
@SuppressWarnings("PMD.TooManyStaticImports")
-public class ImplementNestedLoopJoinRule extends ImplementationCascadesRule {
+public class ImplementNestedLoopJoinRule extends AbstractCascadesRule implements ImplementationCascadesRule {
@Nonnull
private static final Logger logger = LoggerFactory.getLogger(ImplementNestedLoopJoinRule.class);
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementRecursiveUnionRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementRecursiveUnionRule.java
index f0e1701675..4d7b906a37 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementRecursiveUnionRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementRecursiveUnionRule.java
@@ -21,6 +21,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
import com.apple.foundationdb.annotation.API;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.PlanPartition;
@@ -46,7 +47,7 @@
*/
@API(API.Status.EXPERIMENTAL)
@SuppressWarnings("PMD.TooManyStaticImports")
-public class ImplementRecursiveUnionRule extends ImplementationCascadesRule {
+public class ImplementRecursiveUnionRule extends AbstractCascadesRule implements ImplementationCascadesRule {
@Nonnull
private static final BindingMatcher initialPlanPartitionsMatcher = anyPlanPartition();
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementSimpleSelectRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementSimpleSelectRule.java
index f91fd25c56..46e5f7bb60 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementSimpleSelectRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementSimpleSelectRule.java
@@ -21,6 +21,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
import com.apple.foundationdb.annotation.API;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.AliasMap;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
@@ -55,7 +56,7 @@
*/
@API(API.Status.EXPERIMENTAL)
@SuppressWarnings("PMD.TooManyStaticImports")
-public class ImplementSimpleSelectRule extends ImplementationCascadesRule {
+public class ImplementSimpleSelectRule extends AbstractCascadesRule implements ImplementationCascadesRule {
@Nonnull
private static final BindingMatcher innerPlanPartitionMatcher = anyPlanPartition();
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementStreamingAggregationRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementStreamingAggregationRule.java
index 510e2babed..3f87159eb3 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementStreamingAggregationRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementStreamingAggregationRule.java
@@ -21,6 +21,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
import com.apple.foundationdb.annotation.API;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.AliasMap;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
@@ -54,7 +55,7 @@
*/
@API(API.Status.EXPERIMENTAL)
@SuppressWarnings("PMD.TooManyStaticImports")
-public class ImplementStreamingAggregationRule extends ImplementationCascadesRule {
+public class ImplementStreamingAggregationRule extends AbstractCascadesRule implements ImplementationCascadesRule {
@Nonnull
private static final BindingMatcher lowerRefMatcher = ReferenceMatchers.anyRef();
@Nonnull
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementTableFunctionRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementTableFunctionRule.java
index c1aec25b99..060fe31c62 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementTableFunctionRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementTableFunctionRule.java
@@ -21,6 +21,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
import com.apple.foundationdb.annotation.API;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.expressions.TableFunctionExpression;
@@ -35,7 +36,7 @@
* A rule that implements a table function expression into a {@link RecordQueryTableFunctionPlan}.
*/
@API(API.Status.EXPERIMENTAL)
-public class ImplementTableFunctionRule extends ImplementationCascadesRule {
+public class ImplementTableFunctionRule extends AbstractCascadesRule implements ImplementationCascadesRule {
private static final BindingMatcher root =
tableFunctionExpression();
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementTempTableInsertRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementTempTableInsertRule.java
index 8e1aa0179c..8dad77faba 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementTempTableInsertRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementTempTableInsertRule.java
@@ -21,6 +21,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
import com.apple.foundationdb.annotation.API;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.PlanPartition;
@@ -43,7 +44,7 @@
*/
@API(API.Status.EXPERIMENTAL)
@SuppressWarnings("PMD.TooManyStaticImports")
-public class ImplementTempTableInsertRule extends ImplementationCascadesRule {
+public class ImplementTempTableInsertRule extends AbstractCascadesRule implements ImplementationCascadesRule {
@Nonnull
private static final BindingMatcher innerPlanPartitionMatcher = anyPlanPartition();
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementTempTableScanRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementTempTableScanRule.java
index 5ecdf73d5f..2a6525db68 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementTempTableScanRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementTempTableScanRule.java
@@ -20,6 +20,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.expressions.TempTableScanExpression;
@@ -33,7 +34,7 @@
/**
* A rule that implements a {@link TempTableScanExpression} producing a {@link TempTableScanPlan} operator.
*/
-public class ImplementTempTableScanRule extends ImplementationCascadesRule {
+public class ImplementTempTableScanRule extends AbstractCascadesRule implements ImplementationCascadesRule {
@Nonnull
private static final BindingMatcher root = tempTableScanExpression();
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementTypeFilterRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementTypeFilterRule.java
index 32e9382db1..16aa067110 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementTypeFilterRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementTypeFilterRule.java
@@ -21,6 +21,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
import com.apple.foundationdb.annotation.API;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.LinkedIdentitySet;
@@ -56,7 +57,7 @@
*/
@API(API.Status.EXPERIMENTAL)
@SuppressWarnings("PMD.TooManyStaticImports")
-public class ImplementTypeFilterRule extends ImplementationCascadesRule {
+public class ImplementTypeFilterRule extends AbstractCascadesRule implements ImplementationCascadesRule {
@Nonnull
private static final BindingMatcher innerPlanPartitionMatcher = anyPlanPartition();
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementUniqueRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementUniqueRule.java
index ef39573108..ac64ed7223 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementUniqueRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementUniqueRule.java
@@ -20,6 +20,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.PlanPartition;
@@ -47,7 +48,7 @@
* This rule implements {@link LogicalUniqueExpression} by absorbing it if the inner reference is already distinct.
*/
@SuppressWarnings("PMD.TooManyStaticImports")
-public class ImplementUniqueRule extends ImplementationCascadesRule {
+public class ImplementUniqueRule extends AbstractCascadesRule implements ImplementationCascadesRule {
@Nonnull
private static final CollectionMatcher anyPlanPartitionMatcher = all(anyPlanPartition());
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementUnorderedUnionRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementUnorderedUnionRule.java
index 70852c0a3c..99f6e9d0f9 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementUnorderedUnionRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementUnorderedUnionRule.java
@@ -21,6 +21,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
import com.apple.foundationdb.annotation.API;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.PlanPartition;
@@ -51,7 +52,7 @@
*/
@API(API.Status.EXPERIMENTAL)
@SuppressWarnings("PMD.TooManyStaticImports")
-public class ImplementUnorderedUnionRule extends ImplementationCascadesRule {
+public class ImplementUnorderedUnionRule extends AbstractCascadesRule implements ImplementationCascadesRule {
@Nonnull
private static final BindingMatcher unionLegPlanPartitionsMatcher = anyPlanPartition();
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementUpdateRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementUpdateRule.java
index 8b0891ffe2..66b1f11cf9 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementUpdateRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/ImplementUpdateRule.java
@@ -21,6 +21,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
import com.apple.foundationdb.annotation.API;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.PlanPartition;
@@ -46,7 +47,7 @@
*/
@API(API.Status.EXPERIMENTAL)
@SuppressWarnings("PMD.TooManyStaticImports")
-public class ImplementUpdateRule extends ImplementationCascadesRule {
+public class ImplementUpdateRule extends AbstractCascadesRule implements ImplementationCascadesRule {
@Nonnull
private static final BindingMatcher innerPlanPartitionMatcher = anyPlanPartition();
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/InComparisonToExplodeRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/InComparisonToExplodeRule.java
index 44c3d3c0c5..b06f93010e 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/InComparisonToExplodeRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/InComparisonToExplodeRule.java
@@ -23,6 +23,7 @@
import com.apple.foundationdb.annotation.API;
import com.apple.foundationdb.record.RecordCoreException;
import com.apple.foundationdb.record.query.expressions.Comparisons;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.Column;
import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier;
import com.apple.foundationdb.record.query.plan.cascades.ExplorationCascadesRule;
@@ -119,7 +120,7 @@
*/
@API(API.Status.EXPERIMENTAL)
@SuppressWarnings("PMD.TooManyStaticImports")
-public class InComparisonToExplodeRule extends ExplorationCascadesRule {
+public class InComparisonToExplodeRule extends AbstractCascadesRule implements ExplorationCascadesRule {
private static final BindingMatcher inPredicateMatcher =
valuePredicate(ValueMatchers.anyValue(), anyComparisonOfType(Comparisons.Type.IN));
private static final BindingMatcher innerQuantifierMatcher = forEachQuantifier();
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/MatchIntermediateRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/MatchIntermediateRule.java
index e8ecb5160c..9f41824692 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/MatchIntermediateRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/MatchIntermediateRule.java
@@ -25,7 +25,7 @@
import com.apple.foundationdb.record.RecordCoreException;
import com.apple.foundationdb.record.query.combinatorics.EnumeratingIterable;
import com.apple.foundationdb.record.query.plan.cascades.AliasMap;
-import com.apple.foundationdb.record.query.plan.cascades.CascadesRule;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.CascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.Reference;
import com.apple.foundationdb.record.query.plan.cascades.IdentityBiMap;
@@ -149,7 +149,7 @@
*
*/
@API(API.Status.EXPERIMENTAL)
-public class MatchIntermediateRule extends CascadesRule {
+public class MatchIntermediateRule extends AbstractCascadesRule {
private static final BindingMatcher quantifierMatcher = QuantifierMatchers.anyQuantifier();
private static final BindingMatcher root =
RelationalExpressionMatchers.ofTypeOwning(RelationalExpression.class, all(quantifierMatcher));
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/MatchLeafRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/MatchLeafRule.java
index 0b3d83183b..9196d4e53b 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/MatchLeafRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/MatchLeafRule.java
@@ -22,8 +22,8 @@
import com.apple.foundationdb.annotation.API;
import com.apple.foundationdb.record.EvaluationContext;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.AliasMap;
-import com.apple.foundationdb.record.query.plan.cascades.CascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.CascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.Reference;
import com.apple.foundationdb.record.query.plan.cascades.Traversal;
@@ -50,7 +50,7 @@
* further rules such as {@link MatchIntermediateRule} and {@link AdjustMatchRule}.
*/
@API(API.Status.EXPERIMENTAL)
-public class MatchLeafRule extends CascadesRule {
+public class MatchLeafRule extends AbstractCascadesRule {
// match any relational expression that is a leaf, that is, any expression that does not have any children
private static final BindingMatcher root =
RelationalExpressionMatchers.ofTypeOwning(RelationalExpression.class, CollectionMatcher.empty());
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/MergeFetchIntoCoveringIndexRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/MergeFetchIntoCoveringIndexRule.java
index d27db47876..32ebbb044e 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/MergeFetchIntoCoveringIndexRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/MergeFetchIntoCoveringIndexRule.java
@@ -21,6 +21,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
import com.apple.foundationdb.annotation.API;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.matching.structure.BindingMatcher;
@@ -38,7 +39,7 @@
* A rule that merges a fetch into a covering index scan.
*/
@API(API.Status.EXPERIMENTAL)
-public class MergeFetchIntoCoveringIndexRule extends ImplementationCascadesRule {
+public class MergeFetchIntoCoveringIndexRule extends AbstractCascadesRule implements ImplementationCascadesRule {
@Nonnull
private static final BindingMatcher innerPlanMatcher = indexPlan();
@Nonnull
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/MergeProjectionAndFetchRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/MergeProjectionAndFetchRule.java
index dddd260e02..323aa036f8 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/MergeProjectionAndFetchRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/MergeProjectionAndFetchRule.java
@@ -21,6 +21,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
import com.apple.foundationdb.annotation.API;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
@@ -46,7 +47,7 @@
*/
@API(API.Status.EXPERIMENTAL)
@SuppressWarnings("PMD.TooManyStaticImports")
-public class MergeProjectionAndFetchRule extends ImplementationCascadesRule {
+public class MergeProjectionAndFetchRule extends AbstractCascadesRule implements ImplementationCascadesRule {
@Nonnull
private static final BindingMatcher innerPlanMatcher = fetchFromPartialRecordPlan(anyPlan());
@Nonnull
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/NormalizePredicatesRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/NormalizePredicatesRule.java
index 5bec4f2e18..8a2ec95950 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/NormalizePredicatesRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/NormalizePredicatesRule.java
@@ -22,6 +22,7 @@
import com.apple.foundationdb.annotation.API;
import com.apple.foundationdb.record.query.plan.RecordQueryPlannerConfiguration;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ExplorationCascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.ExplorationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.Quantifier;
@@ -51,7 +52,7 @@
* {@link PredicateToLogicalUnionRule}.
*/
@API(API.Status.EXPERIMENTAL)
-public class NormalizePredicatesRule extends ExplorationCascadesRule {
+public class NormalizePredicatesRule extends AbstractCascadesRule implements ExplorationCascadesRule {
private static final CollectionMatcher predicatesMatcher = all(anyPredicate());
private static final CollectionMatcher innerQuantifiersMatcher = all(anyQuantifier());
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PartitionBinarySelectRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PartitionBinarySelectRule.java
index f45c1a446e..cc51aa0ee2 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PartitionBinarySelectRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PartitionBinarySelectRule.java
@@ -21,6 +21,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
import com.apple.foundationdb.annotation.API;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ExplorationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ExplorationCascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.GraphExpansion;
@@ -55,7 +56,7 @@
*/
@API(API.Status.EXPERIMENTAL)
@SuppressWarnings("PMD.TooManyStaticImports")
-public class PartitionBinarySelectRule extends ExplorationCascadesRule {
+public class PartitionBinarySelectRule extends AbstractCascadesRule implements ExplorationCascadesRule {
private static final BindingMatcher leftQuantifierMatcher = anyQuantifier();
private static final BindingMatcher rightQuantifierMatcher = anyQuantifier();
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PartitionSelectRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PartitionSelectRule.java
index f3e8774885..da62e50372 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PartitionSelectRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PartitionSelectRule.java
@@ -22,10 +22,11 @@
import com.apple.foundationdb.annotation.API;
import com.apple.foundationdb.record.RecordCoreException;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.Column;
import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier;
-import com.apple.foundationdb.record.query.plan.cascades.ExplorationCascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.ExplorationCascadesRule;
+import com.apple.foundationdb.record.query.plan.cascades.ExplorationCascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.GraphExpansion;
import com.apple.foundationdb.record.query.plan.cascades.Quantifier;
import com.apple.foundationdb.record.query.plan.cascades.expressions.SelectExpression;
@@ -58,7 +59,7 @@
*/
@API(API.Status.EXPERIMENTAL)
@SuppressWarnings("PMD.TooManyStaticImports")
-public class PartitionSelectRule extends ExplorationCascadesRule {
+public class PartitionSelectRule extends AbstractCascadesRule implements ExplorationCascadesRule {
private static final CollectionMatcher combinationQuantifierMatcher = all(anyQuantifier());
private static final BindingMatcher root =
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PredicatePushDownRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PredicatePushDownRule.java
index 3ae8f51852..b00a0dace6 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PredicatePushDownRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PredicatePushDownRule.java
@@ -21,6 +21,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
import com.apple.foundationdb.annotation.API;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.AliasMap;
import com.apple.foundationdb.record.query.plan.cascades.ExplorationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ExplorationCascadesRuleCall;
@@ -174,7 +175,7 @@
*/
@API(API.Status.EXPERIMENTAL)
@SuppressWarnings("PMD.TooManyStaticImports")
-public class PredicatePushDownRule extends ExplorationCascadesRule {
+public class PredicatePushDownRule extends AbstractCascadesRule implements ExplorationCascadesRule {
@Nonnull
private static final CollectionMatcher belowExpressionsMatcher = all(anyExpression());
@Nonnull
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PredicateToLogicalUnionRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PredicateToLogicalUnionRule.java
index f90549e40c..57632ad35a 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PredicateToLogicalUnionRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PredicateToLogicalUnionRule.java
@@ -24,7 +24,7 @@
import com.apple.foundationdb.record.EvaluationContext;
import com.apple.foundationdb.record.query.plan.RecordQueryPlannerConfiguration;
import com.apple.foundationdb.record.query.plan.cascades.AliasMap;
-import com.apple.foundationdb.record.query.plan.cascades.CascadesRule;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.CascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier;
import com.apple.foundationdb.record.query.plan.cascades.Reference;
@@ -121,7 +121,7 @@
*/
@API(API.Status.EXPERIMENTAL)
@SuppressWarnings("PMD.TooManyStaticImports")
-public class PredicateToLogicalUnionRule extends CascadesRule {
+public class PredicateToLogicalUnionRule extends AbstractCascadesRule {
public static final int DEFAULT_MAX_NUM_CONJUNCTS = 9; // 510 combinations
@Nonnull
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PullUpNullOnEmptyRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PullUpNullOnEmptyRule.java
index 516aca019e..7b51c4e8d9 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PullUpNullOnEmptyRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PullUpNullOnEmptyRule.java
@@ -20,6 +20,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ExplorationCascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.ExplorationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.GraphExpansion;
@@ -51,7 +52,7 @@
* the predicates on top of its {@link Quantifier} with {@code null-on-empty} giving them a chance of acting on any {@code null}s
* produced by this quantifier, which guarantees semantic equivalency.
*/
-public class PullUpNullOnEmptyRule extends ExplorationCascadesRule {
+public class PullUpNullOnEmptyRule extends AbstractCascadesRule implements ExplorationCascadesRule {
@Nonnull
private static final BindingMatcher defaultOnEmptyQuantifier = forEachQuantifierWithDefaultOnEmptyOverRef(anyRef());
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushDistinctBelowFilterRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushDistinctBelowFilterRule.java
index a4bf64e7bd..dba0a32fec 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushDistinctBelowFilterRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushDistinctBelowFilterRule.java
@@ -20,6 +20,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.Quantifier;
@@ -75,7 +76,7 @@
*
* where pred' is rebased along the translation from qun to newQun.
*/
-public class PushDistinctBelowFilterRule extends ImplementationCascadesRule {
+public class PushDistinctBelowFilterRule extends AbstractCascadesRule implements ImplementationCascadesRule {
@Nonnull
private static final BindingMatcher extends Reference> innerRefMatcher = anyRefOverOnlyPlans();
@Nonnull
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushDistinctThroughFetchRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushDistinctThroughFetchRule.java
index 159c7e3dff..d815f1e287 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushDistinctThroughFetchRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushDistinctThroughFetchRule.java
@@ -21,6 +21,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
import com.apple.foundationdb.annotation.API;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
@@ -71,7 +72,7 @@
*
*/
@API(API.Status.EXPERIMENTAL)
-public class PushDistinctThroughFetchRule extends ImplementationCascadesRule {
+public class PushDistinctThroughFetchRule extends AbstractCascadesRule implements ImplementationCascadesRule {
@Nonnull
private static final BindingMatcher innerPlanMatcher = anyPlan();
@Nonnull
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushFilterThroughFetchRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushFilterThroughFetchRule.java
index 84c816d2e2..5fde250ca9 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushFilterThroughFetchRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushFilterThroughFetchRule.java
@@ -22,6 +22,7 @@
import com.apple.foundationdb.annotation.API;
import com.apple.foundationdb.record.query.plan.cascades.AliasMap;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
@@ -138,7 +139,7 @@
*
*/
@API(API.Status.EXPERIMENTAL)
-public class PushFilterThroughFetchRule extends ImplementationCascadesRule {
+public class PushFilterThroughFetchRule extends AbstractCascadesRule implements ImplementationCascadesRule {
@Nonnull
private static final BindingMatcher innerPlanMatcher = anyPlan();
@Nonnull
@@ -240,9 +241,9 @@ private QueryPredicate pushLeafPredicate(@Nonnull final RecordQueryFetchFromPart
final var pushedLeafPredicateOptional =
predicateWithValue.translateValueAndComparisonsMaybe(
value -> fetchPlan.pushValue(value, oldInnerAlias, newInnerAlias),
- comparison -> comparison.replaceValuesMaybe(value -> {
- return fetchPlan.pushValue(value, oldInnerAlias, newInnerAlias);
- }));
+ comparison ->
+ comparison.replaceValuesMaybe(value -> fetchPlan.pushValue(value, oldInnerAlias,
+ newInnerAlias)));
// Something went wrong when attempting to push this value through the fetch.
// We must return null to prevent pushing of this conjunct.
return pushedLeafPredicateOptional.orElse(null);
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushInJoinThroughFetchRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushInJoinThroughFetchRule.java
index 948e7d5959..e2a71a689e 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushInJoinThroughFetchRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushInJoinThroughFetchRule.java
@@ -21,6 +21,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
import com.apple.foundationdb.annotation.API;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
import com.apple.foundationdb.record.query.plan.cascades.Quantifier;
@@ -80,7 +81,7 @@
* {@link RecordQueryInValuesJoinPlan} and {@link RecordQueryInParameterJoinPlan}.
*/
@API(API.Status.EXPERIMENTAL)
-public class PushInJoinThroughFetchRule extends ImplementationCascadesRule
{
+public class PushInJoinThroughFetchRule
extends AbstractCascadesRule
implements ImplementationCascadesRule
{
@Nonnull
private static final BindingMatcher innerPlanMatcher = anyPlan();
@Nonnull
diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushMapThroughFetchRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushMapThroughFetchRule.java
index 9aea56db10..6ea1a13930 100644
--- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushMapThroughFetchRule.java
+++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushMapThroughFetchRule.java
@@ -21,6 +21,7 @@
package com.apple.foundationdb.record.query.plan.cascades.rules;
import com.apple.foundationdb.annotation.API;
+import com.apple.foundationdb.record.query.plan.cascades.AbstractCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRule;
import com.apple.foundationdb.record.query.plan.cascades.ImplementationCascadesRuleCall;
@@ -113,7 +114,7 @@
*
*/
@API(API.Status.EXPERIMENTAL)
-public class PushMapThroughFetchRule extends ImplementationCascadesRule {
+public class PushMapThroughFetchRule extends AbstractCascadesRule