24
24
import com .apple .foundationdb .record .query .plan .cascades .CascadesRuleCall ;
25
25
import com .apple .foundationdb .record .query .plan .cascades .GraphExpansion ;
26
26
import com .apple .foundationdb .record .query .plan .cascades .Quantifier ;
27
- import com .apple .foundationdb .record .query .plan .cascades .Reference ;
28
27
import com .apple .foundationdb .record .query .plan .cascades .expressions .RelationalExpression ;
29
28
import com .apple .foundationdb .record .query .plan .cascades .expressions .SelectExpression ;
30
29
import 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 ;
33
30
import com .google .common .collect .Iterables ;
34
31
35
32
import javax .annotation .Nonnull ;
@@ -71,21 +68,26 @@ public void onMatch(@Nonnull final CascadesRuleCall call) {
71
68
final var bindings = call .getBindings ();
72
69
final var selectExpression = bindings .get (root );
73
70
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
+ }
80
82
}
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 ;
87
85
}
88
- call .memoizeReference (newChildrenQuantifier .getRangesOver ());
86
+
87
+ final var newChildrenQuantifier =
88
+ Quantifier .forEachBuilder ()
89
+ .withAlias (quantifier .getAlias ())
90
+ .build (quantifier .getRangesOver ());
89
91
90
92
// Create the lower select expression.
91
93
final var newSelectExpression = call .memoizeExpression (GraphExpansion .builder ()
@@ -102,27 +104,32 @@ public void onMatch(@Nonnull final CascadesRuleCall call) {
102
104
call .yieldExpression (topLevelSelectExpression );
103
105
}
104
106
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 ) {
111
110
if (!(expression instanceof SelectExpression )) {
112
- return true ;
111
+ return ExpressionClassification . DO_NOT_CARE ;
113
112
}
114
113
115
114
final var selectExpression = (SelectExpression )expression ;
116
115
if (selectExpression .getQuantifiers ().size () > 1 ) {
117
- return true ;
116
+ return ExpressionClassification . PULL_UP ;
118
117
}
119
118
if (!Iterables .getOnlyElement (selectExpression .getQuantifiers ()).getAlias ().equals (quantifier .getAlias ())) {
120
- return true ;
119
+ return ExpressionClassification . PULL_UP ;
121
120
}
122
121
123
122
// if all predicates are not the same, bail out, otherwise, we can pull up.
124
123
final var predicates = selectOnTopExpression .getPredicates ();
125
124
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
127
134
}
128
135
}
0 commit comments