2424import com .apple .foundationdb .record .query .plan .cascades .CascadesRuleCall ;
2525import com .apple .foundationdb .record .query .plan .cascades .GraphExpansion ;
2626import com .apple .foundationdb .record .query .plan .cascades .Quantifier ;
27- import com .apple .foundationdb .record .query .plan .cascades .Reference ;
2827import com .apple .foundationdb .record .query .plan .cascades .expressions .RelationalExpression ;
2928import com .apple .foundationdb .record .query .plan .cascades .expressions .SelectExpression ;
3029import com .apple .foundationdb .record .query .plan .cascades .matching .structure .BindingMatcher ;
31- import com .apple .foundationdb .record .query .plan .plans .RecordQueryPlan ;
32- import com .google .common .collect .ImmutableList ;
3330import com .google .common .collect .Iterables ;
3431
3532import javax .annotation .Nonnull ;
@@ -71,21 +68,26 @@ public void onMatch(@Nonnull final CascadesRuleCall call) {
7168 final var bindings = call .getBindings ();
7269 final var selectExpression = bindings .get (root );
7370 final var quantifier = bindings .get (defaultOnEmptyQuantifier );
74- final var childExpressions = quantifier .getRangesOver ().getMembers ().stream ()
75- .filter (expression -> isPermittedToPullFrom (selectExpression , quantifier , expression ))
76- .collect (ImmutableList .toImmutableList ());
77- if (childExpressions .isEmpty ()) {
78- // it is impossible to pull the expression up, or it might introduce infinite recursion, bailout.
79- return ;
71+ final var childrenExpressions = quantifier .getRangesOver ().getMembers ();
72+ boolean pullUpDesired = false ;
73+ for (final var childExpression : childrenExpressions ) {
74+ final var childClassification =
75+ classifyExpression (selectExpression , quantifier , childExpression );
76+ if (childClassification == ExpressionClassification .DO_NOT_PULL_UP ) {
77+ return ;
78+ }
79+ if (childClassification == ExpressionClassification .PULL_UP ) {
80+ pullUpDesired = true ;
81+ }
8082 }
81-
82- final Quantifier .ForEach newChildrenQuantifier ;
83- if (childExpressions .size () < quantifier .getRangesOver ().getMembers ().size ()) {
84- newChildrenQuantifier = Quantifier .forEach (Reference .from (childExpressions ), quantifier .getAlias ());
85- } else {
86- newChildrenQuantifier = Quantifier .forEachBuilder ().withAlias (quantifier .getAlias ()).build (quantifier .getRangesOver ());
83+ if (!pullUpDesired ) {
84+ return ;
8785 }
88- call .memoizeReference (newChildrenQuantifier .getRangesOver ());
86+
87+ final var newChildrenQuantifier =
88+ Quantifier .forEachBuilder ()
89+ .withAlias (quantifier .getAlias ())
90+ .build (quantifier .getRangesOver ());
8991
9092 // Create the lower select expression.
9193 final var newSelectExpression = call .memoizeExpression (GraphExpansion .builder ()
@@ -102,27 +104,32 @@ public void onMatch(@Nonnull final CascadesRuleCall call) {
102104 call .yieldExpression (topLevelSelectExpression );
103105 }
104106
105- public boolean isPermittedToPullFrom (@ Nonnull final SelectExpression selectOnTopExpression ,
106- @ Nonnull final Quantifier .ForEach quantifier ,
107- @ Nonnull final RelationalExpression expression ) {
108- if (expression instanceof RecordQueryPlan ) {
109- return false ;
110- }
107+ private ExpressionClassification classifyExpression (@ Nonnull final SelectExpression selectOnTopExpression ,
108+ @ Nonnull final Quantifier .ForEach quantifier ,
109+ @ Nonnull final RelationalExpression expression ) {
111110 if (!(expression instanceof SelectExpression )) {
112- return true ;
111+ return ExpressionClassification . DO_NOT_CARE ;
113112 }
114113
115114 final var selectExpression = (SelectExpression )expression ;
116115 if (selectExpression .getQuantifiers ().size () > 1 ) {
117- return true ;
116+ return ExpressionClassification . PULL_UP ;
118117 }
119118 if (!Iterables .getOnlyElement (selectExpression .getQuantifiers ()).getAlias ().equals (quantifier .getAlias ())) {
120- return true ;
119+ return ExpressionClassification . PULL_UP ;
121120 }
122121
123122 // if all predicates are not the same, bail out, otherwise, we can pull up.
124123 final var predicates = selectOnTopExpression .getPredicates ();
125124 final var otherPredicates = selectExpression .getPredicates ();
126- return !predicates .equals (otherPredicates );
125+ return !predicates .equals (otherPredicates )
126+ ? ExpressionClassification .PULL_UP
127+ : ExpressionClassification .DO_NOT_PULL_UP ;
128+ }
129+
130+ private enum ExpressionClassification {
131+ DO_NOT_CARE ,
132+ DO_NOT_PULL_UP ,
133+ PULL_UP
127134 }
128135}
0 commit comments