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
/**
@@ -248,19 +256,31 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me
248
256
RecordQuerySetPlan .resolveComparisonDirection (comparisonOrderingParts );
249
257
comparisonOrderingParts = RecordQuerySetPlan .adjustFixedBindings (comparisonOrderingParts , comparisonIsReverse );
250
258
251
- final var newQuantifiers =
252
- partition
253
- .stream ()
254
- .map (pair -> Objects .requireNonNull (matchToPlanMap .get (pair .getElement ().getPartialMatch ())))
255
- .map (memoizer ::memoizePlans )
256
- .map (Quantifier ::physical )
257
- .collect (ImmutableList .toImmutableList ());
259
+ final var newQuantifiersBuilder = ImmutableList .<Quantifier .Physical >builder ();
260
+ final var candidateTopAliasesBuilder = ImmutableList .<CorrelationIdentifier >builder ();
261
+ for (final var singleMatchedAccessWithIndex : partition ) {
262
+ final var singleMatchedAccess = singleMatchedAccessWithIndex .getElement ();
263
+ final var plan = Objects .requireNonNull (matchToPlanMap .get (
264
+ singleMatchedAccess .getPartialMatch ()));
265
+ final var reference = memoizer .memoizePlans (plan );
266
+ newQuantifiersBuilder .add (Quantifier .physical (reference ));
267
+ candidateTopAliasesBuilder .add (singleMatchedAccess .getCandidateTopAlias ());
268
+ }
258
269
270
+ final var newQuantifiers = newQuantifiersBuilder .build ();
271
+ final var commonAndPickUpValues =
272
+ computeCommonAndPickUpValues (partition , commonPrimaryKeyValues .size ());
273
+ final var intersectionResultValue =
274
+ computeIntersectionResultValue (newQuantifiers , commonAndPickUpValues .getLeft (), commonAndPickUpValues .getRight ());
259
275
final var intersectionPlan =
260
- RecordQueryIntersectionPlan . fromQuantifiers (newQuantifiers ,
261
- comparisonOrderingParts , comparisonIsReverse );
276
+ RecordQueryMultiIntersectionOnValuesPlan . intersection (newQuantifiers ,
277
+ comparisonOrderingParts , intersectionResultValue , comparisonIsReverse );
262
278
final var compensatedIntersection =
263
- compensation .applyAllNeededCompensations (memoizer , intersectionPlan );
279
+ compensation .applyAllNeededCompensations (memoizer , intersectionPlan ,
280
+ baseAlias -> computeTranslationMap (baseAlias ,
281
+ newQuantifiers , candidateTopAliasesBuilder .build (),
282
+ (Type .Record )intersectionResultValue .getResultType (),
283
+ commonPrimaryKeyValues .size ()));
264
284
expressionsBuilder .add (compensatedIntersection );
265
285
}
266
286
}
@@ -269,4 +289,79 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me
269
289
return IntersectionResult .of (hasCommonOrdering ? intersectionOrdering : null , compensation ,
270
290
expressionsBuilder .build ());
271
291
}
292
+
293
+ @ Nonnull
294
+ private static NonnullPair <List <Value >, List <Value >> computeCommonAndPickUpValues (@ Nonnull final List <Vectored <SingleMatchedAccess >> partition ,
295
+ final int numGrouped ) {
296
+ final var commonValuesAndPickUpValueByAccess =
297
+ partition
298
+ .stream ()
299
+ .map (singleMatchedAccessWithIndex ->
300
+ singleMatchedAccessWithIndex .getElement ()
301
+ .getPartialMatch ()
302
+ .getMatchCandidate ())
303
+ .map (matchCandidate -> (AggregateIndexMatchCandidate )matchCandidate )
304
+ .map (AggregateIndexMatchCandidate ::getGroupingAndAggregateAccessors )
305
+ .collect (ImmutableList .toImmutableList ());
306
+
307
+ final var pickUpValuesBuilder = ImmutableList .<Value >builder ();
308
+ for (int i = 0 ; i < commonValuesAndPickUpValueByAccess .size (); i ++) {
309
+ final var commonAndPickUpValuePair = commonValuesAndPickUpValueByAccess .get (i );
310
+ final var commonValues = commonAndPickUpValuePair .getLeft ();
311
+ Verify .verify (commonValues .size () == numGrouped );
312
+ final var pickUpValue = commonAndPickUpValuePair .getRight ();
313
+ pickUpValuesBuilder .add (pickUpValue );
314
+ }
315
+ return NonnullPair .of (commonValuesAndPickUpValueByAccess .get (0 ).getLeft (), pickUpValuesBuilder .build ());
316
+ }
317
+
318
+ @ Nonnull
319
+ private static Value computeIntersectionResultValue (@ Nonnull final List <? extends Quantifier > quantifiers ,
320
+ @ Nonnull final List <Value > commonValues ,
321
+ @ Nonnull final List <Value > pickUpValues ) {
322
+ final var columnBuilder = ImmutableList .<Column <? extends Value >>builder ();
323
+
324
+ // grab the common values from the first quantifier
325
+ final var commonTranslationMap =
326
+ TranslationMap .ofAliases (Quantifier .current (), quantifiers .get (0 ).getAlias ());
327
+ for (final var commonValue : commonValues ) {
328
+ columnBuilder .add (Column .unnamedOf (commonValue .translateCorrelations (commonTranslationMap )));
329
+ }
330
+
331
+ for (int i = 0 ; i < quantifiers .size (); i ++) {
332
+ final var quantifier = quantifiers .get (i );
333
+ final var pickUpTranslationMap =
334
+ TranslationMap .ofAliases (Quantifier .current (), quantifier .getAlias ());
335
+ columnBuilder .add (Column .unnamedOf (pickUpValues .get (i ).translateCorrelations (pickUpTranslationMap )));
336
+ }
337
+
338
+ return RecordConstructorValue .ofColumns (columnBuilder .build ());
339
+ }
340
+
341
+ private static TranslationMap computeTranslationMap (@ Nonnull final CorrelationIdentifier intersectionAlias ,
342
+ @ Nonnull final List <? extends Quantifier > quantifiers ,
343
+ @ Nonnull final List <CorrelationIdentifier > candidateTopAliases ,
344
+ @ Nonnull final Type .Record intersectionResultType ,
345
+ final int numGrouped ) {
346
+ final var builder = TranslationMap .builder ();
347
+ final var deconstructedIntersectionValues =
348
+ Values .deconstructRecord (QuantifiedObjectValue .of (intersectionAlias , intersectionResultType ));
349
+ for (int quantifierIndex = 0 ; quantifierIndex < quantifiers .size (); quantifierIndex ++) {
350
+ final var quantifier = quantifiers .get (quantifierIndex );
351
+ final var quantifierFlowedObjectType = (Type .Record )quantifier .getFlowedObjectType ();
352
+ final var quantifierFields = quantifierFlowedObjectType .getFields ();
353
+ Verify .verify (quantifierFields .size () == numGrouped + 1 );
354
+ final var columnBuilder =
355
+ ImmutableList .<Column <? extends Value >>builder ();
356
+ for (int columnIndex = 0 ; columnIndex < numGrouped ; columnIndex ++) {
357
+ columnBuilder .add (Column .of (quantifierFields .get (columnIndex ), deconstructedIntersectionValues .get (columnIndex )));
358
+ }
359
+ columnBuilder .add (Column .of (quantifierFields .get (numGrouped ),
360
+ deconstructedIntersectionValues .get (numGrouped + quantifierIndex )));
361
+ builder .when (candidateTopAliases .get (quantifierIndex )).then ((alias , leaf ) ->
362
+ RecordConstructorValue .ofColumns (columnBuilder .build ()));
363
+ }
364
+
365
+ return builder .build ();
366
+ }
272
367
}
0 commit comments