21
21
package com .apple .foundationdb .record .query .plan .cascades .rules ;
22
22
23
23
import com .apple .foundationdb .annotation .API ;
24
+ import com .apple .foundationdb .record .query .plan .cascades .AggregateIndexMatchCandidate ;
24
25
import com .apple .foundationdb .record .query .plan .cascades .AliasMap ;
25
26
import com .apple .foundationdb .record .query .plan .cascades .CascadesPlanner ;
26
27
import com .apple .foundationdb .record .query .plan .cascades .CascadesRuleCall ;
28
+ import com .apple .foundationdb .record .query .plan .cascades .Column ;
27
29
import com .apple .foundationdb .record .query .plan .cascades .ComparisonRange ;
28
30
import com .apple .foundationdb .record .query .plan .cascades .Compensation ;
29
31
import com .apple .foundationdb .record .query .plan .cascades .CorrelationIdentifier ;
39
41
import com .apple .foundationdb .record .query .plan .cascades .expressions .RelationalExpression ;
40
42
import com .apple .foundationdb .record .query .plan .cascades .expressions .SelectExpression ;
41
43
import com .apple .foundationdb .record .query .plan .cascades .matching .structure .BindingMatcher ;
44
+ import com .apple .foundationdb .record .query .plan .cascades .typing .Type ;
45
+ import com .apple .foundationdb .record .query .plan .cascades .values .QuantifiedObjectValue ;
46
+ import com .apple .foundationdb .record .query .plan .cascades .values .RecordConstructorValue ;
42
47
import com .apple .foundationdb .record .query .plan .cascades .values .Value ;
43
- import com .apple .foundationdb .record .query .plan .plans .RecordQueryIntersectionPlan ;
48
+ import com .apple .foundationdb .record .query .plan .cascades .values .Values ;
49
+ import com .apple .foundationdb .record .query .plan .cascades .values .translation .TranslationMap ;
50
+ import com .apple .foundationdb .record .query .plan .plans .RecordQueryMultiIntersectionOnValuesPlan ;
44
51
import com .apple .foundationdb .record .query .plan .plans .RecordQueryPlan ;
45
52
import com .apple .foundationdb .record .query .plan .plans .RecordQuerySetPlan ;
46
53
import com .apple .foundationdb .record .util .pair .NonnullPair ;
47
54
import com .apple .foundationdb .record .util .pair .Pair ;
55
+ import com .google .common .base .Verify ;
48
56
import com .google .common .collect .ImmutableList ;
49
57
import com .google .common .collect .ImmutableSet ;
50
58
import com .google .common .collect .Iterables ;
62
70
63
71
import static com .apple .foundationdb .record .query .plan .cascades .matching .structure .MatchPartitionMatchers .ofExpressionAndMatches ;
64
72
import static com .apple .foundationdb .record .query .plan .cascades .matching .structure .MultiMatcher .some ;
65
- import static com .apple .foundationdb .record .query .plan .cascades .matching .structure .PartialMatchMatchers .matchingAggregateIndexMatchCandidate ;
66
73
import static com .apple .foundationdb .record .query .plan .cascades .matching .structure .PartialMatchMatchers .completeMatch ;
74
+ import static com .apple .foundationdb .record .query .plan .cascades .matching .structure .PartialMatchMatchers .matchingAggregateIndexMatchCandidate ;
67
75
import static com .apple .foundationdb .record .query .plan .cascades .matching .structure .RelationalExpressionMatchers .anyExpression ;
68
76
69
77
/**
@@ -246,19 +254,31 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me
246
254
RecordQuerySetPlan .resolveComparisonDirection (comparisonOrderingParts );
247
255
comparisonOrderingParts = RecordQuerySetPlan .adjustFixedBindings (comparisonOrderingParts , comparisonIsReverse );
248
256
249
- final var newQuantifiers =
250
- partition
251
- .stream ()
252
- .map (pair -> Objects .requireNonNull (matchToPlanMap .get (pair .getElement ().getPartialMatch ())))
253
- .map (memoizer ::memoizePlans )
254
- .map (Quantifier ::physical )
255
- .collect (ImmutableList .toImmutableList ());
257
+ final var newQuantifiersBuilder = ImmutableList .<Quantifier .Physical >builder ();
258
+ final var candidateTopAliasesBuilder = ImmutableList .<CorrelationIdentifier >builder ();
259
+ for (final var singleMatchedAccessWithIndex : partition ) {
260
+ final var singleMatchedAccess = singleMatchedAccessWithIndex .getElement ();
261
+ final var plan = Objects .requireNonNull (matchToPlanMap .get (
262
+ singleMatchedAccess .getPartialMatch ()));
263
+ final var reference = memoizer .memoizePlans (plan );
264
+ newQuantifiersBuilder .add (Quantifier .physical (reference ));
265
+ candidateTopAliasesBuilder .add (singleMatchedAccess .getCandidateTopAlias ());
266
+ }
256
267
268
+ final var newQuantifiers = newQuantifiersBuilder .build ();
269
+ final var commonAndPickUpValues =
270
+ computeCommonAndPickUpValues (partition , commonPrimaryKeyValues .size ());
271
+ final var intersectionResultValue =
272
+ computeIntersectionResultValue (newQuantifiers , commonAndPickUpValues .getLeft (), commonAndPickUpValues .getRight ());
257
273
final var intersectionPlan =
258
- RecordQueryIntersectionPlan . fromQuantifiers (newQuantifiers ,
259
- comparisonOrderingParts , comparisonIsReverse );
274
+ RecordQueryMultiIntersectionOnValuesPlan . intersection (newQuantifiers ,
275
+ comparisonOrderingParts , intersectionResultValue , comparisonIsReverse );
260
276
final var compensatedIntersection =
261
- compensation .applyAllNeededCompensations (memoizer , intersectionPlan );
277
+ compensation .applyAllNeededCompensations (memoizer , intersectionPlan ,
278
+ baseAlias -> computeTranslationMap (baseAlias ,
279
+ newQuantifiers , candidateTopAliasesBuilder .build (),
280
+ (Type .Record )intersectionResultValue .getResultType (),
281
+ commonPrimaryKeyValues .size ()));
262
282
expressionsBuilder .add (compensatedIntersection );
263
283
}
264
284
}
@@ -267,4 +287,79 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me
267
287
return IntersectionResult .of (hasCommonOrdering ? intersectionOrdering : null , compensation ,
268
288
expressionsBuilder .build ());
269
289
}
290
+
291
+ @ Nonnull
292
+ private static NonnullPair <List <Value >, List <Value >> computeCommonAndPickUpValues (@ Nonnull final List <Vectored <SingleMatchedAccess >> partition ,
293
+ final int numGrouped ) {
294
+ final var commonValuesAndPickUpValueByAccess =
295
+ partition
296
+ .stream ()
297
+ .map (singleMatchedAccessWithIndex ->
298
+ singleMatchedAccessWithIndex .getElement ()
299
+ .getPartialMatch ()
300
+ .getMatchCandidate ())
301
+ .map (matchCandidate -> (AggregateIndexMatchCandidate )matchCandidate )
302
+ .map (AggregateIndexMatchCandidate ::getGroupingAndAggregateAccessors )
303
+ .collect (ImmutableList .toImmutableList ());
304
+
305
+ final var pickUpValuesBuilder = ImmutableList .<Value >builder ();
306
+ for (int i = 0 ; i < commonValuesAndPickUpValueByAccess .size (); i ++) {
307
+ final var commonAndPickUpValuePair = commonValuesAndPickUpValueByAccess .get (i );
308
+ final var commonValues = commonAndPickUpValuePair .getLeft ();
309
+ Verify .verify (commonValues .size () == numGrouped );
310
+ final var pickUpValue = commonAndPickUpValuePair .getRight ();
311
+ pickUpValuesBuilder .add (pickUpValue );
312
+ }
313
+ return NonnullPair .of (commonValuesAndPickUpValueByAccess .get (0 ).getLeft (), pickUpValuesBuilder .build ());
314
+ }
315
+
316
+ @ Nonnull
317
+ private static Value computeIntersectionResultValue (@ Nonnull final List <? extends Quantifier > quantifiers ,
318
+ @ Nonnull final List <Value > commonValues ,
319
+ @ Nonnull final List <Value > pickUpValues ) {
320
+ final var columnBuilder = ImmutableList .<Column <? extends Value >>builder ();
321
+
322
+ // grab the common values from the first quantifier
323
+ final var commonTranslationMap =
324
+ TranslationMap .ofAliases (Quantifier .current (), quantifiers .get (0 ).getAlias ());
325
+ for (final var commonValue : commonValues ) {
326
+ columnBuilder .add (Column .unnamedOf (commonValue .translateCorrelations (commonTranslationMap )));
327
+ }
328
+
329
+ for (int i = 0 ; i < quantifiers .size (); i ++) {
330
+ final var quantifier = quantifiers .get (i );
331
+ final var pickUpTranslationMap =
332
+ TranslationMap .ofAliases (Quantifier .current (), quantifier .getAlias ());
333
+ columnBuilder .add (Column .unnamedOf (pickUpValues .get (i ).translateCorrelations (pickUpTranslationMap )));
334
+ }
335
+
336
+ return RecordConstructorValue .ofColumns (columnBuilder .build ());
337
+ }
338
+
339
+ private static TranslationMap computeTranslationMap (@ Nonnull final CorrelationIdentifier intersectionAlias ,
340
+ @ Nonnull final List <? extends Quantifier > quantifiers ,
341
+ @ Nonnull final List <CorrelationIdentifier > candidateTopAliases ,
342
+ @ Nonnull final Type .Record intersectionResultType ,
343
+ final int numGrouped ) {
344
+ final var builder = TranslationMap .builder ();
345
+ final var deconstructedIntersectionValues =
346
+ Values .deconstructRecord (QuantifiedObjectValue .of (intersectionAlias , intersectionResultType ));
347
+ for (int quantifierIndex = 0 ; quantifierIndex < quantifiers .size (); quantifierIndex ++) {
348
+ final var quantifier = quantifiers .get (quantifierIndex );
349
+ final var quantifierFlowedObjectType = (Type .Record )quantifier .getFlowedObjectType ();
350
+ final var quantifierFields = quantifierFlowedObjectType .getFields ();
351
+ Verify .verify (quantifierFields .size () == numGrouped + 1 );
352
+ final var columnBuilder =
353
+ ImmutableList .<Column <? extends Value >>builder ();
354
+ for (int columnIndex = 0 ; columnIndex < numGrouped ; columnIndex ++) {
355
+ columnBuilder .add (Column .of (quantifierFields .get (columnIndex ), deconstructedIntersectionValues .get (columnIndex )));
356
+ }
357
+ columnBuilder .add (Column .of (quantifierFields .get (numGrouped ),
358
+ deconstructedIntersectionValues .get (numGrouped + quantifierIndex )));
359
+ builder .when (candidateTopAliases .get (quantifierIndex )).then ((alias , leaf ) ->
360
+ RecordConstructorValue .ofColumns (columnBuilder .build ()));
361
+ }
362
+
363
+ return builder .build ();
364
+ }
270
365
}
0 commit comments