25
25
import com .apple .foundationdb .record .PlanSerializationContext ;
26
26
import com .apple .foundationdb .record .planprotos .PValue ;
27
27
import com .apple .foundationdb .record .query .expressions .Comparisons ;
28
+ import com .apple .foundationdb .record .query .plan .cascades .AggregateIndexExpansionVisitor ;
28
29
import com .apple .foundationdb .record .query .plan .cascades .AliasMap ;
29
30
import com .apple .foundationdb .record .query .plan .cascades .BooleanWithConstraint ;
30
31
import com .apple .foundationdb .record .query .plan .cascades .Column ;
85
86
import java .util .function .BiFunction ;
86
87
import java .util .function .Supplier ;
87
88
88
- import static com .apple .foundationdb .record .query .plan .cascades .BooleanWithConstraint .alwaysTrue ;
89
- import static com .apple .foundationdb .record .query .plan .cascades .BooleanWithConstraint .falseValue ;
90
-
91
89
/**
92
90
* A logical {@code group by} expression that represents grouping incoming tuples and aggregating each group.
93
91
*/
@@ -339,7 +337,7 @@ public Iterable<MatchInfo> subsumedBy(@Nonnull final RelationalExpression candid
339
337
if (otherAggregateValues .size () != 1 ) {
340
338
return ImmutableList .of ();
341
339
}
342
- final var otherPrimitiveAggregateValue = Iterables .getOnlyElement (otherAggregateValues );
340
+ final var otherPrimitiveAggregateValue = ( IndexableAggregateValue ) Iterables .getOnlyElement (otherAggregateValues );
343
341
final var matchedAggregatesMapBuilder = ImmutableBiMap .<Value , Value >builder ();
344
342
final var unmatchedAggregatesMapBuilder =
345
343
ImmutableBiMap .<CorrelationIdentifier , Value >builder ();
@@ -377,6 +375,12 @@ public Iterable<MatchInfo> subsumedBy(@Nonnull final RelationalExpression candid
377
375
final var matchedGroupingsMap = subsumedGroupingsResult .getMatchedGroupingsMap ();
378
376
final var rollUpToGroupingValues = subsumedGroupingsResult .getRollUpToValues ();
379
377
378
+ if (rollUpToGroupingValues != null &&
379
+ !AggregateIndexExpansionVisitor .canBeRolledUp (otherPrimitiveAggregateValue .getIndexTypeName ())) {
380
+ // We determined we need a roll up, but we cannot do it base on the aggregations.
381
+ return ImmutableList .of ();
382
+ }
383
+
380
384
final var unmatchedTranslatedAggregateValueMap =
381
385
unmatchedTranslatedAggregatesValueMapBuilder .buildKeepingLast ();
382
386
final var translatedResultValue = getResultValue ().translateCorrelations (translationMap , true );
@@ -414,7 +418,7 @@ private SubsumedGroupingsResult subsumedGroupings(@Nonnull final Quantifier cand
414
418
@ Nonnull final TranslationMap translationMap ,
415
419
@ Nonnull final ValueEquivalence valueEquivalence ) {
416
420
if (groupingValue == null && candidateGroupingValue == null ) {
417
- return SubsumedGroupingsResult .withoutRollUp (alwaysTrue (), ImmutableBiMap .of ());
421
+ return SubsumedGroupingsResult .withoutRollUp (BooleanWithConstraint . alwaysTrue (), ImmutableBiMap .of ());
418
422
}
419
423
if (candidateGroupingValue == null ) {
420
424
return SubsumedGroupingsResult .noSubsumption ();
@@ -424,7 +428,7 @@ private SubsumedGroupingsResult subsumedGroupings(@Nonnull final Quantifier cand
424
428
final BiMap <Value , Value > matchedGroupingsMap ;
425
429
if (groupingValue != null ) {
426
430
final var translatedGroupingsValuesBuilder = ImmutableList .<Value >builder ();
427
- final var matchedGroupingsMapBuilder = ImmutableBiMap .<Value , Value >builder ();
431
+ final var matchedGroupingsMapBuilder = ImmutableMap .<Value , Value >builder ();
428
432
final var groupingValues =
429
433
Values .primitiveAccessorsForType (groupingValue .getResultType (), () -> groupingValue ).stream ()
430
434
.map (primitiveGroupingValue -> primitiveGroupingValue .simplify (AliasMap .emptyMap (),
@@ -438,7 +442,14 @@ private SubsumedGroupingsResult subsumedGroupings(@Nonnull final Quantifier cand
438
442
matchedGroupingsMapBuilder .put (primitiveGroupingValue , translatedPrimitiveGroupingValue );
439
443
}
440
444
translatedGroupingValues = translatedGroupingsValuesBuilder .build ();
441
- matchedGroupingsMap = matchedGroupingsMapBuilder .build ();
445
+
446
+ //
447
+ // We know that if there are duplicates, they will be on the query side. Immutable bi-maps do not support
448
+ // duplicated keys at all while regular maps do. The simplest and also the cheapest solution is to just
449
+ // use an immutable map builder (which then is de-duped when built) and then use that map to build the
450
+ // bi-map.
451
+ //
452
+ matchedGroupingsMap = ImmutableBiMap .copyOf (matchedGroupingsMapBuilder .buildKeepingLast ());
442
453
} else {
443
454
translatedGroupingValues = ImmutableList .of ();
444
455
matchedGroupingsMap = ImmutableBiMap .of ();
@@ -474,7 +485,7 @@ private SubsumedGroupingsResult subsumedGroupings(@Nonnull final Quantifier cand
474
485
// 3. For each candidate grouping value in the set of (yet) unmatched candidate group values, try to find a
475
486
// predicate that binds that groupingValue.
476
487
//
477
- var booleanWithConstraint = alwaysTrue ();
488
+ var booleanWithConstraint = BooleanWithConstraint . alwaysTrue ();
478
489
for (final var translatedGroupingValue : translatedGroupingValuesSet ) {
479
490
var found = false ;
480
491
@@ -561,7 +572,8 @@ private SubsumedGroupingsResult subsumedGroupings(@Nonnull final Quantifier cand
561
572
}
562
573
563
574
if (!unmatchedCandidateValues .isEmpty ()) {
564
- Verify .verify (candidateGroupingValues .size () > translatedGroupingValues .size ());
575
+ Verify .verify (candidateGroupingValues .size () > translatedGroupingValuesSet .size ());
576
+
565
577
//
566
578
// This is a potential roll-up case, but only if the query side's groupings are completely subsumed
567
579
// by the prefix of the candidate side. Iterate up to the smaller query side's grouping values to
@@ -629,14 +641,7 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch,
629
641
630
642
final var childCompensation = childCompensationOptional .get ();
631
643
632
- if (childCompensation .isImpossible ()
633
- // ||
634
- // //
635
- // // TODO This needs some improvement as GB a, b, c WHERE a= AND c= needs to reapply the
636
- // // predicate on c which is currently refused here.
637
- // //
638
- // childCompensation.isNeededForFiltering()
639
- ) {
644
+ if (childCompensation .isImpossible ()) {
640
645
//
641
646
// Note that it may be better to just return the child compensation verbatim as that compensation
642
647
// may be combinable with something else to make it possible while the statically impossible compensation
@@ -730,7 +735,7 @@ public static Value flattenedResults(@Nullable final Value groupingKeyValue,
730
735
return rcv .simplify (AliasMap .identitiesFor (rcv .getCorrelatedTo ()), ImmutableSet .of ());
731
736
}
732
737
733
- public static class UnmatchedAggregateValue extends AbstractValue implements Value .NonEvaluableValue , IndexableAggregateValue {
738
+ public static class UnmatchedAggregateValue extends AbstractValue implements Value .NonEvaluableValue {
734
739
@ Nonnull
735
740
private final CorrelationIdentifier unmatchedId ;
736
741
@@ -749,12 +754,6 @@ protected Iterable<? extends Value> computeChildren() {
749
754
return ImmutableList .of ();
750
755
}
751
756
752
- @ Nonnull
753
- @ Override
754
- public String getIndexTypeName () {
755
- throw new UnsupportedOperationException ();
756
- }
757
-
758
757
@ Nonnull
759
758
@ Override
760
759
public ExplainTokensWithPrecedence explain (@ Nonnull final Iterable <Supplier <ExplainTokensWithPrecedence >> explainSuppliers ) {
@@ -831,7 +830,7 @@ public List<Value> getRollUpToValues() {
831
830
832
831
@ Nonnull
833
832
public static SubsumedGroupingsResult noSubsumption () {
834
- return of (falseValue (), ImmutableBiMap .of (), null );
833
+ return of (BooleanWithConstraint . falseValue (), ImmutableBiMap .of (), null );
835
834
}
836
835
837
836
@ Nonnull
0 commit comments