From 26698f4f5c7517cab3515c1eb4dac1659ca82b52 Mon Sep 17 00:00:00 2001 From: Normen Seemann Date: Mon, 3 Mar 2025 15:23:19 -0800 Subject: [PATCH 01/20] save point --- .../AggregateIndexExpansionVisitor.java | 67 +++++-- .../AggregateIndexMatchCandidate.java | 17 +- .../query/plan/cascades/PlannerRuleSet.java | 10 +- .../WithPrimaryKeyMatchCandidate.java | 24 ++- .../expressions/GroupByExpression.java | 18 +- .../structure/PartialMatchMatchers.java | 45 +++++ .../rules/AbstractDataAccessRule.java | 5 +- ...Rule.java => AggregateDataAccessRule.java} | 15 +- .../rules/WithPrimaryKeyDataAccessRule.java | 177 ++++++++++++++++++ .../values/translation/MaxMatchMap.java | 68 ++++++- 10 files changed, 401 insertions(+), 45 deletions(-) rename fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/{SelectDataAccessRule.java => AggregateDataAccessRule.java} (93%) create mode 100644 fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/WithPrimaryKeyDataAccessRule.java diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexExpansionVisitor.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexExpansionVisitor.java index 781cb1bea5..e966237487 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexExpansionVisitor.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexExpansionVisitor.java @@ -43,6 +43,7 @@ import com.apple.foundationdb.record.query.plan.cascades.values.RecordConstructorValue; import com.apple.foundationdb.record.query.plan.cascades.values.Value; import com.apple.foundationdb.record.query.plan.cascades.values.Values; +import com.apple.foundationdb.record.query.plan.cascades.values.translation.TranslationMap; import com.apple.foundationdb.record.util.pair.NonnullPair; import com.google.common.base.Preconditions; import com.google.common.base.Suppliers; @@ -56,7 +57,6 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; @@ -138,9 +138,9 @@ public MatchCandidate expand(@Nonnull final Supplier baseQua .addAll(groupByPlaceholders).build(); // 3. construct SELECT-HAVING with SORT on top. - final var selectHavingAndPlaceholderAliases = constructSelectHaving(groupByQun, placeholders); - final var selectHaving = selectHavingAndPlaceholderAliases.getLeft(); - final var placeHolderAliases = selectHavingAndPlaceholderAliases.getRight(); + final var constructSelectHavingResult = constructSelectHaving(groupByQun, placeholders); + final var selectHaving = constructSelectHavingResult.getSelectExpression(); + final var placeHolderAliases = constructSelectHavingResult.getPlaceholderAliases(); // 4. add sort on top, if necessary, this will be absorbed later on as an ordering property of the match candidate. final var maybeWithSort = placeHolderAliases.isEmpty() @@ -154,7 +154,8 @@ public MatchCandidate expand(@Nonnull final Supplier baseQua recordTypes, baseQuantifier.getFlowedObjectType(), groupByQun.getRangesOver().get().getResultValue(), - selectHaving); + selectHaving, + constructSelectHavingResult.getGroupByValues()); } @Nonnull @@ -274,19 +275,23 @@ protected NonnullPair> constructGroupBy(@Nonnull f } @Nonnull - private NonnullPair> constructSelectHaving(@Nonnull final Quantifier groupByQun, - @Nonnull final List selectWherePlaceholders) { + private ConstructSelectHavingResult constructSelectHaving(@Nonnull final Quantifier groupByQun, + @Nonnull final List selectWherePlaceholders) { + final var rangesOverExpression = groupByQun.getRangesOver().get(); + Verify.verify(rangesOverExpression instanceof GroupByExpression); + final var groupByExpression = (GroupByExpression)rangesOverExpression; + // the grouping value in GroupByExpression comes first (if set). @Nullable final var groupingValueReference = - (groupByQun.getRangesOver().get() instanceof GroupByExpression && ((GroupByExpression)groupByQun.getRangesOver().get()).getGroupingValue() == null) - ? null - : FieldValue.ofOrdinalNumber(groupByQun.getFlowedObjectValue(), 0); + groupByExpression.getGroupingValue() == null + ? null : FieldValue.ofOrdinalNumber(groupByQun.getFlowedObjectValue(), 0); final var aggregateValueReference = FieldValue.ofOrdinalNumberAndFuseIfPossible(FieldValue.ofOrdinalNumber(groupByQun.getFlowedObjectValue(), groupingValueReference == null ? 0 : 1), 0); final var placeholderAliases = ImmutableList.builder(); final var selectHavingGraphExpansionBuilder = GraphExpansion.builder().addQuantifier(groupByQun); - final List groupingValues = groupingValueReference == null ? Collections.emptyList() : Values.deconstructRecord(groupingValueReference); + final List groupingValues = groupingValueReference == null + ? ImmutableList.of() : Values.deconstructRecord(groupingValueReference); if (groupingValueReference != null) { int i = 0; for (final var groupingValue : groupingValues) { @@ -318,7 +323,13 @@ private NonnullPair> constructSele } else { finalPlaceholders = placeholderAliases.build(); } - return NonnullPair.of(selectHavingGraphExpansionBuilder.build().buildSelect(), finalPlaceholders); + + final var currentGroupingValues = groupingValues.stream() + .map(groupingValue -> groupingValue.translateCorrelations(TranslationMap.ofAliases(groupByQun.getAlias(), Quantifier.current()))) + .collect(ImmutableList.toImmutableList()); + + return new ConstructSelectHavingResult(selectHavingGraphExpansionBuilder.build().buildSelect(), + finalPlaceholders, currentGroupingValues); } @Nonnull @@ -335,4 +346,36 @@ private static Map> computeAggregateMap mapBuilder.put(IndexTypes.PERMUTED_MIN, new NumericAggregationValue.MinFn()); return mapBuilder.build(); } + + private static class ConstructSelectHavingResult { + @Nonnull + private final SelectExpression selectExpression; + @Nonnull + private final List placeholderAliases; + @Nonnull + private final List groupByValues; + + private ConstructSelectHavingResult(@Nonnull final SelectExpression selectExpression, + @Nonnull final List placeholderAliases, + @Nonnull final List groupByValues) { + this.selectExpression = selectExpression; + this.placeholderAliases = placeholderAliases; + this.groupByValues = groupByValues; + } + + @Nonnull + public SelectExpression getSelectExpression() { + return selectExpression; + } + + @Nonnull + public List getPlaceholderAliases() { + return placeholderAliases; + } + + @Nonnull + public List getGroupByValues() { + return groupByValues; + } + } } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java index d252392fc4..d457f10bad 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java @@ -95,6 +95,9 @@ public class AggregateIndexMatchCandidate implements MatchCandidate, WithBaseQua @Nonnull private final SelectExpression selectHavingExpression; + @Nonnull + private final List groupByValues; + /** * Creates a new instance of {@link AggregateIndexMatchCandidate}. * @@ -112,7 +115,8 @@ public AggregateIndexMatchCandidate(@Nonnull final Index index, @Nonnull final Collection recordTypes, @Nonnull final Type baseType, @Nonnull final Value groupByResultValue, - @Nonnull final SelectExpression selectHavingExpression) { + @Nonnull final SelectExpression selectHavingExpression, + @Nonnull final List groupByValues) { Preconditions.checkArgument(!recordTypes.isEmpty()); this.index = index; this.traversal = traversal; @@ -121,6 +125,7 @@ public AggregateIndexMatchCandidate(@Nonnull final Index index, this.baseType = baseType; this.groupByResultValue = groupByResultValue; this.selectHavingExpression = selectHavingExpression; + this.groupByValues = ImmutableList.copyOf(groupByValues); } @Nonnull @@ -147,6 +152,16 @@ public List getOrderingAliases() { return sargableAndOrderAliases; } + @Nonnull + public SelectExpression getSelectHavingExpression() { + return selectHavingExpression; + } + + @Nonnull + public List getGroupByValues() { + return groupByValues; + } + @Nonnull @Override public KeyExpression getFullKeyExpression() { diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PlannerRuleSet.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PlannerRuleSet.java index ab5a5ee58a..808b3fc0d6 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PlannerRuleSet.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PlannerRuleSet.java @@ -24,8 +24,9 @@ import com.apple.foundationdb.annotation.SpotBugsSuppressWarnings; import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression; import com.apple.foundationdb.record.query.plan.cascades.rules.AdjustMatchRule; +import com.apple.foundationdb.record.query.plan.cascades.rules.AggregateDataAccessRule; import com.apple.foundationdb.record.query.plan.cascades.rules.CombineFilterRule; -import com.apple.foundationdb.record.query.plan.cascades.rules.DataAccessRule; +import com.apple.foundationdb.record.query.plan.cascades.rules.WithPrimaryKeyDataAccessRule; import com.apple.foundationdb.record.query.plan.cascades.rules.ImplementDeleteRule; import com.apple.foundationdb.record.query.plan.cascades.rules.ImplementDistinctRule; import com.apple.foundationdb.record.query.plan.cascades.rules.ImplementDistinctUnionRule; @@ -40,8 +41,10 @@ import com.apple.foundationdb.record.query.plan.cascades.rules.ImplementIntersectionRule; import com.apple.foundationdb.record.query.plan.cascades.rules.ImplementNestedLoopJoinRule; import com.apple.foundationdb.record.query.plan.cascades.rules.ImplementPhysicalScanRule; +import com.apple.foundationdb.record.query.plan.cascades.rules.ImplementRecursiveUnionRule; import com.apple.foundationdb.record.query.plan.cascades.rules.ImplementSimpleSelectRule; import com.apple.foundationdb.record.query.plan.cascades.rules.ImplementStreamingAggregationRule; +import com.apple.foundationdb.record.query.plan.cascades.rules.ImplementTempTableInsertRule; import com.apple.foundationdb.record.query.plan.cascades.rules.ImplementTempTableScanRule; import com.apple.foundationdb.record.query.plan.cascades.rules.ImplementTypeFilterRule; import com.apple.foundationdb.record.query.plan.cascades.rules.ImplementUniqueRule; @@ -83,7 +86,6 @@ import com.apple.foundationdb.record.query.plan.cascades.rules.PushTypeFilterBelowFilterRule; import com.apple.foundationdb.record.query.plan.cascades.rules.RemoveProjectionRule; import com.apple.foundationdb.record.query.plan.cascades.rules.RemoveSortRule; -import com.apple.foundationdb.record.query.plan.cascades.rules.SelectDataAccessRule; import com.apple.foundationdb.record.query.plan.cascades.rules.SplitSelectExtractIndependentQuantifiersRule; import com.apple.foundationdb.record.query.plan.plans.RecordQueryInParameterJoinPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryInUnionOnValuesPlan; @@ -194,8 +196,8 @@ public class PlannerRuleSet { new AdjustMatchRule() ); private static final List> MATCH_PARTITION_RULES = ImmutableList.of( - new DataAccessRule(), - new SelectDataAccessRule(), + new WithPrimaryKeyDataAccessRule(), + new AggregateDataAccessRule(), new PredicateToLogicalUnionRule() ); private static final List> ALL_EXPRESSION_RULES = diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/WithPrimaryKeyMatchCandidate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/WithPrimaryKeyMatchCandidate.java index d2419376d3..8a6d3b9a07 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/WithPrimaryKeyMatchCandidate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/WithPrimaryKeyMatchCandidate.java @@ -34,26 +34,30 @@ public interface WithPrimaryKeyMatchCandidate extends MatchCandidate { Optional> getPrimaryKeyValuesMaybe(); @Nonnull - static Optional> commonPrimaryKeyValuesMaybe(@Nonnull Iterable matchCandidates) { + static Optional> commonRecordKeyValuesMaybe(@Nonnull Iterable matchCandidates) { List common = null; var first = true; for (final var matchCandidate : matchCandidates) { + final List key; if (matchCandidate instanceof WithPrimaryKeyMatchCandidate) { final var withPrimaryKeyMatchCandidate = (WithPrimaryKeyMatchCandidate)matchCandidate; - final var primaryKeyMaybe = withPrimaryKeyMatchCandidate.getPrimaryKeyValuesMaybe(); - if (primaryKeyMaybe.isEmpty()) { - return Optional.empty(); - } - final var primaryKey = primaryKeyMaybe.get(); - if (first) { - common = primaryKey; - first = false; - } else if (!common.equals(primaryKey)) { + final var keyMaybe = withPrimaryKeyMatchCandidate.getPrimaryKeyValuesMaybe(); + if (keyMaybe.isEmpty()) { return Optional.empty(); } + key = keyMaybe.get(); + } else if (matchCandidate instanceof AggregateIndexMatchCandidate) { + final var aggregateIndexMatchCandidate = (AggregateIndexMatchCandidate)matchCandidate; + key = aggregateIndexMatchCandidate.getGroupByValues(); } else { return Optional.empty(); } + if (first) { + common = key; + first = false; + } else if (!common.equals(key)) { + return Optional.empty(); + } } return Optional.ofNullable(common); // common can only be null if we didn't have any match candidates to start with } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java index f8ad7deac6..84c085337e 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java @@ -315,10 +315,10 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid final var translatedAggregateValues = Values.primitiveAccessorsForType(translatedAggregateValue.getResultType(), () -> translatedAggregateValue).stream() - .map(primitiveGroupingValue -> primitiveGroupingValue.simplify(AliasMap.emptyMap(), + .map(primitiveAggregateValue -> primitiveAggregateValue.simplify(AliasMap.emptyMap(), ImmutableSet.of())) .collect(ImmutableSet.toImmutableSet()); - if (translatedAggregateValues.size() != 1) { + if (translatedAggregateValues.isEmpty()) { return ImmutableList.of(); } @@ -328,16 +328,16 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid .map(primitiveAggregateValue -> primitiveAggregateValue.simplify(AliasMap.emptyMap(), ImmutableSet.of())) .collect(ImmutableSet.toImmutableSet()); - if (translatedAggregateValues.size() != 1) { + if (otherAggregateValues.size() != 1) { return ImmutableList.of(); } - final var subsumedAggregations = - Iterables.getOnlyElement(translatedAggregateValues).semanticEquals(Iterables.getOnlyElement(otherAggregateValues), - valueEquivalence); - if (subsumedAggregations.isFalse()) { - return ImmutableList.of(); - } + final var subsumedAggregations = BooleanWithConstraint.alwaysTrue(); +// Iterables.getOnlyElement(translatedAggregateValues).semanticEquals(Iterables.getOnlyElement(otherAggregateValues), +// valueEquivalence); +// if (subsumedAggregations.isFalse()) { +// return ImmutableList.of(); +// } final var subsumedGroupings = subsumedAggregations diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/matching/structure/PartialMatchMatchers.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/matching/structure/PartialMatchMatchers.java index d0a5f2e13a..7aa4579150 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/matching/structure/PartialMatchMatchers.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/matching/structure/PartialMatchMatchers.java @@ -21,7 +21,9 @@ package com.apple.foundationdb.record.query.plan.cascades.matching.structure; import com.apple.foundationdb.record.query.plan.RecordQueryPlannerConfiguration; +import com.apple.foundationdb.record.query.plan.cascades.AggregateIndexMatchCandidate; import com.apple.foundationdb.record.query.plan.cascades.PartialMatch; +import com.apple.foundationdb.record.query.plan.cascades.WithPrimaryKeyMatchCandidate; import javax.annotation.Nonnull; import java.util.stream.Stream; @@ -89,4 +91,47 @@ public Stream bindMatchesSafely(@Nonnull final RecordQueryPlann } }; } + + /** + * Matches any {@link PartialMatch} that is a match with a + * {@link com.apple.foundationdb.record.query.plan.cascades.MatchCandidate} that is backed by data structure that + * understands the concept of a primary key. Those match candidates are primary scan candidates, value indexes, + * and windowed indexes. + * @return a matcher matching a {@link PartialMatch} whose + * {@link com.apple.foundationdb.record.query.plan.cascades.MatchCandidate} implements + * {@link WithPrimaryKeyMatchCandidate}. + */ + @Nonnull + @SuppressWarnings("PMD.CompareObjectsWithEquals") + public static BindingMatcher matchingWithPrimaryKeyMatchCandidate() { + return new TypedMatcher<>(PartialMatch.class) { + @Nonnull + @Override + public Stream bindMatchesSafely(@Nonnull final RecordQueryPlannerConfiguration plannerConfiguration, + @Nonnull final PlannerBindings outerBindings, @Nonnull final PartialMatch in) { + return super.bindMatchesSafely(plannerConfiguration, outerBindings, in) + .filter(bindings -> in.getMatchCandidate() instanceof WithPrimaryKeyMatchCandidate); + } + }; + } + + /** + * Matches any {@link PartialMatch} that is a match with an {@link AggregateIndexMatchCandidate}. + * @return a matcher matching any partial match whose + * {@link com.apple.foundationdb.record.query.plan.cascades.MatchCandidate} is of type + * {@link AggregateIndexMatchCandidate}. + */ + @Nonnull + @SuppressWarnings("PMD.CompareObjectsWithEquals") + public static BindingMatcher matchingAggregateIndexMatchCandidate() { + return new TypedMatcher<>(PartialMatch.class) { + @Nonnull + @Override + public Stream bindMatchesSafely(@Nonnull final RecordQueryPlannerConfiguration plannerConfiguration, + @Nonnull final PlannerBindings outerBindings, @Nonnull final PartialMatch in) { + return super.bindMatchesSafely(plannerConfiguration, outerBindings, in) + .filter(bindings -> in.getMatchCandidate() instanceof AggregateIndexMatchCandidate); + } + }; + } } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java index 93e4a0ffa3..39f8e1f594 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java @@ -285,7 +285,7 @@ protected Set dataAccessForMatchPartition(@Nonnu distinctMatchToScanMap(call, bestMatchToPlanMap); final var commonPrimaryKeyValuesOptional = - WithPrimaryKeyMatchCandidate.commonPrimaryKeyValuesMaybe( + WithPrimaryKeyMatchCandidate.commonRecordKeyValuesMaybe( bestMaximumCoverageMatches.stream() .map(singleMatchedAccessVectored -> singleMatchedAccessVectored.getElement().getPartialMatch().getMatchCandidate()) .collect(ImmutableList.toImmutableList())); @@ -818,7 +818,8 @@ private static IntersectionResult createIntersectionAndCompensation(@Nonnull fin .flatMap(orderingPartsPair -> orderingPartsPair.getKey() .stream() - .filter(boundOrderingKey -> boundOrderingKey.getComparisonRangeType() == ComparisonRange.Type.EQUALITY) + .filter(boundOrderingKey -> boundOrderingKey.getComparisonRangeType() == + ComparisonRange.Type.EQUALITY) .map(MatchedOrderingPart::getValue)) .collect(ImmutableSet.toImmutableSet()); diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/SelectDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java similarity index 93% rename from fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/SelectDataAccessRule.java rename to fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java index 6a001de6c0..1d07d0aa36 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/SelectDataAccessRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java @@ -1,5 +1,5 @@ /* - * SelectDataAccessRule.java + * AggregateDataAccessRule.java * * This source file is part of the FoundationDB open source project * @@ -31,6 +31,7 @@ import com.apple.foundationdb.record.query.plan.cascades.Quantifier; import com.apple.foundationdb.record.query.plan.cascades.Quantifiers; import com.apple.foundationdb.record.query.plan.cascades.RequestedOrderingConstraint; +import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression; import com.apple.foundationdb.record.query.plan.cascades.expressions.SelectExpression; import com.apple.foundationdb.record.query.plan.cascades.matching.structure.BindingMatcher; import com.apple.foundationdb.record.util.pair.NonnullPair; @@ -49,8 +50,9 @@ import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.MatchPartitionMatchers.ofExpressionAndMatches; import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.MultiMatcher.some; +import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.PartialMatchMatchers.matchingAggregateIndexMatchCandidate; import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.PartialMatchMatchers.completeMatch; -import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.RelationalExpressionMatchers.ofType; +import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.RelationalExpressionMatchers.anyExpression; /** * A rule that utilizes index matching information compiled by {@link CascadesPlanner} to create one or more @@ -62,14 +64,15 @@ */ @API(API.Status.EXPERIMENTAL) @SuppressWarnings("PMD.TooManyStaticImports") -public class SelectDataAccessRule extends AbstractDataAccessRule { - private static final BindingMatcher completeMatchMatcher = completeMatch(); - private static final BindingMatcher expressionMatcher = ofType(SelectExpression.class); +public class AggregateDataAccessRule extends AbstractDataAccessRule { + private static final BindingMatcher completeMatchMatcher = + completeMatch().and(matchingAggregateIndexMatchCandidate()); + private static final BindingMatcher expressionMatcher = anyExpression(); private static final BindingMatcher rootMatcher = ofExpressionAndMatches(expressionMatcher, some(completeMatchMatcher)); - public SelectDataAccessRule() { + public AggregateDataAccessRule() { super(rootMatcher, completeMatchMatcher, expressionMatcher); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/WithPrimaryKeyDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/WithPrimaryKeyDataAccessRule.java new file mode 100644 index 0000000000..bce03736b9 --- /dev/null +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/WithPrimaryKeyDataAccessRule.java @@ -0,0 +1,177 @@ +/* + * WithPrimaryKeyDataAccessRule.java + * + * This source file is part of the FoundationDB open source project + * + * Copyright 2015-2021 Apple Inc. and the FoundationDB project authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.apple.foundationdb.record.query.plan.cascades.rules; + +import com.apple.foundationdb.annotation.API; +import com.apple.foundationdb.record.query.plan.cascades.AliasMap; +import com.apple.foundationdb.record.query.plan.cascades.CascadesPlanner; +import com.apple.foundationdb.record.query.plan.cascades.CascadesRuleCall; +import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier; +import com.apple.foundationdb.record.query.plan.cascades.LinkedIdentitySet; +import com.apple.foundationdb.record.query.plan.cascades.MatchPartition; +import com.apple.foundationdb.record.query.plan.cascades.PartialMatch; +import com.apple.foundationdb.record.query.plan.cascades.Quantifier; +import com.apple.foundationdb.record.query.plan.cascades.Quantifiers; +import com.apple.foundationdb.record.query.plan.cascades.RequestedOrderingConstraint; +import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression; +import com.apple.foundationdb.record.query.plan.cascades.expressions.SelectExpression; +import com.apple.foundationdb.record.query.plan.cascades.matching.structure.BindingMatcher; +import com.apple.foundationdb.record.util.pair.NonnullPair; +import com.apple.foundationdb.record.util.pair.Pair; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; + +import javax.annotation.Nonnull; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.MatchPartitionMatchers.ofExpressionAndMatches; +import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.MultiMatcher.some; +import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.PartialMatchMatchers.completeMatch; +import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.PartialMatchMatchers.matchingWithPrimaryKeyMatchCandidate; +import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.RelationalExpressionMatchers.anyExpression; + +/** + * A rule that utilizes index matching information compiled by {@link CascadesPlanner} to create one or more + * expressions for data access specifically for a {@link SelectExpression}. A {@link SelectExpression} behaves + * different compared to essentially all other expressions in a way that we can conceptually deconstruct such an expression + * on the fly and only replace the matched part of the original expression with the scan over the materialized view. + * That allows us to relax restrictions (.e.g. to match all quantifiers the select expression owns) while matching + * select expressions. + */ +@API(API.Status.EXPERIMENTAL) +@SuppressWarnings("PMD.TooManyStaticImports") +public class WithPrimaryKeyDataAccessRule extends AbstractDataAccessRule { + private static final BindingMatcher completeMatchMatcher = + completeMatch().and(matchingWithPrimaryKeyMatchCandidate()); + private static final BindingMatcher expressionMatcher = anyExpression(); + + private static final BindingMatcher rootMatcher = + ofExpressionAndMatches(expressionMatcher, some(completeMatchMatcher)); + + public WithPrimaryKeyDataAccessRule() { + super(rootMatcher, completeMatchMatcher, expressionMatcher); + } + + @Override + public void onMatch(@Nonnull final CascadesRuleCall call) { + final var bindings = call.getBindings(); + final var completeMatches = bindings.getAll(getCompleteMatchMatcher()); + if (completeMatches.isEmpty()) { + return; + } + + final var expression = bindings.get(getExpressionMatcher()); + final var correlatedTo = expression.getCorrelatedTo(); + + // + // return if there is no pre-determined interesting ordering + // + final var requestedOrderingsOptional = call.getPlannerConstraint(RequestedOrderingConstraint.REQUESTED_ORDERING); + if (requestedOrderingsOptional.isEmpty()) { + return; + } + + final var requestedOrderings = requestedOrderingsOptional.get(); + final var aliasToQuantifierMap = Quantifiers.aliasToQuantifierMap(expression.getQuantifiers()); + final var aliases = aliasToQuantifierMap.keySet(); + + // group all successful matches by their sets of compensated aliases + final var matchPartitionByMatchAliasMap = + completeMatches + .stream() + .flatMap(match -> { + final var compensatedAliases = match.getCompensatedAliases(); + if (!compensatedAliases.containsAll(aliases)) { + return Stream.empty(); + } + final Set matchedForEachAliases = + compensatedAliases.stream() + .filter(matchedAlias -> Objects.requireNonNull(aliasToQuantifierMap.get(matchedAlias)) instanceof Quantifier.ForEach) + .collect(ImmutableSet.toImmutableSet()); + if (matchedForEachAliases.size() == 1) { + return Stream.of(NonnullPair.of(Iterables.getOnlyElement(matchedForEachAliases), match)); + } + return Stream.empty(); + }) + .collect(Collectors.groupingBy( + Pair::getLeft, + LinkedHashMap::new, + Collectors.mapping(Pair::getRight, ImmutableList.toImmutableList()))); + + // loop through all compensated alias sets and their associated match partitions + for (final var matchPartitionByMatchAliasEntry : matchPartitionByMatchAliasMap.entrySet()) { + final var matchedAlias = matchPartitionByMatchAliasEntry.getKey(); + final var matchPartitionForMatchedAlias = matchPartitionByMatchAliasEntry.getValue(); + + // + // Pull down the requested orderings along the matchedAlias + // + final var pushedRequestedOrderings = + requestedOrderings.stream() + .map(requestedOrdering -> requestedOrdering.pushDown(expression.getResultValue(), matchedAlias, AliasMap.emptyMap(), correlatedTo)) + .collect(ImmutableSet.toImmutableSet()); + + // + // We do know that local predicates (which includes predicates only using the matchedAlias quantifier) + // are definitely handled by the logic expressed by the partial matches of the current match partition. + // Join predicates are different in a sense that there will be matches that handle those predicates and + // there will be matches where these predicates will not be handled. We further need to sub-partition the + // current match partition, by the predicates that are being handled by the matches. + // + // TODO this should just be exactly one key + final var matchPartitionsForAliasesByPredicates = + matchPartitionForMatchedAlias + .stream() + .collect(Collectors.groupingBy(match -> + new LinkedIdentitySet<>(match.getRegularMatchInfo().getPredicateMap().keySet()), + HashMap::new, + ImmutableList.toImmutableList())); + + // + // Note that this works because there is only one for-each and potentially 0 - n existential quantifiers + // that are covered by the match partition. Even though that logically forms a join, the existential + // quantifiers do not mutate the result of the join, they only cause filtering, that is, the resulting + // record is exactly what the for each quantifier produced filtered by the predicates expressed on the + // existential quantifiers. + // + for (final var matchPartitionEntry : matchPartitionsForAliasesByPredicates.entrySet()) { + final var matchPartition = matchPartitionEntry.getValue(); + + // + // The current match partition covers all matches that match the aliases in matchedAliases + // as well as all predicates in matchedPredicates. In other words we now have to compensate + // for all the remaining quantifiers and all remaining predicates. + // + final var dataAccessExpressions = + dataAccessForMatchPartition(call, + pushedRequestedOrderings, + matchPartition); + call.yieldExpression(dataAccessExpressions); + } + } + } +} diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/translation/MaxMatchMap.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/translation/MaxMatchMap.java index a9cf3274ff..cb56eb1426 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/translation/MaxMatchMap.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/translation/MaxMatchMap.java @@ -20,12 +20,16 @@ package com.apple.foundationdb.record.query.plan.cascades.values.translation; +import com.apple.foundationdb.record.PlanSerializationContext; +import com.apple.foundationdb.record.planprotos.PValue; import com.apple.foundationdb.record.query.combinatorics.CrossProduct; import com.apple.foundationdb.record.query.plan.QueryPlanConstraint; import com.apple.foundationdb.record.query.plan.cascades.AliasMap; import com.apple.foundationdb.record.query.plan.cascades.BooleanWithConstraint; import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier; import com.apple.foundationdb.record.query.plan.cascades.ValueEquivalence; +import com.apple.foundationdb.record.query.plan.cascades.values.AbstractValue; +import com.apple.foundationdb.record.query.plan.cascades.values.IndexableAggregateValue; import com.apple.foundationdb.record.query.plan.cascades.values.QuantifiedObjectValue; import com.apple.foundationdb.record.query.plan.cascades.values.QuantifiedRecordValue; import com.apple.foundationdb.record.query.plan.cascades.values.QuantifiedValue; @@ -46,6 +50,7 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Sets; import com.google.common.collect.Streams; +import com.google.protobuf.Message; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -752,7 +757,7 @@ private static Pair findMatchingReachableCandidate @Nonnull final ValueEquivalence valueEquivalence) { for (final var currentCandidateValue : candidateValue // when traversing the candidate in pre-order, only descend into structures that can be referenced - // from the top expression. For example, RCV's components can be referenced however an Arithmetic + // from the top expression. For example, rcv's components can be referenced however an arithmetic // operator's children can not be referenced. // It is crucial to do this in pre-order to guarantee matching the maximum (sub-)value of the candidate. .preOrderIterable(v -> v instanceof RecordConstructorValue)) { @@ -768,6 +773,11 @@ private static Pair findMatchingReachableCandidate return Pair.of(semanticEquals, currentCandidateValue); } } + + if (currentQueryValue instanceof IndexableAggregateValue) { + return Pair.of(BooleanWithConstraint.alwaysTrue(), new UnmatchedAggregateValue(ImmutableList.of())); + } + return Pair.of(BooleanWithConstraint.falseValue(), null); } @@ -1056,4 +1066,60 @@ public static MatchResult notMatched() { return NOT_MATCHED; } } + + public static class UnmatchedAggregateValue extends AbstractValue implements Value.NonEvaluableValue, IndexableAggregateValue { + @Nonnull + private final List children; + + public UnmatchedAggregateValue(@Nonnull final Iterable children) { + this.children = ImmutableList.copyOf(children); + } + + @Nonnull + @Override + protected Iterable computeChildren() { + return children; + } + + @Nonnull + @Override + public String getIndexTypeName() { + throw new UnsupportedOperationException(); + } + + @Nonnull + @Override + public ExplainTokensWithPrecedence explain(@Nonnull final Iterable> explainSuppliers) { + return ExplainTokensWithPrecedence.of(new ExplainTokens().addFunctionCall("unmatched", + Value.explainFunctionArguments(explainSuppliers))); + } + + @Override + public int hashCodeWithoutChildren() { + return 0; + } + + @Nonnull + @Override + public PValue toValueProto(@Nonnull final PlanSerializationContext serializationContext) { + throw new UnsupportedOperationException(); + } + + @Override + public int planHash(@Nonnull final PlanHashMode hashMode) { + return 0; + } + + @Nonnull + @Override + public Message toProto(@Nonnull final PlanSerializationContext serializationContext) { + throw new UnsupportedOperationException(); + } + + @Nonnull + @Override + public Value withChildren(final Iterable newChildren) { + return new UnmatchedAggregateValue(newChildren); + } + } } From cfc52fa2012fb62ffe102d17beb43ebf73dcd007 Mon Sep 17 00:00:00 2001 From: Normen Seemann Date: Thu, 6 Mar 2025 09:35:33 -0800 Subject: [PATCH 02/20] pulling up matchedAggregationValueMap works --- .../record/query/plan/cascades/MatchInfo.java | 139 +++++++++++++++++- .../expressions/GroupByExpression.java | 33 +++-- .../expressions/MatchableSortExpression.java | 4 +- .../expressions/RelationalExpression.java | 7 +- .../expressions/SelectExpression.java | 8 +- .../plan/cascades/rules/AdjustMatchRule.java | 6 +- 6 files changed, 168 insertions(+), 29 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchInfo.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchInfo.java index ed5c0dc87d..b88a344f1e 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchInfo.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchInfo.java @@ -25,6 +25,7 @@ import com.apple.foundationdb.record.query.plan.cascades.PredicateMultiMap.PredicateMapping; import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression; import com.apple.foundationdb.record.query.plan.cascades.predicates.QueryPredicate; +import com.apple.foundationdb.record.query.plan.cascades.values.Value; import com.apple.foundationdb.record.query.plan.cascades.values.translation.MaxMatchMap; import com.apple.foundationdb.record.query.plan.cascades.values.translation.PullUp; import com.google.common.base.Equivalence; @@ -68,11 +69,42 @@ default boolean isRegular() { Map collectPulledUpPredicateMappings(@Nonnull RelationalExpression candidateExpression, @Nonnull Set interestingPredicates); + @Nonnull + Map getMatchedAggregateValueMap(); + @Nonnull default AdjustedBuilder adjustedBuilder() { return new AdjustedBuilder(this, getMatchedOrderingParts(), - getMaxMatchMap()); + getMaxMatchMap(), + getMatchedAggregateValueMap()); + } + + @Nonnull + default Map adjustMatchedAggregateMap(@Nonnull final PartialMatch partialMatch, + @Nonnull final Quantifier candidateQuantifier) { + final var matchedAggregateValueMapBuilder = ImmutableMap.builder(); + final var matchedAggregateValueMap = getMatchedAggregateValueMap(); + for (final var matchedAggregateValueMapEntry : matchedAggregateValueMap.entrySet()) { + final var queryAggregateValue = matchedAggregateValueMapEntry.getKey(); + final var candidateAggregateValue = matchedAggregateValueMapEntry.getValue(); + final var candidateLowerExpression = + Iterables.getOnlyElement(partialMatch.getCandidateRef().getMembers()); + final var candidateLowerResultValue = candidateLowerExpression.getResultValue(); + final var candidatePullUpMap = + candidateLowerResultValue.pullUp(ImmutableList.of(candidateAggregateValue), + AliasMap.emptyMap(), + Sets.difference(candidateAggregateValue.getCorrelatedToWithoutChildren(), + candidateLowerExpression.getCorrelatedTo()), + candidateQuantifier.getAlias()); + final var pulledUpCandidateAggregateValue = candidatePullUpMap.get(candidateAggregateValue); + if (pulledUpCandidateAggregateValue == null) { + return ImmutableMap.of(); + } + matchedAggregateValueMapBuilder.put(queryAggregateValue, pulledUpCandidateAggregateValue); + } + + return matchedAggregateValueMapBuilder.build(); } /** @@ -113,6 +145,9 @@ class RegularMatchInfo implements MatchInfo { @Nonnull private final MaxMatchMap maxMatchMap; + @Nonnull + private final Map matchedAggregateValueMap; + /** * Field to hold additional query plan constraints that need to be imposed on the potentially realized match. */ @@ -125,6 +160,7 @@ private RegularMatchInfo(@Nonnull final Map matchedOrderingParts, @Nonnull final MaxMatchMap maxMatchMap, + @Nonnull final Map matchedAggregateValueMap, @Nonnull final QueryPlanConstraint additionalPlanConstraint) { this.parameterBindingMap = ImmutableMap.copyOf(parameterBindingMap); this.bindingAliasMap = bindingAliasMap; @@ -138,6 +174,7 @@ private RegularMatchInfo(@Nonnull final Map getMatchedAggregateValueMap() { + return matchedAggregateValueMap; + } + @Nonnull public QueryPlanConstraint getAdditionalPlanConstraint() { return additionalPlanConstraint; @@ -247,7 +290,7 @@ public static Optional tryFromMatchMap(@Nonnull final AliasMap bindin @Nonnull final IdentityBiMap partialMatchMap, @Nonnull final MaxMatchMap maxMatchMap) { return tryMerge(bindingAliasMap, partialMatchMap, ImmutableMap.of(), PredicateMap.empty(), - maxMatchMap, maxMatchMap.getQueryPlanConstraint()); + maxMatchMap, ImmutableMap.of(), maxMatchMap.getQueryPlanConstraint()); } @Nonnull @@ -256,6 +299,7 @@ public static Optional tryMerge(@Nonnull final AliasMap bindingAliasM @Nonnull final Map parameterBindingMap, @Nonnull final PredicateMultiMap predicateMap, @Nonnull final MaxMatchMap maxMatchMap, + @Nonnull final Map additionalMatchedAggregateValueMap, @Nonnull final QueryPlanConstraint additionalPlanConstraint) { final var parameterMapsBuilder = ImmutableList.>builder(); final var matchInfos = PartialMatch.matchInfosFromMap(partialMatchMap); @@ -281,6 +325,10 @@ public static Optional tryMerge(@Nonnull final AliasMap bindingAliasM final Optional> mergedParameterBindingsOptional = tryMergeParameterBindings(parameterMapsBuilder.build()); + final var matchedAggregateValueMap = + pullUpAndMergeMatchedAggregateMap(bindingAliasMap, partialMatchMap, + additionalMatchedAggregateValueMap); + return mergedParameterBindingsOptional .map(mergedParameterBindings -> new RegularMatchInfo(mergedParameterBindings, bindingAliasMap, @@ -288,6 +336,7 @@ public static Optional tryMerge(@Nonnull final AliasMap bindingAliasM predicateMap, orderingParts, maxMatchMap, + matchedAggregateValueMap, additionalPlanConstraint)); } @@ -312,6 +361,51 @@ public static Optional> tryMergePara return Optional.of(resultMap); } + + @Nonnull + private static Map pullUpAndMergeMatchedAggregateMap(@Nonnull final AliasMap bindingAliasMap, + @Nonnull final IdentityBiMap partialMatchMap, + @Nonnull final Map additionalMatchedAggregateValueMap) { + final var matchedAggregateValueMapBuilder = ImmutableMap.builder(); + matchedAggregateValueMapBuilder.putAll(additionalMatchedAggregateValueMap); + for (final var partialMatchMapEntry : partialMatchMap.entrySet()) { + final var quantifier = partialMatchMapEntry.getKey().get(); + if (quantifier instanceof Quantifier.ForEach) { + final var partialMatch = partialMatchMapEntry.getValue().get(); + final var matchInfo = partialMatch.getMatchInfo(); + final var matchedAggregateValueMap = matchInfo.getMatchedAggregateValueMap(); + for (final var matchedAggregateValueMapEntry : matchedAggregateValueMap.entrySet()) { + final var queryAggregateValue = matchedAggregateValueMapEntry.getKey(); + final var lowerQueryExpression = partialMatch.getQueryExpression(); + final var lowerResultValue = lowerQueryExpression.getResultValue(); + final var pullUpMap = + lowerResultValue.pullUp(ImmutableList.of(queryAggregateValue), AliasMap.emptyMap(), + Sets.difference(queryAggregateValue.getCorrelatedToWithoutChildren(), + lowerQueryExpression.getCorrelatedTo()), quantifier.getAlias()); + final var pulledUpQueryAggregateValue = pullUpMap.get(queryAggregateValue); + if (pulledUpQueryAggregateValue == null) { + return ImmutableMap.of(); + } + final var candidateAggregateValue = matchedAggregateValueMapEntry.getValue(); + final var candidateLowerExpression = + Iterables.getOnlyElement(partialMatch.getCandidateRef().getMembers()); + final var candidateLowerResultValue = candidateLowerExpression.getResultValue(); + final var candidatePullUpMap = + candidateLowerResultValue.pullUp(ImmutableList.of(candidateAggregateValue), + AliasMap.emptyMap(), + Sets.difference(candidateAggregateValue.getCorrelatedToWithoutChildren(), + candidateLowerExpression.getCorrelatedTo()), + Objects.requireNonNull(bindingAliasMap.getTarget(quantifier.getAlias()))); + final var pulledUpCandidateAggregateValue = candidatePullUpMap.get(candidateAggregateValue); + if (pulledUpCandidateAggregateValue == null) { + return ImmutableMap.of(); + } + matchedAggregateValueMapBuilder.put(pulledUpQueryAggregateValue, pulledUpCandidateAggregateValue); + } + } + } + return matchedAggregateValueMapBuilder.build(); + } } /** @@ -346,12 +440,17 @@ class AdjustedMatchInfo implements MatchInfo { @Nonnull private final MaxMatchMap maxMatchMap; - public AdjustedMatchInfo(@Nonnull final MatchInfo underlying, - @Nonnull final List matchedOrderingParts, - @Nonnull final MaxMatchMap maxMatchMap) { + @Nonnull + private final Map matchedAggregateValueMap; + + private AdjustedMatchInfo(@Nonnull final MatchInfo underlying, + @Nonnull final List matchedOrderingParts, + @Nonnull final MaxMatchMap maxMatchMap, + @Nonnull final Map matchedAggregateValueMap) { this.underlying = underlying; this.matchedOrderingParts = matchedOrderingParts; this.maxMatchMap = maxMatchMap; + this.matchedAggregateValueMap = ImmutableMap.copyOf(matchedAggregateValueMap); } @Nonnull @@ -371,6 +470,12 @@ public MaxMatchMap getMaxMatchMap() { return maxMatchMap; } + @Nonnull + @Override + public Map getMatchedAggregateValueMap() { + return matchedAggregateValueMap; + } + @Override public boolean isAdjusted() { return true; @@ -424,6 +529,9 @@ class AdjustedBuilder { @Nonnull private List matchedOrderingParts; + @Nonnull + private Map matchedAggregateValueMap; + /** * A map of maximum matches between the query result {@code Value} and the corresponding candidate's result * {@code Value}. @@ -433,10 +541,12 @@ class AdjustedBuilder { private AdjustedBuilder(@Nonnull final MatchInfo underlying, @Nonnull final List matchedOrderingParts, - @Nonnull final MaxMatchMap maxMatchMap) { + @Nonnull final MaxMatchMap maxMatchMap, + @Nonnull final Map matchedAggregateValueMap) { this.underlying = underlying; this.matchedOrderingParts = matchedOrderingParts; this.maxMatchMap = maxMatchMap; + this.matchedAggregateValueMap = matchedAggregateValueMap; } @Nonnull @@ -449,22 +559,37 @@ public AdjustedBuilder setMatchedOrderingParts(@Nonnull final List matchedAggregateValueMap) { + this.matchedAggregateValueMap = matchedAggregateValueMap; + return this; + } + @Nonnull public MaxMatchMap getMaxMatchMap() { return maxMatchMap; } + @Nonnull public AdjustedBuilder setMaxMatchMap(@Nonnull final MaxMatchMap maxMatchMap) { this.maxMatchMap = maxMatchMap; return this; } + + + @Nonnull + public Map getMatchedAggregateValueMap() { + return matchedAggregateValueMap; + } + @Nonnull public MatchInfo build() { return new AdjustedMatchInfo( underlying, matchedOrderingParts, - maxMatchMap); + maxMatchMap, + matchedAggregateValueMap); } } } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java index 84c085337e..55339b3979 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java @@ -310,15 +310,12 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid ValueEquivalence.fromAliasMap(bindingAliasMap) .then(ValueEquivalence.constantEquivalenceWithEvaluationContext(evaluationContext)); - final var translatedAggregateValue = - aggregateValue.translateCorrelations(translationMap, true); - final var translatedAggregateValues = - Values.primitiveAccessorsForType(translatedAggregateValue.getResultType(), - () -> translatedAggregateValue).stream() + final var aggregateValues = + Values.primitiveAccessorsForType(aggregateValue.getResultType(), () -> aggregateValue).stream() .map(primitiveAggregateValue -> primitiveAggregateValue.simplify(AliasMap.emptyMap(), ImmutableSet.of())) .collect(ImmutableSet.toImmutableSet()); - if (translatedAggregateValues.isEmpty()) { + if (aggregateValues.isEmpty()) { return ImmutableList.of(); } @@ -331,13 +328,21 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid if (otherAggregateValues.size() != 1) { return ImmutableList.of(); } - - final var subsumedAggregations = BooleanWithConstraint.alwaysTrue(); -// Iterables.getOnlyElement(translatedAggregateValues).semanticEquals(Iterables.getOnlyElement(otherAggregateValues), -// valueEquivalence); -// if (subsumedAggregations.isFalse()) { -// return ImmutableList.of(); -// } + final var otherPrimitiveAggregateValue = Iterables.getOnlyElement(otherAggregateValues); + final var matchedAggregateValueMapBuilder = ImmutableMap.builder(); + var subsumedAggregations = BooleanWithConstraint.alwaysTrue(); + for (final var primitiveAggregateValue : aggregateValues) { + final var translatedPrimitiveAggregateValue = + primitiveAggregateValue.translateCorrelations(translationMap, true); + + final var semanticEquals = + translatedPrimitiveAggregateValue.semanticEquals(otherPrimitiveAggregateValue, valueEquivalence); + if (semanticEquals.isTrue()) { + matchedAggregateValueMapBuilder.put(primitiveAggregateValue, otherPrimitiveAggregateValue); + subsumedAggregations = semanticEquals; + break; + } + } final var subsumedGroupings = subsumedAggregations @@ -357,7 +362,7 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid subsumedGroupings.getConstraint().compose(maxMatchMap.getQueryPlanConstraint()); return RegularMatchInfo.tryMerge(bindingAliasMap, partialMatchMap, ImmutableMap.of(), PredicateMap.empty(), - maxMatchMap, queryPlanConstraint) + maxMatchMap, matchedAggregateValueMapBuilder.build(), queryPlanConstraint) .map(ImmutableList::of) .orElse(ImmutableList.of()); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/MatchableSortExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/MatchableSortExpression.java index e0f4bc2885..cd2a19d485 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/MatchableSortExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/MatchableSortExpression.java @@ -212,7 +212,8 @@ public MatchableSortExpression translateCorrelations(@Nonnull final TranslationM @Nonnull @Override - public Optional adjustMatch(@Nonnull final PartialMatch partialMatch) { + public Optional adjustMatch(@Nonnull final PartialMatch partialMatch, + @Nonnull final Quantifier candidateQuantifier) { final var childMatchInfo = partialMatch.getMatchInfo(); final var maxMatchMap = childMatchInfo.getMaxMatchMap(); final var innerQuantifier = Iterables.getOnlyElement(getQuantifiers()); @@ -223,6 +224,7 @@ public Optional adjustMatch(@Nonnull final PartialMatch partialMatch) childMatchInfo.adjustedBuilder() .setMaxMatchMap(adjustedMaxMatchMap) .setMatchedOrderingParts(forPartialMatch(partialMatch)) + .setMatchedAggregateValueMap(childMatchInfo.adjustMatchedAggregateMap(partialMatch, candidateQuantifier)) .build()); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/RelationalExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/RelationalExpression.java index b99fbed728..93ae2e3e06 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/RelationalExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/RelationalExpression.java @@ -749,12 +749,15 @@ static Optional pullUpAndComposeTranslationMapsMaybe(@Nonnull fi /** * Override that is called by {@link AdjustMatchRule} to improve an already existing {@link PartialMatch}. - * @param partialMatch the partial match already existing between {@code expression} and {@code this} + * @param partialMatch the partial match already existing between {@code expression} and the only child of + * {@code this} + * @param candidateQuantifier the quantifier we adjust along * @return {@code Optional.empty()} if the match could not be adjusted, Optional.of(matchInfo) for a new adjusted * match, otherwise. */ @Nonnull - default Optional adjustMatch(@Nonnull final PartialMatch partialMatch) { + default Optional adjustMatch(@Nonnull final PartialMatch partialMatch, + @Nonnull final Quantifier candidateQuantifier) { return Optional.empty(); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java index 41e953d685..181bee4d30 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java @@ -463,7 +463,7 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid MaxMatchMap.compute(translatedResultValue, candidateExpression.getResultValue(), Quantifiers.aliases(candidateExpression.getQuantifiers()), bindingValueEquivalence); return RegularMatchInfo.tryMerge(bindingAliasMap, partialMatchMap, mergedParameterBindingMap, - PredicateMap.empty(), maxMatchMap, maxMatchMap.getQueryPlanConstraint()) + PredicateMap.empty(), maxMatchMap, ImmutableMap.of(), maxMatchMap.getQueryPlanConstraint()) .map(ImmutableList::of) .orElse(ImmutableList.of()); } else { @@ -582,7 +582,7 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid bindingValueEquivalence); return RegularMatchInfo.tryMerge(bindingAliasMap, partialMatchMap, allParameterBindingMap, predicateMap, - maxMatchMap, + maxMatchMap, ImmutableMap.of(), maxMatchMap.getQueryPlanConstraint()); }) .map(ImmutableList::of) @@ -594,7 +594,8 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid @Nonnull @Override - public Optional adjustMatch(@Nonnull final PartialMatch partialMatch) { + public Optional adjustMatch(@Nonnull final PartialMatch partialMatch, + @Nonnull final Quantifier candidateQuantifier) { final var childMatchInfo = partialMatch.getMatchInfo(); for (final var predicate : getPredicates()) { @@ -618,6 +619,7 @@ public Optional adjustMatch(@Nonnull final PartialMatch partialMatch) .map(adjustedMaxMatchMap -> childMatchInfo.adjustedBuilder() .setMaxMatchMap(adjustedMaxMatchMap) + .setMatchedAggregateValueMap(childMatchInfo.adjustMatchedAggregateMap(partialMatch, candidateQuantifier)) .build()); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AdjustMatchRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AdjustMatchRule.java index c7abf635ce..b471a1a172 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AdjustMatchRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AdjustMatchRule.java @@ -23,6 +23,7 @@ import com.apple.foundationdb.annotation.API; import com.apple.foundationdb.record.query.plan.cascades.CascadesRule; import com.apple.foundationdb.record.query.plan.cascades.CascadesRuleCall; +import com.apple.foundationdb.record.query.plan.cascades.Quantifier; import com.apple.foundationdb.record.query.plan.cascades.Reference; import com.apple.foundationdb.record.query.plan.cascades.MatchCandidate; import com.apple.foundationdb.record.query.plan.cascades.MatchInfo; @@ -100,8 +101,9 @@ private Optional matchWithCandidate(@Nonnull final PartialMatch parti return Optional.empty(); } + final Quantifier candidateQuantifier = Iterables.getOnlyElement(candidateExpression.getQuantifiers()); final Reference otherRangesOver = - Iterables.getOnlyElement(candidateExpression.getQuantifiers()).getRangesOver(); + candidateQuantifier.getRangesOver(); if (!candidateExpression.getCorrelatedTo().equals(otherRangesOver.getCorrelatedTo())) { return Optional.empty(); @@ -111,6 +113,6 @@ private Optional matchWithCandidate(@Nonnull final PartialMatch parti return Optional.empty(); } - return candidateExpression.adjustMatch(partialMatch); + return candidateExpression.adjustMatch(partialMatch, candidateQuantifier); } } From 9ff207a0d8df5eaf7bdcfa67c7b3bbf66c5f6799 Mon Sep 17 00:00:00 2001 From: Normen Seemann Date: Sun, 9 Mar 2025 09:49:19 -0700 Subject: [PATCH 03/20] pre pulling up unmatched values --- .../query/plan/cascades/Compensation.java | 39 ++++- .../record/query/plan/cascades/MatchInfo.java | 78 +++++---- .../query/plan/cascades/PartialMatch.java | 12 -- .../plan/cascades/PredicateMultiMap.java | 159 +++++++++++++++++- .../expressions/GroupByExpression.java | 30 ++-- .../LogicalTypeFilterExpression.java | 31 ++-- .../expressions/SelectExpression.java | 23 ++- .../cascades/predicates/AndPredicate.java | 17 +- .../cascades/predicates/ExistsPredicate.java | 7 +- .../predicates/LeafQueryPredicate.java | 7 +- .../cascades/predicates/NotPredicate.java | 15 +- .../plan/cascades/predicates/OrPredicate.java | 31 ++-- .../cascades/predicates/QueryPredicate.java | 7 +- 13 files changed, 334 insertions(+), 122 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java index 7f28ce263e..a8718abcb0 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java @@ -27,9 +27,11 @@ import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression; import com.apple.foundationdb.record.query.plan.cascades.predicates.QueryPredicate; import com.apple.foundationdb.record.query.plan.cascades.rules.DataAccessRule; +import com.apple.foundationdb.record.query.plan.cascades.values.Value; import com.google.common.base.Suppliers; import com.google.common.base.Verify; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; @@ -39,6 +41,7 @@ import java.util.Map; import java.util.Set; import java.util.function.Supplier; +import java.util.stream.Stream; /** * Interface for all kinds of compensation. A compensation is the byproduct of expression DAG matching. @@ -383,7 +386,8 @@ default ForMatch derived(final boolean isImpossible, @Nonnull final Collection matchedQuantifiers, @Nonnull final Set unmatchedQuantifiers, @Nonnull final Set compensatedAliases, - @Nonnull final ResultCompensationFunction resultCompensationFunction) { + @Nonnull final ResultCompensationFunction resultCompensationFunction, + @Nonnull final Map matchedAggregateValueMap) { // // At least one of these conditions must be true: // - it is an impossible compensation (in which case the predicate compensation map may be empty) @@ -396,7 +400,7 @@ default ForMatch derived(final boolean isImpossible, !predicateCompensationMap.isEmpty() || resultCompensationFunction.isNeeded() || isNeededForFiltering()); return new ForMatch(isImpossible, this, predicateCompensationMap, matchedQuantifiers, - unmatchedQuantifiers, compensatedAliases, resultCompensationFunction); + unmatchedQuantifiers, compensatedAliases, resultCompensationFunction, matchedAggregateValueMap); } /** @@ -446,6 +450,9 @@ default boolean isFinalNeeded() { @Nonnull ResultCompensationFunction getResultCompensationFunction(); + @Nonnull + Map getMatchedAggregateValueMap(); + /** * Specific implementation of union-ing two compensations both of type {@link WithSelectCompensation}. * This implementation delegates to its super method if {@code otherCompensation} is not of type @@ -538,7 +545,8 @@ default Compensation union(@Nonnull Compensation otherCompensation) { unionedMatchedQuantifiers, ImmutableSet.of(), Sets.union(getCompensatedAliases(), otherWithSelectCompensation.getCompensatedAliases()), - newResultResultCompensationFunction); + newResultResultCompensationFunction, + ImmutableMap.of()); } /** @@ -591,7 +599,8 @@ default Compensation intersect(@Nonnull Compensation otherCompensation) { Verify.verify(!(childCompensation instanceof WithSelectCompensation) || ((WithSelectCompensation)childCompensation).getUnmatchedForEachQuantifiers().isEmpty()); - final Compensation intersectedChildCompensation = childCompensation.intersect(otherWithSelectCompensation.getChildCompensation()); + final Compensation intersectedChildCompensation = + childCompensation.intersect(otherWithSelectCompensation.getChildCompensation()); if (intersectedChildCompensation.isImpossible() || !intersectedChildCompensation.canBeDeferred()) { return Compensation.impossibleCompensation(); } @@ -605,6 +614,13 @@ default Compensation intersect(@Nonnull Compensation otherCompensation) { return intersectedChildCompensation; } + final var newMatchedAggregateValueMap = + Stream.concat(getMatchedAggregateValueMap().entrySet().stream(), + otherWithSelectCompensation.getMatchedAggregateValueMap().entrySet().stream()) + .collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, + Map.Entry::getValue, + (l, r) -> l)); + // Note that at the current time each side can only contribute at most one foreach quantifier, thus the // intersection should also only contain at most one for each quantifier. final Sets.SetView intersectedMatchedQuantifiers = @@ -625,7 +641,8 @@ default Compensation intersect(@Nonnull Compensation otherCompensation) { intersectedMatchedQuantifiers, intersectedUnmatchedQuantifiers, getCompensatedAliases(), // both compensated aliases must be identical, but too expensive to check - newResultResultCompensationFunction); + newResultResultCompensationFunction, + newMatchedAggregateValueMap); } } @@ -654,6 +671,8 @@ class ForMatch implements WithSelectCompensation { private final Set compensatedAliases; @Nonnull private final ResultCompensationFunction resultCompensationFunction; + @Nonnull + private final Map matchedAggregateValueMap; @Nonnull private final Supplier> unmatchedForEachQuantifiersSupplier; @@ -664,7 +683,8 @@ private ForMatch(final boolean isImpossible, @Nonnull final Collection matchedQuantifiers, @Nonnull final Collection unmatchedQuantifiers, @Nonnull final Set compensatedAliases, - @Nonnull final ResultCompensationFunction resultCompensationFunction) { + @Nonnull final ResultCompensationFunction resultCompensationFunction, + @Nonnull final Map matchedAggregateValueMap) { this.isImpossible = isImpossible; this.childCompensation = childCompensation; this.predicateCompensationMap = new LinkedIdentityMap<>(); @@ -675,6 +695,7 @@ private ForMatch(final boolean isImpossible, this.unmatchedQuantifiers.addAll(unmatchedQuantifiers); this.compensatedAliases = ImmutableSet.copyOf(compensatedAliases); this.resultCompensationFunction = resultCompensationFunction; + this.matchedAggregateValueMap = ImmutableMap.copyOf(matchedAggregateValueMap); this.unmatchedForEachQuantifiersSupplier = Suppliers.memoize(this::computeUnmatchedForEachQuantifiers); } @@ -733,6 +754,12 @@ public ResultCompensationFunction getResultCompensationFunction() { return resultCompensationFunction; } + @Nonnull + @Override + public Map getMatchedAggregateValueMap() { + return matchedAggregateValueMap; + } + /** * When applied to a reference this method returns a {@link RelationalExpression} consuming the * reference passed in that applies additional predicates as expressed by the predicate compensation map. diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchInfo.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchInfo.java index b88a344f1e..594440fcc7 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchInfo.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchInfo.java @@ -369,43 +369,59 @@ private static Map pullUpAndMergeMatchedAggregateMap(@Nonnull fina final var matchedAggregateValueMapBuilder = ImmutableMap.builder(); matchedAggregateValueMapBuilder.putAll(additionalMatchedAggregateValueMap); for (final var partialMatchMapEntry : partialMatchMap.entrySet()) { - final var quantifier = partialMatchMapEntry.getKey().get(); + final var partialMatchMapEntryKey = partialMatchMapEntry.getKey(); + final var quantifier = partialMatchMapEntryKey.get(); if (quantifier instanceof Quantifier.ForEach) { final var partialMatch = partialMatchMapEntry.getValue().get(); - final var matchInfo = partialMatch.getMatchInfo(); - final var matchedAggregateValueMap = matchInfo.getMatchedAggregateValueMap(); - for (final var matchedAggregateValueMapEntry : matchedAggregateValueMap.entrySet()) { - final var queryAggregateValue = matchedAggregateValueMapEntry.getKey(); - final var lowerQueryExpression = partialMatch.getQueryExpression(); - final var lowerResultValue = lowerQueryExpression.getResultValue(); - final var pullUpMap = - lowerResultValue.pullUp(ImmutableList.of(queryAggregateValue), AliasMap.emptyMap(), - Sets.difference(queryAggregateValue.getCorrelatedToWithoutChildren(), - lowerQueryExpression.getCorrelatedTo()), quantifier.getAlias()); - final var pulledUpQueryAggregateValue = pullUpMap.get(queryAggregateValue); - if (pulledUpQueryAggregateValue == null) { - return ImmutableMap.of(); - } - final var candidateAggregateValue = matchedAggregateValueMapEntry.getValue(); - final var candidateLowerExpression = - Iterables.getOnlyElement(partialMatch.getCandidateRef().getMembers()); - final var candidateLowerResultValue = candidateLowerExpression.getResultValue(); - final var candidatePullUpMap = - candidateLowerResultValue.pullUp(ImmutableList.of(candidateAggregateValue), - AliasMap.emptyMap(), - Sets.difference(candidateAggregateValue.getCorrelatedToWithoutChildren(), - candidateLowerExpression.getCorrelatedTo()), - Objects.requireNonNull(bindingAliasMap.getTarget(quantifier.getAlias()))); - final var pulledUpCandidateAggregateValue = candidatePullUpMap.get(candidateAggregateValue); - if (pulledUpCandidateAggregateValue == null) { - return ImmutableMap.of(); - } - matchedAggregateValueMapBuilder.put(pulledUpQueryAggregateValue, pulledUpCandidateAggregateValue); - } + final var pulledUpMatchedAggregateValueMap = + pullUpMatchedAggregateValueMap(partialMatch, + quantifier.getAlias(), + Objects.requireNonNull(bindingAliasMap.getTarget(quantifier.getAlias()))); + + matchedAggregateValueMapBuilder.putAll(pulledUpMatchedAggregateValueMap); } } return matchedAggregateValueMapBuilder.build(); } + + @Nonnull + public static Map pullUpMatchedAggregateValueMap(@Nonnull final PartialMatch partialMatch, + @Nonnull final CorrelationIdentifier queryAlias, + @Nonnull final CorrelationIdentifier candidateAlias) { + final var matchInfo = partialMatch.getMatchInfo(); + final var queryExpression = partialMatch.getQueryExpression(); + final var resultValue = queryExpression.getResultValue(); + final var matchedAggregateValueMapBuilder = ImmutableMap.builder(); + final var matchedAggregateValueMap = matchInfo.getMatchedAggregateValueMap(); + for (final var matchedAggregateValueMapEntry : matchedAggregateValueMap.entrySet()) { + final var queryAggregateValue = matchedAggregateValueMapEntry.getKey(); + final var pullUpMap = + resultValue.pullUp(ImmutableList.of(queryAggregateValue), AliasMap.emptyMap(), + Sets.difference(queryAggregateValue.getCorrelatedToWithoutChildren(), + queryExpression.getCorrelatedTo()), queryAlias); + final var pulledUpQueryAggregateValue = pullUpMap.get(queryAggregateValue); + if (pulledUpQueryAggregateValue == null) { + return ImmutableMap.of(); + } + final var candidateAggregateValue = matchedAggregateValueMapEntry.getValue(); + final var candidateLowerExpression = + Iterables.getOnlyElement(partialMatch.getCandidateRef().getMembers()); + final var candidateLowerResultValue = candidateLowerExpression.getResultValue(); + final var candidatePullUpMap = + candidateLowerResultValue.pullUp(ImmutableList.of(candidateAggregateValue), + AliasMap.emptyMap(), + Sets.difference(candidateAggregateValue.getCorrelatedToWithoutChildren(), + candidateLowerExpression.getCorrelatedTo()), + candidateAlias); + final var pulledUpCandidateAggregateValue = candidatePullUpMap.get(candidateAggregateValue); + if (pulledUpCandidateAggregateValue == null) { + return ImmutableMap.of(); + } + matchedAggregateValueMapBuilder.put(pulledUpQueryAggregateValue, pulledUpCandidateAggregateValue); + } + + return matchedAggregateValueMapBuilder.build(); + } } /** diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PartialMatch.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PartialMatch.java index 2db5e40432..dc8fcb932d 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PartialMatch.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PartialMatch.java @@ -336,18 +336,6 @@ public Map pullUpToParent(@Nonnull final Corre return resultsMap; } - @Nonnull - public Map getPulledUpPredicateMappings(@Nonnull final Predicate predicateFilter) { - final var interestingPredicates = - getAccumulatedPredicateMap().getMap() - .keySet() - .stream() - .filter(predicateFilter) - .collect(LinkedIdentitySet.toLinkedIdentitySet()); - - return getPulledUpPredicateMappings(interestingPredicates); - } - @Nonnull public Map getPulledUpPredicateMappings(@Nonnull final Set interestingPredicates) { final var resultMap = new LinkedIdentityMap(); diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PredicateMultiMap.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PredicateMultiMap.java index 4a657d815b..9818dc609e 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PredicateMultiMap.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PredicateMultiMap.java @@ -20,10 +20,16 @@ package com.apple.foundationdb.record.query.plan.cascades; +import com.apple.foundationdb.record.query.expressions.Comparisons; import com.apple.foundationdb.record.query.plan.QueryPlanConstraint; +import com.apple.foundationdb.record.query.plan.cascades.predicates.ExistsPredicate; +import com.apple.foundationdb.record.query.plan.cascades.predicates.PredicateWithComparisons; +import com.apple.foundationdb.record.query.plan.cascades.predicates.PredicateWithValue; import com.apple.foundationdb.record.query.plan.cascades.predicates.QueryPredicate; import com.apple.foundationdb.record.query.plan.cascades.values.Value; +import com.apple.foundationdb.record.query.plan.cascades.values.translation.MaxMatchMap; import com.apple.foundationdb.record.query.plan.cascades.values.translation.PullUp; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.Multimaps; import com.google.common.collect.SetMultimap; @@ -32,11 +38,12 @@ import javax.annotation.Nonnull; import java.util.Collection; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; -import java.util.function.Function; +import java.util.function.BiFunction; /** * Map that maps from a {@link QueryPredicate} of a query to a {@link QueryPredicate} of a {@link MatchCandidate}. @@ -82,6 +89,12 @@ public boolean isImpossible() { return false; } + @Nonnull + @Override + public PredicateCompensationFunction amendWithOtherMatchInfo(@Nonnull final MatchInfo matchInfo) { + return this; + } + @Nonnull @Override public Set applyCompensationForPredicate(@Nonnull final CorrelationIdentifier baseAlias) { @@ -101,6 +114,12 @@ public boolean isImpossible() { return true; } + @Nonnull + @Override + public PredicateCompensationFunction amendWithOtherMatchInfo(@Nonnull final MatchInfo matchInfo) { + return this; + } + @Nonnull @Override public Set applyCompensationForPredicate(@Nonnull final CorrelationIdentifier baseAlias) { @@ -113,11 +132,71 @@ public Set applyCompensationForPredicate(@Nonnull final Correlat boolean isImpossible(); + @Nonnull + PredicateCompensationFunction amendWithOtherMatchInfo(@Nonnull final MatchInfo matchInfo); + @Nonnull Set applyCompensationForPredicate(@Nonnull CorrelationIdentifier baseAlias); @Nonnull - static PredicateCompensationFunction of(@Nonnull final Function> compensationFunction) { + static PredicateCompensationFunction ofPulledUpPredicate(@Nonnull final QueryPredicate pulledUpPredicate, + @Nonnull final BiFunction> compensationFunction) { + final var isImpossible = predicateContainsUnmatchedValues(pulledUpPredicate); + + return new PredicateCompensationFunction() { + @Override + public boolean isNeeded() { + return true; + } + + @Override + public boolean isImpossible() { + return isImpossible; + } + + @Nonnull + @Override + public PredicateCompensationFunction amendWithOtherMatchInfo(@Nonnull final MatchInfo matchInfo) { + // TODO + return ofPulledUpPredicate(pulledUpPredicate, compensationFunction); + } + + @Nonnull + @Override + public Set applyCompensationForPredicate(@Nonnull final CorrelationIdentifier baseAlias) { + return compensationFunction.apply(pulledUpPredicate, baseAlias); + } + }; + } + + private static boolean predicateContainsUnmatchedValues(final @Nonnull QueryPredicate pulledUpPredicate) { + if (pulledUpPredicate instanceof PredicateWithValue) { + final var value = Objects.requireNonNull(((PredicateWithValue)pulledUpPredicate).getValue()); + if (value.preOrderStream() + .anyMatch(v -> v instanceof MaxMatchMap.UnmatchedAggregateValue)) { + return true; + } + } + + if (pulledUpPredicate instanceof PredicateWithComparisons) { + final var comparisons = ((PredicateWithComparisons)pulledUpPredicate).getComparisons(); + for (final var comparison : comparisons) { + if (comparison instanceof Comparisons.ValueComparison) { + final var comparisonValue = comparison.getValue(); + if (comparisonValue.preOrderStream() + .anyMatch(v -> v instanceof MaxMatchMap.UnmatchedAggregateValue)) { + return true; + } + } + } + } + return false; + } + + @Nonnull + static PredicateCompensationFunction ofExistentialPredicate(@Nonnull final ExistsPredicate existsPredicate) { + final var result = LinkedIdentitySet.of((QueryPredicate)existsPredicate); + return new PredicateCompensationFunction() { @Override public boolean isNeeded() { @@ -129,10 +208,48 @@ public boolean isImpossible() { return false; } + @Nonnull + @Override + public PredicateCompensationFunction amendWithOtherMatchInfo(@Nonnull final MatchInfo matchInfo) { + return this; + } + @Nonnull @Override public Set applyCompensationForPredicate(@Nonnull final CorrelationIdentifier baseAlias) { - return compensationFunction.apply(baseAlias); + return result; + } + }; + } + + @Nonnull + static PredicateCompensationFunction ofChildrenCompensationFunctions(@Nonnull final List childrenCompensationFunctions, + @Nonnull final BiFunction, CorrelationIdentifier, Set> compensationFunction) { + return new PredicateCompensationFunction() { + @Override + public boolean isNeeded() { + return true; + } + + @Override + public boolean isImpossible() { + return childrenCompensationFunctions.stream().anyMatch(PredicateCompensationFunction::isImpossible); + } + + @Nonnull + @Override + public PredicateCompensationFunction amendWithOtherMatchInfo(@Nonnull final MatchInfo matchInfo) { + final var amendedChildrenCompensationFunctions = + childrenCompensationFunctions.stream() + .map(childrenCompensationFunction -> childrenCompensationFunction.amendWithOtherMatchInfo(matchInfo)) + .collect(ImmutableList.toImmutableList()); + return ofChildrenCompensationFunctions(amendedChildrenCompensationFunctions, compensationFunction); + } + + @Nonnull + @Override + public Set applyCompensationForPredicate(@Nonnull final CorrelationIdentifier baseAlias) { + return compensationFunction.apply(childrenCompensationFunctions, baseAlias); } }; } @@ -164,6 +281,12 @@ public boolean isImpossible() { return false; } + @Nonnull + @Override + public ResultCompensationFunction amendWithOtherMatchInfo(@Nonnull final MatchInfo matchInfo) { + return this; + } + @Nonnull @Override public Value applyCompensationForResult(@Nonnull final CorrelationIdentifier baseAlias) { @@ -183,6 +306,12 @@ public boolean isImpossible() { return true; } + @Nonnull + @Override + public ResultCompensationFunction amendWithOtherMatchInfo(@Nonnull final MatchInfo matchInfo) { + return this; + } + @Nonnull @Override public Value applyCompensationForResult(@Nonnull final CorrelationIdentifier baseAlias) { @@ -195,11 +324,17 @@ public Value applyCompensationForResult(@Nonnull final CorrelationIdentifier bas boolean isImpossible(); + @Nonnull + ResultCompensationFunction amendWithOtherMatchInfo(@Nonnull MatchInfo matchInfo); + @Nonnull Value applyCompensationForResult(@Nonnull CorrelationIdentifier baseAlias); @Nonnull - static ResultCompensationFunction of(@Nonnull final Function compensationFunction) { + static ResultCompensationFunction ofValue(@Nonnull final Value value, + @Nonnull final BiFunction compensationFunction) { + final var isImpossible = valueContainsUnmatchedValues(value); + return new ResultCompensationFunction() { @Override public boolean isNeeded() { @@ -208,13 +343,20 @@ public boolean isNeeded() { @Override public boolean isImpossible() { - return false; + return isImpossible; + } + + @Nonnull + @Override + public ResultCompensationFunction amendWithOtherMatchInfo(@Nonnull final MatchInfo matchInfo) { + // TODO + return ofValue(value, compensationFunction); } @Nonnull @Override public Value applyCompensationForResult(@Nonnull final CorrelationIdentifier baseAlias) { - return compensationFunction.apply(baseAlias); + return compensationFunction.apply(value, baseAlias); } }; } @@ -228,6 +370,11 @@ static ResultCompensationFunction noCompensationNeeded() { static ResultCompensationFunction impossibleCompensation() { return IMPOSSIBLE_COMPENSATION; } + + private static boolean valueContainsUnmatchedValues(final @Nonnull Value pulledUpValue) { + return pulledUpValue.preOrderStream() + .anyMatch(v -> v instanceof MaxMatchMap.UnmatchedAggregateValue); + } } /** diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java index 55339b3979..8540d5fd7c 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java @@ -37,7 +37,7 @@ import com.apple.foundationdb.record.query.plan.cascades.OrderingPart.RequestedSortOrder; import com.apple.foundationdb.record.query.plan.cascades.PartialMatch; import com.apple.foundationdb.record.query.plan.cascades.PredicateMap; -import com.apple.foundationdb.record.query.plan.cascades.PredicateMultiMap; +import com.apple.foundationdb.record.query.plan.cascades.PredicateMultiMap.ResultCompensationFunction; import com.apple.foundationdb.record.query.plan.cascades.Quantifier; import com.apple.foundationdb.record.query.plan.cascades.Quantifiers; import com.apple.foundationdb.record.query.plan.cascades.RequestedOrdering; @@ -529,6 +529,7 @@ private RequestedOrdering computeRequestedOrdering() { innerQuantifier.getCorrelatedTo()); } + @SuppressWarnings("ConstantValue") @Nonnull @Override public Compensation compensate(@Nonnull final PartialMatch partialMatch, @@ -564,23 +565,31 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, return Compensation.impossibleCompensation(); } - final PredicateMultiMap.ResultCompensationFunction resultCompensationFunction; + boolean isCompensationImpossible = false; + final ResultCompensationFunction resultCompensationFunction; + final Map pulledUpMatchedAggregateValueMap; if (pullUp != null) { - resultCompensationFunction = PredicateMultiMap.ResultCompensationFunction.noCompensationNeeded(); + resultCompensationFunction = ResultCompensationFunction.noCompensationNeeded(); + pulledUpMatchedAggregateValueMap = ImmutableMap.of(); } else { final var rootPullUp = adjustedPullUp.getRootPullUp(); final var maxMatchMap = matchInfo.getMaxMatchMap(); - final var pulledUpResultValueOptional = + final var pulledUpTranslatedResultValueOptional = rootPullUp.pullUpMaybe(maxMatchMap.getQueryValue()); - if (pulledUpResultValueOptional.isEmpty()) { + if (pulledUpTranslatedResultValueOptional.isEmpty()) { return Compensation.impossibleCompensation(); } - final var pulledUpResultValue = pulledUpResultValueOptional.get(); + final var pulledUpTranslatedResultValue = pulledUpTranslatedResultValueOptional.get(); resultCompensationFunction = - PredicateMultiMap.ResultCompensationFunction.of(baseAlias -> pulledUpResultValue.translateCorrelations( - TranslationMap.ofAliases(rootPullUp.getNestingAlias(), baseAlias), false)); + ResultCompensationFunction.ofValue(pulledUpTranslatedResultValue, + (value, baseAlias) -> value.translateCorrelations( + TranslationMap.ofAliases(rootPullUp.getNestingAlias(), baseAlias), false)); + isCompensationImpossible |= resultCompensationFunction.isImpossible(); + + pulledUpMatchedAggregateValueMap = + RegularMatchInfo.pullUpMatchedAggregateValueMap(partialMatch, Quantifier.current(), nestingAlias); } final var unmatchedQuantifiers = partialMatch.getUnmatchedQuantifiers(); @@ -590,12 +599,13 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, return Compensation.noCompensation(); } - return childCompensation.derived(false, + return childCompensation.derived(isCompensationImpossible, new LinkedIdentityMap<>(), getMatchedQuantifiers(partialMatch), unmatchedQuantifiers, partialMatch.getCompensatedAliases(), - resultCompensationFunction); + resultCompensationFunction, + pulledUpMatchedAggregateValueMap); } @Nonnull diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/LogicalTypeFilterExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/LogicalTypeFilterExpression.java index 87ea8c440a..03a83dd106 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/LogicalTypeFilterExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/LogicalTypeFilterExpression.java @@ -30,8 +30,9 @@ import com.apple.foundationdb.record.query.plan.cascades.IdentityBiMap; import com.apple.foundationdb.record.query.plan.cascades.LinkedIdentityMap; import com.apple.foundationdb.record.query.plan.cascades.MatchInfo; +import com.apple.foundationdb.record.query.plan.cascades.MatchInfo.RegularMatchInfo; import com.apple.foundationdb.record.query.plan.cascades.PartialMatch; -import com.apple.foundationdb.record.query.plan.cascades.PredicateMultiMap; +import com.apple.foundationdb.record.query.plan.cascades.PredicateMultiMap.ResultCompensationFunction; import com.apple.foundationdb.record.query.plan.cascades.Quantifier; import com.apple.foundationdb.record.query.plan.cascades.explain.Attribute; import com.apple.foundationdb.record.query.plan.cascades.explain.NodeInfo; @@ -175,6 +176,7 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid return exactlySubsumedBy(candidateExpression, bindingAliasMap, partialMatchMap, translationMapOptional.get()); } + @SuppressWarnings("ConstantValue") @Nonnull @Override public Compensation compensate(@Nonnull final PartialMatch partialMatch, @@ -199,23 +201,31 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, return Compensation.impossibleCompensation(); } - final PredicateMultiMap.ResultCompensationFunction resultCompensationFunction; + boolean isCompensationImpossible = false; + final ResultCompensationFunction resultCompensationFunction; + final Map pulledUpMatchedAggregateValueMap; if (pullUp != null) { - resultCompensationFunction = PredicateMultiMap.ResultCompensationFunction.noCompensationNeeded(); + resultCompensationFunction = ResultCompensationFunction.noCompensationNeeded(); + pulledUpMatchedAggregateValueMap = ImmutableMap.of(); } else { final var rootPullUp = adjustedPullUp.getRootPullUp(); final var maxMatchMap = matchInfo.getMaxMatchMap(); - final var pulledUpResultValueOptional = + final var pulledUpTranslatedResultValueOptional = rootPullUp.pullUpMaybe(maxMatchMap.getQueryValue()); - if (pulledUpResultValueOptional.isEmpty()) { + if (pulledUpTranslatedResultValueOptional.isEmpty()) { return Compensation.impossibleCompensation(); } - final var pulledUpResultValue = pulledUpResultValueOptional.get(); + final var pulledUpTranslatedResultValue = pulledUpTranslatedResultValueOptional.get(); resultCompensationFunction = - PredicateMultiMap.ResultCompensationFunction.of(baseAlias -> pulledUpResultValue.translateCorrelations( - TranslationMap.ofAliases(rootPullUp.getNestingAlias(), baseAlias), false)); + ResultCompensationFunction.ofValue(pulledUpTranslatedResultValue, + (value, baseAlias) -> value.translateCorrelations( + TranslationMap.ofAliases(rootPullUp.getNestingAlias(), baseAlias), false)); + isCompensationImpossible |= resultCompensationFunction.isImpossible(); + + pulledUpMatchedAggregateValueMap = + RegularMatchInfo.pullUpMatchedAggregateValueMap(partialMatch, Quantifier.current(), nestingAlias); } final var unmatchedQuantifiers = partialMatch.getUnmatchedQuantifiers(); @@ -225,12 +235,13 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, return Compensation.noCompensation(); } - return childCompensation.derived(false, + return childCompensation.derived(isCompensationImpossible, new LinkedIdentityMap<>(), getMatchedQuantifiers(partialMatch), unmatchedQuantifiers, partialMatch.getCompensatedAliases(), - resultCompensationFunction); + resultCompensationFunction, + pulledUpMatchedAggregateValueMap); } @Nonnull diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java index 181bee4d30..14dafe0744 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java @@ -860,22 +860,29 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, } final ResultCompensationFunction resultCompensationFunction; + final Map pulledUpMatchedAggregateValueMap; if (pullUp != null) { resultCompensationFunction = ResultCompensationFunction.noCompensationNeeded(); + pulledUpMatchedAggregateValueMap = ImmutableMap.of(); } else { final var rootPullUp = adjustedPullUp.getRootPullUp(); final var maxMatchMap = matchInfo.getMaxMatchMap(); - final var pulledUpResultValueOptional = + final var pulledUpTranslatedResultValueOptional = rootPullUp.pullUpMaybe(maxMatchMap.getQueryValue()); - if (pulledUpResultValueOptional.isEmpty()) { + if (pulledUpTranslatedResultValueOptional.isEmpty()) { return Compensation.impossibleCompensation(); } - final var pulledUpResultValue = pulledUpResultValueOptional.get(); + final var pulledUpTranslatedResultValue = pulledUpTranslatedResultValueOptional.get(); resultCompensationFunction = - ResultCompensationFunction.of(baseAlias -> pulledUpResultValue.translateCorrelations( - TranslationMap.ofAliases(rootPullUp.getNestingAlias(), baseAlias), false)); + ResultCompensationFunction.ofValue(pulledUpTranslatedResultValue, + (value, baseAlias) -> value.translateCorrelations( + TranslationMap.ofAliases(rootPullUp.getNestingAlias(), baseAlias), false)); + isAnyCompensationFunctionImpossible |= resultCompensationFunction.isImpossible(); + + pulledUpMatchedAggregateValueMap = + RegularMatchInfo.pullUpMatchedAggregateValueMap(partialMatch, Quantifier.current(), nestingAlias); } final var isCompensationNeeded = @@ -895,7 +902,8 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, // final var partialMatchMap = regularMatchInfo.getPartialMatchMap(); if (quantifiers.stream() - .filter(quantifier -> quantifier instanceof Quantifier.ForEach && partialMatchMap.containsKeyUnwrapped(quantifier)) + .filter(quantifier -> quantifier instanceof Quantifier.ForEach && + partialMatchMap.containsKeyUnwrapped(quantifier)) .count() > 1) { return Compensation.impossibleCompensation(); } @@ -905,6 +913,7 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, getMatchedQuantifiers(partialMatch), partialMatch.getUnmatchedQuantifiers(), partialMatch.getCompensatedAliases(), - resultCompensationFunction); + resultCompensationFunction, + pulledUpMatchedAggregateValueMap); } } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/AndPredicate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/AndPredicate.java index 1e284a189b..60192e55dd 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/AndPredicate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/AndPredicate.java @@ -128,10 +128,10 @@ public AndPredicate withChildren(final Iterable newChi public PredicateCompensationFunction computeCompensationFunction(@Nonnull final PartialMatch partialMatch, @Nonnull final QueryPredicate originalQueryPredicate, @Nonnull final Map boundParameterPrefixMap, - @Nonnull final List childrenResults, + @Nonnull final List childrenCompensationFunctions, @Nonnull final PullUp pullUp) { boolean isNeeded = false; - for (final var childPredicateCompensationFunction : childrenResults) { + for (final var childPredicateCompensationFunction : childrenCompensationFunctions) { isNeeded |= childPredicateCompensationFunction.isNeeded(); if (childPredicateCompensationFunction.isImpossible()) { return PredicateCompensationFunction.impossibleCompensation(); @@ -142,12 +142,13 @@ public PredicateCompensationFunction computeCompensationFunction(@Nonnull final return PredicateCompensationFunction.noCompensationNeeded(); } - return PredicateCompensationFunction.of( - baseAlias -> childrenResults.stream() - .filter(PredicateCompensationFunction::isNeeded) - .flatMap(predicateCompensationFunction -> - predicateCompensationFunction.applyCompensationForPredicate(baseAlias).stream()) - .collect(LinkedIdentitySet.toLinkedIdentitySet())); + return PredicateCompensationFunction.ofChildrenCompensationFunctions(childrenCompensationFunctions, + (functions, baseAlias) -> + functions.stream() + .filter(PredicateCompensationFunction::isNeeded) + .flatMap(predicateCompensationFunction -> + predicateCompensationFunction.applyCompensationForPredicate(baseAlias).stream()) + .collect(LinkedIdentitySet.toLinkedIdentitySet())); } @Nonnull diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/ExistsPredicate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/ExistsPredicate.java index d73b4b0795..267f102047 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/ExistsPredicate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/ExistsPredicate.java @@ -36,9 +36,6 @@ import com.apple.foundationdb.record.query.plan.cascades.BooleanWithConstraint; import com.apple.foundationdb.record.query.plan.cascades.ComparisonRange; import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier; -import com.apple.foundationdb.record.query.plan.explain.ExplainTokens; -import com.apple.foundationdb.record.query.plan.explain.ExplainTokensWithPrecedence; -import com.apple.foundationdb.record.query.plan.cascades.LinkedIdentitySet; import com.apple.foundationdb.record.query.plan.cascades.Memoizer; import com.apple.foundationdb.record.query.plan.cascades.PartialMatch; import com.apple.foundationdb.record.query.plan.cascades.PredicateMultiMap.PredicateCompensationFunction; @@ -49,6 +46,8 @@ import com.apple.foundationdb.record.query.plan.cascades.values.QuantifiedObjectValue; import com.apple.foundationdb.record.query.plan.cascades.values.translation.PullUp; import com.apple.foundationdb.record.query.plan.cascades.values.translation.TranslationMap; +import com.apple.foundationdb.record.query.plan.explain.ExplainTokens; +import com.apple.foundationdb.record.query.plan.explain.ExplainTokensWithPrecedence; import com.google.auto.service.AutoService; import com.google.common.base.Verify; import com.google.common.collect.ImmutableSet; @@ -238,7 +237,7 @@ private PredicateCompensationFunction computeCompensationFunction(@Nonnull final // Note that this predicate does NOT need to be pulled up as the existential quantifier is separately // added in. // - return PredicateCompensationFunction.of(baseAlias -> LinkedIdentitySet.of(originalExistsPredicate)); + return PredicateCompensationFunction.ofExistentialPredicate(originalExistsPredicate); } return PredicateCompensationFunction.noCompensationNeeded(); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/LeafQueryPredicate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/LeafQueryPredicate.java index 57d68eed27..81df811b9a 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/LeafQueryPredicate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/LeafQueryPredicate.java @@ -84,9 +84,10 @@ default PredicateMultiMap.PredicateCompensationFunction computeCompensationFunct return toResidualPredicate() .replaceValuesMaybe(pullUp::pullUpMaybe) .map(queryPredicate -> - PredicateMultiMap.PredicateCompensationFunction.of(baseAlias -> - LinkedIdentitySet.of(queryPredicate.translateCorrelations( - TranslationMap.ofAliases(pullUp.getTopAlias(), baseAlias), false)))) + PredicateMultiMap.PredicateCompensationFunction.ofPulledUpPredicate(queryPredicate, + (pulledUpPredicate, baseAlias) -> + LinkedIdentitySet.of(pulledUpPredicate.translateCorrelations( + TranslationMap.ofAliases(pullUp.getTopAlias(), baseAlias), false)))) .orElse(PredicateMultiMap.PredicateCompensationFunction.impossibleCompensation()); } } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/NotPredicate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/NotPredicate.java index d23f41871b..53b3ecbca6 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/NotPredicate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/NotPredicate.java @@ -149,18 +149,19 @@ public NotPredicate withChild(@Nonnull final QueryPredicate newChild) { public PredicateCompensationFunction computeCompensationFunction(@Nonnull final PartialMatch partialMatch, @Nonnull final QueryPredicate originalQueryPredicate, @Nonnull final Map boundParameterPrefixMap, - @Nonnull final List childrenResults, + @Nonnull final List childrenCompensationFunctions, @Nonnull final PullUp pullUp) { - Verify.verify(childrenResults.size() == 1); - final var predicateCompensationFunction = Iterables.getOnlyElement(childrenResults); + Verify.verify(childrenCompensationFunctions.size() == 1); + final var predicateCompensationFunction = Iterables.getOnlyElement(childrenCompensationFunctions); if (!predicateCompensationFunction.isNeeded()) { return PredicateCompensationFunction.noCompensationNeeded(); } - return PredicateCompensationFunction.of(baseAlias -> { - final var childPredicates = predicateCompensationFunction.applyCompensationForPredicate(baseAlias); - return LinkedIdentitySet.of(not(AndPredicate.and(childPredicates))); - }); + return PredicateCompensationFunction.ofChildrenCompensationFunctions(childrenCompensationFunctions, + (functions, baseAlias) -> { + final var childPredicates = Iterables.getOnlyElement(functions).applyCompensationForPredicate(baseAlias); + return LinkedIdentitySet.of(not(AndPredicate.and(childPredicates))); + }); } @Nonnull diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/OrPredicate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/OrPredicate.java index a055ad4c9e..ee4215a8c1 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/OrPredicate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/OrPredicate.java @@ -354,10 +354,10 @@ private Optional impliesWithValuesAndRanges(@Nonnull final Val public PredicateCompensationFunction computeCompensationFunction(@Nonnull final PartialMatch partialMatch, @Nonnull final QueryPredicate originalQueryPredicate, @Nonnull final Map boundParameterPrefixMap, - @Nonnull final List childrenResults, + @Nonnull final List childrenCompensationFunctions, @Nonnull final PullUp pullUp) { boolean isNeeded = false; - for (final var childPredicateCompensationFunction : childrenResults) { + for (final var childPredicateCompensationFunction : childrenCompensationFunctions) { isNeeded |= childPredicateCompensationFunction.isNeeded(); if (childPredicateCompensationFunction.isImpossible()) { return PredicateCompensationFunction.impossibleCompensation(); @@ -368,19 +368,20 @@ public PredicateCompensationFunction computeCompensationFunction(@Nonnull final return PredicateCompensationFunction.noCompensationNeeded(); } - return PredicateCompensationFunction.of(baseAlias -> { - final var childPredicatesList = - childrenResults.stream() - .filter(PredicateCompensationFunction::isNeeded) - .map(predicateCompensationFunction -> predicateCompensationFunction.applyCompensationForPredicate(baseAlias)) - .collect(ImmutableList.toImmutableList()); - // take the predicates from each individual expansion, "and" them, and then "or" them - final var predicates = LinkedIdentitySet.of(); - for (final var childPredicates : childPredicatesList) { - predicates.add(AndPredicate.and(childPredicates)); - } - return LinkedIdentitySet.of(OrPredicate.or(predicates)); - }); + return PredicateCompensationFunction.ofChildrenCompensationFunctions(childrenCompensationFunctions, + (functions, baseAlias) -> { + final var childPredicatesList = + functions.stream() + .filter(PredicateCompensationFunction::isNeeded) + .map(predicateCompensationFunction -> predicateCompensationFunction.applyCompensationForPredicate(baseAlias)) + .collect(ImmutableList.toImmutableList()); + // take the predicates from each individual expansion, "and" them, and then "or" them + final var predicates = LinkedIdentitySet.of(); + for (final var childPredicates : childPredicatesList) { + predicates.add(AndPredicate.and(childPredicates)); + } + return LinkedIdentitySet.of(OrPredicate.or(predicates)); + }); } @Nonnull diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/QueryPredicate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/QueryPredicate.java index 328eaacc20..6c815e0c01 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/QueryPredicate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/QueryPredicate.java @@ -251,9 +251,10 @@ default PredicateCompensationFunction computeCompensationFunction(@Nonnull final return toResidualPredicate() .replaceValuesMaybe(pullUp::pullUpMaybe) .map(queryPredicate -> - PredicateCompensationFunction.of(baseAlias -> - LinkedIdentitySet.of(queryPredicate.translateCorrelations( - TranslationMap.ofAliases(pullUp.getTopAlias(), baseAlias), false)))) + PredicateCompensationFunction.ofPulledUpPredicate(queryPredicate, + (pulledUpPredicate, baseAlias) -> + LinkedIdentitySet.of(pulledUpPredicate.translateCorrelations( + TranslationMap.ofAliases(pullUp.getTopAlias(), baseAlias), false)))) .orElse(PredicateCompensationFunction.impossibleCompensation()); } From a48b81d9ec67489adf5b18d4e5dbc30817f30f23 Mon Sep 17 00:00:00 2001 From: Normen Seemann Date: Tue, 11 Mar 2025 10:47:21 -0700 Subject: [PATCH 04/20] pullng up unmatched values --- .../plan/cascades/AggregateMappings.java | 62 +++++++ .../query/plan/cascades/Compensation.java | 69 ++++---- .../plan/cascades/CorrelationIdentifier.java | 10 +- .../KeyExpressionExpansionVisitor.java | 2 +- .../record/query/plan/cascades/MatchInfo.java | 162 +++++++++++------- .../query/plan/cascades/PartialMatch.java | 24 +-- .../plan/cascades/PredicateMultiMap.java | 70 +++++--- .../query/plan/cascades/Quantifier.java | 2 +- .../expressions/ExplodeExpression.java | 2 +- .../FullUnorderedScanExpression.java | 2 +- .../expressions/GroupByExpression.java | 129 ++++++++++++-- .../LogicalTypeFilterExpression.java | 17 +- .../expressions/MatchableSortExpression.java | 2 +- .../expressions/RelationalExpression.java | 2 +- .../expressions/SelectExpression.java | 24 +-- .../predicates/LeafQueryPredicate.java | 2 +- .../cascades/predicates/QueryPredicate.java | 2 +- .../values/translation/MaxMatchMap.java | 115 ++++--------- .../cascades/values/translation/PullUp.java | 36 ++-- .../RecordQueryStreamingAggregationPlan.java | 4 +- .../foundationdb/query/FDBInQueryTest.java | 4 +- .../FDBLongArithmeticFunctionQueryTest.java | 2 +- .../foundationdb/query/TempTableTest.java | 10 +- .../plan/explain/ExplainPlanVisitorTest.java | 2 +- .../recordlayer/query/Expression.java | 2 +- 25 files changed, 469 insertions(+), 289 deletions(-) create mode 100644 fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateMappings.java diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateMappings.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateMappings.java new file mode 100644 index 0000000000..cdb1c53665 --- /dev/null +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateMappings.java @@ -0,0 +1,62 @@ +/* + * AggregateMappings.java + * + * This source file is part of the FoundationDB open source project + * + * Copyright 2015-2025 Apple Inc. and the FoundationDB project authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.apple.foundationdb.record.query.plan.cascades; + +import com.apple.foundationdb.record.query.plan.cascades.values.Value; +import com.google.common.collect.BiMap; +import com.google.common.collect.ImmutableBiMap; +import com.google.common.collect.ImmutableMap; + +import javax.annotation.Nonnull; +import java.util.Map; + +public class AggregateMappings { + @Nonnull + private final Map matchedAggregateMap; + + @Nonnull + private final BiMap unmatchedAggregateMap; + + private AggregateMappings(@Nonnull final Map matchedAggregateMap, @Nonnull final BiMap unmatchedAggregateMap) { + this.matchedAggregateMap = matchedAggregateMap; + this.unmatchedAggregateMap = unmatchedAggregateMap; + } + + @Nonnull + public Map getMatchedAggregateMap() { + return matchedAggregateMap; + } + + @Nonnull + public BiMap getUnmatchedAggregateMap() { + return unmatchedAggregateMap; + } + + public static AggregateMappings empty() { + return of(ImmutableBiMap.of(), ImmutableBiMap.of()); + } + + @Nonnull + public static AggregateMappings of(@Nonnull final BiMap matchedAggregateMap, + @Nonnull final BiMap unmatchedAggregateMap) { + return new AggregateMappings(ImmutableMap.copyOf(matchedAggregateMap), ImmutableBiMap.copyOf(unmatchedAggregateMap)); + } +} diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java index a8718abcb0..d46139e1cb 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java @@ -27,7 +27,6 @@ import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression; import com.apple.foundationdb.record.query.plan.cascades.predicates.QueryPredicate; import com.apple.foundationdb.record.query.plan.cascades.rules.DataAccessRule; -import com.apple.foundationdb.record.query.plan.cascades.values.Value; import com.google.common.base.Suppliers; import com.google.common.base.Verify; import com.google.common.collect.ImmutableList; @@ -387,7 +386,7 @@ default ForMatch derived(final boolean isImpossible, @Nonnull final Set unmatchedQuantifiers, @Nonnull final Set compensatedAliases, @Nonnull final ResultCompensationFunction resultCompensationFunction, - @Nonnull final Map matchedAggregateValueMap) { + @Nonnull final AggregateMappings aggregateMappings) { // // At least one of these conditions must be true: // - it is an impossible compensation (in which case the predicate compensation map may be empty) @@ -400,7 +399,7 @@ default ForMatch derived(final boolean isImpossible, !predicateCompensationMap.isEmpty() || resultCompensationFunction.isNeeded() || isNeededForFiltering()); return new ForMatch(isImpossible, this, predicateCompensationMap, matchedQuantifiers, - unmatchedQuantifiers, compensatedAliases, resultCompensationFunction, matchedAggregateValueMap); + unmatchedQuantifiers, compensatedAliases, resultCompensationFunction, aggregateMappings); } /** @@ -451,7 +450,7 @@ default boolean isFinalNeeded() { ResultCompensationFunction getResultCompensationFunction(); @Nonnull - Map getMatchedAggregateValueMap(); + AggregateMappings getAggregateMappings(); /** * Specific implementation of union-ing two compensations both of type {@link WithSelectCompensation}. @@ -490,6 +489,11 @@ default Compensation union(@Nonnull Compensation otherCompensation) { return impossibleCompensation(); } + final Compensation unionedChildCompensation = getChildCompensation().union(otherWithSelectCompensation.getChildCompensation()); + if (unionedChildCompensation.isImpossible() || !unionedChildCompensation.canBeDeferred()) { + return Compensation.impossibleCompensation(); + } + final ResultCompensationFunction newResultResultCompensationFunction; final var resultCompensationFunction = getResultCompensationFunction(); final var otherResultCompensationFunction = otherWithSelectCompensation.getResultCompensationFunction(); @@ -503,7 +507,8 @@ default Compensation union(@Nonnull Compensation otherCompensation) { newResultResultCompensationFunction = resultCompensationFunction; } - final var otherCompensationMap = otherWithSelectCompensation.getPredicateCompensationMap(); + final var otherCompensationMap = + otherWithSelectCompensation.getPredicateCompensationMap(); final var combinedPredicateMap = new LinkedIdentityMap(); combinedPredicateMap.putAll(getPredicateCompensationMap()); @@ -526,11 +531,6 @@ default Compensation union(@Nonnull Compensation otherCompensation) { combinedPredicateMap.put(otherEntry.getKey(), otherEntry.getValue()); } - final Compensation unionedChildCompensation = getChildCompensation().union(otherWithSelectCompensation.getChildCompensation()); - if (unionedChildCompensation.isImpossible() || !unionedChildCompensation.canBeDeferred()) { - return Compensation.impossibleCompensation(); - } - if (!unionedChildCompensation.isNeededForFiltering() && !newResultResultCompensationFunction.isNeeded() && combinedPredicateMap.isEmpty()) { return Compensation.noCompensation(); @@ -546,7 +546,7 @@ default Compensation union(@Nonnull Compensation otherCompensation) { ImmutableSet.of(), Sets.union(getCompensatedAliases(), otherWithSelectCompensation.getCompensatedAliases()), newResultResultCompensationFunction, - ImmutableMap.of()); + AggregateMappings.empty()); } /** @@ -567,6 +567,23 @@ default Compensation intersect(@Nonnull Compensation otherCompensation) { } final var otherWithSelectCompensation = (WithSelectCompensation)otherCompensation; + final Compensation childCompensation = getChildCompensation(); + Verify.verify(!(childCompensation instanceof WithSelectCompensation) || + ((WithSelectCompensation)childCompensation).getUnmatchedForEachQuantifiers().isEmpty()); + + final Compensation intersectedChildCompensation = + childCompensation.intersect(otherWithSelectCompensation.getChildCompensation()); + if (intersectedChildCompensation.isImpossible() || !intersectedChildCompensation.canBeDeferred()) { + return Compensation.impossibleCompensation(); + } + + final var newMatchedAggregateMap = + Stream.concat(getAggregateMappings().getMatchedAggregateMap().entrySet().stream(), + otherWithSelectCompensation.getAggregateMappings().getMatchedAggregateMap().entrySet().stream()) + .collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, + Map.Entry::getValue, + (l, r) -> l)); + final ResultCompensationFunction newResultResultCompensationFunction; final var resultCompensationFunction = getResultCompensationFunction(); final var otherResultCompensationFunction = otherWithSelectCompensation.getResultCompensationFunction(); @@ -595,16 +612,6 @@ default Compensation intersect(@Nonnull Compensation otherCompensation) { } } - final Compensation childCompensation = getChildCompensation(); - Verify.verify(!(childCompensation instanceof WithSelectCompensation) || - ((WithSelectCompensation)childCompensation).getUnmatchedForEachQuantifiers().isEmpty()); - - final Compensation intersectedChildCompensation = - childCompensation.intersect(otherWithSelectCompensation.getChildCompensation()); - if (intersectedChildCompensation.isImpossible() || !intersectedChildCompensation.canBeDeferred()) { - return Compensation.impossibleCompensation(); - } - if (!intersectedChildCompensation.isNeededForFiltering() && !newResultResultCompensationFunction.isNeeded() && combinedPredicateMap.isEmpty()) { return Compensation.noCompensation(); @@ -614,13 +621,6 @@ default Compensation intersect(@Nonnull Compensation otherCompensation) { return intersectedChildCompensation; } - final var newMatchedAggregateValueMap = - Stream.concat(getMatchedAggregateValueMap().entrySet().stream(), - otherWithSelectCompensation.getMatchedAggregateValueMap().entrySet().stream()) - .collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, - Map.Entry::getValue, - (l, r) -> l)); - // Note that at the current time each side can only contribute at most one foreach quantifier, thus the // intersection should also only contain at most one for each quantifier. final Sets.SetView intersectedMatchedQuantifiers = @@ -642,7 +642,7 @@ default Compensation intersect(@Nonnull Compensation otherCompensation) { intersectedUnmatchedQuantifiers, getCompensatedAliases(), // both compensated aliases must be identical, but too expensive to check newResultResultCompensationFunction, - newMatchedAggregateValueMap); + AggregateMappings.empty()); } } @@ -672,7 +672,7 @@ class ForMatch implements WithSelectCompensation { @Nonnull private final ResultCompensationFunction resultCompensationFunction; @Nonnull - private final Map matchedAggregateValueMap; + private final AggregateMappings aggregateMappings; @Nonnull private final Supplier> unmatchedForEachQuantifiersSupplier; @@ -684,7 +684,7 @@ private ForMatch(final boolean isImpossible, @Nonnull final Collection unmatchedQuantifiers, @Nonnull final Set compensatedAliases, @Nonnull final ResultCompensationFunction resultCompensationFunction, - @Nonnull final Map matchedAggregateValueMap) { + @Nonnull final AggregateMappings aggregateMappings) { this.isImpossible = isImpossible; this.childCompensation = childCompensation; this.predicateCompensationMap = new LinkedIdentityMap<>(); @@ -695,7 +695,7 @@ private ForMatch(final boolean isImpossible, this.unmatchedQuantifiers.addAll(unmatchedQuantifiers); this.compensatedAliases = ImmutableSet.copyOf(compensatedAliases); this.resultCompensationFunction = resultCompensationFunction; - this.matchedAggregateValueMap = ImmutableMap.copyOf(matchedAggregateValueMap); + this.aggregateMappings = aggregateMappings; this.unmatchedForEachQuantifiersSupplier = Suppliers.memoize(this::computeUnmatchedForEachQuantifiers); } @@ -716,7 +716,6 @@ public Set getMatchedQuantifiers() { return matchedQuantifiers; } - @Nonnull @Override public Set getUnmatchedQuantifiers() { @@ -756,8 +755,8 @@ public ResultCompensationFunction getResultCompensationFunction() { @Nonnull @Override - public Map getMatchedAggregateValueMap() { - return matchedAggregateValueMap; + public AggregateMappings getAggregateMappings() { + return aggregateMappings; } /** diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/CorrelationIdentifier.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/CorrelationIdentifier.java index 72dc45bcb8..26604b4b0d 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/CorrelationIdentifier.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/CorrelationIdentifier.java @@ -61,8 +61,8 @@ public static CorrelationIdentifier of(@Nonnull final String id) { * @return a new unique {@link CorrelationIdentifier} */ @Nonnull - public static CorrelationIdentifier uniqueID() { - return uniqueID(CorrelationIdentifier.class); + public static CorrelationIdentifier uniqueId() { + return uniqueId(CorrelationIdentifier.class); } /** @@ -73,8 +73,8 @@ public static CorrelationIdentifier uniqueID() { * @return a new unique {@link CorrelationIdentifier} */ @Nonnull - public static CorrelationIdentifier uniqueID(@Nonnull final Class clazz) { - return uniqueID(clazz, clazz.getSimpleName().substring(0, 1).toLowerCase(Locale.ROOT)); + public static CorrelationIdentifier uniqueId(@Nonnull final Class clazz) { + return uniqueId(clazz, clazz.getSimpleName().substring(0, 1).toLowerCase(Locale.ROOT)); } /** @@ -86,7 +86,7 @@ public static CorrelationIdentifier uniqueID(@Nonnull final Class clazz) { * @return a new unique {@link CorrelationIdentifier} */ @Nonnull - public static CorrelationIdentifier uniqueID(@Nonnull final Class clazz, @Nonnull final String prefix) { + public static CorrelationIdentifier uniqueId(@Nonnull final Class clazz, @Nonnull final String prefix) { final CorrelationIdentifier id = Debugger.getIndexOptional(clazz) .map(i -> CorrelationIdentifier.of(prefix + i)) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/KeyExpressionExpansionVisitor.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/KeyExpressionExpansionVisitor.java index aa7a24caa6..abcacc3644 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/KeyExpressionExpansionVisitor.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/KeyExpressionExpansionVisitor.java @@ -306,7 +306,7 @@ public GraphExpansion visitExpression(@Nonnull final ListKeyExpression listKeyEx * a unique alias based on an increasing number that is human-readable otherwise. */ protected static CorrelationIdentifier newParameterAlias() { - return CorrelationIdentifier.uniqueID(PredicateWithValueAndRanges.class); + return CorrelationIdentifier.uniqueId(PredicateWithValueAndRanges.class); } /** diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchInfo.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchInfo.java index 594440fcc7..ababd15c01 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchInfo.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchInfo.java @@ -30,6 +30,7 @@ import com.apple.foundationdb.record.query.plan.cascades.values.translation.PullUp; import com.google.common.base.Equivalence; import com.google.common.base.Suppliers; +import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; @@ -37,6 +38,7 @@ import com.google.common.collect.Sets; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Collection; import java.util.List; import java.util.Map; @@ -70,24 +72,25 @@ Map collectPulledUpPredicateMappings(@Nonnull @Nonnull Set interestingPredicates); @Nonnull - Map getMatchedAggregateValueMap(); + AggregateMappings getAggregateMappings(); @Nonnull default AdjustedBuilder adjustedBuilder() { return new AdjustedBuilder(this, getMatchedOrderingParts(), getMaxMatchMap(), - getMatchedAggregateValueMap()); + getAggregateMappings()); } @Nonnull - default Map adjustMatchedAggregateMap(@Nonnull final PartialMatch partialMatch, - @Nonnull final Quantifier candidateQuantifier) { - final var matchedAggregateValueMapBuilder = ImmutableMap.builder(); - final var matchedAggregateValueMap = getMatchedAggregateValueMap(); - for (final var matchedAggregateValueMapEntry : matchedAggregateValueMap.entrySet()) { - final var queryAggregateValue = matchedAggregateValueMapEntry.getKey(); - final var candidateAggregateValue = matchedAggregateValueMapEntry.getValue(); + default AggregateMappings adjustAggregateMappings(@Nonnull final PartialMatch partialMatch, + @Nonnull final Quantifier candidateQuantifier) { + final var adjustedMatchedAggregateMapBuilder = ImmutableBiMap.builder(); + final var aggregateMappings = getAggregateMappings(); + final var matchedAggregateMap = aggregateMappings.getMatchedAggregateMap(); + for (final var matchedAggregateMapEntry : matchedAggregateMap.entrySet()) { + final var queryAggregateValue = matchedAggregateMapEntry.getKey(); + final var candidateAggregateValue = matchedAggregateMapEntry.getValue(); final var candidateLowerExpression = Iterables.getOnlyElement(partialMatch.getCandidateRef().getMembers()); final var candidateLowerResultValue = candidateLowerExpression.getResultValue(); @@ -99,12 +102,13 @@ default Map adjustMatchedAggregateMap(@Nonnull final PartialMatch candidateQuantifier.getAlias()); final var pulledUpCandidateAggregateValue = candidatePullUpMap.get(candidateAggregateValue); if (pulledUpCandidateAggregateValue == null) { - return ImmutableMap.of(); + return AggregateMappings.empty(); } - matchedAggregateValueMapBuilder.put(queryAggregateValue, pulledUpCandidateAggregateValue); + adjustedMatchedAggregateMapBuilder.put(queryAggregateValue, pulledUpCandidateAggregateValue); } - return matchedAggregateValueMapBuilder.build(); + return AggregateMappings.of(adjustedMatchedAggregateMapBuilder.build(), + aggregateMappings.getUnmatchedAggregateMap()); } /** @@ -146,7 +150,7 @@ class RegularMatchInfo implements MatchInfo { private final MaxMatchMap maxMatchMap; @Nonnull - private final Map matchedAggregateValueMap; + private final AggregateMappings aggregateMappings; /** * Field to hold additional query plan constraints that need to be imposed on the potentially realized match. @@ -160,7 +164,7 @@ private RegularMatchInfo(@Nonnull final Map matchedOrderingParts, @Nonnull final MaxMatchMap maxMatchMap, - @Nonnull final Map matchedAggregateValueMap, + @Nonnull final AggregateMappings aggregateMappings, @Nonnull final QueryPlanConstraint additionalPlanConstraint) { this.parameterBindingMap = ImmutableMap.copyOf(parameterBindingMap); this.bindingAliasMap = bindingAliasMap; @@ -174,7 +178,7 @@ private RegularMatchInfo(@Nonnull final Map collectPulledUpPredicateMappings(@N for (final var childPartialMatchEntry : partialMatchMap.entrySet()) { final var queryQuantifier = childPartialMatchEntry.getKey().get(); final PartialMatch childPartialMatch = Objects.requireNonNull(childPartialMatchEntry.getValue().get()); - final var nestingAlias = + final var candidateAlias = Objects.requireNonNull(bindingAliasMap.getTarget(queryQuantifier.getAlias())); - resultsMap.putAll(childPartialMatch.pullUpToParent(nestingAlias, interestingPredicates)); + resultsMap.putAll(childPartialMatch.pullUpToParent(candidateAlias, interestingPredicates)); } return resultsMap; } @@ -247,8 +251,8 @@ public MaxMatchMap getMaxMatchMap() { @Nonnull @Override - public Map getMatchedAggregateValueMap() { - return matchedAggregateValueMap; + public AggregateMappings getAggregateMappings() { + return aggregateMappings; } @Nonnull @@ -290,7 +294,7 @@ public static Optional tryFromMatchMap(@Nonnull final AliasMap bindin @Nonnull final IdentityBiMap partialMatchMap, @Nonnull final MaxMatchMap maxMatchMap) { return tryMerge(bindingAliasMap, partialMatchMap, ImmutableMap.of(), PredicateMap.empty(), - maxMatchMap, ImmutableMap.of(), maxMatchMap.getQueryPlanConstraint()); + maxMatchMap, AggregateMappings.empty(), maxMatchMap.getQueryPlanConstraint()); } @Nonnull @@ -299,7 +303,7 @@ public static Optional tryMerge(@Nonnull final AliasMap bindingAliasM @Nonnull final Map parameterBindingMap, @Nonnull final PredicateMultiMap predicateMap, @Nonnull final MaxMatchMap maxMatchMap, - @Nonnull final Map additionalMatchedAggregateValueMap, + @Nonnull final AggregateMappings additionalAggregateMappings, @Nonnull final QueryPlanConstraint additionalPlanConstraint) { final var parameterMapsBuilder = ImmutableList.>builder(); final var matchInfos = PartialMatch.matchInfosFromMap(partialMatchMap); @@ -326,8 +330,8 @@ public static Optional tryMerge(@Nonnull final AliasMap bindingAliasM tryMergeParameterBindings(parameterMapsBuilder.build()); final var matchedAggregateValueMap = - pullUpAndMergeMatchedAggregateMap(bindingAliasMap, partialMatchMap, - additionalMatchedAggregateValueMap); + pullUpAndMergeAggregateMappings(bindingAliasMap, partialMatchMap, + additionalAggregateMappings); return mergedParameterBindingsOptional .map(mergedParameterBindings -> new RegularMatchInfo(mergedParameterBindings, @@ -363,47 +367,61 @@ public static Optional> tryMergePara } @Nonnull - private static Map pullUpAndMergeMatchedAggregateMap(@Nonnull final AliasMap bindingAliasMap, - @Nonnull final IdentityBiMap partialMatchMap, - @Nonnull final Map additionalMatchedAggregateValueMap) { - final var matchedAggregateValueMapBuilder = ImmutableMap.builder(); - matchedAggregateValueMapBuilder.putAll(additionalMatchedAggregateValueMap); + private static AggregateMappings pullUpAndMergeAggregateMappings(@Nonnull final AliasMap bindingAliasMap, + @Nonnull final IdentityBiMap partialMatchMap, + @Nonnull final AggregateMappings additionalAggregateMappings) { + final var matchedAggregateMapBuilder = ImmutableBiMap.builder(); + matchedAggregateMapBuilder.putAll(additionalAggregateMappings.getMatchedAggregateMap()); + final var unatchedAggregateMapBuilder = ImmutableBiMap.builder(); + unatchedAggregateMapBuilder.putAll(additionalAggregateMappings.getUnmatchedAggregateMap()); for (final var partialMatchMapEntry : partialMatchMap.entrySet()) { final var partialMatchMapEntryKey = partialMatchMapEntry.getKey(); final var quantifier = partialMatchMapEntryKey.get(); if (quantifier instanceof Quantifier.ForEach) { final var partialMatch = partialMatchMapEntry.getValue().get(); - final var pulledUpMatchedAggregateValueMap = - pullUpMatchedAggregateValueMap(partialMatch, + final var pulledUpAggregateMappings = + pullUpAggregateMappings(partialMatch, quantifier.getAlias(), Objects.requireNonNull(bindingAliasMap.getTarget(quantifier.getAlias()))); - matchedAggregateValueMapBuilder.putAll(pulledUpMatchedAggregateValueMap); + matchedAggregateMapBuilder.putAll(pulledUpAggregateMappings.getMatchedAggregateMap()); + unatchedAggregateMapBuilder.putAll(pulledUpAggregateMappings.getUnmatchedAggregateMap()); } } - return matchedAggregateValueMapBuilder.build(); + return AggregateMappings.of(matchedAggregateMapBuilder.build(), unatchedAggregateMapBuilder.build()); } @Nonnull - public static Map pullUpMatchedAggregateValueMap(@Nonnull final PartialMatch partialMatch, - @Nonnull final CorrelationIdentifier queryAlias, - @Nonnull final CorrelationIdentifier candidateAlias) { + public static AggregateMappings pullUpAggregateMappings(@Nonnull final PartialMatch partialMatch, + @Nonnull final CorrelationIdentifier candidateAlias) { + return pullUpAggregateMappings(partialMatch, null, candidateAlias); + } + + @Nonnull + public static AggregateMappings pullUpAggregateMappings(@Nonnull final PartialMatch partialMatch, + @Nullable final CorrelationIdentifier queryAlias, + @Nonnull final CorrelationIdentifier candidateAlias) { final var matchInfo = partialMatch.getMatchInfo(); final var queryExpression = partialMatch.getQueryExpression(); final var resultValue = queryExpression.getResultValue(); - final var matchedAggregateValueMapBuilder = ImmutableMap.builder(); - final var matchedAggregateValueMap = matchInfo.getMatchedAggregateValueMap(); - for (final var matchedAggregateValueMapEntry : matchedAggregateValueMap.entrySet()) { - final var queryAggregateValue = matchedAggregateValueMapEntry.getKey(); - final var pullUpMap = - resultValue.pullUp(ImmutableList.of(queryAggregateValue), AliasMap.emptyMap(), - Sets.difference(queryAggregateValue.getCorrelatedToWithoutChildren(), - queryExpression.getCorrelatedTo()), queryAlias); - final var pulledUpQueryAggregateValue = pullUpMap.get(queryAggregateValue); - if (pulledUpQueryAggregateValue == null) { - return ImmutableMap.of(); + final var aggregateMappings = matchInfo.getAggregateMappings(); + final var matchedAggregateMapBuilder = ImmutableBiMap.builder(); + for (final var matchedAggregateMapEntry : aggregateMappings.getMatchedAggregateMap().entrySet()) { + final var queryAggregateValue = matchedAggregateMapEntry.getKey(); + final Value pulledUpQueryAggregateValue; + if (queryAlias != null) { + final var pullUpMap = + resultValue.pullUp(ImmutableList.of(queryAggregateValue), AliasMap.emptyMap(), + Sets.difference(queryAggregateValue.getCorrelatedToWithoutChildren(), + queryExpression.getCorrelatedTo()), queryAlias); + pulledUpQueryAggregateValue = pullUpMap.get(queryAggregateValue); + if (pulledUpQueryAggregateValue == null) { + return AggregateMappings.empty(); + } + } else { + pulledUpQueryAggregateValue = queryAggregateValue; } - final var candidateAggregateValue = matchedAggregateValueMapEntry.getValue(); + final var candidateAggregateValue = matchedAggregateMapEntry.getValue(); final var candidateLowerExpression = Iterables.getOnlyElement(partialMatch.getCandidateRef().getMembers()); final var candidateLowerResultValue = candidateLowerExpression.getResultValue(); @@ -415,12 +433,30 @@ public static Map pullUpMatchedAggregateValueMap(@Nonnull final Pa candidateAlias); final var pulledUpCandidateAggregateValue = candidatePullUpMap.get(candidateAggregateValue); if (pulledUpCandidateAggregateValue == null) { - return ImmutableMap.of(); + return AggregateMappings.empty(); } - matchedAggregateValueMapBuilder.put(pulledUpQueryAggregateValue, pulledUpCandidateAggregateValue); + matchedAggregateMapBuilder.put(pulledUpQueryAggregateValue, pulledUpCandidateAggregateValue); + } + + final var unmatchedAggregateMapBuilder = ImmutableBiMap.builder(); + if (queryAlias != null) { + for (final var unmatchedAggregateMapEntry : aggregateMappings.getUnmatchedAggregateMap().entrySet()) { + final var queryAggregateValue = unmatchedAggregateMapEntry.getValue(); + final var pullUpMap = + resultValue.pullUp(ImmutableList.of(queryAggregateValue), AliasMap.emptyMap(), + Sets.difference(queryAggregateValue.getCorrelatedToWithoutChildren(), + queryExpression.getCorrelatedTo()), queryAlias); + final var pulledUpQueryAggregateValue = pullUpMap.get(queryAggregateValue); + if (pulledUpQueryAggregateValue == null) { + return AggregateMappings.empty(); + } + unmatchedAggregateMapBuilder.put(unmatchedAggregateMapEntry.getKey(), pulledUpQueryAggregateValue); + } + } else { + unmatchedAggregateMapBuilder.putAll(aggregateMappings.getUnmatchedAggregateMap()); } - return matchedAggregateValueMapBuilder.build(); + return AggregateMappings.of(matchedAggregateMapBuilder.build(), unmatchedAggregateMapBuilder.build()); } } @@ -457,16 +493,16 @@ class AdjustedMatchInfo implements MatchInfo { private final MaxMatchMap maxMatchMap; @Nonnull - private final Map matchedAggregateValueMap; + private final AggregateMappings aggregateMappings; private AdjustedMatchInfo(@Nonnull final MatchInfo underlying, @Nonnull final List matchedOrderingParts, @Nonnull final MaxMatchMap maxMatchMap, - @Nonnull final Map matchedAggregateValueMap) { + @Nonnull final AggregateMappings aggregateMappings) { this.underlying = underlying; this.matchedOrderingParts = matchedOrderingParts; this.maxMatchMap = maxMatchMap; - this.matchedAggregateValueMap = ImmutableMap.copyOf(matchedAggregateValueMap); + this.aggregateMappings = aggregateMappings; } @Nonnull @@ -488,8 +524,8 @@ public MaxMatchMap getMaxMatchMap() { @Nonnull @Override - public Map getMatchedAggregateValueMap() { - return matchedAggregateValueMap; + public AggregateMappings getAggregateMappings() { + return aggregateMappings; } @Override @@ -546,7 +582,7 @@ class AdjustedBuilder { private List matchedOrderingParts; @Nonnull - private Map matchedAggregateValueMap; + private AggregateMappings aggregateMappings; /** * A map of maximum matches between the query result {@code Value} and the corresponding candidate's result @@ -558,11 +594,11 @@ class AdjustedBuilder { private AdjustedBuilder(@Nonnull final MatchInfo underlying, @Nonnull final List matchedOrderingParts, @Nonnull final MaxMatchMap maxMatchMap, - @Nonnull final Map matchedAggregateValueMap) { + @Nonnull final AggregateMappings aggregateMappings) { this.underlying = underlying; this.matchedOrderingParts = matchedOrderingParts; this.maxMatchMap = maxMatchMap; - this.matchedAggregateValueMap = matchedAggregateValueMap; + this.aggregateMappings = aggregateMappings; } @Nonnull @@ -576,8 +612,8 @@ public AdjustedBuilder setMatchedOrderingParts(@Nonnull final List matchedAggregateValueMap) { - this.matchedAggregateValueMap = matchedAggregateValueMap; + public AdjustedBuilder setAggregateMappings(@Nonnull final AggregateMappings aggregateMappings) { + this.aggregateMappings = aggregateMappings; return this; } @@ -595,8 +631,8 @@ public AdjustedBuilder setMaxMatchMap(@Nonnull final MaxMatchMap maxMatchMap) { @Nonnull - public Map getMatchedAggregateValueMap() { - return matchedAggregateValueMap; + public AggregateMappings getAggregateMappings() { + return aggregateMappings; } @Nonnull @@ -605,7 +641,7 @@ public MatchInfo build() { underlying, matchedOrderingParts, maxMatchMap, - matchedAggregateValueMap); + aggregateMappings); } } } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PartialMatch.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PartialMatch.java index dc8fcb932d..4e15108400 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PartialMatch.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PartialMatch.java @@ -304,7 +304,7 @@ private PredicateMap computeAccumulatedPredicateMap() { } @Nonnull - public Map pullUpToParent(@Nonnull final CorrelationIdentifier nestingAlias, + public Map pullUpToParent(@Nonnull final CorrelationIdentifier candidateAlias, @Nonnull final Predicate predicateFilter) { final var interestingPredicates = getAccumulatedPredicateMap().getMap() @@ -313,17 +313,17 @@ public Map pullUpToParent(@Nonnull final Corre .filter(predicateFilter) .collect(LinkedIdentitySet.toLinkedIdentitySet()); - return pullUpToParent(nestingAlias, interestingPredicates); + return pullUpToParent(candidateAlias, interestingPredicates); } @Nonnull - public Map pullUpToParent(@Nonnull final CorrelationIdentifier nestingAlias, + public Map pullUpToParent(@Nonnull final CorrelationIdentifier candidateAlias, @Nonnull final Set interestingPredicates) { final var childPredicateMappings = getPulledUpPredicateMappings(interestingPredicates); final var resultsMap = new LinkedIdentityMap(); - final var pullUp = pullUp(nestingAlias); + final var pullUp = pullUp(candidateAlias); for (final var childPredicateMappingEntry : childPredicateMappings.entrySet()) { final var originalQueryPredicate = childPredicateMappingEntry.getKey(); final var childPredicateMapping = childPredicateMappingEntry.getValue(); @@ -375,8 +375,8 @@ public Compensation compensateCompleteMatch() { @Nonnull public Compensation compensate(@Nonnull final Map boundParameterPrefixMap, @Nonnull final PullUp pullUp, - @Nonnull final CorrelationIdentifier nestingAlias) { - return queryExpression.compensate(this, boundParameterPrefixMap, pullUp, nestingAlias); + @Nonnull final CorrelationIdentifier candidateAlias) { + return queryExpression.compensate(this, boundParameterPrefixMap, pullUp, candidateAlias); } @Nonnull @@ -385,19 +385,19 @@ public Compensation compensateExistential(@Nonnull final Map currentQuantifiers = currentCandidateExpression.getQuantifiers(); Verify.verify(currentQuantifiers.size() == 1); final Quantifier currentQuantifier = currentQuantifiers.get(0); - currentNestingAlias = currentQuantifier.getAlias(); + currentCandidateAlias = currentQuantifier.getAlias(); currentCandidateRef = currentQuantifier.getRangesOver(); currentMatchInfo = ((MatchInfo.AdjustedMatchInfo)currentMatchInfo).getUnderlying(); diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PredicateMultiMap.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PredicateMultiMap.java index 9818dc609e..716cb34290 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PredicateMultiMap.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PredicateMultiMap.java @@ -22,13 +22,14 @@ import com.apple.foundationdb.record.query.expressions.Comparisons; import com.apple.foundationdb.record.query.plan.QueryPlanConstraint; +import com.apple.foundationdb.record.query.plan.cascades.expressions.GroupByExpression; import com.apple.foundationdb.record.query.plan.cascades.predicates.ExistsPredicate; import com.apple.foundationdb.record.query.plan.cascades.predicates.PredicateWithComparisons; import com.apple.foundationdb.record.query.plan.cascades.predicates.PredicateWithValue; import com.apple.foundationdb.record.query.plan.cascades.predicates.QueryPredicate; import com.apple.foundationdb.record.query.plan.cascades.values.Value; -import com.apple.foundationdb.record.query.plan.cascades.values.translation.MaxMatchMap; import com.apple.foundationdb.record.query.plan.cascades.values.translation.PullUp; +import com.google.common.base.Verify; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.Multimaps; @@ -62,6 +63,24 @@ public class PredicateMultiMap { @Nonnull private final ImmutableSetMultimap map; + @Nonnull + private static Value amendValue(final @Nonnull AggregateMappings aggregateMappings, final Value rootValue) { + return Objects.requireNonNull(rootValue.replace(currentValue -> { + if (currentValue instanceof GroupByExpression.UnmatchedAggregateValue) { + final var unmatchedId = + ((GroupByExpression.UnmatchedAggregateValue)currentValue).getUnmatchedId(); + final var queryValue = + Objects.requireNonNull(aggregateMappings.getUnmatchedAggregateMap().get(unmatchedId)); + final var translatedQueryValue = + aggregateMappings.getMatchedAggregateMap().get(queryValue); + if (translatedQueryValue != null) { + return translatedQueryValue; + } + } + return currentValue; + })); + } + /** * Functional interface to reapply a predicate if necessary. */ @@ -91,7 +110,7 @@ public boolean isImpossible() { @Nonnull @Override - public PredicateCompensationFunction amendWithOtherMatchInfo(@Nonnull final MatchInfo matchInfo) { + public PredicateCompensationFunction amend(@Nonnull final AggregateMappings aggregateMappings) { return this; } @@ -116,7 +135,7 @@ public boolean isImpossible() { @Nonnull @Override - public PredicateCompensationFunction amendWithOtherMatchInfo(@Nonnull final MatchInfo matchInfo) { + public PredicateCompensationFunction amend(@Nonnull final AggregateMappings aggregateMappings) { return this; } @@ -133,15 +152,15 @@ public Set applyCompensationForPredicate(@Nonnull final Correlat boolean isImpossible(); @Nonnull - PredicateCompensationFunction amendWithOtherMatchInfo(@Nonnull final MatchInfo matchInfo); + PredicateCompensationFunction amend(@Nonnull final AggregateMappings aggregateMappings); @Nonnull Set applyCompensationForPredicate(@Nonnull CorrelationIdentifier baseAlias); @Nonnull - static PredicateCompensationFunction ofPulledUpPredicate(@Nonnull final QueryPredicate pulledUpPredicate, - @Nonnull final BiFunction> compensationFunction) { - final var isImpossible = predicateContainsUnmatchedValues(pulledUpPredicate); + static PredicateCompensationFunction ofPredicate(@Nonnull final QueryPredicate predicate, + @Nonnull final BiFunction> compensationFunction) { + final var isImpossible = predicateContainsUnmatchedValues(predicate); return new PredicateCompensationFunction() { @Override @@ -156,15 +175,18 @@ public boolean isImpossible() { @Nonnull @Override - public PredicateCompensationFunction amendWithOtherMatchInfo(@Nonnull final MatchInfo matchInfo) { - // TODO - return ofPulledUpPredicate(pulledUpPredicate, compensationFunction); + public PredicateCompensationFunction amend(@Nonnull final AggregateMappings aggregateMappings) { + final var amendedTranslatedPredicateOptional = + predicate.replaceValuesMaybe(rootValue -> + Optional.of(amendValue(aggregateMappings, rootValue))); + Verify.verify(amendedTranslatedPredicateOptional.isPresent()); + return ofPredicate(amendedTranslatedPredicateOptional.get(), compensationFunction); } @Nonnull @Override public Set applyCompensationForPredicate(@Nonnull final CorrelationIdentifier baseAlias) { - return compensationFunction.apply(pulledUpPredicate, baseAlias); + return compensationFunction.apply(predicate, baseAlias); } }; } @@ -173,7 +195,7 @@ private static boolean predicateContainsUnmatchedValues(final @Nonnull QueryPred if (pulledUpPredicate instanceof PredicateWithValue) { final var value = Objects.requireNonNull(((PredicateWithValue)pulledUpPredicate).getValue()); if (value.preOrderStream() - .anyMatch(v -> v instanceof MaxMatchMap.UnmatchedAggregateValue)) { + .anyMatch(v -> v instanceof GroupByExpression.UnmatchedAggregateValue)) { return true; } } @@ -184,7 +206,7 @@ private static boolean predicateContainsUnmatchedValues(final @Nonnull QueryPred if (comparison instanceof Comparisons.ValueComparison) { final var comparisonValue = comparison.getValue(); if (comparisonValue.preOrderStream() - .anyMatch(v -> v instanceof MaxMatchMap.UnmatchedAggregateValue)) { + .anyMatch(v -> v instanceof GroupByExpression.UnmatchedAggregateValue)) { return true; } } @@ -210,7 +232,7 @@ public boolean isImpossible() { @Nonnull @Override - public PredicateCompensationFunction amendWithOtherMatchInfo(@Nonnull final MatchInfo matchInfo) { + public PredicateCompensationFunction amend(@Nonnull final AggregateMappings aggregateMappings) { return this; } @@ -238,10 +260,10 @@ public boolean isImpossible() { @Nonnull @Override - public PredicateCompensationFunction amendWithOtherMatchInfo(@Nonnull final MatchInfo matchInfo) { + public PredicateCompensationFunction amend(@Nonnull final AggregateMappings aggregateMappings) { final var amendedChildrenCompensationFunctions = childrenCompensationFunctions.stream() - .map(childrenCompensationFunction -> childrenCompensationFunction.amendWithOtherMatchInfo(matchInfo)) + .map(childrenCompensationFunction -> childrenCompensationFunction.amend(aggregateMappings)) .collect(ImmutableList.toImmutableList()); return ofChildrenCompensationFunctions(amendedChildrenCompensationFunctions, compensationFunction); } @@ -283,7 +305,7 @@ public boolean isImpossible() { @Nonnull @Override - public ResultCompensationFunction amendWithOtherMatchInfo(@Nonnull final MatchInfo matchInfo) { + public ResultCompensationFunction amend(@Nonnull final AggregateMappings aggregateMappings) { return this; } @@ -308,7 +330,7 @@ public boolean isImpossible() { @Nonnull @Override - public ResultCompensationFunction amendWithOtherMatchInfo(@Nonnull final MatchInfo matchInfo) { + public ResultCompensationFunction amend(@Nonnull final AggregateMappings aggregateMappings) { return this; } @@ -325,7 +347,7 @@ public Value applyCompensationForResult(@Nonnull final CorrelationIdentifier bas boolean isImpossible(); @Nonnull - ResultCompensationFunction amendWithOtherMatchInfo(@Nonnull MatchInfo matchInfo); + ResultCompensationFunction amend(@Nonnull AggregateMappings aggregateMappings); @Nonnull Value applyCompensationForResult(@Nonnull CorrelationIdentifier baseAlias); @@ -348,9 +370,11 @@ public boolean isImpossible() { @Nonnull @Override - public ResultCompensationFunction amendWithOtherMatchInfo(@Nonnull final MatchInfo matchInfo) { - // TODO - return ofValue(value, compensationFunction); + public ResultCompensationFunction amend(@Nonnull final AggregateMappings aggregateMappings) { + final var amendedTranslatedQueryValue = + amendValue(aggregateMappings, value); + + return ofValue(amendedTranslatedQueryValue, compensationFunction); } @Nonnull @@ -373,7 +397,7 @@ static ResultCompensationFunction impossibleCompensation() { private static boolean valueContainsUnmatchedValues(final @Nonnull Value pulledUpValue) { return pulledUpValue.preOrderStream() - .anyMatch(v -> v instanceof MaxMatchMap.UnmatchedAggregateValue); + .anyMatch(v -> v instanceof GroupByExpression.UnmatchedAggregateValue); } } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Quantifier.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Quantifier.java index 56fe5333f6..9d18a983e7 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Quantifier.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Quantifier.java @@ -792,7 +792,7 @@ public Quantifier translateCorrelations(@Nonnull final TranslationMap translatio @Nonnull public static CorrelationIdentifier uniqueID() { - return CorrelationIdentifier.uniqueID(Quantifier.class); + return CorrelationIdentifier.uniqueId(Quantifier.class); } @Nonnull diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/ExplodeExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/ExplodeExpression.java index 6ed43afed2..d9dc9cbb59 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/ExplodeExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/ExplodeExpression.java @@ -146,7 +146,7 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid public Compensation compensate(@Nonnull final PartialMatch partialMatch, @Nonnull final Map boundParameterPrefixMap, @Nullable final PullUp pullUp, - @Nonnull final CorrelationIdentifier nestingAlias) { + @Nonnull final CorrelationIdentifier candidateAlias) { // subsumedBy() is based on equality and this expression is always a leaf, thus we return empty here as // if there is a match, it's exact return Compensation.noCompensation(); diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/FullUnorderedScanExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/FullUnorderedScanExpression.java index 031a4355a3..82901f9947 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/FullUnorderedScanExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/FullUnorderedScanExpression.java @@ -180,7 +180,7 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid public Compensation compensate(@Nonnull final PartialMatch partialMatch, @Nonnull final Map boundParameterPrefixMap, @Nullable final PullUp pullUp, - @Nonnull final CorrelationIdentifier nestingAlias) { + @Nonnull final CorrelationIdentifier candidateAlias) { return Compensation.noCompensation(); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java index 8540d5fd7c..290da8d7e9 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java @@ -22,6 +22,8 @@ import com.apple.foundationdb.annotation.API; import com.apple.foundationdb.record.EvaluationContext; +import com.apple.foundationdb.record.PlanSerializationContext; +import com.apple.foundationdb.record.planprotos.PValue; import com.apple.foundationdb.record.query.expressions.Comparisons; import com.apple.foundationdb.record.query.plan.cascades.AliasMap; import com.apple.foundationdb.record.query.plan.cascades.BooleanWithConstraint; @@ -32,6 +34,7 @@ import com.apple.foundationdb.record.query.plan.cascades.IdentityBiMap; import com.apple.foundationdb.record.query.plan.cascades.LinkedIdentityMap; import com.apple.foundationdb.record.query.plan.cascades.MatchInfo; +import com.apple.foundationdb.record.query.plan.cascades.AggregateMappings; import com.apple.foundationdb.record.query.plan.cascades.MatchInfo.RegularMatchInfo; import com.apple.foundationdb.record.query.plan.cascades.OrderingPart.RequestedOrderingPart; import com.apple.foundationdb.record.query.plan.cascades.OrderingPart.RequestedSortOrder; @@ -49,20 +52,26 @@ import com.apple.foundationdb.record.query.plan.cascades.predicates.PredicateWithValue; import com.apple.foundationdb.record.query.plan.cascades.predicates.PredicateWithValueAndRanges; import com.apple.foundationdb.record.query.plan.cascades.typing.Type; +import com.apple.foundationdb.record.query.plan.cascades.values.AbstractValue; import com.apple.foundationdb.record.query.plan.cascades.values.AggregateValue; import com.apple.foundationdb.record.query.plan.cascades.values.FieldValue; +import com.apple.foundationdb.record.query.plan.cascades.values.IndexableAggregateValue; import com.apple.foundationdb.record.query.plan.cascades.values.RecordConstructorValue; import com.apple.foundationdb.record.query.plan.cascades.values.Value; import com.apple.foundationdb.record.query.plan.cascades.values.Values; import com.apple.foundationdb.record.query.plan.cascades.values.translation.MaxMatchMap; import com.apple.foundationdb.record.query.plan.cascades.values.translation.PullUp; import com.apple.foundationdb.record.query.plan.cascades.values.translation.TranslationMap; +import com.apple.foundationdb.record.query.plan.explain.ExplainTokens; +import com.apple.foundationdb.record.query.plan.explain.ExplainTokensWithPrecedence; import com.google.common.base.Suppliers; import com.google.common.base.Verify; +import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; +import com.google.protobuf.Message; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -329,7 +338,11 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid return ImmutableList.of(); } final var otherPrimitiveAggregateValue = Iterables.getOnlyElement(otherAggregateValues); - final var matchedAggregateValueMapBuilder = ImmutableMap.builder(); + final var matchedAggregateMapBuilder = ImmutableBiMap.builder(); + final var unmatchedAggregateMapBuilder = + ImmutableBiMap.builder(); + final var unmatchedTranslatedAggregateValueMapBuilder = + ImmutableMap.builder(); var subsumedAggregations = BooleanWithConstraint.alwaysTrue(); for (final var primitiveAggregateValue : aggregateValues) { final var translatedPrimitiveAggregateValue = @@ -338,35 +351,53 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid final var semanticEquals = translatedPrimitiveAggregateValue.semanticEquals(otherPrimitiveAggregateValue, valueEquivalence); if (semanticEquals.isTrue()) { - matchedAggregateValueMapBuilder.put(primitiveAggregateValue, otherPrimitiveAggregateValue); + matchedAggregateMapBuilder.put(primitiveAggregateValue, otherPrimitiveAggregateValue); subsumedAggregations = semanticEquals; - break; + } else { + final var unmatchedId = UnmatchedAggregateValue.uniqueId(); + unmatchedAggregateMapBuilder.put(unmatchedId, primitiveAggregateValue); + unmatchedTranslatedAggregateValueMapBuilder.put(translatedPrimitiveAggregateValue, unmatchedId); } } final var subsumedGroupings = subsumedAggregations .compose(ignored -> groupingSubsumedBy(candidateInnerQuantifier, - Objects.requireNonNull(partialMatchMap.getUnwrapped(innerQuantifier)), candidateGroupingValue, - translationMap, valueEquivalence)); + Objects.requireNonNull(partialMatchMap.getUnwrapped(innerQuantifier)), + candidateGroupingValue, translationMap, valueEquivalence)); if (subsumedGroupings.isFalse()) { return ImmutableList.of(); } + final var unmatchedTranslatedAggregateValueMap = + unmatchedTranslatedAggregateValueMapBuilder.buildKeepingLast(); final var translatedResultValue = getResultValue().translateCorrelations(translationMap, true); final var maxMatchMap = MaxMatchMap.compute(translatedResultValue, candidateExpression.getResultValue(), - Quantifiers.aliases(candidateExpression.getQuantifiers()), valueEquivalence); + Quantifiers.aliases(candidateExpression.getQuantifiers()), valueEquivalence, + translatedUnmatchedValue -> onUnmatchedValue(unmatchedTranslatedAggregateValueMap, translatedUnmatchedValue)); final var queryPlanConstraint = subsumedGroupings.getConstraint().compose(maxMatchMap.getQueryPlanConstraint()); return RegularMatchInfo.tryMerge(bindingAliasMap, partialMatchMap, ImmutableMap.of(), PredicateMap.empty(), - maxMatchMap, matchedAggregateValueMapBuilder.build(), queryPlanConstraint) + maxMatchMap, + AggregateMappings.of(matchedAggregateMapBuilder.build(), unmatchedAggregateMapBuilder.build()), + queryPlanConstraint) .map(ImmutableList::of) .orElse(ImmutableList.of()); } + @Nonnull + private Optional onUnmatchedValue(@Nonnull final Map unmatchedTranslatedAggregateValueMap, + @Nonnull final Value translatedUnmatchedValue) { + final var unmatchedId = unmatchedTranslatedAggregateValueMap.get(translatedUnmatchedValue); + if (unmatchedId == null) { + return Optional.empty(); + } + return Optional.of(new UnmatchedAggregateValue(unmatchedId)); + } + @Nonnull private BooleanWithConstraint groupingSubsumedBy(@Nonnull final Quantifier candidateInnerQuantifier, @Nonnull final PartialMatch childMatch, @@ -535,12 +566,12 @@ private RequestedOrdering computeRequestedOrdering() { public Compensation compensate(@Nonnull final PartialMatch partialMatch, @Nonnull final Map boundParameterPrefixMap, @Nullable final PullUp pullUp, - @Nonnull final CorrelationIdentifier nestingAlias) { + @Nonnull final CorrelationIdentifier candidateAlias) { final var matchInfo = partialMatch.getMatchInfo(); final var regularMatchInfo = partialMatch.getRegularMatchInfo(); final var quantifier = Iterables.getOnlyElement(getQuantifiers()); - final var adjustedPullUp = partialMatch.nestPullUp(pullUp, nestingAlias); + final var adjustedPullUp = partialMatch.nestPullUp(pullUp, candidateAlias); // if the match requires, for the moment, any, compensation, we reject it. final Optional childCompensationOptional = regularMatchInfo.getChildPartialMatchMaybe(quantifier) @@ -567,10 +598,10 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, boolean isCompensationImpossible = false; final ResultCompensationFunction resultCompensationFunction; - final Map pulledUpMatchedAggregateValueMap; + final AggregateMappings pulledUpAggregateMappings; if (pullUp != null) { resultCompensationFunction = ResultCompensationFunction.noCompensationNeeded(); - pulledUpMatchedAggregateValueMap = ImmutableMap.of(); + pulledUpAggregateMappings = AggregateMappings.empty(); } else { final var rootPullUp = adjustedPullUp.getRootPullUp(); final var maxMatchMap = matchInfo.getMaxMatchMap(); @@ -585,11 +616,11 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, resultCompensationFunction = ResultCompensationFunction.ofValue(pulledUpTranslatedResultValue, (value, baseAlias) -> value.translateCorrelations( - TranslationMap.ofAliases(rootPullUp.getNestingAlias(), baseAlias), false)); + TranslationMap.ofAliases(rootPullUp.getCandidateAlias(), baseAlias), false)); isCompensationImpossible |= resultCompensationFunction.isImpossible(); - pulledUpMatchedAggregateValueMap = - RegularMatchInfo.pullUpMatchedAggregateValueMap(partialMatch, Quantifier.current(), nestingAlias); + pulledUpAggregateMappings = + RegularMatchInfo.pullUpAggregateMappings(partialMatch, candidateAlias); } final var unmatchedQuantifiers = partialMatch.getUnmatchedQuantifiers(); @@ -605,7 +636,7 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, unmatchedQuantifiers, partialMatch.getCompensatedAliases(), resultCompensationFunction, - pulledUpMatchedAggregateValueMap); + pulledUpAggregateMappings); } @Nonnull @@ -652,4 +683,72 @@ public static Value flattenedResults(@Nullable final Value groupingKeyValue, final var rcv = RecordConstructorValue.ofUnnamed(valuesBuilder.build()); return rcv.simplify(AliasMap.identitiesFor(rcv.getCorrelatedTo()), ImmutableSet.of()); } + + public static class UnmatchedAggregateValue extends AbstractValue implements Value.NonEvaluableValue, IndexableAggregateValue { + @Nonnull + private final CorrelationIdentifier unmatchedId; + + public UnmatchedAggregateValue(@Nonnull final CorrelationIdentifier unmatchedId) { + this.unmatchedId = unmatchedId; + } + + @Nonnull + public CorrelationIdentifier getUnmatchedId() { + return unmatchedId; + } + + @Nonnull + @Override + protected Iterable computeChildren() { + return ImmutableList.of(); + } + + @Nonnull + @Override + public String getIndexTypeName() { + throw new UnsupportedOperationException(); + } + + @Nonnull + @Override + public ExplainTokensWithPrecedence explain(@Nonnull final Iterable> explainSuppliers) { + Verify.verify(Iterables.isEmpty(explainSuppliers)); + return ExplainTokensWithPrecedence.of(new ExplainTokens().addFunctionCall("unmatched", + new ExplainTokens().addIdentifier(unmatchedId.getId()))); + } + + @Override + public int hashCodeWithoutChildren() { + return 0; + } + + @Nonnull + @Override + public PValue toValueProto(@Nonnull final PlanSerializationContext serializationContext) { + throw new UnsupportedOperationException(); + } + + @Override + public int planHash(@Nonnull final PlanHashMode hashMode) { + return 0; + } + + @Nonnull + @Override + public Message toProto(@Nonnull final PlanSerializationContext serializationContext) { + throw new UnsupportedOperationException(); + } + + @Nonnull + @Override + public Value withChildren(final Iterable newChildren) { + Verify.verify(Iterables.isEmpty(newChildren)); + return new UnmatchedAggregateValue(getUnmatchedId()); + } + + @Nonnull + public static CorrelationIdentifier uniqueId() { + return CorrelationIdentifier.uniqueId(UnmatchedAggregateValue.class); + } + } } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/LogicalTypeFilterExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/LogicalTypeFilterExpression.java index 03a83dd106..8f16d4c9dc 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/LogicalTypeFilterExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/LogicalTypeFilterExpression.java @@ -30,6 +30,7 @@ import com.apple.foundationdb.record.query.plan.cascades.IdentityBiMap; import com.apple.foundationdb.record.query.plan.cascades.LinkedIdentityMap; import com.apple.foundationdb.record.query.plan.cascades.MatchInfo; +import com.apple.foundationdb.record.query.plan.cascades.AggregateMappings; import com.apple.foundationdb.record.query.plan.cascades.MatchInfo.RegularMatchInfo; import com.apple.foundationdb.record.query.plan.cascades.PartialMatch; import com.apple.foundationdb.record.query.plan.cascades.PredicateMultiMap.ResultCompensationFunction; @@ -182,10 +183,10 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid public Compensation compensate(@Nonnull final PartialMatch partialMatch, @Nonnull final Map boundParameterPrefixMap, @Nullable final PullUp pullUp, - @Nonnull final CorrelationIdentifier nestingAlias) { + @Nonnull final CorrelationIdentifier candidateAlias) { final var matchInfo = partialMatch.getMatchInfo(); final var regularMatchInfo = partialMatch.getRegularMatchInfo(); - final var adjustedPullUp = partialMatch.nestPullUp(pullUp, nestingAlias); + final var adjustedPullUp = partialMatch.nestPullUp(pullUp, candidateAlias); final var bindingAliasMap = regularMatchInfo.getBindingAliasMap(); final PartialMatch childPartialMatch = @@ -203,10 +204,10 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, boolean isCompensationImpossible = false; final ResultCompensationFunction resultCompensationFunction; - final Map pulledUpMatchedAggregateValueMap; + final AggregateMappings aggregateMappings; if (pullUp != null) { resultCompensationFunction = ResultCompensationFunction.noCompensationNeeded(); - pulledUpMatchedAggregateValueMap = ImmutableMap.of(); + aggregateMappings = AggregateMappings.empty(); } else { final var rootPullUp = adjustedPullUp.getRootPullUp(); final var maxMatchMap = matchInfo.getMaxMatchMap(); @@ -221,11 +222,11 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, resultCompensationFunction = ResultCompensationFunction.ofValue(pulledUpTranslatedResultValue, (value, baseAlias) -> value.translateCorrelations( - TranslationMap.ofAliases(rootPullUp.getNestingAlias(), baseAlias), false)); + TranslationMap.ofAliases(rootPullUp.getCandidateAlias(), baseAlias), false)); isCompensationImpossible |= resultCompensationFunction.isImpossible(); - pulledUpMatchedAggregateValueMap = - RegularMatchInfo.pullUpMatchedAggregateValueMap(partialMatch, Quantifier.current(), nestingAlias); + aggregateMappings = + RegularMatchInfo.pullUpAggregateMappings(partialMatch, candidateAlias); } final var unmatchedQuantifiers = partialMatch.getUnmatchedQuantifiers(); @@ -241,7 +242,7 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, unmatchedQuantifiers, partialMatch.getCompensatedAliases(), resultCompensationFunction, - pulledUpMatchedAggregateValueMap); + aggregateMappings); } @Nonnull diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/MatchableSortExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/MatchableSortExpression.java index cd2a19d485..0221c03f52 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/MatchableSortExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/MatchableSortExpression.java @@ -224,7 +224,7 @@ public Optional adjustMatch(@Nonnull final PartialMatch partialMatch, childMatchInfo.adjustedBuilder() .setMaxMatchMap(adjustedMaxMatchMap) .setMatchedOrderingParts(forPartialMatch(partialMatch)) - .setMatchedAggregateValueMap(childMatchInfo.adjustMatchedAggregateMap(partialMatch, candidateQuantifier)) + .setAggregateMappings(childMatchInfo.adjustAggregateMappings(partialMatch, candidateQuantifier)) .build()); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/RelationalExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/RelationalExpression.java index 93ae2e3e06..f15b522f96 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/RelationalExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/RelationalExpression.java @@ -790,7 +790,7 @@ default boolean hasIncompatibleBoundQuantifiers(final AliasMap aliasMap, final C default Compensation compensate(@Nonnull final PartialMatch partialMatch, @Nonnull final Map boundParameterPrefixMap, @Nullable final PullUp pullUp, - @Nonnull final CorrelationIdentifier nestingAlias) { + @Nonnull final CorrelationIdentifier candidateAlias) { throw new RecordCoreException("expression matched but no compensation logic implemented"); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java index 14dafe0744..29d783e446 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java @@ -32,6 +32,7 @@ import com.apple.foundationdb.record.query.plan.cascades.IterableHelpers; import com.apple.foundationdb.record.query.plan.cascades.LinkedIdentityMap; import com.apple.foundationdb.record.query.plan.cascades.MatchInfo; +import com.apple.foundationdb.record.query.plan.cascades.AggregateMappings; import com.apple.foundationdb.record.query.plan.cascades.MatchInfo.RegularMatchInfo; import com.apple.foundationdb.record.query.plan.cascades.PartialMatch; import com.apple.foundationdb.record.query.plan.cascades.PredicateMap; @@ -463,7 +464,8 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid MaxMatchMap.compute(translatedResultValue, candidateExpression.getResultValue(), Quantifiers.aliases(candidateExpression.getQuantifiers()), bindingValueEquivalence); return RegularMatchInfo.tryMerge(bindingAliasMap, partialMatchMap, mergedParameterBindingMap, - PredicateMap.empty(), maxMatchMap, ImmutableMap.of(), maxMatchMap.getQueryPlanConstraint()) + PredicateMap.empty(), maxMatchMap, AggregateMappings.empty(), + maxMatchMap.getQueryPlanConstraint()) .map(ImmutableList::of) .orElse(ImmutableList.of()); } else { @@ -582,7 +584,7 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid bindingValueEquivalence); return RegularMatchInfo.tryMerge(bindingAliasMap, partialMatchMap, allParameterBindingMap, predicateMap, - maxMatchMap, ImmutableMap.of(), + maxMatchMap, AggregateMappings.empty(), maxMatchMap.getQueryPlanConstraint()); }) .map(ImmutableList::of) @@ -619,7 +621,7 @@ public Optional adjustMatch(@Nonnull final PartialMatch partialMatch, .map(adjustedMaxMatchMap -> childMatchInfo.adjustedBuilder() .setMaxMatchMap(adjustedMaxMatchMap) - .setMatchedAggregateValueMap(childMatchInfo.adjustMatchedAggregateMap(partialMatch, candidateQuantifier)) + .setAggregateMappings(childMatchInfo.adjustAggregateMappings(partialMatch, candidateQuantifier)) .build()); } @@ -767,14 +769,14 @@ private static List flattenPredicate(@Nonnull final Class boundParameterPrefixMap, @Nullable final PullUp pullUp, - @Nonnull final CorrelationIdentifier nestingAlias) { + @Nonnull final CorrelationIdentifier candidateAlias) { final var predicateCompensationMap = new LinkedIdentityMap(); final var matchInfo = partialMatch.getMatchInfo(); final var regularMatchInfo = partialMatch.getRegularMatchInfo(); final var quantifiers = getQuantifiers(); final var adjustedPullUp = - partialMatch.nestPullUp(pullUp, nestingAlias); + partialMatch.nestPullUp(pullUp, candidateAlias); // // The partial match we are called with here has child matches that have compensations on their own. @@ -860,10 +862,10 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, } final ResultCompensationFunction resultCompensationFunction; - final Map pulledUpMatchedAggregateValueMap; + final AggregateMappings aggregateMappings; if (pullUp != null) { resultCompensationFunction = ResultCompensationFunction.noCompensationNeeded(); - pulledUpMatchedAggregateValueMap = ImmutableMap.of(); + aggregateMappings = AggregateMappings.empty(); } else { final var rootPullUp = adjustedPullUp.getRootPullUp(); final var maxMatchMap = matchInfo.getMaxMatchMap(); @@ -878,11 +880,11 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, resultCompensationFunction = ResultCompensationFunction.ofValue(pulledUpTranslatedResultValue, (value, baseAlias) -> value.translateCorrelations( - TranslationMap.ofAliases(rootPullUp.getNestingAlias(), baseAlias), false)); + TranslationMap.ofAliases(rootPullUp.getCandidateAlias(), baseAlias), false)); isAnyCompensationFunctionImpossible |= resultCompensationFunction.isImpossible(); - pulledUpMatchedAggregateValueMap = - RegularMatchInfo.pullUpMatchedAggregateValueMap(partialMatch, Quantifier.current(), nestingAlias); + aggregateMappings = + RegularMatchInfo.pullUpAggregateMappings(partialMatch, candidateAlias); } final var isCompensationNeeded = @@ -914,6 +916,6 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, partialMatch.getUnmatchedQuantifiers(), partialMatch.getCompensatedAliases(), resultCompensationFunction, - pulledUpMatchedAggregateValueMap); + aggregateMappings); } } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/LeafQueryPredicate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/LeafQueryPredicate.java index 81df811b9a..a8b9406177 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/LeafQueryPredicate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/LeafQueryPredicate.java @@ -84,7 +84,7 @@ default PredicateMultiMap.PredicateCompensationFunction computeCompensationFunct return toResidualPredicate() .replaceValuesMaybe(pullUp::pullUpMaybe) .map(queryPredicate -> - PredicateMultiMap.PredicateCompensationFunction.ofPulledUpPredicate(queryPredicate, + PredicateMultiMap.PredicateCompensationFunction.ofPredicate(queryPredicate, (pulledUpPredicate, baseAlias) -> LinkedIdentitySet.of(pulledUpPredicate.translateCorrelations( TranslationMap.ofAliases(pullUp.getTopAlias(), baseAlias), false)))) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/QueryPredicate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/QueryPredicate.java index 6c815e0c01..37f27cf5aa 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/QueryPredicate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/QueryPredicate.java @@ -251,7 +251,7 @@ default PredicateCompensationFunction computeCompensationFunction(@Nonnull final return toResidualPredicate() .replaceValuesMaybe(pullUp::pullUpMaybe) .map(queryPredicate -> - PredicateCompensationFunction.ofPulledUpPredicate(queryPredicate, + PredicateCompensationFunction.ofPredicate(queryPredicate, (pulledUpPredicate, baseAlias) -> LinkedIdentitySet.of(pulledUpPredicate.translateCorrelations( TranslationMap.ofAliases(pullUp.getTopAlias(), baseAlias), false)))) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/translation/MaxMatchMap.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/translation/MaxMatchMap.java index cb56eb1426..a9c01df03f 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/translation/MaxMatchMap.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/translation/MaxMatchMap.java @@ -20,16 +20,12 @@ package com.apple.foundationdb.record.query.plan.cascades.values.translation; -import com.apple.foundationdb.record.PlanSerializationContext; -import com.apple.foundationdb.record.planprotos.PValue; import com.apple.foundationdb.record.query.combinatorics.CrossProduct; import com.apple.foundationdb.record.query.plan.QueryPlanConstraint; import com.apple.foundationdb.record.query.plan.cascades.AliasMap; import com.apple.foundationdb.record.query.plan.cascades.BooleanWithConstraint; import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier; import com.apple.foundationdb.record.query.plan.cascades.ValueEquivalence; -import com.apple.foundationdb.record.query.plan.cascades.values.AbstractValue; -import com.apple.foundationdb.record.query.plan.cascades.values.IndexableAggregateValue; import com.apple.foundationdb.record.query.plan.cascades.values.QuantifiedObjectValue; import com.apple.foundationdb.record.query.plan.cascades.values.QuantifiedRecordValue; import com.apple.foundationdb.record.query.plan.cascades.values.QuantifiedValue; @@ -50,7 +46,6 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Sets; import com.google.common.collect.Streams; -import com.google.protobuf.Message; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -321,6 +316,15 @@ public static MaxMatchMap compute(@Nonnull final Value queryValue, ValueEquivalence.empty()); } + @Nonnull + public static MaxMatchMap compute(@Nonnull final Value queryValue, + @Nonnull final Value candidateValue, + @Nonnull final Set rangedOverAliases, + @Nonnull final ValueEquivalence valueEquivalence) { + return compute(queryValue, candidateValue, rangedOverAliases, valueEquivalence, + ignored -> Optional.empty()); + } + /** * Computes the maximum sub-{@link Value}s in {@code queryValue} that have an exact match in the * {@code candidateValue}. @@ -332,6 +336,8 @@ public static MaxMatchMap compute(@Nonnull final Value queryValue, * @param candidateValue the candidate result {@code Value} we want to search for maximum matches * @param rangedOverAliases a set of aliases that should be considered constant * @param valueEquivalence an {@link ValueEquivalence} that informs the logic about equivalent value subtrees + * @param unmatchedHandlerFunction function that is invoked if a match between a query {@link Value} and a candidate + * {@link Value} cannot be established * @return a {@link MaxMatchMap} of all maximum matches. Note that the returned {@link MaxMatchMap} always exists, * it is possible, however, that it might not contain all necessary mappings to perform a pull-up when it * is used. @@ -340,7 +346,8 @@ public static MaxMatchMap compute(@Nonnull final Value queryValue, public static MaxMatchMap compute(@Nonnull final Value queryValue, @Nonnull final Value candidateValue, @Nonnull final Set rangedOverAliases, - @Nonnull final ValueEquivalence valueEquivalence) { + @Nonnull final ValueEquivalence valueEquivalence, + @Nonnull final Function> unmatchedHandlerFunction) { if (logger.isDebugEnabled()) { logger.debug("calculate begin queryValue={}, candidateValue={}", queryValue, candidateValue); } @@ -358,8 +365,8 @@ public static MaxMatchMap compute(@Nonnull final Value queryValue, // final var resultsMap = recurseQueryResultValue(queryValue, candidateValue, rangedOverAliases, - valueEquivalence, new IdentityHashMap<>(), -1, new ArrayDeque<>(), - Integer.MAX_VALUE, new HashSet<>()); + valueEquivalence, unmatchedHandlerFunction, new IdentityHashMap<>(), -1, + new ArrayDeque<>(), Integer.MAX_VALUE, new HashSet<>()); // // Pick a match which has the minimum max depth among all the matches. @@ -490,6 +497,7 @@ private static Map recurseQueryResultValue(@Nonnull final Va @Nonnull final Value candidateValue, @Nonnull final Set rangedOverAliases, @Nonnull final ValueEquivalence valueEquivalence, + @Nonnull final Function> unmatchedHandlerFunction, @Nonnull final IdentityHashMap> knownValueMap, final int descendOrdinal, @Nonnull final Deque matchers, @@ -547,7 +555,7 @@ private static Map recurseQueryResultValue(@Nonnull final Va if (Iterables.isEmpty(children)) { final var resultForCurrent = computeForCurrent(maxDepthBound, currentQueryValue, candidateValue, rangedOverAliases, - valueEquivalence, ImmutableList.of()); + valueEquivalence, unmatchedHandlerFunction, ImmutableList.of()); bestMatches.put(currentQueryValue, resultForCurrent); } else { final BooleanWithConstraint isFound; @@ -560,7 +568,8 @@ private static Map recurseQueryResultValue(@Nonnull final Va final var matchingPair = findMatchingReachableCandidateValue(currentQueryValue, candidateValue, - valueEquivalence); + valueEquivalence, + unmatchedHandlerFunction); isFound = Objects.requireNonNull(matchingPair.getLeft()); if (isFound.isTrue()) { bestMatches.put(currentQueryValue, MatchResult.of(ImmutableMap.of(currentQueryValue, @@ -595,7 +604,8 @@ private static Map recurseQueryResultValue(@Nonnull final Va } final var childrenResultsMap = recurseQueryResultValue(child, candidateValue, rangedOverAliases, valueEquivalence, - knownValueMap, i, localMatchers, childrenMaxDepthBound, expandedValues); + unmatchedHandlerFunction, knownValueMap, i, localMatchers, childrenMaxDepthBound, + expandedValues); childrenResultsBuilder.add(childrenResultsMap.entrySet()); } @@ -625,8 +635,8 @@ private static Map recurseQueryResultValue(@Nonnull final Va } final var resultForCurrent = - computeForCurrent(maxDepthBound, resultQueryValue, candidateValue, - rangedOverAliases, valueEquivalence, childrenResultEntries); + computeForCurrent(maxDepthBound, resultQueryValue, candidateValue, rangedOverAliases, + valueEquivalence, unmatchedHandlerFunction, childrenResultEntries); bestMatches.put(resultQueryValue, resultForCurrent); } } @@ -661,10 +671,8 @@ private static Map recurseQueryResultValue(@Nonnull final Va final var expandedResultsMap = recurseQueryResultValue(expandedCurrentQueryValue, candidateValue, - rangedOverAliases, valueEquivalence, knownValueMap, descendOrdinal, - matchers, - currentMaxDepthBound, - expandedValues); + rangedOverAliases, valueEquivalence, unmatchedHandlerFunction, knownValueMap, + descendOrdinal, matchers, currentMaxDepthBound, expandedValues); for (final var expandedResultsEntry : expandedResultsMap.entrySet()) { bestMatches.put(expandedResultsEntry.getKey(), expandedResultsEntry.getValue()); } @@ -707,13 +715,15 @@ private static MatchResult computeForCurrent(final int maxDepthBound, @Nonnull final Value candidateValue, @Nonnull final Set rangedOverAliases, @Nonnull final ValueEquivalence valueEquivalence, + @Nonnull final Function> unmatchedHandlerFunction, @Nonnull final List> childrenResultEntries) { Verify.verify(maxDepthBound > 0); final var matchingPair = findMatchingReachableCandidateValue(resultQueryValue, candidateValue, - valueEquivalence); + valueEquivalence, + unmatchedHandlerFunction); final var isFound = Objects.requireNonNull(matchingPair.getLeft()); if (isFound.isTrue()) { return MatchResult.of(ImmutableMap.of(resultQueryValue, @@ -754,7 +764,8 @@ private static MatchResult computeForCurrent(final int maxDepthBound, @SuppressWarnings("PMD.CompareObjectsWithEquals") private static Pair findMatchingReachableCandidateValue(@Nonnull final Value currentQueryValue, @Nonnull final Value candidateValue, - @Nonnull final ValueEquivalence valueEquivalence) { + @Nonnull final ValueEquivalence valueEquivalence, + @Nonnull final Function> unmatchedHandlerFunction) { for (final var currentCandidateValue : candidateValue // when traversing the candidate in pre-order, only descend into structures that can be referenced // from the top expression. For example, rcv's components can be referenced however an arithmetic @@ -774,11 +785,13 @@ private static Pair findMatchingReachableCandidate } } - if (currentQueryValue instanceof IndexableAggregateValue) { - return Pair.of(BooleanWithConstraint.alwaysTrue(), new UnmatchedAggregateValue(ImmutableList.of())); - } + final var unmatchedHandlerResult = unmatchedHandlerFunction.apply(currentQueryValue); + return unmatchedHandlerResult.map(value -> Pair.of(BooleanWithConstraint.alwaysTrue(), value)) + .orElseGet(() -> Pair.of(BooleanWithConstraint.falseValue(), null)); - return Pair.of(BooleanWithConstraint.falseValue(), null); +// if (currentQueryValue instanceof IndexableAggregateValue) { +// return Pair.of(BooleanWithConstraint.alwaysTrue(), new UnmatchedAggregateValue(ImmutableList.of())); +// } } /** @@ -1066,60 +1079,4 @@ public static MatchResult notMatched() { return NOT_MATCHED; } } - - public static class UnmatchedAggregateValue extends AbstractValue implements Value.NonEvaluableValue, IndexableAggregateValue { - @Nonnull - private final List children; - - public UnmatchedAggregateValue(@Nonnull final Iterable children) { - this.children = ImmutableList.copyOf(children); - } - - @Nonnull - @Override - protected Iterable computeChildren() { - return children; - } - - @Nonnull - @Override - public String getIndexTypeName() { - throw new UnsupportedOperationException(); - } - - @Nonnull - @Override - public ExplainTokensWithPrecedence explain(@Nonnull final Iterable> explainSuppliers) { - return ExplainTokensWithPrecedence.of(new ExplainTokens().addFunctionCall("unmatched", - Value.explainFunctionArguments(explainSuppliers))); - } - - @Override - public int hashCodeWithoutChildren() { - return 0; - } - - @Nonnull - @Override - public PValue toValueProto(@Nonnull final PlanSerializationContext serializationContext) { - throw new UnsupportedOperationException(); - } - - @Override - public int planHash(@Nonnull final PlanHashMode hashMode) { - return 0; - } - - @Nonnull - @Override - public Message toProto(@Nonnull final PlanSerializationContext serializationContext) { - throw new UnsupportedOperationException(); - } - - @Nonnull - @Override - public Value withChildren(final Iterable newChildren) { - return new UnmatchedAggregateValue(newChildren); - } - } } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/translation/PullUp.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/translation/PullUp.java index 65e5e897c8..8c7db7845d 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/translation/PullUp.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/translation/PullUp.java @@ -44,7 +44,7 @@ public class PullUp { @Nullable private final PullUp parentPullUp; @Nonnull - private final CorrelationIdentifier nestingAlias; + private final CorrelationIdentifier candidateAlias; @Nonnull private final Value pullThroughValue; @Nonnull @@ -54,11 +54,11 @@ public class PullUp { private final PullUp rootPullUp; private PullUp(@Nullable final PullUp parentPullUp, - @Nonnull final CorrelationIdentifier nestingAlias, + @Nonnull final CorrelationIdentifier candidateAlias, @Nonnull final Value pullThroughValue, @Nonnull final Set rangedOverAliases) { this.parentPullUp = parentPullUp; - this.nestingAlias = nestingAlias; + this.candidateAlias = candidateAlias; this.pullThroughValue = pullThroughValue; this.rangedOverAliases = ImmutableSet.copyOf(rangedOverAliases); this.rootPullUp = parentPullUp == null ? this : parentPullUp.getRootPullUp(); @@ -75,8 +75,8 @@ public PullUp getRootPullUp() { } @Nonnull - public CorrelationIdentifier getNestingAlias() { - return nestingAlias; + public CorrelationIdentifier getCandidateAlias() { + return candidateAlias; } public boolean isRoot() { @@ -95,25 +95,25 @@ public Set getRangedOverAliases() { @Nonnull public CorrelationIdentifier getTopAlias() { - return getRootPullUp().getNestingAlias(); + return getRootPullUp().getCandidateAlias(); } @Nonnull private static PullUp of(@Nullable final PullUp parentPullUp, - @Nonnull final CorrelationIdentifier nestingAlias, + @Nonnull final CorrelationIdentifier candidateAlias, @Nonnull final CorrelationIdentifier lowerAlias, @Nonnull final Type lowerType, @Nonnull final Set rangedOverAliases) { - return of(parentPullUp, nestingAlias, QuantifiedObjectValue.of(lowerAlias, lowerType), + return of(parentPullUp, candidateAlias, QuantifiedObjectValue.of(lowerAlias, lowerType), rangedOverAliases); } @Nonnull private static PullUp of(@Nullable final PullUp parentPullUp, - @Nonnull final CorrelationIdentifier nestingAlias, + @Nonnull final CorrelationIdentifier candidateAlias, @Nonnull final Value lowerPullThroughValue, @Nonnull final Set rangedOverAliases) { - return new PullUp(parentPullUp, nestingAlias, lowerPullThroughValue, rangedOverAliases); + return new PullUp(parentPullUp, candidateAlias, lowerPullThroughValue, rangedOverAliases); } /** @@ -141,7 +141,7 @@ public Optional pullUpMaybe(@Nonnull final Value value) { MaxMatchMap.compute(currentValue, currentPullUp.getPullThroughValue(), currentPullUp.getRangedOverAliases()); final var currentValueOptional = - maxMatchMap.translateQueryValueMaybe(currentPullUp.getNestingAlias()); + maxMatchMap.translateQueryValueMaybe(currentPullUp.getCandidateAlias()); if (currentValueOptional.isEmpty()) { return Optional.empty(); } @@ -156,26 +156,26 @@ public Optional pullUpMaybe(@Nonnull final Value value) { @Nonnull public static RelationalExpressionVisitor visitor(@Nullable final PullUp parentPullUp, - @Nonnull final CorrelationIdentifier nestingAlias) { - return new PullUpVisitor(parentPullUp, nestingAlias); + @Nonnull final CorrelationIdentifier candidateAlias) { + return new PullUpVisitor(parentPullUp, candidateAlias); } private static class PullUpVisitor implements RelationalExpressionVisitorWithDefaults { @Nullable private final PullUp parentPullUp; @Nonnull - private final CorrelationIdentifier nestingAlias; + private final CorrelationIdentifier candidateAlias; public PullUpVisitor(@Nullable final PullUp parentPullUp, - @Nonnull final CorrelationIdentifier nestingAlias) { + @Nonnull final CorrelationIdentifier candidateAlias) { this.parentPullUp = parentPullUp; - this.nestingAlias = nestingAlias; + this.candidateAlias = candidateAlias; } @Nonnull @Override public PullUp visitLogicalTypeFilterExpression(@Nonnull final LogicalTypeFilterExpression logicalTypeFilterExpression) { - return of(parentPullUp, nestingAlias, logicalTypeFilterExpression.getInnerQuantifier().getAlias(), + return of(parentPullUp, candidateAlias, logicalTypeFilterExpression.getInnerQuantifier().getAlias(), logicalTypeFilterExpression.getInnerQuantifier().getFlowedObjectType(), Quantifiers.aliases(logicalTypeFilterExpression.getQuantifiers())); } @@ -183,7 +183,7 @@ public PullUp visitLogicalTypeFilterExpression(@Nonnull final LogicalTypeFilterE @Nonnull @Override public PullUp visitDefault(@Nonnull final RelationalExpression relationalExpression) { - return of(parentPullUp, nestingAlias, relationalExpression.getResultValue(), + return of(parentPullUp, candidateAlias, relationalExpression.getResultValue(), Quantifiers.aliases(relationalExpression.getQuantifiers())); } } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryStreamingAggregationPlan.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryStreamingAggregationPlan.java index 17772363f0..12e961e003 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryStreamingAggregationPlan.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryStreamingAggregationPlan.java @@ -418,8 +418,8 @@ public static RecordQueryStreamingAggregationPlan of(@Nonnull final Quantifier.P @Nullable final Value groupingKeyValue, @Nonnull final AggregateValue aggregateValue, @Nonnull final BiFunction resultValueFunction) { - final var groupingKeyAlias = CorrelationIdentifier.uniqueID(); - final var aggregateAlias = CorrelationIdentifier.uniqueID(); + final var groupingKeyAlias = CorrelationIdentifier.uniqueId(); + final var aggregateAlias = CorrelationIdentifier.uniqueId(); final var referencedGroupingKeyValue = groupingKeyValue == null diff --git a/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/query/FDBInQueryTest.java b/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/query/FDBInQueryTest.java index 7b4e5d7441..b2136d6f35 100644 --- a/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/query/FDBInQueryTest.java +++ b/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/query/FDBInQueryTest.java @@ -312,7 +312,7 @@ void testInQueryIndex(boolean reverse) throws Exception { @DualPlannerTest(planner = DualPlannerTest.Planner.CASCADES) void testInQueryWithConstantValueUnsorted() throws Exception { complexQuerySetup(NO_HOOK); - final ConstantObjectValue constant = ConstantObjectValue.of(CorrelationIdentifier.uniqueID(), "0", new Type.Array(false, Type.primitiveType(Type.TypeCode.INT, false))); + final ConstantObjectValue constant = ConstantObjectValue.of(CorrelationIdentifier.uniqueId(), "0", new Type.Array(false, Type.primitiveType(Type.TypeCode.INT, false))); final RecordQueryPlan plan = planGraph(() -> { final Quantifier base = fullTypeScan(recordStore.getRecordMetaData(), "MySimpleRecord"); var select = GraphExpansion.builder() @@ -1104,7 +1104,7 @@ void testConstantObjectInQuerySortedWithExtraUnorderedColumns(boolean reverse) t .andThen(metaDataBuilder -> metaDataBuilder.addIndex("MySimpleRecord", index)); complexQuerySetup(hook); - final CorrelationIdentifier constantAlias = CorrelationIdentifier.uniqueID(); + final CorrelationIdentifier constantAlias = CorrelationIdentifier.uniqueId(); final ConstantObjectValue nv2Constant = ConstantObjectValue.of(constantAlias, "0", Type.primitiveType(Type.TypeCode.INT, false)); final ConstantObjectValue listConstant = ConstantObjectValue.of(constantAlias, "1", new Type.Array(false, Type.primitiveType(Type.TypeCode.INT, false))); planner.setConfiguration(planner.getConfiguration().asBuilder().setAttemptFailedInJoinAsUnionMaxSize(10).build()); diff --git a/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/query/FDBLongArithmeticFunctionQueryTest.java b/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/query/FDBLongArithmeticFunctionQueryTest.java index b71f9b910d..d59d819476 100644 --- a/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/query/FDBLongArithmeticFunctionQueryTest.java +++ b/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/query/FDBLongArithmeticFunctionQueryTest.java @@ -416,7 +416,7 @@ void matchConstantMaskValue() { openSimpleRecordStore(context, hook); final String maskResultParam = "masked"; - final CorrelationIdentifier baseConstantId = CorrelationIdentifier.uniqueID(); + final CorrelationIdentifier baseConstantId = CorrelationIdentifier.uniqueId(); final ConstantObjectValue maskConstantValue = ConstantObjectValue.of(baseConstantId, "mask", Type.primitiveType(Type.TypeCode.LONG, false)); for (int i = 0; i < 3; i++) { final long mask = (1 << i); diff --git a/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/query/TempTableTest.java b/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/query/TempTableTest.java index 459dbf1891..a3ffd141a0 100644 --- a/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/query/TempTableTest.java +++ b/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/query/TempTableTest.java @@ -72,7 +72,7 @@ void scanTempTableWorksCorrectly() throws Exception { try (FDBRecordContext context = openContext()) { // select id, value from . final var tempTable = tempTableInstance(); - final var tempTableId = CorrelationIdentifier.uniqueID(); + final var tempTableId = CorrelationIdentifier.uniqueId(); final var plan = createAndOptimizeTempTableScanPlan(tempTableId); addSampleDataToTempTable(tempTable); final var expectedResults = ImmutableList.of(Pair.of(42L, "fortySecondValue"), @@ -87,7 +87,7 @@ void scanTempTableWithPredicateWorksCorrectly() throws Exception { try (FDBRecordContext context = openContext()) { final var tempTable = tempTableInstance(); addSampleDataToTempTable(tempTable); - final var tempTableId = CorrelationIdentifier.uniqueID(); + final var tempTableId = CorrelationIdentifier.uniqueId(); final var tempTableScanQun = Quantifier.forEach(Reference.of(TempTableScanExpression.ofCorrelated(tempTableId, getTempTableType()))); final var selectExpressionBuilder = GraphExpansion.builder() .addAllResultColumns(ImmutableList.of(getIdCol(tempTableScanQun), getValueCol(tempTableScanQun))) @@ -107,7 +107,7 @@ void insertIntoTempTableWorksCorrectly() throws Exception { // insert into values ((1, 'first'), (2, 'second')) try (FDBRecordContext context = openContext()) { final var tempTable = tempTableInstance(); - final var tempTableId = CorrelationIdentifier.uniqueID(); + final var tempTableId = CorrelationIdentifier.uniqueId(); final var firstRecord = rcv(1L, "first"); final var secondArray = rcv(2L, "second"); final var explodeExpression = new ExplodeExpression(AbstractArrayConstructorValue.LightArrayConstructorValue.of(firstRecord, secondArray)); @@ -136,7 +136,7 @@ void insertIntoTempTableWorksCorrectlyAcrossContinuations() throws Exception { // insert into values ((1, 'first'), stop, resume, then insert (2, 'second')) byte[] continuation = null; RecordQueryPlan planToResume = null; - final var tempTableId = CorrelationIdentifier.uniqueID(); + final var tempTableId = CorrelationIdentifier.uniqueId(); { final var tempTable = tempTableInstance(); @@ -183,7 +183,7 @@ void scanTempTableWithPredicateWorksCorrectlyAcrossContinuations() { // select id, value from where id < 44L. byte[] continuation = null; RecordQueryPlan planToResume = null; - final var tempTableId = CorrelationIdentifier.uniqueID(); + final var tempTableId = CorrelationIdentifier.uniqueId(); final var tempTable = tempTableInstance(); try (FDBRecordContext context = openContext()) { tempTable.add(queryResult(1L, "one")); diff --git a/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/query/plan/explain/ExplainPlanVisitorTest.java b/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/query/plan/explain/ExplainPlanVisitorTest.java index cb0ae69bb5..6ebbe3e903 100644 --- a/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/query/plan/explain/ExplainPlanVisitorTest.java +++ b/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/query/plan/explain/ExplainPlanVisitorTest.java @@ -303,7 +303,7 @@ private static NonnullPair randomExplodePlan(@Nonnull R if (r.nextBoolean()) { collectionValue = LiteralValue.ofList(List.of(1, 2, 3, 4, 5)); } else { - collectionValue = ConstantObjectValue.of(CorrelationIdentifier.uniqueID(), "__const_" + r.nextInt(10), new Type.Array(Type.primitiveType(Type.TypeCode.LONG, false))); + collectionValue = ConstantObjectValue.of(CorrelationIdentifier.uniqueId(), "__const_" + r.nextInt(10), new Type.Array(Type.primitiveType(Type.TypeCode.LONG, false))); } return NonnullPair.of(new RecordQueryExplodePlan(collectionValue), String.format("EXPLODE %s", collectionValue)); } diff --git a/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/Expression.java b/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/Expression.java index 072f24972b..ae88404df2 100644 --- a/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/Expression.java +++ b/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/Expression.java @@ -191,7 +191,7 @@ public boolean canBeDerivedFrom(@Nonnull final Expression expression, final var aliasMap = AliasMap.identitiesFor(value.getCorrelatedTo()); final var simplifiedValue = value.simplify(aliasMap, constantAliases); final var thisValue = getUnderlying(); - final var quantifier = CorrelationIdentifier.uniqueID(); + final var quantifier = CorrelationIdentifier.uniqueId(); final var result = simplifiedValue.pullUp(ImmutableList.of(thisValue), aliasMap, constantAliases, quantifier); return result.containsKey(thisValue); } From d13ea46cf338303355df5ea6b5501cb058cbe4b2 Mon Sep 17 00:00:00 2001 From: Normen Seemann Date: Tue, 11 Mar 2025 22:31:46 -0700 Subject: [PATCH 05/20] intersection complete --- .../plan/cascades/AggregateMappings.java | 2 +- .../query/plan/cascades/Compensation.java | 39 ++++- .../record/query/plan/cascades/MatchInfo.java | 6 +- .../expressions/GroupByExpression.java | 2 +- .../rules/AbstractDataAccessRule.java | 153 ++++++++++++++---- 5 files changed, 166 insertions(+), 36 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateMappings.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateMappings.java index cdb1c53665..acf8000a6a 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateMappings.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateMappings.java @@ -55,7 +55,7 @@ public static AggregateMappings empty() { } @Nonnull - public static AggregateMappings of(@Nonnull final BiMap matchedAggregateMap, + public static AggregateMappings of(@Nonnull final Map matchedAggregateMap, @Nonnull final BiMap unmatchedAggregateMap) { return new AggregateMappings(ImmutableMap.copyOf(matchedAggregateMap), ImmutableBiMap.copyOf(unmatchedAggregateMap)); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java index d46139e1cb..b04906e478 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java @@ -27,8 +27,10 @@ import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression; import com.apple.foundationdb.record.query.plan.cascades.predicates.QueryPredicate; import com.apple.foundationdb.record.query.plan.cascades.rules.DataAccessRule; +import com.apple.foundationdb.record.query.plan.cascades.values.Value; import com.google.common.base.Suppliers; import com.google.common.base.Verify; +import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -583,6 +585,19 @@ default Compensation intersect(@Nonnull Compensation otherCompensation) { .collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, Map.Entry::getValue, (l, r) -> l)); + final var newUnmatchedAggregateMapBuilder = + ImmutableBiMap.builder(); + for (final var entry : getAggregateMappings().getUnmatchedAggregateMap().entrySet()) { + if (!newMatchedAggregateMap.containsKey(entry.getValue())) { + newUnmatchedAggregateMapBuilder.put(entry); + } + } + for (final var entry : otherWithSelectCompensation.getAggregateMappings().getUnmatchedAggregateMap().entrySet()) { + if (!newMatchedAggregateMap.containsKey(entry.getValue())) { + newUnmatchedAggregateMapBuilder.put(entry); + } + } + final var newAggregateMappings = AggregateMappings.of(newMatchedAggregateMap, newUnmatchedAggregateMapBuilder.build()); final ResultCompensationFunction newResultResultCompensationFunction; final var resultCompensationFunction = getResultCompensationFunction(); @@ -594,7 +609,7 @@ default Compensation intersect(@Nonnull Compensation otherCompensation) { Verify.verify(resultCompensationFunction.isNeeded()); Verify.verify(otherResultCompensationFunction.isNeeded()); // pick the one from this side -- it does not matter as both candidates have the same shape - newResultResultCompensationFunction = resultCompensationFunction; + newResultResultCompensationFunction = resultCompensationFunction.amend(newAggregateMappings); } final var otherCompensationMap = otherWithSelectCompensation.getPredicateCompensationMap(); @@ -608,7 +623,8 @@ default Compensation intersect(@Nonnull Compensation otherCompensation) { // reapplication we need to generate plan variants with either compensation and let the planner // figure out which one wins. // We just pick one side here. - combinedPredicateMap.put(entry.getKey(), entry.getValue()); + combinedPredicateMap.put(entry.getKey(), + entry.getValue().amend(newAggregateMappings)); } } @@ -642,7 +658,7 @@ default Compensation intersect(@Nonnull Compensation otherCompensation) { intersectedUnmatchedQuantifiers, getCompensatedAliases(), // both compensated aliases must be identical, but too expensive to check newResultResultCompensationFunction, - AggregateMappings.empty()); + newAggregateMappings); } } @@ -905,5 +921,22 @@ public RelationalExpression applyFinal(@Nonnull final Memoizer memoizer, .build() .buildSelectWithResultValue(resultValue); } + + @Nonnull + @Override + public String toString() { + final var result = new StringBuilder(); + if (isNeeded()) { + result.append("needed; "); + } else { + result.append("not needed; "); + } + if (isImpossible()) { + result.append("impossible"); + } else { + result.append("possible"); + } + return result.toString(); + } } } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchInfo.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchInfo.java index ababd15c01..7711e3a70e 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchInfo.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchInfo.java @@ -85,7 +85,7 @@ default AdjustedBuilder adjustedBuilder() { @Nonnull default AggregateMappings adjustAggregateMappings(@Nonnull final PartialMatch partialMatch, @Nonnull final Quantifier candidateQuantifier) { - final var adjustedMatchedAggregateMapBuilder = ImmutableBiMap.builder(); + final var adjustedMatchedAggregateMapBuilder = ImmutableMap.builder(); final var aggregateMappings = getAggregateMappings(); final var matchedAggregateMap = aggregateMappings.getMatchedAggregateMap(); for (final var matchedAggregateMapEntry : matchedAggregateMap.entrySet()) { @@ -370,7 +370,7 @@ public static Optional> tryMergePara private static AggregateMappings pullUpAndMergeAggregateMappings(@Nonnull final AliasMap bindingAliasMap, @Nonnull final IdentityBiMap partialMatchMap, @Nonnull final AggregateMappings additionalAggregateMappings) { - final var matchedAggregateMapBuilder = ImmutableBiMap.builder(); + final var matchedAggregateMapBuilder = ImmutableMap.builder(); matchedAggregateMapBuilder.putAll(additionalAggregateMappings.getMatchedAggregateMap()); final var unatchedAggregateMapBuilder = ImmutableBiMap.builder(); unatchedAggregateMapBuilder.putAll(additionalAggregateMappings.getUnmatchedAggregateMap()); @@ -405,7 +405,7 @@ public static AggregateMappings pullUpAggregateMappings(@Nonnull final PartialMa final var queryExpression = partialMatch.getQueryExpression(); final var resultValue = queryExpression.getResultValue(); final var aggregateMappings = matchInfo.getAggregateMappings(); - final var matchedAggregateMapBuilder = ImmutableBiMap.builder(); + final var matchedAggregateMapBuilder = ImmutableMap.builder(); for (final var matchedAggregateMapEntry : aggregateMappings.getMatchedAggregateMap().entrySet()) { final var queryAggregateValue = matchedAggregateMapEntry.getKey(); final Value pulledUpQueryAggregateValue; diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java index 290da8d7e9..4e4c0d9439 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java @@ -343,7 +343,7 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid ImmutableBiMap.builder(); final var unmatchedTranslatedAggregateValueMapBuilder = ImmutableMap.builder(); - var subsumedAggregations = BooleanWithConstraint.alwaysTrue(); + var subsumedAggregations = BooleanWithConstraint.falseValue(); for (final var primitiveAggregateValue : aggregateValues) { final var translatedPrimitiveAggregateValue = primitiveAggregateValue.translateCorrelations(translationMap, true); diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java index 39f8e1f594..e1516429d2 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java @@ -28,6 +28,7 @@ import com.apple.foundationdb.record.query.plan.cascades.CascadesRuleCall; import com.apple.foundationdb.record.query.plan.cascades.ComparisonRange; import com.apple.foundationdb.record.query.plan.cascades.Compensation; +import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier; import com.apple.foundationdb.record.query.plan.cascades.LinkedIdentitySet; import com.apple.foundationdb.record.query.plan.cascades.MatchCandidate; import com.apple.foundationdb.record.query.plan.cascades.MatchPartition; @@ -76,6 +77,7 @@ import java.util.BitSet; import java.util.Collection; import java.util.Comparator; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -826,9 +828,15 @@ private static IntersectionResult createIntersectionAndCompensation(@Nonnull fin final var isPartitionRedundant = isPartitionRedundant(intersectionInfoMap, partition, equalityBoundKeyValues); if (isPartitionRedundant) { - return IntersectionResult.of(ImmutableList.of(), null); + return IntersectionResult.noCommonOrdering(); } + final var compensation = + partition + .stream() + .map(pair -> pair.getElement().getCompensation()) + .reduce(Compensation.impossibleCompensation(), Compensation::intersect); + boolean hasCommonOrdering = false; final var expressionsBuilder = ImmutableList.builder(); for (final var requestedOrdering : requestedOrderings) { @@ -842,13 +850,6 @@ private static IntersectionResult createIntersectionAndCompensation(@Nonnull fin } hasCommonOrdering = true; - - final var compensation = - partition - .stream() - .map(pair -> pair.getElement().getCompensation()) - .reduce(Compensation.impossibleCompensation(), Compensation::intersect); - if (!compensation.isImpossible()) { var comparisonOrderingParts = intersectionOrdering.directionalOrderingParts(comparisonKeyValues, requestedOrdering, @@ -875,7 +876,8 @@ private static IntersectionResult createIntersectionAndCompensation(@Nonnull fin } } - return IntersectionResult.of(expressionsBuilder.build(), hasCommonOrdering ? intersectionOrdering : null); + return IntersectionResult.of(hasCommonOrdering ? intersectionOrdering : null, compensation, + expressionsBuilder.build()); } private static boolean isPartitionRedundant(@Nonnull final Map intersectionInfoMap, @@ -891,17 +893,80 @@ private static boolean isPartitionRedundant(@Nonnull final Map> unmatchedIdsMaybe(@Nonnull final Map intersectionInfoMap, + @Nonnull final List> partition) { + final var iterator = partition.iterator(); + + var unmatchedIdsOptional = + unmatchedIdsMaybe(Objects.requireNonNull(intersectionInfoMap.get(intersectionInfoKey(iterator.next())))); + if (unmatchedIdsOptional.isEmpty()) { + return Optional.empty(); + } + + var intersectedUniqueIds = new LinkedHashSet<>(unmatchedIdsOptional.get()); + while (iterator.hasNext()) { + unmatchedIdsOptional = + unmatchedIdsMaybe(Objects.requireNonNull(intersectionInfoMap.get(intersectionInfoKey(iterator.next())))); + if (unmatchedIdsOptional.isEmpty()) { + return Optional.empty(); + } + intersectedUniqueIds.retainAll(unmatchedIdsOptional.get()); + } + + return Optional.of(intersectedUniqueIds); + } + + @Nonnull + private static Optional compensationMaybe(@Nonnull final IntersectionInfo intersectionInfo) { + final var compensation = intersectionInfo.getCompensation(); + if (!(compensation instanceof Compensation.WithSelectCompensation)) { + return Optional.empty(); + } + return Optional.of((Compensation.WithSelectCompensation)compensation); + } + + @Nonnull + private static Optional> unmatchedIdsMaybe(@Nonnull final IntersectionInfo intersectionInfo) { + final var compensationOptional = compensationMaybe(intersectionInfo); + return compensationOptional.map(compensation -> + compensation.getAggregateMappings().getUnmatchedAggregateMap().keySet()); + } + @Nonnull private static Ordering orderingFromSingleMatchedAccess(@Nonnull final SingleMatchedAccess singleMatchedAccess) { final var singlePartitionOrderingPartsPair = @@ -1004,15 +1069,18 @@ private static void addToIntersectionInfoMap(@Nonnull final Map compensatedExpressionOptional) { final var cacheKey = new BitSet(); cacheKey.set(singleAccessWithIndex.getPosition()); - final var orderingFromSingleMatchedAccess = orderingFromSingleMatchedAccess(singleAccessWithIndex.getElement()); + final var singleMatchedAccess = singleAccessWithIndex.getElement(); + final var compensation = singleMatchedAccess.getCompensation(); + final var orderingFromSingleMatchedAccess = orderingFromSingleMatchedAccess(singleMatchedAccess); if (compensatedExpressionOptional.isEmpty()) { - intersectionInfoMap.put(cacheKey, IntersectionInfo.ofImpossibleAccess(orderingFromSingleMatchedAccess)); + intersectionInfoMap.put(cacheKey, IntersectionInfo.ofImpossibleAccess(orderingFromSingleMatchedAccess, + compensation)); } else { final var compensatedExpression = compensatedExpressionOptional.get(); final var cardinalities = CardinalitiesProperty.evaluate(compensatedExpression); intersectionInfoMap.put(cacheKey, - IntersectionInfo.ofSingleAccess(orderingFromSingleMatchedAccess, compensatedExpression, + IntersectionInfo.ofSingleAccess(orderingFromSingleMatchedAccess, compensation, compensatedExpression, cardinalities.getMaxCardinality())); } } @@ -1040,7 +1108,7 @@ private static void updateIntersectionInfoMap(@Nonnull final Map Vectored of(@Nonnull final T element, final int position) { } private static class IntersectionResult { - @Nonnull - private final List expressions; @Nullable private final Ordering.Intersection commonIntersectionOrdering; + @Nonnull + private final Compensation compensation; + @Nonnull + private final List expressions; - private IntersectionResult(@Nonnull final List expressions, - @Nullable final Ordering.Intersection commonIntersectionOrdering) { + private IntersectionResult(@Nullable final Ordering.Intersection commonIntersectionOrdering, + @Nonnull final Compensation compensation, + @Nonnull final List expressions) { Verify.verify(commonIntersectionOrdering != null || expressions.isEmpty()); this.expressions = ImmutableList.copyOf(expressions); this.commonIntersectionOrdering = commonIntersectionOrdering; + this.compensation = compensation; } @Nonnull @@ -1185,15 +1257,27 @@ public Ordering.Intersection getCommonIntersectionOrdering() { } @Nonnull - public static IntersectionResult of(@Nonnull final List expressions, - @Nullable final Ordering.Intersection commonIntersectionOrdering) { - return new IntersectionResult(expressions, commonIntersectionOrdering); + public Compensation getCompensation() { + return compensation; + } + + @Nonnull + public static IntersectionResult noCommonOrdering() { + return new IntersectionResult(null, Compensation.noCompensation(), ImmutableList.of()); + } + + @Nonnull + public static IntersectionResult of(@Nullable final Ordering.Intersection commonIntersectionOrdering, + @Nonnull final Compensation compensation, + @Nonnull final List expressions) { + return new IntersectionResult(commonIntersectionOrdering, compensation, expressions); } @Override public String toString() { - return "[" + expressions + ", ordering=" + - (commonIntersectionOrdering == null ? "no common ordering" : commonIntersectionOrdering) + "]"; + return "[ordering=" + + (commonIntersectionOrdering == null ? "no common ordering" : commonIntersectionOrdering) + ", " + + compensation + "]"; } } @@ -1207,14 +1291,18 @@ private static class IntersectionInfo { @Nonnull private final Ordering intersectionOrdering; @Nonnull + private final Compensation compensation; + @Nonnull private final List expressions; @Nonnull private final Cardinality maxCardinality; private IntersectionInfo(@Nonnull final Ordering intersectionOrdering, + @Nonnull final Compensation compensation, @Nonnull final List expressions, @Nonnull final Cardinality maxCardinality) { this.intersectionOrdering = intersectionOrdering; + this.compensation = compensation; this.expressions = expressions; this.maxCardinality = maxCardinality; } @@ -1224,6 +1312,11 @@ public Ordering getIntersectionOrdering() { return intersectionOrdering; } + @Nonnull + public Compensation getCompensation() { + return compensation; + } + @Nonnull public List getExpressions() { return expressions; @@ -1240,20 +1333,24 @@ public void evictExpressions() { @Nonnull public static IntersectionInfo ofSingleAccess(@Nonnull final Ordering ordering, + @Nonnull final Compensation compensation, @Nonnull final RelationalExpression expression, @Nonnull final Cardinality maxCardinality) { - return new IntersectionInfo(ordering, Lists.newArrayList(expression), maxCardinality); + return new IntersectionInfo(ordering, compensation, Lists.newArrayList(expression), maxCardinality); } @Nonnull - public static IntersectionInfo ofImpossibleAccess(@Nonnull final Ordering ordering) { - return new IntersectionInfo(ordering, Lists.newArrayList(), Cardinality.unknownCardinality()); + public static IntersectionInfo ofImpossibleAccess(@Nonnull final Ordering ordering, + @Nonnull final Compensation compensation) { + return new IntersectionInfo(ordering, compensation, Lists.newArrayList(), Cardinality.unknownCardinality()); } @Nonnull public static IntersectionInfo ofIntersection(@Nonnull final Ordering ordering, + @Nonnull final Compensation compensation, @Nonnull final List expressions) { - return new IntersectionInfo(ordering, Lists.newArrayList(expressions), Cardinality.unknownCardinality()); + return new IntersectionInfo(ordering, compensation, Lists.newArrayList(expressions), + Cardinality.unknownCardinality()); } } } From 8ea6eb032c88bd6c9e9da6dda092107b6fed1237 Mon Sep 17 00:00:00 2001 From: Normen Seemann Date: Wed, 12 Mar 2025 15:33:08 -0700 Subject: [PATCH 06/20] intersection complete --- .../plan/cascades/AggregateMappings.java | 3 +- .../query/plan/cascades/Compensation.java | 17 ++++--- .../query/plan/cascades/PartialMatch.java | 6 +-- .../plan/cascades/PredicateMultiMap.java | 48 ++++++++++++------- .../query/plan/cascades/Quantifier.java | 8 ++-- .../rules/AbstractDataAccessRule.java | 16 +++++-- .../rules/MergeProjectionAndFetchRule.java | 2 +- .../cascades/rules/PartitionSelectRule.java | 2 +- .../rules/PushDistinctThroughFetchRule.java | 2 +- .../rules/PushFilterThroughFetchRule.java | 2 +- .../rules/PushMapThroughFetchRule.java | 2 +- .../PushSetOperationThroughFetchRule.java | 2 +- .../query/plan/plans/RecordQuerySetPlan.java | 2 +- .../foundationdb/query/FDBInQueryTest.java | 2 +- .../query/FDBPermutedMinMaxQueryTest.java | 6 +-- 15 files changed, 75 insertions(+), 45 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateMappings.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateMappings.java index acf8000a6a..744f622ca1 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateMappings.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateMappings.java @@ -35,7 +35,8 @@ public class AggregateMappings { @Nonnull private final BiMap unmatchedAggregateMap; - private AggregateMappings(@Nonnull final Map matchedAggregateMap, @Nonnull final BiMap unmatchedAggregateMap) { + private AggregateMappings(@Nonnull final Map matchedAggregateMap, + @Nonnull final BiMap unmatchedAggregateMap) { this.matchedAggregateMap = matchedAggregateMap; this.unmatchedAggregateMap = unmatchedAggregateMap; } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java index b04906e478..6bf3d18dfd 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java @@ -323,7 +323,7 @@ public RelationalExpression apply(@Nonnull final Memoizer memoizer, @Override public RelationalExpression applyFinal(@Nonnull final Memoizer memoizer, @Nonnull final RelationalExpression relationalExpression) { - return Compensation.this.apply(memoizer, otherCompensation.apply(memoizer, relationalExpression)); + return Compensation.this.applyFinal(memoizer, otherCompensation.applyFinal(memoizer, relationalExpression)); } }; } @@ -352,8 +352,8 @@ public RelationalExpression apply(@Nonnull final Memoizer memoizer, @Override public RelationalExpression applyFinal(@Nonnull final Memoizer memoizer, @Nonnull final RelationalExpression relationalExpression) { - return Compensation.this.apply(memoizer, - otherCompensation.apply(memoizer, relationalExpression)); + return Compensation.this.applyFinal(memoizer, + otherCompensation.applyFinal(memoizer, relationalExpression)); } }; } @@ -587,7 +587,8 @@ default Compensation intersect(@Nonnull Compensation otherCompensation) { (l, r) -> l)); final var newUnmatchedAggregateMapBuilder = ImmutableBiMap.builder(); - for (final var entry : getAggregateMappings().getUnmatchedAggregateMap().entrySet()) { + final var unmatchedAggregateMap = getAggregateMappings().getUnmatchedAggregateMap(); + for (final var entry : unmatchedAggregateMap.entrySet()) { if (!newMatchedAggregateMap.containsKey(entry.getValue())) { newUnmatchedAggregateMapBuilder.put(entry); } @@ -609,10 +610,12 @@ default Compensation intersect(@Nonnull Compensation otherCompensation) { Verify.verify(resultCompensationFunction.isNeeded()); Verify.verify(otherResultCompensationFunction.isNeeded()); // pick the one from this side -- it does not matter as both candidates have the same shape - newResultResultCompensationFunction = resultCompensationFunction.amend(newAggregateMappings); + newResultResultCompensationFunction = + resultCompensationFunction.amend(unmatchedAggregateMap, newMatchedAggregateMap); } - final var otherCompensationMap = otherWithSelectCompensation.getPredicateCompensationMap(); + final var otherCompensationMap = + otherWithSelectCompensation.getPredicateCompensationMap(); final var combinedPredicateMap = new LinkedIdentityMap(); for (final var entry : getPredicateCompensationMap().entrySet()) { // if the other side does not have compensation for this key, we don't need compensation @@ -624,7 +627,7 @@ default Compensation intersect(@Nonnull Compensation otherCompensation) { // figure out which one wins. // We just pick one side here. combinedPredicateMap.put(entry.getKey(), - entry.getValue().amend(newAggregateMappings)); + entry.getValue().amend(unmatchedAggregateMap, newMatchedAggregateMap)); } } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PartialMatch.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PartialMatch.java index 4e15108400..43d5b4de9c 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PartialMatch.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PartialMatch.java @@ -368,8 +368,8 @@ public Map getPulledUpPredicateMappings(@Nonnu } @Nonnull - public Compensation compensateCompleteMatch() { - return queryExpression.compensate(this, getBoundParameterPrefixMap(), null, Quantifier.uniqueID()); + public Compensation compensateCompleteMatch(@Nonnull final CorrelationIdentifier candidateTopAlias) { + return queryExpression.compensate(this, getBoundParameterPrefixMap(), null, candidateTopAlias); } @Nonnull @@ -381,7 +381,7 @@ public Compensation compensate(@Nonnull final Map boundParameterPrefixMap) { - return queryExpression.compensate(this, boundParameterPrefixMap, null, Quantifier.uniqueID()); + return queryExpression.compensate(this, boundParameterPrefixMap, null, Quantifier.uniqueId()); } @Nonnull diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PredicateMultiMap.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PredicateMultiMap.java index 716cb34290..ca680e2bbb 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PredicateMultiMap.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PredicateMultiMap.java @@ -30,6 +30,7 @@ import com.apple.foundationdb.record.query.plan.cascades.values.Value; import com.apple.foundationdb.record.query.plan.cascades.values.translation.PullUp; import com.google.common.base.Verify; +import com.google.common.collect.BiMap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.Multimaps; @@ -64,15 +65,17 @@ public class PredicateMultiMap { private final ImmutableSetMultimap map; @Nonnull - private static Value amendValue(final @Nonnull AggregateMappings aggregateMappings, final Value rootValue) { + private static Value amendValue(@Nonnull final BiMap unmatchedAggregateMap, + @Nonnull final Map amendedMatchedAggregateMap, + @Nonnull final Value rootValue) { return Objects.requireNonNull(rootValue.replace(currentValue -> { if (currentValue instanceof GroupByExpression.UnmatchedAggregateValue) { final var unmatchedId = ((GroupByExpression.UnmatchedAggregateValue)currentValue).getUnmatchedId(); final var queryValue = - Objects.requireNonNull(aggregateMappings.getUnmatchedAggregateMap().get(unmatchedId)); + Objects.requireNonNull(unmatchedAggregateMap.get(unmatchedId)); final var translatedQueryValue = - aggregateMappings.getMatchedAggregateMap().get(queryValue); + amendedMatchedAggregateMap.get(queryValue); if (translatedQueryValue != null) { return translatedQueryValue; } @@ -110,7 +113,8 @@ public boolean isImpossible() { @Nonnull @Override - public PredicateCompensationFunction amend(@Nonnull final AggregateMappings aggregateMappings) { + public PredicateCompensationFunction amend(@Nonnull final BiMap unmatchedAggregateMap, + @Nonnull final Map amendedMatchedAggregateMap) { return this; } @@ -135,7 +139,8 @@ public boolean isImpossible() { @Nonnull @Override - public PredicateCompensationFunction amend(@Nonnull final AggregateMappings aggregateMappings) { + public PredicateCompensationFunction amend(@Nonnull final BiMap unmatchedAggregateMap, + @Nonnull final Map amendedMatchedAggregateMap) { return this; } @@ -152,7 +157,8 @@ public Set applyCompensationForPredicate(@Nonnull final Correlat boolean isImpossible(); @Nonnull - PredicateCompensationFunction amend(@Nonnull final AggregateMappings aggregateMappings); + PredicateCompensationFunction amend(@Nonnull BiMap unmatchedAggregateMap, + @Nonnull Map amendedMatchedAggregateMap); @Nonnull Set applyCompensationForPredicate(@Nonnull CorrelationIdentifier baseAlias); @@ -175,10 +181,12 @@ public boolean isImpossible() { @Nonnull @Override - public PredicateCompensationFunction amend(@Nonnull final AggregateMappings aggregateMappings) { + public PredicateCompensationFunction amend(@Nonnull final BiMap unmatchedAggregateMap, + @Nonnull final Map amendedMatchedAggregateMap) { final var amendedTranslatedPredicateOptional = predicate.replaceValuesMaybe(rootValue -> - Optional.of(amendValue(aggregateMappings, rootValue))); + Optional.of(amendValue(unmatchedAggregateMap, amendedMatchedAggregateMap, + rootValue))); Verify.verify(amendedTranslatedPredicateOptional.isPresent()); return ofPredicate(amendedTranslatedPredicateOptional.get(), compensationFunction); } @@ -232,7 +240,8 @@ public boolean isImpossible() { @Nonnull @Override - public PredicateCompensationFunction amend(@Nonnull final AggregateMappings aggregateMappings) { + public PredicateCompensationFunction amend(@Nonnull final BiMap unmatchedAggregateMap, + @Nonnull final Map amendedMatchedAggregateMap) { return this; } @@ -260,10 +269,13 @@ public boolean isImpossible() { @Nonnull @Override - public PredicateCompensationFunction amend(@Nonnull final AggregateMappings aggregateMappings) { + public PredicateCompensationFunction amend(@Nonnull final BiMap unmatchedAggregateMap, + @Nonnull final Map amendedMatchedAggregateMap) { final var amendedChildrenCompensationFunctions = childrenCompensationFunctions.stream() - .map(childrenCompensationFunction -> childrenCompensationFunction.amend(aggregateMappings)) + .map(childrenCompensationFunction -> + childrenCompensationFunction.amend(unmatchedAggregateMap, + amendedMatchedAggregateMap)) .collect(ImmutableList.toImmutableList()); return ofChildrenCompensationFunctions(amendedChildrenCompensationFunctions, compensationFunction); } @@ -305,7 +317,8 @@ public boolean isImpossible() { @Nonnull @Override - public ResultCompensationFunction amend(@Nonnull final AggregateMappings aggregateMappings) { + public ResultCompensationFunction amend(@Nonnull final BiMap unmatchedAggregateMap, + @Nonnull final Map amendedMatchedAggregateMap) { return this; } @@ -330,7 +343,8 @@ public boolean isImpossible() { @Nonnull @Override - public ResultCompensationFunction amend(@Nonnull final AggregateMappings aggregateMappings) { + public ResultCompensationFunction amend(@Nonnull final BiMap unmatchedAggregateMap, + @Nonnull final Map amendedMatchedAggregateMap) { return this; } @@ -347,7 +361,8 @@ public Value applyCompensationForResult(@Nonnull final CorrelationIdentifier bas boolean isImpossible(); @Nonnull - ResultCompensationFunction amend(@Nonnull AggregateMappings aggregateMappings); + ResultCompensationFunction amend(@Nonnull BiMap unmatchedAggregateMap, + @Nonnull Map amendedMatchedAggregateMap); @Nonnull Value applyCompensationForResult(@Nonnull CorrelationIdentifier baseAlias); @@ -370,9 +385,10 @@ public boolean isImpossible() { @Nonnull @Override - public ResultCompensationFunction amend(@Nonnull final AggregateMappings aggregateMappings) { + public ResultCompensationFunction amend(@Nonnull final BiMap unmatchedAggregateMap, + @Nonnull final Map amendedMatchedAggregateMap) { final var amendedTranslatedQueryValue = - amendValue(aggregateMappings, value); + amendValue(unmatchedAggregateMap, amendedMatchedAggregateMap, value); return ofValue(amendedTranslatedQueryValue, compensationFunction); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Quantifier.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Quantifier.java index 9d18a983e7..6353e92754 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Quantifier.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Quantifier.java @@ -170,7 +170,7 @@ public ForEachBuilder from(final ForEach quantifier) { @Nonnull @Override public ForEach build(@Nonnull final Reference rangesOver) { - return new ForEach(alias == null ? Quantifier.uniqueID() : alias, rangesOver, isNullOnEmpty); + return new ForEach(alias == null ? Quantifier.uniqueId() : alias, rangesOver, isNullOnEmpty); } } @@ -341,7 +341,7 @@ public static class ExistentialBuilder extends Builder { @Nonnull @Override public Physical build(@Nonnull final Reference rangesOver) { - return new Physical(alias == null ? Quantifier.uniqueID() : alias, rangesOver); + return new Physical(alias == null ? Quantifier.uniqueId() : alias, rangesOver); } /** @@ -791,7 +791,7 @@ public Quantifier translateCorrelations(@Nonnull final TranslationMap translatio } @Nonnull - public static CorrelationIdentifier uniqueID() { + public static CorrelationIdentifier uniqueId() { return CorrelationIdentifier.uniqueId(Quantifier.class); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java index e1516429d2..e3a5200278 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java @@ -552,11 +552,12 @@ private static List prepareMatchesAndCompensations(final @N Verify.verify(scanDirection == ScanDirection.FORWARD || scanDirection == ScanDirection.REVERSE || scanDirection == ScanDirection.BOTH); - final var compensation = partialMatch.compensateCompleteMatch(); + final var candidateTopAlias = Quantifier.uniqueId(); + final var compensation = partialMatch.compensateCompleteMatch(candidateTopAlias); if (scanDirection == ScanDirection.FORWARD || scanDirection == ScanDirection.BOTH) { partialMatchesWithCompensation.add(new SingleMatchedAccess(partialMatch, compensation, - false, satisfyingOrderingsPair.getRight())); + candidateTopAlias, false, satisfyingOrderingsPair.getRight())); } // @@ -569,7 +570,7 @@ private static List prepareMatchesAndCompensations(final @N // if (scanDirection == ScanDirection.REVERSE /* || scanDirection == ScanDirection.BOTH */) { partialMatchesWithCompensation.add(new SingleMatchedAccess(partialMatch, compensation, - true, satisfyingOrderingsPair.getRight())); + candidateTopAlias, true, satisfyingOrderingsPair.getRight())); } } @@ -1145,16 +1146,20 @@ private static class SingleMatchedAccess { private final PartialMatch partialMatch; @Nonnull private final Compensation compensation; + @Nonnull + private CorrelationIdentifier candidateTopAlias; private final boolean reverseScanOrder; @Nonnull private final Set satisfyingRequestedOrderings; public SingleMatchedAccess(@Nonnull final PartialMatch partialMatch, @Nonnull final Compensation compensation, + @Nonnull final CorrelationIdentifier candidateTopAlias, final boolean reverseScanOrder, @Nonnull final Set satisfyingRequestedOrderings) { this.partialMatch = partialMatch; this.compensation = compensation; + this.candidateTopAlias = candidateTopAlias; this.reverseScanOrder = reverseScanOrder; this.satisfyingRequestedOrderings = ImmutableSet.copyOf(satisfyingRequestedOrderings); } @@ -1169,6 +1174,11 @@ public Compensation getCompensation() { return compensation; } + @Nonnull + public CorrelationIdentifier getCandidateTopAlias() { + return candidateTopAlias; + } + public boolean isReverseScanOrder() { return reverseScanOrder; } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/MergeProjectionAndFetchRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/MergeProjectionAndFetchRule.java index a3a983c783..a46c037bea 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/MergeProjectionAndFetchRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/MergeProjectionAndFetchRule.java @@ -65,7 +65,7 @@ public void onMatch(@Nonnull final CascadesRuleCall call) { // if the fetch is able to push all values we can eliminate the fetch as well final RecordQueryFetchFromPartialRecordPlan fetchPlan = call.get(innerPlanMatcher); final CorrelationIdentifier oldInnerAlias = Iterables.getOnlyElement(projectionExpression.getQuantifiers()).getAlias(); - final CorrelationIdentifier newInnerAlias = Quantifier.uniqueID(); + final CorrelationIdentifier newInnerAlias = Quantifier.uniqueId(); final List projectedValues = projectionExpression.getProjectedValues(); final boolean allPushable = projectedValues .stream() diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PartitionSelectRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PartitionSelectRule.java index 497ee5afc4..03c26cc1e9 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PartitionSelectRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PartitionSelectRule.java @@ -150,7 +150,7 @@ public void onMatch(@Nonnull final CascadesRuleCall call) { final CorrelationIdentifier lowerAliasCorrelatedToByUpperAliases; if (lowersCorrelatedToByUpperAliases.isEmpty()) { - lowerAliasCorrelatedToByUpperAliases = Quantifier.uniqueID(); + lowerAliasCorrelatedToByUpperAliases = Quantifier.uniqueId(); } else { lowerAliasCorrelatedToByUpperAliases = Iterables.getOnlyElement(lowersCorrelatedToByUpperAliases); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushDistinctThroughFetchRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushDistinctThroughFetchRule.java index 709ab435ca..fe0cae08b0 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushDistinctThroughFetchRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushDistinctThroughFetchRule.java @@ -92,7 +92,7 @@ public void onMatch(@Nonnull final CascadesRuleCall call) { final RecordQueryFetchFromPartialRecordPlan fetchPlan = bindings.get(fetchPlanMatcher); final RecordQueryPlan innerPlan = bindings.get(innerPlanMatcher); - final CorrelationIdentifier newInnerAlias = Quantifier.uniqueID(); + final CorrelationIdentifier newInnerAlias = Quantifier.uniqueId(); final Quantifier.Physical newInnerQuantifier = Quantifier.physical(call.memoizePlans(innerPlan), newInnerAlias); diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushFilterThroughFetchRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushFilterThroughFetchRule.java index 3ed78c6ce6..137f9eabc7 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushFilterThroughFetchRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushFilterThroughFetchRule.java @@ -173,7 +173,7 @@ public void onMatch(@Nonnull final CascadesRuleCall call) { final ImmutableList.Builder pushedPredicatesBuilder = ImmutableList.builder(); final ImmutableList.Builder residualPredicatesBuilder = ImmutableList.builder(); - final CorrelationIdentifier newInnerAlias = Quantifier.uniqueID(); + final CorrelationIdentifier newInnerAlias = Quantifier.uniqueId(); for (final QueryPredicate queryPredicate : queryPredicates) { final Optional pushedPredicateOptional = diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushMapThroughFetchRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushMapThroughFetchRule.java index 463376415b..e40434df70 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushMapThroughFetchRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushMapThroughFetchRule.java @@ -143,7 +143,7 @@ public void onMatch(@Nonnull final CascadesRuleCall call) { final var resultValue = mapPlan.getResultValue(); // try to push these field values - final CorrelationIdentifier newInnerAlias = Quantifier.uniqueID(); + final CorrelationIdentifier newInnerAlias = Quantifier.uniqueId(); final var pushedResultValueOptional = fetchPlan.pushValue(resultValue, quantifierOverFetch.getAlias(), newInnerAlias); if (pushedResultValueOptional.isEmpty()) { diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushSetOperationThroughFetchRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushSetOperationThroughFetchRule.java index 044a46aec7..6596a9dca2 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushSetOperationThroughFetchRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/PushSetOperationThroughFetchRule.java @@ -173,7 +173,7 @@ public void onMatch(@Nonnull final CascadesRuleCall call) { Verify.verify(quantifiersOverFetches.size() == fetchPlans.size()); Verify.verify(fetchPlans.size() == dependentFunctions.size()); - final CorrelationIdentifier sourceAlias = Quantifier.uniqueID(); + final CorrelationIdentifier sourceAlias = Quantifier.uniqueId(); final List requiredValues = setOperationPlan.getRequiredValues(sourceAlias, Quantifiers.getFlowedTypeForSetOperation(quantifiersOverFetches)); final Set pushableAliases = setOperationPlan.tryPushValues(dependentFunctions, quantifiersOverFetches, requiredValues, sourceAlias); diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQuerySetPlan.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQuerySetPlan.java index 6cbcffefc8..437ba6e9dd 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQuerySetPlan.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQuerySetPlan.java @@ -123,7 +123,7 @@ default Set tryPushValues(@Nonnull final List selectMaxWithInOrderByMax() { - ConstantObjectValue constant = ConstantObjectValue.of(Quantifier.uniqueID(), "0", new Type.Array(false, Type.primitiveType(Type.TypeCode.INT, false))); + ConstantObjectValue constant = ConstantObjectValue.of(Quantifier.uniqueId(), "0", new Type.Array(false, Type.primitiveType(Type.TypeCode.INT, false))); return Stream.of( new InComparisonCase("byParameter", new Comparisons.ParameterComparison(Comparisons.Type.IN, "numValue2List"), nv2List -> Bindings.newBuilder().set("numValue2List", nv2List).build(), 2026350341, -272644765), new InComparisonCase("byLiteral", new Comparisons.ListComparison(Comparisons.Type.IN, List.of(-1, -1)), nv2List -> { @@ -489,7 +489,7 @@ void selectMaxWithInOrderByMax(InComparisonCase inComparisonCase) throws Excepti @Nonnull static Stream testMaxWithInAndDupes() { - ConstantObjectValue constant = ConstantObjectValue.of(Quantifier.uniqueID(), "0", new Type.Array(false, Type.primitiveType(Type.TypeCode.STRING, false))); + ConstantObjectValue constant = ConstantObjectValue.of(Quantifier.uniqueId(), "0", new Type.Array(false, Type.primitiveType(Type.TypeCode.STRING, false))); return Stream.of( new InComparisonCase("byParameter", new Comparisons.ParameterComparison(Comparisons.Type.IN, "strValueList"), strValueList -> Bindings.newBuilder().set("strValueList", strValueList).build(), 2106093264, 1809779597), new InComparisonCase("byLiteral", new Comparisons.ListComparison(Comparisons.Type.IN, List.of("even", "odd")), strValueList -> { @@ -629,7 +629,7 @@ void testSortedMaxWithEqualityOnRepeater() { @Nonnull static Stream testSortedMaxWithInOnRepeater() { - ConstantObjectValue constant = ConstantObjectValue.of(Quantifier.uniqueID(), "0", new Type.Array(false, Type.primitiveType(Type.TypeCode.INT, false))); + ConstantObjectValue constant = ConstantObjectValue.of(Quantifier.uniqueId(), "0", new Type.Array(false, Type.primitiveType(Type.TypeCode.INT, false))); return Stream.of( new InComparisonCase("byParameter", new Comparisons.ParameterComparison(Comparisons.Type.IN, "xValueList"), xValueList -> Bindings.newBuilder().set("xValueList", xValueList).build(), -1502950720, -1056018522), new InComparisonCase("byLiteral", new Comparisons.ListComparison(Comparisons.Type.IN, List.of(0, 0)), strValueList -> { From 7ffa112e75f5cc16306d44c1720f77902ea5eb45 Mon Sep 17 00:00:00 2001 From: Normen Seemann Date: Thu, 13 Mar 2025 21:44:26 -0700 Subject: [PATCH 07/20] save-point --- .../query/plan/cascades/Compensation.java | 84 +++++-- .../plan/cascades/PredicateMultiMap.java | 33 +-- .../expressions/GroupByExpression.java | 4 +- .../LogicalTypeFilterExpression.java | 4 +- .../expressions/SelectExpression.java | 4 +- .../predicates/LeafQueryPredicate.java | 7 +- .../cascades/predicates/QueryPredicate.java | 6 +- .../rules/AbstractDataAccessRule.java | 123 ++------- .../rules/AggregateDataAccessRule.java | 93 +++++++ .../plan/cascades/rules/DataAccessRule.java | 116 --------- .../rules/WithPrimaryKeyDataAccessRule.java | 110 ++++++++ ...ordQueryMultiIntersectionOnValuesPlan.java | 235 ++++++++++++++++++ 12 files changed, 551 insertions(+), 268 deletions(-) delete mode 100644 fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/DataAccessRule.java create mode 100644 fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryMultiIntersectionOnValuesPlan.java diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java index 6bf3d18dfd..ba5dc7bd97 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java @@ -26,8 +26,8 @@ import com.apple.foundationdb.record.query.plan.cascades.expressions.LogicalFilterExpression; import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression; import com.apple.foundationdb.record.query.plan.cascades.predicates.QueryPredicate; -import com.apple.foundationdb.record.query.plan.cascades.rules.DataAccessRule; import com.apple.foundationdb.record.query.plan.cascades.values.Value; +import com.apple.foundationdb.record.query.plan.cascades.values.translation.TranslationMap; import com.google.common.base.Suppliers; import com.google.common.base.Verify; import com.google.common.collect.ImmutableBiMap; @@ -41,6 +41,7 @@ import java.util.Collection; import java.util.Map; import java.util.Set; +import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Stream; @@ -107,9 +108,8 @@ *
* Compensation is computed either during the matching process or is computed after a complete match has been found * utilizing helper structures such as {@link PartialMatch} and {@link MatchInfo}, which are themselves - * built during matching. Logic in - * {@link DataAccessRule} computes and applies compensation - * as needed when a complete index match has been found. + * built during matching. Logic in the data access rules computes and applies compensation as needed when a complete + * index match has been found. *
* A query sub graph can have multiple matches that could be utilized. In the example above, another index on {@code b} * would also match but use {@code b} for the index scan and a predicate {@code WHERE a = 3}. Both match the query, @@ -143,14 +143,16 @@ public Compensation intersect(@Nonnull final Compensation otherCompensation) { @Nonnull @Override public RelationalExpression apply(@Nonnull final Memoizer memoizer, - @Nonnull final RelationalExpression relationalExpression) { + @Nonnull final RelationalExpression relationalExpression, + @Nonnull Function matchedToRealizedTranslationMapFunction) { throw new RecordCoreException("this method should not be called"); } @Nonnull @Override public RelationalExpression applyFinal(@Nonnull final Memoizer memoizer, - @Nonnull final RelationalExpression relationalExpression) { + @Nonnull final RelationalExpression relationalExpression, + @Nonnull Function matchedToRealizedTranslationMapFunction) { throw new RecordCoreException("this method should not be called"); } }; @@ -187,26 +189,29 @@ public Compensation intersect(@Nonnull final Compensation otherCompensation) { @Nonnull @Override public RelationalExpression apply(@Nonnull final Memoizer memoizer, - @Nonnull final RelationalExpression relationalExpression) { + @Nonnull final RelationalExpression relationalExpression, + @Nonnull Function matchedToRealizedTranslationMapFunction) { throw new RecordCoreException("this method should not be called"); } @Nonnull @Override public RelationalExpression applyFinal(@Nonnull final Memoizer memoizer, - @Nonnull final RelationalExpression relationalExpression) { + @Nonnull final RelationalExpression relationalExpression, + @Nonnull Function matchedToRealizedTranslationMapFunction) { throw new RecordCoreException("this method should not be called"); } }; @Nonnull default RelationalExpression applyAllNeededCompensations(@Nonnull final Memoizer memoizer, - @Nonnull RelationalExpression relationalExpression) { + @Nonnull RelationalExpression relationalExpression, + @Nonnull Function matchedToRealizedTranslationMapFunction) { if (isNeededForFiltering()) { - relationalExpression = apply(memoizer, relationalExpression); + relationalExpression = apply(memoizer, relationalExpression, matchedToRealizedTranslationMapFunction); } if (isFinalNeeded()) { - relationalExpression = applyFinal(memoizer, relationalExpression); + relationalExpression = applyFinal(memoizer, relationalExpression, matchedToRealizedTranslationMapFunction); } return relationalExpression; @@ -218,11 +223,15 @@ default RelationalExpression applyAllNeededCompensations(@Nonnull final Memoizer * {@link WithSelectCompensation}. * @param memoizer the memoizer for new {@link Reference}s * @param relationalExpression root of graph to apply compensation to + * @param matchedToRealizedTranslationMapFunction a function that given an alias for the quantifier over the + * realized compensation, returns a {@link TranslationMap} that is then used to translate + * from {@link QueryPredicate}s and {@link Value}s using matched aliases to the realized alias * @return a new relational expression that corrects the result of {@code reference} by applying appropriate * filters and/or transformations */ @Nonnull - RelationalExpression apply(@Nonnull Memoizer memoizer, @Nonnull RelationalExpression relationalExpression); + RelationalExpression apply(@Nonnull Memoizer memoizer, @Nonnull RelationalExpression relationalExpression, + @Nonnull Function matchedToRealizedTranslationMapFunction); /** * When applied to a reference this method returns a {@link RelationalExpression} consuming the @@ -230,11 +239,15 @@ default RelationalExpression applyAllNeededCompensations(@Nonnull final Memoizer * {@link WithSelectCompensation}. * @param memoizer the memoizer for new {@link Reference}s * @param relationalExpression root of graph to apply compensation to + * @param matchedToRealizedTranslationMapFunction a function that given an alias for the quantifier over the + * realized compensation, returns a {@link TranslationMap} that is then used to translate + * from {@link QueryPredicate}s and {@link Value}s using matched aliases to the realized alias * @return a new relational expression that corrects the result of {@code reference} by applying a final shape * correction of the resulting records. */ @Nonnull - RelationalExpression applyFinal(@Nonnull Memoizer memoizer, @Nonnull RelationalExpression relationalExpression); + RelationalExpression applyFinal(@Nonnull Memoizer memoizer, @Nonnull RelationalExpression relationalExpression, + @Nonnull Function matchedToRealizedTranslationMapFunction); /** * Returns if this compensation object needs to be applied in order to correct the result of a match. @@ -315,15 +328,20 @@ default Compensation union(@Nonnull Compensation otherCompensation) { @Nonnull @Override public RelationalExpression apply(@Nonnull final Memoizer memoizer, - @Nonnull final RelationalExpression relationalExpression) { - return Compensation.this.apply(memoizer, otherCompensation.apply(memoizer, relationalExpression)); + @Nonnull final RelationalExpression relationalExpression, + @Nonnull Function matchedToRealizedTranslationMapFunction) { + return Compensation.this.apply(memoizer, otherCompensation.apply(memoizer, relationalExpression, + matchedToRealizedTranslationMapFunction), matchedToRealizedTranslationMapFunction); } @Nonnull @Override public RelationalExpression applyFinal(@Nonnull final Memoizer memoizer, - @Nonnull final RelationalExpression relationalExpression) { - return Compensation.this.applyFinal(memoizer, otherCompensation.applyFinal(memoizer, relationalExpression)); + @Nonnull final RelationalExpression relationalExpression, + @Nonnull Function matchedToRealizedTranslationMapFunction) { + return Compensation.this.applyFinal(memoizer, otherCompensation.applyFinal(memoizer, + relationalExpression, matchedToRealizedTranslationMapFunction), + matchedToRealizedTranslationMapFunction); } }; } @@ -343,17 +361,21 @@ default Compensation intersect(@Nonnull Compensation otherCompensation) { @Nonnull @Override public RelationalExpression apply(@Nonnull final Memoizer memoizer, - @Nonnull final RelationalExpression relationalExpression) { + @Nonnull final RelationalExpression relationalExpression, + @Nonnull Function matchedToRealizedTranslationMapFunction) { return Compensation.this.apply(memoizer, - otherCompensation.apply(memoizer, relationalExpression)); + otherCompensation.apply(memoizer, relationalExpression, + matchedToRealizedTranslationMapFunction), matchedToRealizedTranslationMapFunction); } @Nonnull @Override public RelationalExpression applyFinal(@Nonnull final Memoizer memoizer, - @Nonnull final RelationalExpression relationalExpression) { + @Nonnull final RelationalExpression relationalExpression, + @Nonnull Function matchedToRealizedTranslationMapFunction) { return Compensation.this.applyFinal(memoizer, - otherCompensation.applyFinal(memoizer, relationalExpression)); + otherCompensation.applyFinal(memoizer, relationalExpression, + matchedToRealizedTranslationMapFunction), matchedToRealizedTranslationMapFunction); } }; } @@ -784,6 +806,9 @@ public AggregateMappings getAggregateMappings() { * * @param memoizer the memoizer for new {@link Reference}s * @param relationalExpression root of graph to apply compensation to + * @param matchedToRealizedTranslationMapFunction a function that given an alias for the quantifier over the + * realized compensation, returns a {@link TranslationMap} that is then used to translate + * from {@link QueryPredicate}s and {@link Value}s using matched aliases to the realized alias * * @return a new relational expression that corrects the result of {@code reference} by applying appropriate * filters and/or transformations @@ -791,21 +816,25 @@ public AggregateMappings getAggregateMappings() { @Nonnull @Override public RelationalExpression apply(@Nonnull final Memoizer memoizer, - @Nonnull RelationalExpression relationalExpression) { + @Nonnull RelationalExpression relationalExpression, + @Nonnull final Function matchedToRealizedTranslationMapFunction) { Verify.verify(!isImpossible()); // apply the child as needed if (childCompensation.isNeededForFiltering()) { - relationalExpression = childCompensation.apply(memoizer, relationalExpression); + relationalExpression = childCompensation.apply(memoizer, relationalExpression, + matchedToRealizedTranslationMapFunction); } final var matchedForEachAlias = getMatchedForEachAlias(); + final var matchedToRealizedTranslationMap = matchedToRealizedTranslationMapFunction.apply(matchedForEachAlias); final var compensatedPredicates = new LinkedIdentitySet(); final var injectCompensationFunctions = predicateCompensationMap.values(); for (final var predicateCompensationFunction : injectCompensationFunctions) { // TODO construct a translation map using matchedForEachAlias as target - compensatedPredicates.addAll(predicateCompensationFunction.applyCompensationForPredicate(matchedForEachAlias)); + compensatedPredicates.addAll( + predicateCompensationFunction.applyCompensationForPredicate(matchedToRealizedTranslationMap)); } final var compensatedPredicatesCorrelatedTo = @@ -904,13 +933,16 @@ private CorrelationIdentifier getMatchedForEachAlias() { @Nonnull @Override public RelationalExpression applyFinal(@Nonnull final Memoizer memoizer, - @Nonnull RelationalExpression relationalExpression) { + @Nonnull RelationalExpression relationalExpression, + @Nonnull Function matchedToRealizedTranslationMapFunction) { Verify.verify(!isImpossible()); Verify.verify(resultCompensationFunction.isNeeded()); final var matchedForEachAlias = getMatchedForEachAlias(); - final var resultValue = resultCompensationFunction.applyCompensationForResult(matchedForEachAlias); + final var resultValue = + resultCompensationFunction.applyCompensationForResult( + matchedToRealizedTranslationMapFunction.apply(matchedForEachAlias)); // // At this point we definitely need a new SELECT expression. diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PredicateMultiMap.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PredicateMultiMap.java index ca680e2bbb..2adc122dbb 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PredicateMultiMap.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PredicateMultiMap.java @@ -29,6 +29,7 @@ import com.apple.foundationdb.record.query.plan.cascades.predicates.QueryPredicate; import com.apple.foundationdb.record.query.plan.cascades.values.Value; import com.apple.foundationdb.record.query.plan.cascades.values.translation.PullUp; +import com.apple.foundationdb.record.query.plan.cascades.values.translation.TranslationMap; import com.google.common.base.Verify; import com.google.common.collect.BiMap; import com.google.common.collect.ImmutableList; @@ -120,7 +121,7 @@ public PredicateCompensationFunction amend(@Nonnull final BiMap applyCompensationForPredicate(@Nonnull final CorrelationIdentifier baseAlias) { + public Set applyCompensationForPredicate(@Nonnull final TranslationMap translationMap) { throw new IllegalArgumentException("this method should not be called"); } }; @@ -146,7 +147,7 @@ public PredicateCompensationFunction amend(@Nonnull final BiMap applyCompensationForPredicate(@Nonnull final CorrelationIdentifier baseAlias) { + public Set applyCompensationForPredicate(@Nonnull final TranslationMap translationMap) { throw new IllegalArgumentException("this method should not be called"); } }; @@ -161,11 +162,11 @@ PredicateCompensationFunction amend(@Nonnull BiMap @Nonnull Map amendedMatchedAggregateMap); @Nonnull - Set applyCompensationForPredicate(@Nonnull CorrelationIdentifier baseAlias); + Set applyCompensationForPredicate(@Nonnull TranslationMap translationMap); @Nonnull static PredicateCompensationFunction ofPredicate(@Nonnull final QueryPredicate predicate, - @Nonnull final BiFunction> compensationFunction) { + @Nonnull final BiFunction> compensationFunction) { final var isImpossible = predicateContainsUnmatchedValues(predicate); return new PredicateCompensationFunction() { @@ -193,8 +194,8 @@ public PredicateCompensationFunction amend(@Nonnull final BiMap applyCompensationForPredicate(@Nonnull final CorrelationIdentifier baseAlias) { - return compensationFunction.apply(predicate, baseAlias); + public Set applyCompensationForPredicate(@Nonnull final TranslationMap translationMap) { + return compensationFunction.apply(predicate, translationMap); } }; } @@ -247,7 +248,7 @@ public PredicateCompensationFunction amend(@Nonnull final BiMap applyCompensationForPredicate(@Nonnull final CorrelationIdentifier baseAlias) { + public Set applyCompensationForPredicate(@Nonnull final TranslationMap translationMap) { return result; } }; @@ -255,7 +256,7 @@ public Set applyCompensationForPredicate(@Nonnull final Correlat @Nonnull static PredicateCompensationFunction ofChildrenCompensationFunctions(@Nonnull final List childrenCompensationFunctions, - @Nonnull final BiFunction, CorrelationIdentifier, Set> compensationFunction) { + @Nonnull final BiFunction, TranslationMap, Set> compensationFunction) { return new PredicateCompensationFunction() { @Override public boolean isNeeded() { @@ -282,8 +283,8 @@ public PredicateCompensationFunction amend(@Nonnull final BiMap applyCompensationForPredicate(@Nonnull final CorrelationIdentifier baseAlias) { - return compensationFunction.apply(childrenCompensationFunctions, baseAlias); + public Set applyCompensationForPredicate(@Nonnull final TranslationMap translationMap) { + return compensationFunction.apply(childrenCompensationFunctions, translationMap); } }; } @@ -324,7 +325,7 @@ public ResultCompensationFunction amend(@Nonnull final BiMap un @Nonnull Map amendedMatchedAggregateMap); @Nonnull - Value applyCompensationForResult(@Nonnull CorrelationIdentifier baseAlias); + Value applyCompensationForResult(@Nonnull TranslationMap translationMap); @Nonnull static ResultCompensationFunction ofValue(@Nonnull final Value value, - @Nonnull final BiFunction compensationFunction) { + @Nonnull final BiFunction compensationFunction) { final var isImpossible = valueContainsUnmatchedValues(value); return new ResultCompensationFunction() { @@ -395,8 +396,8 @@ public ResultCompensationFunction amend(@Nonnull final BiMap value.translateCorrelations( - TranslationMap.ofAliases(rootPullUp.getCandidateAlias(), baseAlias), false)); + (value, translationMap) -> value.translateCorrelations(translationMap, + false)); isCompensationImpossible |= resultCompensationFunction.isImpossible(); pulledUpAggregateMappings = diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/LogicalTypeFilterExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/LogicalTypeFilterExpression.java index 8f16d4c9dc..3c75887181 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/LogicalTypeFilterExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/LogicalTypeFilterExpression.java @@ -221,8 +221,8 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, resultCompensationFunction = ResultCompensationFunction.ofValue(pulledUpTranslatedResultValue, - (value, baseAlias) -> value.translateCorrelations( - TranslationMap.ofAliases(rootPullUp.getCandidateAlias(), baseAlias), false)); + (value, translationMap) -> value.translateCorrelations(translationMap, + false)); isCompensationImpossible |= resultCompensationFunction.isImpossible(); aggregateMappings = diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java index 29d783e446..8b8a1408ea 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java @@ -879,8 +879,8 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, resultCompensationFunction = ResultCompensationFunction.ofValue(pulledUpTranslatedResultValue, - (value, baseAlias) -> value.translateCorrelations( - TranslationMap.ofAliases(rootPullUp.getCandidateAlias(), baseAlias), false)); + (value, translationMap) -> value.translateCorrelations(translationMap, + false)); isAnyCompensationFunctionImpossible |= resultCompensationFunction.isImpossible(); aggregateMappings = diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/LeafQueryPredicate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/LeafQueryPredicate.java index a8b9406177..f8568ab6f6 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/LeafQueryPredicate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/LeafQueryPredicate.java @@ -27,7 +27,6 @@ import com.apple.foundationdb.record.query.plan.cascades.PartialMatch; import com.apple.foundationdb.record.query.plan.cascades.PredicateMultiMap; import com.apple.foundationdb.record.query.plan.cascades.values.translation.PullUp; -import com.apple.foundationdb.record.query.plan.cascades.values.translation.TranslationMap; import com.google.common.base.Verify; import com.google.common.collect.ImmutableList; @@ -85,9 +84,9 @@ default PredicateMultiMap.PredicateCompensationFunction computeCompensationFunct .replaceValuesMaybe(pullUp::pullUpMaybe) .map(queryPredicate -> PredicateMultiMap.PredicateCompensationFunction.ofPredicate(queryPredicate, - (pulledUpPredicate, baseAlias) -> - LinkedIdentitySet.of(pulledUpPredicate.translateCorrelations( - TranslationMap.ofAliases(pullUp.getTopAlias(), baseAlias), false)))) + (pulledUpPredicate, translationMap) -> + LinkedIdentitySet.of(pulledUpPredicate.translateCorrelations(translationMap, + false)))) .orElse(PredicateMultiMap.PredicateCompensationFunction.impossibleCompensation()); } } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/QueryPredicate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/QueryPredicate.java index 37f27cf5aa..cd70392d41 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/QueryPredicate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/QueryPredicate.java @@ -252,9 +252,9 @@ default PredicateCompensationFunction computeCompensationFunction(@Nonnull final .replaceValuesMaybe(pullUp::pullUpMaybe) .map(queryPredicate -> PredicateCompensationFunction.ofPredicate(queryPredicate, - (pulledUpPredicate, baseAlias) -> - LinkedIdentitySet.of(pulledUpPredicate.translateCorrelations( - TranslationMap.ofAliases(pullUp.getTopAlias(), baseAlias), false)))) + (pulledUpPredicate, translationMap) -> + LinkedIdentitySet.of(pulledUpPredicate.translateCorrelations(translationMap, + false)))) .orElse(PredicateCompensationFunction.impossibleCompensation()); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java index e3a5200278..5b8f54df4c 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java @@ -56,9 +56,8 @@ import com.apple.foundationdb.record.query.plan.cascades.properties.CardinalitiesProperty; import com.apple.foundationdb.record.query.plan.cascades.properties.CardinalitiesProperty.Cardinality; import com.apple.foundationdb.record.query.plan.cascades.values.Value; -import com.apple.foundationdb.record.query.plan.plans.RecordQueryIntersectionPlan; +import com.apple.foundationdb.record.query.plan.cascades.values.translation.TranslationMap; import com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan; -import com.apple.foundationdb.record.query.plan.plans.RecordQuerySetPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryUnorderedPrimaryKeyDistinctPlan; import com.apple.foundationdb.record.util.pair.NonnullPair; import com.google.common.base.Verify; @@ -782,11 +781,13 @@ private static Optional applyCompensationForSingleDataAcce if (compensation.isImpossible()) { return Optional.empty(); } - return Optional.of(compensation.applyAllNeededCompensations(memoizer, plan)); + return Optional.of(compensation.applyAllNeededCompensations(memoizer, plan, + realizedAlias -> + TranslationMap.ofAliases(singleMatchedAccess.getCandidateTopAlias(), realizedAlias))); } /** - * Private helper method to plan an intersection and subsequently compensate it using the partial match structures + * Protected helper method to plan an intersection and subsequently compensate it using the partial match structures * kept for all participating data accesses. * Planning the data access and its compensation for a given match is a two-step approach as we compute * the compensation for intersections by intersecting the {@link Compensation} for the single data accesses first @@ -802,88 +803,16 @@ private static Optional applyCompensationForSingleDataAcce * realized data access and its compensation. */ @Nonnull - private static IntersectionResult createIntersectionAndCompensation(@Nonnull final Memoizer memoizer, - @Nonnull final Map intersectionInfoMap, - @Nonnull final List commonPrimaryKeyValues, - @Nonnull final Map matchToPlanMap, - @Nonnull final List> partition, - @Nonnull final Set requestedOrderings) { - final var partitionOrderings = - partition.stream() - .map(Vectored::getElement) - .map(AbstractDataAccessRule::adjustMatchedOrderingParts) - .collect(ImmutableList.toImmutableList()); - final var intersectionOrdering = intersectOrderings(partitionOrderings); - - final var equalityBoundKeyValues = - partitionOrderings - .stream() - .flatMap(orderingPartsPair -> - orderingPartsPair.getKey() - .stream() - .filter(boundOrderingKey -> boundOrderingKey.getComparisonRangeType() == - ComparisonRange.Type.EQUALITY) - .map(MatchedOrderingPart::getValue)) - .collect(ImmutableSet.toImmutableSet()); - - final var isPartitionRedundant = - isPartitionRedundant(intersectionInfoMap, partition, equalityBoundKeyValues); - if (isPartitionRedundant) { - return IntersectionResult.noCommonOrdering(); - } - - final var compensation = - partition - .stream() - .map(pair -> pair.getElement().getCompensation()) - .reduce(Compensation.impossibleCompensation(), Compensation::intersect); - - boolean hasCommonOrdering = false; - final var expressionsBuilder = ImmutableList.builder(); - for (final var requestedOrdering : requestedOrderings) { - final var comparisonKeyValuesIterable = - intersectionOrdering.enumerateSatisfyingComparisonKeyValues(requestedOrdering); - for (final var comparisonKeyValues : comparisonKeyValuesIterable) { - if (!isCompatibleComparisonKey(comparisonKeyValues, - commonPrimaryKeyValues, - equalityBoundKeyValues)) { - continue; - } - - hasCommonOrdering = true; - if (!compensation.isImpossible()) { - var comparisonOrderingParts = - intersectionOrdering.directionalOrderingParts(comparisonKeyValues, requestedOrdering, - OrderingPart.ProvidedSortOrder.FIXED); - final var comparisonIsReverse = - RecordQuerySetPlan.resolveComparisonDirection(comparisonOrderingParts); - comparisonOrderingParts = RecordQuerySetPlan.adjustFixedBindings(comparisonOrderingParts, comparisonIsReverse); - - final var newQuantifiers = - partition - .stream() - .map(pair -> Objects.requireNonNull(matchToPlanMap.get(pair.getElement().getPartialMatch()))) - .map(memoizer::memoizePlans) - .map(Quantifier::physical) - .collect(ImmutableList.toImmutableList()); - - final var intersectionPlan = - RecordQueryIntersectionPlan.fromQuantifiers(newQuantifiers, - comparisonOrderingParts, comparisonIsReverse); - final var compensatedIntersection = - compensation.applyAllNeededCompensations(memoizer, intersectionPlan); - expressionsBuilder.add(compensatedIntersection); - } - } - } - - return IntersectionResult.of(hasCommonOrdering ? intersectionOrdering : null, compensation, - expressionsBuilder.build()); - } - - private static boolean isPartitionRedundant(@Nonnull final Map intersectionInfoMap, - @Nonnull final List> partition, - @Nonnull final ImmutableSet equalityBoundKeyValues) { + protected abstract IntersectionResult createIntersectionAndCompensation(@Nonnull final Memoizer memoizer, + @Nonnull final Map intersectionInfoMap, + @Nonnull final List commonPrimaryKeyValues, + @Nonnull final Map matchToPlanMap, + @Nonnull final List> partition, + @Nonnull final Set requestedOrderings); + + protected static boolean isPartitionRedundant(@Nonnull final Map intersectionInfoMap, + @Nonnull final List> partition, + @Nonnull final ImmutableSet equalityBoundKeyValues) { // if one of the single accesses has a max cardinality of 0 or 1 it is not useful to create this intersection for (final var singleMatchedAccessWithIndex : partition) { final var infoKey = intersectionInfoKey(singleMatchedAccessWithIndex); @@ -986,7 +915,7 @@ private static Ordering orderingFromSingleMatchedAccess(@Nonnull final SingleMat * computed from */ @Nonnull - private static NonnullPair, Boolean> adjustMatchedOrderingParts(@Nonnull final SingleMatchedAccess singleMatchedAccess) { + protected static NonnullPair, Boolean> adjustMatchedOrderingParts(@Nonnull final SingleMatchedAccess singleMatchedAccess) { final var partialMatch = singleMatchedAccess.getPartialMatch(); final var boundParametersPrefixMap = partialMatch.getBoundParameterPrefixMap(); @@ -1009,7 +938,7 @@ private static NonnullPair, Boolean> adjustMatchedOrde */ @SuppressWarnings("java:S1066") @Nonnull - private static Ordering.Intersection intersectOrderings(@Nonnull final List, Boolean>> partitionOrderingPairs) { + protected static Ordering.Intersection intersectOrderings(@Nonnull final List, Boolean>> partitionOrderingPairs) { final var orderings = partitionOrderingPairs .stream() @@ -1051,9 +980,9 @@ private static Ordering orderingFromOrderingParts(final @Nonnull List comparisonKeyValues, - @Nonnull List commonPrimaryKeyValues, - @Nonnull ImmutableSet equalityBoundKeyValues) { + protected static boolean isCompatibleComparisonKey(@Nonnull Collection comparisonKeyValues, + @Nonnull List commonPrimaryKeyValues, + @Nonnull ImmutableSet equalityBoundKeyValues) { if (comparisonKeyValues.isEmpty()) { // everything is in one row return true; @@ -1141,13 +1070,13 @@ private static BitSet intersectionInfoKey(@Nonnull Collection satisfyingRequestedOrderings; @@ -1189,7 +1118,7 @@ public Set getSatisfyingRequestedOrderings() { } } - private static class Vectored { + protected static class Vectored { @Nonnull private final T element; final int position; @@ -1235,7 +1164,7 @@ public static Vectored of(@Nonnull final T element, final int position) { } } - private static class IntersectionResult { + protected static class IntersectionResult { @Nullable private final Ordering.Intersection commonIntersectionOrdering; @Nonnull @@ -1291,13 +1220,13 @@ public String toString() { } } - private enum ScanDirection { + protected enum ScanDirection { FORWARD, REVERSE, BOTH } - private static class IntersectionInfo { + protected static class IntersectionInfo { @Nonnull private final Ordering intersectionOrdering; @Nonnull diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java index 1d07d0aa36..66f41769c6 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java @@ -24,16 +24,25 @@ import com.apple.foundationdb.record.query.plan.cascades.AliasMap; import com.apple.foundationdb.record.query.plan.cascades.CascadesPlanner; import com.apple.foundationdb.record.query.plan.cascades.CascadesRuleCall; +import com.apple.foundationdb.record.query.plan.cascades.ComparisonRange; +import com.apple.foundationdb.record.query.plan.cascades.Compensation; import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier; import com.apple.foundationdb.record.query.plan.cascades.LinkedIdentitySet; import com.apple.foundationdb.record.query.plan.cascades.MatchPartition; +import com.apple.foundationdb.record.query.plan.cascades.Memoizer; +import com.apple.foundationdb.record.query.plan.cascades.OrderingPart; import com.apple.foundationdb.record.query.plan.cascades.PartialMatch; import com.apple.foundationdb.record.query.plan.cascades.Quantifier; import com.apple.foundationdb.record.query.plan.cascades.Quantifiers; +import com.apple.foundationdb.record.query.plan.cascades.RequestedOrdering; import com.apple.foundationdb.record.query.plan.cascades.RequestedOrderingConstraint; import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression; import com.apple.foundationdb.record.query.plan.cascades.expressions.SelectExpression; import com.apple.foundationdb.record.query.plan.cascades.matching.structure.BindingMatcher; +import com.apple.foundationdb.record.query.plan.cascades.values.Value; +import com.apple.foundationdb.record.query.plan.plans.RecordQueryIntersectionPlan; +import com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan; +import com.apple.foundationdb.record.query.plan.plans.RecordQuerySetPlan; import com.apple.foundationdb.record.util.pair.NonnullPair; import com.apple.foundationdb.record.util.pair.Pair; import com.google.common.collect.ImmutableList; @@ -41,8 +50,11 @@ import com.google.common.collect.Iterables; import javax.annotation.Nonnull; +import java.util.BitSet; import java.util.HashMap; import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -174,4 +186,85 @@ public void onMatch(@Nonnull final CascadesRuleCall call) { } } } + + @Nonnull + @Override + protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Memoizer memoizer, + @Nonnull final Map intersectionInfoMap, + @Nonnull final List commonPrimaryKeyValues, + @Nonnull final Map matchToPlanMap, + @Nonnull final List> partition, + @Nonnull final Set requestedOrderings) { + final var partitionOrderings = + partition.stream() + .map(Vectored::getElement) + .map(AbstractDataAccessRule::adjustMatchedOrderingParts) + .collect(ImmutableList.toImmutableList()); + final var intersectionOrdering = intersectOrderings(partitionOrderings); + + final var equalityBoundKeyValues = + partitionOrderings + .stream() + .flatMap(orderingPartsPair -> + orderingPartsPair.getKey() + .stream() + .filter(boundOrderingKey -> boundOrderingKey.getComparisonRangeType() == + ComparisonRange.Type.EQUALITY) + .map(OrderingPart.MatchedOrderingPart::getValue)) + .collect(ImmutableSet.toImmutableSet()); + + final var isPartitionRedundant = + isPartitionRedundant(intersectionInfoMap, partition, equalityBoundKeyValues); + if (isPartitionRedundant) { + return IntersectionResult.noCommonOrdering(); + } + + final var compensation = + partition + .stream() + .map(pair -> pair.getElement().getCompensation()) + .reduce(Compensation.impossibleCompensation(), Compensation::intersect); + + boolean hasCommonOrdering = false; + final var expressionsBuilder = ImmutableList.builder(); + for (final var requestedOrdering : requestedOrderings) { + final var comparisonKeyValuesIterable = + intersectionOrdering.enumerateSatisfyingComparisonKeyValues(requestedOrdering); + for (final var comparisonKeyValues : comparisonKeyValuesIterable) { + if (!isCompatibleComparisonKey(comparisonKeyValues, + commonPrimaryKeyValues, + equalityBoundKeyValues)) { + continue; + } + + hasCommonOrdering = true; + if (!compensation.isImpossible()) { + var comparisonOrderingParts = + intersectionOrdering.directionalOrderingParts(comparisonKeyValues, requestedOrdering, + OrderingPart.ProvidedSortOrder.FIXED); + final var comparisonIsReverse = + RecordQuerySetPlan.resolveComparisonDirection(comparisonOrderingParts); + comparisonOrderingParts = RecordQuerySetPlan.adjustFixedBindings(comparisonOrderingParts, comparisonIsReverse); + + final var newQuantifiers = + partition + .stream() + .map(pair -> Objects.requireNonNull(matchToPlanMap.get(pair.getElement().getPartialMatch()))) + .map(memoizer::memoizePlans) + .map(Quantifier::physical) + .collect(ImmutableList.toImmutableList()); + + final var intersectionPlan = + RecordQueryIntersectionPlan.fromQuantifiers(newQuantifiers, + comparisonOrderingParts, comparisonIsReverse); + final var compensatedIntersection = + compensation.applyAllNeededCompensations(memoizer, intersectionPlan); + expressionsBuilder.add(compensatedIntersection); + } + } + } + + return IntersectionResult.of(hasCommonOrdering ? intersectionOrdering : null, compensation, + expressionsBuilder.build()); + } } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/DataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/DataAccessRule.java deleted file mode 100644 index ead2456cb9..0000000000 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/DataAccessRule.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * DataAccessRule.java - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2015-2019 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.apple.foundationdb.record.query.plan.cascades.rules; - -import com.apple.foundationdb.annotation.API; -import com.apple.foundationdb.record.query.plan.cascades.CascadesPlanner; -import com.apple.foundationdb.record.query.plan.cascades.CascadesRuleCall; -import com.apple.foundationdb.record.query.plan.cascades.MatchCandidate; -import com.apple.foundationdb.record.query.plan.cascades.MatchPartition; -import com.apple.foundationdb.record.query.plan.cascades.Memoizer; -import com.apple.foundationdb.record.query.plan.cascades.PartialMatch; -import com.apple.foundationdb.record.query.plan.cascades.PlanContext; -import com.apple.foundationdb.record.query.plan.cascades.PrimaryScanMatchCandidate; -import com.apple.foundationdb.record.query.plan.cascades.RequestedOrderingConstraint; -import com.apple.foundationdb.record.query.plan.cascades.ValueIndexScanMatchCandidate; -import com.apple.foundationdb.record.query.plan.cascades.expressions.LogicalIntersectionExpression; -import com.apple.foundationdb.record.query.plan.cascades.expressions.PrimaryScanExpression; -import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression; -import com.apple.foundationdb.record.query.plan.cascades.expressions.SelectExpression; -import com.apple.foundationdb.record.query.plan.cascades.matching.structure.BindingMatcher; -import com.google.common.collect.ImmutableList; - -import javax.annotation.Nonnull; - -import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.MatchPartitionMatchers.ofExpressionAndMatches; -import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.MultiMatcher.some; -import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.NotMatcher.not; -import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.PartialMatchMatchers.completeMatch; -import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.RelationalExpressionMatchers.anyExpression; -import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.RelationalExpressionMatchers.ofType; - -/** - * A rule that utilizes index matching information compiled by {@link CascadesPlanner} to create one or more - * expressions for data access. While this rule delegates specifics to the {@link MatchCandidate}s, the following are - * possible outcomes of the application of this transformation rule. Based on the match info, we may create for a single match: - * - *
    - *
  • a {@link PrimaryScanExpression} for a single {@link PrimaryScanMatchCandidate},
  • - *
  • an index scan/index scan + fetch for a single {@link ValueIndexScanMatchCandidate}
  • - *
  • an intersection ({@link LogicalIntersectionExpression}) of data accesses
  • - *
- * - * The logic that this rules delegates to actually create the expressions can be found in - * {@link MatchCandidate#toEquivalentPlan(PartialMatch, PlanContext, Memoizer, boolean)} - * - */ -@API(API.Status.EXPERIMENTAL) -@SuppressWarnings("PMD.TooManyStaticImports") -public class DataAccessRule extends AbstractDataAccessRule { - private static final BindingMatcher completeMatchMatcher = completeMatch(); - private static final BindingMatcher expressionMatcher = anyExpression().where(not(ofType(SelectExpression.class))); - - private static final BindingMatcher rootMatcher = - ofExpressionAndMatches(expressionMatcher, some(completeMatchMatcher)); - - public DataAccessRule() { - super(rootMatcher, completeMatchMatcher, expressionMatcher); - } - - @Override - public void onMatch(@Nonnull final CascadesRuleCall call) { - final var bindings = call.getBindings(); - final var completeMatches = bindings.getAll(getCompleteMatchMatcher()); - if (completeMatches.isEmpty()) { - return; - } - - final var expression = bindings.get(getExpressionMatcher()); - - if (expression.getQuantifiers().size() != 1) { - return; - } - - // - // return if there is no pre-determined interesting ordering - // - final var requestedOrderingsOptional = call.getPlannerConstraint(RequestedOrderingConstraint.REQUESTED_ORDERING); - if (requestedOrderingsOptional.isEmpty()) { - return; - } - - final var requestedOrderings = requestedOrderingsOptional.get(); - - final var matchPartition = - completeMatches - .stream() - .filter(match -> { - final var matchedQuantifiers = - expression.getMatchedQuantifiers(match); - return matchedQuantifiers.size() == 1; - }) - .collect(ImmutableList.toImmutableList()); - - call.yieldExpression(dataAccessForMatchPartition(call, - requestedOrderings, - matchPartition)); - } -} diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/WithPrimaryKeyDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/WithPrimaryKeyDataAccessRule.java index bce03736b9..ad9e678491 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/WithPrimaryKeyDataAccessRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/WithPrimaryKeyDataAccessRule.java @@ -24,16 +24,26 @@ import com.apple.foundationdb.record.query.plan.cascades.AliasMap; import com.apple.foundationdb.record.query.plan.cascades.CascadesPlanner; import com.apple.foundationdb.record.query.plan.cascades.CascadesRuleCall; +import com.apple.foundationdb.record.query.plan.cascades.ComparisonRange; +import com.apple.foundationdb.record.query.plan.cascades.Compensation; import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier; import com.apple.foundationdb.record.query.plan.cascades.LinkedIdentitySet; import com.apple.foundationdb.record.query.plan.cascades.MatchPartition; +import com.apple.foundationdb.record.query.plan.cascades.Memoizer; +import com.apple.foundationdb.record.query.plan.cascades.OrderingPart; import com.apple.foundationdb.record.query.plan.cascades.PartialMatch; import com.apple.foundationdb.record.query.plan.cascades.Quantifier; import com.apple.foundationdb.record.query.plan.cascades.Quantifiers; +import com.apple.foundationdb.record.query.plan.cascades.RequestedOrdering; import com.apple.foundationdb.record.query.plan.cascades.RequestedOrderingConstraint; import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression; import com.apple.foundationdb.record.query.plan.cascades.expressions.SelectExpression; import com.apple.foundationdb.record.query.plan.cascades.matching.structure.BindingMatcher; +import com.apple.foundationdb.record.query.plan.cascades.values.Value; +import com.apple.foundationdb.record.query.plan.cascades.values.translation.TranslationMap; +import com.apple.foundationdb.record.query.plan.plans.RecordQueryIntersectionPlan; +import com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan; +import com.apple.foundationdb.record.query.plan.plans.RecordQuerySetPlan; import com.apple.foundationdb.record.util.pair.NonnullPair; import com.apple.foundationdb.record.util.pair.Pair; import com.google.common.collect.ImmutableList; @@ -41,10 +51,14 @@ import com.google.common.collect.Iterables; import javax.annotation.Nonnull; +import java.util.BitSet; import java.util.HashMap; import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -174,4 +188,100 @@ public void onMatch(@Nonnull final CascadesRuleCall call) { } } } + + @Nonnull + @Override + protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Memoizer memoizer, + @Nonnull final Map intersectionInfoMap, + @Nonnull final List commonPrimaryKeyValues, + @Nonnull final Map matchToPlanMap, + @Nonnull final List> partition, + @Nonnull final Set requestedOrderings) { + final var partitionOrderings = + partition.stream() + .map(Vectored::getElement) + .map(AbstractDataAccessRule::adjustMatchedOrderingParts) + .collect(ImmutableList.toImmutableList()); + final var intersectionOrdering = intersectOrderings(partitionOrderings); + + final var equalityBoundKeyValues = + partitionOrderings + .stream() + .flatMap(orderingPartsPair -> + orderingPartsPair.getKey() + .stream() + .filter(boundOrderingKey -> boundOrderingKey.getComparisonRangeType() == + ComparisonRange.Type.EQUALITY) + .map(OrderingPart.MatchedOrderingPart::getValue)) + .collect(ImmutableSet.toImmutableSet()); + + final var isPartitionRedundant = + isPartitionRedundant(intersectionInfoMap, partition, equalityBoundKeyValues); + if (isPartitionRedundant) { + return IntersectionResult.noCommonOrdering(); + } + + final var compensation = + partition + .stream() + .map(pair -> pair.getElement().getCompensation()) + .reduce(Compensation.impossibleCompensation(), Compensation::intersect); + final Function matchedToRealizedTranslationMapFunction = + realizedAlias -> matchedToRealizedTranslationMap(partition, realizedAlias); + + boolean hasCommonOrdering = false; + final var expressionsBuilder = ImmutableList.builder(); + for (final var requestedOrdering : requestedOrderings) { + final var comparisonKeyValuesIterable = + intersectionOrdering.enumerateSatisfyingComparisonKeyValues(requestedOrdering); + for (final var comparisonKeyValues : comparisonKeyValuesIterable) { + if (!isCompatibleComparisonKey(comparisonKeyValues, + commonPrimaryKeyValues, + equalityBoundKeyValues)) { + continue; + } + + hasCommonOrdering = true; + if (!compensation.isImpossible()) { + var comparisonOrderingParts = + intersectionOrdering.directionalOrderingParts(comparisonKeyValues, requestedOrdering, + OrderingPart.ProvidedSortOrder.FIXED); + final var comparisonIsReverse = + RecordQuerySetPlan.resolveComparisonDirection(comparisonOrderingParts); + comparisonOrderingParts = RecordQuerySetPlan.adjustFixedBindings(comparisonOrderingParts, comparisonIsReverse); + + final var newQuantifiers = + partition + .stream() + .map(pair -> + Objects.requireNonNull(matchToPlanMap.get(pair.getElement().getPartialMatch()))) + .map(memoizer::memoizePlans) + .map(Quantifier::physical) + .collect(ImmutableList.toImmutableList()); + + final var intersectionPlan = + RecordQueryIntersectionPlan.fromQuantifiers(newQuantifiers, + comparisonOrderingParts, comparisonIsReverse); + final var compensatedIntersection = + compensation.applyAllNeededCompensations(memoizer, intersectionPlan, + matchedToRealizedTranslationMapFunction); + expressionsBuilder.add(compensatedIntersection); + } + } + } + + return IntersectionResult.of(hasCommonOrdering ? intersectionOrdering : null, compensation, + expressionsBuilder.build()); + } + + private static TranslationMap matchedToRealizedTranslationMap(@Nonnull final List> partition, + @Nonnull final CorrelationIdentifier realizedAlias) { + final var translationMapBuilder = TranslationMap.builder(); + for (final var singleMatchedAccessWithIndex : partition) { + translationMapBuilder.when(singleMatchedAccessWithIndex.getElement().getCandidateTopAlias()) + .then((sourceAlias, leafValue) -> leafValue.rebaseLeaf( + realizedAlias)); + } + return translationMapBuilder.build(); + } } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryMultiIntersectionOnValuesPlan.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryMultiIntersectionOnValuesPlan.java new file mode 100644 index 0000000000..803aedfce1 --- /dev/null +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryMultiIntersectionOnValuesPlan.java @@ -0,0 +1,235 @@ +/* + * RecordQueryIntersectionOnValuesPlan.java + * + * This source file is part of the FoundationDB open source project + * + * Copyright 2015-2022 Apple Inc. and the FoundationDB project authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.apple.foundationdb.record.query.plan.plans; + +import com.apple.foundationdb.record.EvaluationContext; +import com.apple.foundationdb.record.EvaluationContextBuilder; +import com.apple.foundationdb.record.ExecuteProperties; +import com.apple.foundationdb.record.PlanDeserializer; +import com.apple.foundationdb.record.PlanSerializationContext; +import com.apple.foundationdb.record.RecordCoreException; +import com.apple.foundationdb.record.RecordCursor; +import com.apple.foundationdb.record.metadata.expressions.KeyExpression; +import com.apple.foundationdb.record.planprotos.PRecordQueryIntersectionOnValuesPlan; +import com.apple.foundationdb.record.planprotos.PRecordQueryPlan; +import com.apple.foundationdb.record.provider.foundationdb.FDBRecordStoreBase; +import com.apple.foundationdb.record.provider.foundationdb.cursors.IntersectionCursor; +import com.apple.foundationdb.record.provider.foundationdb.cursors.IntersectionMultiCursor; +import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier; +import com.apple.foundationdb.record.query.plan.cascades.Memoizer; +import com.apple.foundationdb.record.query.plan.cascades.OrderingPart.ProvidedOrderingPart; +import com.apple.foundationdb.record.query.plan.cascades.Quantifier; +import com.apple.foundationdb.record.query.plan.cascades.Quantifiers; +import com.apple.foundationdb.record.query.plan.cascades.Reference; +import com.apple.foundationdb.record.query.plan.cascades.typing.Type; +import com.apple.foundationdb.record.query.plan.cascades.values.Value; +import com.apple.foundationdb.record.query.plan.cascades.values.translation.TranslationMap; +import com.google.auto.service.AutoService; +import com.google.common.base.Verify; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.protobuf.Message; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * Intersection plan that compares using a {@link Value}. + */ +@SuppressWarnings("java:S2160") +public class RecordQueryMultiIntersectionOnValuesPlan extends RecordQueryIntersectionPlan implements RecordQueryPlanWithComparisonKeyValues { + + /** + * A list of {@link ProvidedOrderingPart}s that is used to compute the comparison key function. This attribute is + * transient and therefore not plan-serialized + */ + @Nullable + private final List comparisonKeyOrderingParts; + @Nonnull + private final Value resultValue; + + protected RecordQueryMultiIntersectionOnValuesPlan(@Nonnull final PlanSerializationContext serializationContext, + @Nonnull final PRecordQueryIntersectionOnValuesPlan recordQueryIntersectionOnValuesPlanProto) { + super(serializationContext, Objects.requireNonNull(recordQueryIntersectionOnValuesPlanProto.getSuper())); + this.comparisonKeyOrderingParts = null; + } + + private RecordQueryMultiIntersectionOnValuesPlan(@Nonnull final List quantifiers, + @Nullable final List comparisonKeyOrderingParts, + @Nonnull final List comparisonKeyValues, + final boolean reverse) { + super(quantifiers, + new ComparisonKeyFunction.OnValues(Quantifier.current(), comparisonKeyValues), + reverse); + this.comparisonKeyOrderingParts = + comparisonKeyOrderingParts == null ? null : ImmutableList.copyOf(comparisonKeyOrderingParts); + } + + @Nonnull + @Override + public ComparisonKeyFunction.OnValues getComparisonKeyFunction() { + return (ComparisonKeyFunction.OnValues)super.getComparisonKeyFunction(); + } + + @Nonnull + @Override + public List getRequiredValues(@Nonnull final CorrelationIdentifier newBaseAlias, + @Nonnull final Type inputType) { + throw new RecordCoreException("this plan does not support getRequiredValues()"); + } + + @Nonnull + @Override + public Set getRequiredFields() { + throw new RecordCoreException("this plan does not support getRequiredFields()"); + } + + @Nonnull + @Override + public List getComparisonKeyOrderingParts() { + return Objects.requireNonNull(comparisonKeyOrderingParts); + } + + @Nonnull + @Override + public List getComparisonKeyValues() { + return getComparisonKeyFunction().getComparisonKeyValues(); + } + + @Nonnull + @Override + public Set getDynamicTypes() { + return getComparisonKeyValues().stream().flatMap(comparisonKeyValue -> comparisonKeyValue.getDynamicTypes().stream()).collect(ImmutableSet.toImmutableSet()); + } + + @Nonnull + @Override + @SuppressWarnings("resource") + public RecordCursor executePlan(@Nonnull final FDBRecordStoreBase store, + @Nonnull final EvaluationContext context, + @Nullable final byte[] continuation, + @Nonnull final ExecuteProperties executeProperties) { + final var quantifiers = getQuantifiers(); + final ExecuteProperties childExecuteProperties = executeProperties.clearSkipAndLimit(); + return IntersectionMultiCursor.create( + getComparisonKeyFunction().apply(store, context), + reverse, + quantifiers.stream() + .map(physical -> ((Quantifier.Physical)physical).getRangesOverPlan()) + .map(childPlan -> (Function>) + ((byte[] childContinuation) -> childPlan + .executePlan(store, context, childContinuation, childExecuteProperties))) + .collect(Collectors.toList()), + continuation, + store.getTimer()) + .map(multiResult -> { + Verify.verify(getQuantifiers().size() == multiResult.size()); + final var childEvaluationContextBuilder = context.childBuilder(); + for (int i = 0; i < quantifiers.size(); i++) { + childEvaluationContextBuilder.setBinding(quantifiers.get(i).getAlias(), multiResult.get(i)); + } + final var childEvaluationContext = + childEvaluationContextBuilder.build(context.getTypeRepository()); + + }) + .skipThenLimit(executeProperties.getSkip(), executeProperties.getReturnedRowLimit()); + } + + @Nonnull + @Override + public RecordQueryMultiIntersectionOnValuesPlan translateCorrelations(@Nonnull final TranslationMap translationMap, + final boolean shouldSimplifyValues, + @Nonnull final List translatedQuantifiers) { + return new RecordQueryMultiIntersectionOnValuesPlan(Quantifiers.narrow(Quantifier.Physical.class, translatedQuantifiers), + comparisonKeyOrderingParts, + getComparisonKeyValues(), + isReverse()); + } + + @Nonnull + @Override + public RecordQueryMultiIntersectionOnValuesPlan withChildrenReferences(@Nonnull final List newChildren) { + return new RecordQueryMultiIntersectionOnValuesPlan( + newChildren.stream() + .map(Quantifier::physical) + .collect(ImmutableList.toImmutableList()), + comparisonKeyOrderingParts, + getComparisonKeyValues(), + isReverse()); + } + + @Override + public RecordQueryMultiIntersectionOnValuesPlan strictlySorted(@Nonnull final Memoizer memoizer) { + return this; + } + + @Nonnull + @Override + public PRecordQueryIntersectionOnValuesPlan toProto(@Nonnull final PlanSerializationContext serializationContext) { + return PRecordQueryIntersectionOnValuesPlan.newBuilder().setSuper(toRecordQueryIntersectionPlan(serializationContext)).build(); + } + + @Nonnull + @Override + public PRecordQueryPlan toRecordQueryPlanProto(@Nonnull final PlanSerializationContext serializationContext) { + return PRecordQueryPlan.newBuilder().setIntersectionOnValuesPlan(toProto(serializationContext)).build(); + } + + @Nonnull + public static RecordQueryMultiIntersectionOnValuesPlan fromProto(@Nonnull final PlanSerializationContext serializationContext, + @Nonnull final PRecordQueryIntersectionOnValuesPlan recordQueryIntersectionOnValuesPlanProto) { + return new RecordQueryMultiIntersectionOnValuesPlan(serializationContext, recordQueryIntersectionOnValuesPlanProto); + } + + @Nonnull + public static RecordQueryMultiIntersectionOnValuesPlan intersection(@Nonnull final List quantifiers, + @Nonnull final List comparisonKeyOrderingParts, + final boolean isReverse) { + return new RecordQueryMultiIntersectionOnValuesPlan(quantifiers, + comparisonKeyOrderingParts, + ProvidedOrderingPart.comparisonKeyValues(comparisonKeyOrderingParts, isReverse), + isReverse); + } + + /** + * Deserializer. + */ + @AutoService(PlanDeserializer.class) + public static class Deserializer implements PlanDeserializer { + @Nonnull + @Override + public Class getProtoMessageClass() { + return PRecordQueryIntersectionOnValuesPlan.class; + } + + @Nonnull + @Override + public RecordQueryMultiIntersectionOnValuesPlan fromProto(@Nonnull final PlanSerializationContext serializationContext, + @Nonnull final PRecordQueryIntersectionOnValuesPlan recordQueryIntersectionOnValuesPlanProto) { + return RecordQueryMultiIntersectionOnValuesPlan.fromProto(serializationContext, recordQueryIntersectionOnValuesPlanProto); + } + } +} From 576d70acbbbc407af084a6deeb578305ac6c025d Mon Sep 17 00:00:00 2001 From: Normen Seemann Date: Sat, 15 Mar 2025 10:18:06 -0700 Subject: [PATCH 08/20] serialization for multi intersection implemented --- .../AggregateIndexExpansionVisitor.java | 4 +- .../AggregateIndexMatchCandidate.java | 18 ++++ .../plans/RecordQueryIntersectionPlan.java | 17 ++-- ...ordQueryMultiIntersectionOnValuesPlan.java | 89 +++++++++++++++---- .../src/main/proto/record_query_plan.proto | 9 ++ 5 files changed, 114 insertions(+), 23 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexExpansionVisitor.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexExpansionVisitor.java index e966237487..f19d481ce0 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexExpansionVisitor.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexExpansionVisitor.java @@ -286,7 +286,9 @@ private ConstructSelectHavingResult constructSelectHaving(@Nonnull final Quantif groupByExpression.getGroupingValue() == null ? null : FieldValue.ofOrdinalNumber(groupByQun.getFlowedObjectValue(), 0); - final var aggregateValueReference = FieldValue.ofOrdinalNumberAndFuseIfPossible(FieldValue.ofOrdinalNumber(groupByQun.getFlowedObjectValue(), groupingValueReference == null ? 0 : 1), 0); + final var aggregateValueReference = + FieldValue.ofOrdinalNumberAndFuseIfPossible(FieldValue.ofOrdinalNumber(groupByQun.getFlowedObjectValue(), + groupingValueReference == null ? 0 : 1), 0); final var placeholderAliases = ImmutableList.builder(); final var selectHavingGraphExpansionBuilder = GraphExpansion.builder().addQuantifier(groupByQun); diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java index d457f10bad..ac895f3c07 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java @@ -49,6 +49,7 @@ import com.apple.foundationdb.record.query.plan.plans.RecordQueryFetchFromPartialRecordPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan; +import com.apple.foundationdb.record.util.pair.NonnullPair; import com.google.common.base.Preconditions; import com.google.common.base.Verify; import com.google.common.collect.ImmutableList; @@ -409,6 +410,23 @@ protected int getGroupingCount() { : keyExpressionGroupingCount; } + @Nonnull + public NonnullPair, Value> getGroupingAndAggregateAccessors() { + final var selectHavingResultValue = selectHavingExpression.getResultValue(); + final var selectHavingResultType = (Type.Record)selectHavingResultValue.getResultType(); + final var unbasedResultValue = + QuantifiedObjectValue.of(Quantifier.current(), selectHavingResultType); + + final var groupingCount = getGroupingCount(); + Verify.verify(selectHavingResultType.getFields().size() >= groupingCount); + + final var deconstructedRecord = Values.deconstructRecord(unbasedResultValue); + final var groupingAccessorValues = + ImmutableList.copyOf(deconstructedRecord.subList(0, groupingCount)); + final var aggregateAccessorValue = deconstructedRecord.get(groupingCount); + return NonnullPair.of(groupingAccessorValues, aggregateAccessorValue); + } + /** * Creates a new {@link IndexKeyValueToPartialRecord} to facilitate the correct copying of information from the * index-tuple structure to a partial record (which in this case is dynamically-typed). diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryIntersectionPlan.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryIntersectionPlan.java index deede8b769..990b016820 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryIntersectionPlan.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryIntersectionPlan.java @@ -36,7 +36,6 @@ import com.apple.foundationdb.record.provider.foundationdb.FDBStoreTimer; import com.apple.foundationdb.record.provider.foundationdb.cursors.IntersectionCursor; import com.apple.foundationdb.record.query.plan.AvailableFields; -import com.apple.foundationdb.record.query.plan.explain.ExplainPlanVisitor; import com.apple.foundationdb.record.query.plan.cascades.AliasMap; import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier; import com.apple.foundationdb.record.query.plan.cascades.OrderingPart.ProvidedOrderingPart; @@ -48,6 +47,8 @@ import com.apple.foundationdb.record.query.plan.cascades.explain.PlannerGraph; import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression; import com.apple.foundationdb.record.query.plan.cascades.values.Value; +import com.apple.foundationdb.record.query.plan.explain.ExplainPlanVisitor; +import com.google.common.base.Suppliers; import com.google.common.base.Verify; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -62,6 +63,7 @@ import java.util.Objects; import java.util.Set; import java.util.function.Function; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -88,7 +90,7 @@ public abstract class RecordQueryIntersectionPlan implements RecordQueryPlanWith protected final boolean reverse; @Nonnull - private final Value resultValue; + private final Supplier resultValueSupplier; protected RecordQueryIntersectionPlan(@Nonnull final PlanSerializationContext serializationContext, @Nonnull final PRecordQueryIntersectionPlan recordQueryIntersectionPlanProto) { @@ -100,7 +102,7 @@ protected RecordQueryIntersectionPlan(@Nonnull final PlanSerializationContext se this.quantifiers = quantifiersBuilder.build(); this.comparisonKeyFunction = ComparisonKeyFunction.fromComparisonKeyFunctionProto(serializationContext, Objects.requireNonNull(recordQueryIntersectionPlanProto.getComparisonKeyFunction())); this.reverse = recordQueryIntersectionPlanProto.getReverse(); - this.resultValue = RecordQuerySetPlan.mergeValues(quantifiers); + this.resultValueSupplier = Suppliers.memoize(this::computeResultValue); } @SuppressWarnings("PMD.UnusedFormalParameter") @@ -110,7 +112,7 @@ protected RecordQueryIntersectionPlan(@Nonnull List quantif this.quantifiers = ImmutableList.copyOf(quantifiers); this.comparisonKeyFunction = comparisonKeyFunction; this.reverse = reverse; - this.resultValue = RecordQuerySetPlan.mergeValues(quantifiers); + this.resultValueSupplier = Suppliers.memoize(this::computeResultValue); } @Nonnull @@ -177,7 +179,12 @@ public Set getCorrelatedToWithoutChildren() { @Nonnull @Override public Value getResultValue() { - return resultValue; + return resultValueSupplier.get(); + } + + @Nonnull + protected Value computeResultValue() { + return RecordQuerySetPlan.mergeValues(quantifiers); } @Override diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryMultiIntersectionOnValuesPlan.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryMultiIntersectionOnValuesPlan.java index 803aedfce1..b76c20c7e6 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryMultiIntersectionOnValuesPlan.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryMultiIntersectionOnValuesPlan.java @@ -21,18 +21,17 @@ package com.apple.foundationdb.record.query.plan.plans; import com.apple.foundationdb.record.EvaluationContext; -import com.apple.foundationdb.record.EvaluationContextBuilder; import com.apple.foundationdb.record.ExecuteProperties; import com.apple.foundationdb.record.PlanDeserializer; import com.apple.foundationdb.record.PlanSerializationContext; import com.apple.foundationdb.record.RecordCoreException; import com.apple.foundationdb.record.RecordCursor; import com.apple.foundationdb.record.metadata.expressions.KeyExpression; -import com.apple.foundationdb.record.planprotos.PRecordQueryIntersectionOnValuesPlan; +import com.apple.foundationdb.record.planprotos.PRecordQueryMultiIntersectionOnValuesPlan; import com.apple.foundationdb.record.planprotos.PRecordQueryPlan; import com.apple.foundationdb.record.provider.foundationdb.FDBRecordStoreBase; -import com.apple.foundationdb.record.provider.foundationdb.cursors.IntersectionCursor; import com.apple.foundationdb.record.provider.foundationdb.cursors.IntersectionMultiCursor; +import com.apple.foundationdb.record.query.plan.cascades.Column; import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier; import com.apple.foundationdb.record.query.plan.cascades.Memoizer; import com.apple.foundationdb.record.query.plan.cascades.OrderingPart.ProvidedOrderingPart; @@ -40,6 +39,7 @@ import com.apple.foundationdb.record.query.plan.cascades.Quantifiers; import com.apple.foundationdb.record.query.plan.cascades.Reference; import com.apple.foundationdb.record.query.plan.cascades.typing.Type; +import com.apple.foundationdb.record.query.plan.cascades.values.RecordConstructorValue; import com.apple.foundationdb.record.query.plan.cascades.values.Value; import com.apple.foundationdb.record.query.plan.cascades.values.translation.TranslationMap; import com.google.auto.service.AutoService; @@ -72,20 +72,34 @@ public class RecordQueryMultiIntersectionOnValuesPlan extends RecordQueryInterse private final Value resultValue; protected RecordQueryMultiIntersectionOnValuesPlan(@Nonnull final PlanSerializationContext serializationContext, - @Nonnull final PRecordQueryIntersectionOnValuesPlan recordQueryIntersectionOnValuesPlanProto) { - super(serializationContext, Objects.requireNonNull(recordQueryIntersectionOnValuesPlanProto.getSuper())); + @Nonnull final PRecordQueryMultiIntersectionOnValuesPlan recordQueryMultiIntersectionOnValuesPlanProto) { + super(serializationContext, Objects.requireNonNull(recordQueryMultiIntersectionOnValuesPlanProto.getSuper())); this.comparisonKeyOrderingParts = null; + this.resultValue = Value.fromValueProto(serializationContext, + recordQueryMultiIntersectionOnValuesPlanProto.getResultValue()); } private RecordQueryMultiIntersectionOnValuesPlan(@Nonnull final List quantifiers, @Nullable final List comparisonKeyOrderingParts, @Nonnull final List comparisonKeyValues, + @Nonnull final List commonValues, + @Nonnull final List pickupValues, + final boolean reverse) { + this(quantifiers, comparisonKeyOrderingParts, comparisonKeyValues, + computeResultValue(quantifiers, commonValues, pickupValues), reverse); + } + + private RecordQueryMultiIntersectionOnValuesPlan(@Nonnull final List quantifiers, + @Nullable final List comparisonKeyOrderingParts, + @Nonnull final List comparisonKeyValues, + @Nonnull final Value resultValue, final boolean reverse) { super(quantifiers, new ComparisonKeyFunction.OnValues(Quantifier.current(), comparisonKeyValues), reverse); this.comparisonKeyOrderingParts = comparisonKeyOrderingParts == null ? null : ImmutableList.copyOf(comparisonKeyOrderingParts); + this.resultValue = resultValue; } @Nonnull @@ -122,7 +136,38 @@ public List getComparisonKeyValues() { @Nonnull @Override public Set getDynamicTypes() { - return getComparisonKeyValues().stream().flatMap(comparisonKeyValue -> comparisonKeyValue.getDynamicTypes().stream()).collect(ImmutableSet.toImmutableSet()); + return getComparisonKeyValues().stream() + .flatMap(comparisonKeyValue -> + comparisonKeyValue.getDynamicTypes().stream()).collect(ImmutableSet.toImmutableSet()); + } + + @Nonnull + @Override + protected Value computeResultValue() { + return resultValue; + } + + @Nonnull + private static Value computeResultValue(@Nonnull final List quantifiers, + @Nonnull final List commonValues, + @Nonnull final List pickupValues) { + final var columnBuilder = ImmutableList.>builder(); + + // grab the common values from the first quantifier + final var commonTranslationMap = + TranslationMap.ofAliases(Quantifier.current(), quantifiers.get(0).getAlias()); + for (final var commonValue : commonValues) { + columnBuilder.add(Column.unnamedOf(commonValue.translateCorrelations(commonTranslationMap))); + } + + for (int i = 0; i < quantifiers.size(); i++) { + final var quantifier = quantifiers.get(i); + final var pickUpTranslationMap = + TranslationMap.ofAliases(Quantifier.current(), quantifier.getAlias()); + columnBuilder.add(Column.unnamedOf(pickupValues.get(i).translateCorrelations(pickUpTranslationMap))); + } + + return RecordConstructorValue.ofColumns(columnBuilder.build()); } @Nonnull @@ -153,7 +198,7 @@ public RecordCursor executePlan(@Nonnull final } final var childEvaluationContext = childEvaluationContextBuilder.build(context.getTypeRepository()); - + return QueryResult.ofComputed(getResultValue().eval(store, childEvaluationContext)); }) .skipThenLimit(executeProperties.getSkip(), executeProperties.getReturnedRowLimit()); } @@ -166,6 +211,7 @@ public RecordQueryMultiIntersectionOnValuesPlan translateCorrelations(@Nonnull f return new RecordQueryMultiIntersectionOnValuesPlan(Quantifiers.narrow(Quantifier.Physical.class, translatedQuantifiers), comparisonKeyOrderingParts, getComparisonKeyValues(), + resultValue, isReverse()); } @@ -178,6 +224,7 @@ public RecordQueryMultiIntersectionOnValuesPlan withChildrenReferences(@Nonnull .collect(ImmutableList.toImmutableList()), comparisonKeyOrderingParts, getComparisonKeyValues(), + resultValue, isReverse()); } @@ -188,29 +235,37 @@ public RecordQueryMultiIntersectionOnValuesPlan strictlySorted(@Nonnull final Me @Nonnull @Override - public PRecordQueryIntersectionOnValuesPlan toProto(@Nonnull final PlanSerializationContext serializationContext) { - return PRecordQueryIntersectionOnValuesPlan.newBuilder().setSuper(toRecordQueryIntersectionPlan(serializationContext)).build(); + public PRecordQueryMultiIntersectionOnValuesPlan toProto(@Nonnull final PlanSerializationContext serializationContext) { + return PRecordQueryMultiIntersectionOnValuesPlan.newBuilder() + .setSuper(toRecordQueryIntersectionPlan(serializationContext)) + .setResultValue(resultValue.toValueProto(serializationContext)) + .build(); } @Nonnull @Override public PRecordQueryPlan toRecordQueryPlanProto(@Nonnull final PlanSerializationContext serializationContext) { - return PRecordQueryPlan.newBuilder().setIntersectionOnValuesPlan(toProto(serializationContext)).build(); + return PRecordQueryPlan.newBuilder() + .setMultiIntersectionOnValuesPlan(toProto(serializationContext)).build(); } @Nonnull public static RecordQueryMultiIntersectionOnValuesPlan fromProto(@Nonnull final PlanSerializationContext serializationContext, - @Nonnull final PRecordQueryIntersectionOnValuesPlan recordQueryIntersectionOnValuesPlanProto) { - return new RecordQueryMultiIntersectionOnValuesPlan(serializationContext, recordQueryIntersectionOnValuesPlanProto); + @Nonnull final PRecordQueryMultiIntersectionOnValuesPlan recordQueryMultiIntersectionOnValuesPlanProto) { + return new RecordQueryMultiIntersectionOnValuesPlan(serializationContext, recordQueryMultiIntersectionOnValuesPlanProto); } @Nonnull public static RecordQueryMultiIntersectionOnValuesPlan intersection(@Nonnull final List quantifiers, @Nonnull final List comparisonKeyOrderingParts, + @Nonnull final List commonValues, + @Nonnull final List pickupValues, final boolean isReverse) { return new RecordQueryMultiIntersectionOnValuesPlan(quantifiers, comparisonKeyOrderingParts, ProvidedOrderingPart.comparisonKeyValues(comparisonKeyOrderingParts, isReverse), + commonValues, + pickupValues, isReverse); } @@ -218,18 +273,18 @@ public static RecordQueryMultiIntersectionOnValuesPlan intersection(@Nonnull fin * Deserializer. */ @AutoService(PlanDeserializer.class) - public static class Deserializer implements PlanDeserializer { + public static class Deserializer implements PlanDeserializer { @Nonnull @Override - public Class getProtoMessageClass() { - return PRecordQueryIntersectionOnValuesPlan.class; + public Class getProtoMessageClass() { + return PRecordQueryMultiIntersectionOnValuesPlan.class; } @Nonnull @Override public RecordQueryMultiIntersectionOnValuesPlan fromProto(@Nonnull final PlanSerializationContext serializationContext, - @Nonnull final PRecordQueryIntersectionOnValuesPlan recordQueryIntersectionOnValuesPlanProto) { - return RecordQueryMultiIntersectionOnValuesPlan.fromProto(serializationContext, recordQueryIntersectionOnValuesPlanProto); + @Nonnull final PRecordQueryMultiIntersectionOnValuesPlan recordQueryMultiIntersectionOnValuesPlanProto) { + return RecordQueryMultiIntersectionOnValuesPlan.fromProto(serializationContext, recordQueryMultiIntersectionOnValuesPlanProto); } } } diff --git a/fdb-record-layer-core/src/main/proto/record_query_plan.proto b/fdb-record-layer-core/src/main/proto/record_query_plan.proto index 33bcf47d8c..db2c34a7e5 100644 --- a/fdb-record-layer-core/src/main/proto/record_query_plan.proto +++ b/fdb-record-layer-core/src/main/proto/record_query_plan.proto @@ -1274,6 +1274,7 @@ message PRecordQueryPlan { PTempTableInsertPlan temp_table_insert_plan = 35; PRecursiveUnionQueryPlan recursive_union_query_plan = 36; PRecordQueryTableFunctionPlan table_function_plan = 37; + PRecordQueryMultiIntersectionOnValuesPlan multi_intersection_on_values_plan = 38; } } @@ -1637,6 +1638,14 @@ message PRecordQueryIntersectionOnValuesPlan { optional PRecordQueryIntersectionPlan super = 1; } +// +// PRecordQueryMultiIntersectionOnValuesPlan +// +message PRecordQueryMultiIntersectionOnValuesPlan { + optional PRecordQueryIntersectionPlan super = 1; + optional PValue result_value = 2; +} + // // PRecordQueryInUnionPlan // From 14b1aa7671eb6cec030b998c2b76e015c5bbabac Mon Sep 17 00:00:00 2001 From: Normen Seemann Date: Tue, 18 Mar 2025 01:50:48 +0100 Subject: [PATCH 09/20] first plans --- .../properties/CardinalitiesProperty.java | 12 +- .../properties/DerivationsProperty.java | 7 ++ .../properties/DistinctRecordsProperty.java | 7 ++ .../cascades/properties/OrderingProperty.java | 7 ++ .../properties/PrimaryKeyProperty.java | 7 ++ .../properties/StoredRecordProperty.java | 7 ++ .../rules/AggregateDataAccessRule.java | 119 ++++++++++++++++-- .../plan/explain/ExplainPlanVisitor.java | 7 ++ ...ordQueryMultiIntersectionOnValuesPlan.java | 57 +++------ 9 files changed, 177 insertions(+), 53 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/CardinalitiesProperty.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/CardinalitiesProperty.java index 8c835f70d3..a8de4803bb 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/CardinalitiesProperty.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/CardinalitiesProperty.java @@ -75,6 +75,7 @@ import com.apple.foundationdb.record.query.plan.plans.RecordQueryInValuesJoinPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryInsertPlan; +import com.apple.foundationdb.record.query.plan.plans.RecordQueryMultiIntersectionOnValuesPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryRecursiveUnionPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryTableFunctionPlan; import com.apple.foundationdb.record.query.plan.plans.TempTableScanPlan; @@ -265,7 +266,7 @@ public Cardinalities visitTempTableInsertPlan(@Nonnull final TempTableInsertPlan @Nonnull @Override public Cardinalities visitRecordQueryIntersectionOnValuesPlan(@Nonnull final RecordQueryIntersectionOnValuesPlan intersectionOnValuesPlan) { - return weakenCardinalities(fromChildren(intersectionOnValuesPlan)); + return intersectCardinalities(fromChildren(intersectionOnValuesPlan)); } @Nonnull @@ -406,6 +407,12 @@ public Cardinalities visitRecordQueryInUnionPlan(@Nonnull final RecordQueryInUni return inSourcesCardinalities.times(childCardinalities); } + @Nonnull + @Override + public Cardinalities visitRecordQueryMultiIntersectionOnValuesPlan(@Nonnull final RecordQueryMultiIntersectionOnValuesPlan recordQueryMultiIntersectionOnValuesPlan) { + return intersectCardinalities(fromChildren(recordQueryMultiIntersectionOnValuesPlan)); + } + @Nonnull @Override public Cardinalities visitRecordQueryInParameterJoinPlan(@Nonnull final RecordQueryInParameterJoinPlan element) { @@ -698,7 +705,8 @@ private Cardinalities intersectCardinalities(@Nonnull Iterable ca maxCardinality = cardinalities.getMaxCardinality(); } else { if (!cardinalities.getMaxCardinality().isUnknown()) { - maxCardinality = Cardinality.ofCardinality(Math.min(maxCardinality.getCardinality(), cardinalities.getMaxCardinality().getCardinality())); + maxCardinality = Cardinality.ofCardinality(Math.min(maxCardinality.getCardinality(), + cardinalities.getMaxCardinality().getCardinality())); } else { maxCardinality = Cardinality.unknownCardinality(); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/DerivationsProperty.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/DerivationsProperty.java index 92b7493ea2..c14d3dcac7 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/DerivationsProperty.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/DerivationsProperty.java @@ -60,6 +60,7 @@ import com.apple.foundationdb.record.query.plan.plans.RecordQueryInValuesJoinPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryInsertPlan; +import com.apple.foundationdb.record.query.plan.plans.RecordQueryMultiIntersectionOnValuesPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryRecursiveUnionPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryTableFunctionPlan; import com.apple.foundationdb.record.query.plan.plans.TempTableInsertPlan; @@ -536,6 +537,12 @@ public Derivations visitInUnionOnKeyExpressionPlan(@Nonnull final RecordQueryInU throw new RecordCoreException("unsupported plan operator"); } + @Nonnull + @Override + public Derivations visitMultiIntersectionOnValuesPlan(@Nonnull final RecordQueryMultiIntersectionOnValuesPlan element) { + return null; //TODO + } + @Nonnull @Override public Derivations visitInParameterJoinPlan(@Nonnull final RecordQueryInParameterJoinPlan inParameterJoinPlan) { diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/DistinctRecordsProperty.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/DistinctRecordsProperty.java index 3a62e651cb..288ab6ca77 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/DistinctRecordsProperty.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/DistinctRecordsProperty.java @@ -46,6 +46,7 @@ import com.apple.foundationdb.record.query.plan.plans.RecordQueryInValuesJoinPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryInsertPlan; +import com.apple.foundationdb.record.query.plan.plans.RecordQueryMultiIntersectionOnValuesPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryRecursiveUnionPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryTableFunctionPlan; import com.apple.foundationdb.record.query.plan.plans.TempTableInsertPlan; @@ -317,6 +318,12 @@ public Boolean visitInUnionOnKeyExpressionPlan(@Nonnull final RecordQueryInUnion return true; } + @Nonnull + @Override + public Boolean visitMultiIntersectionOnValuesPlan(@Nonnull final RecordQueryMultiIntersectionOnValuesPlan element) { + return true; + } + @Nonnull @Override public Boolean visitInParameterJoinPlan(@Nonnull final RecordQueryInParameterJoinPlan inParameterJoinPlan) { diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/OrderingProperty.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/OrderingProperty.java index 3e82785a1e..1bb5d784b2 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/OrderingProperty.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/OrderingProperty.java @@ -58,6 +58,7 @@ import com.apple.foundationdb.record.query.plan.plans.RecordQueryInValuesJoinPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryInsertPlan; +import com.apple.foundationdb.record.query.plan.plans.RecordQueryMultiIntersectionOnValuesPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryRecursiveUnionPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryTableFunctionPlan; import com.apple.foundationdb.record.query.plan.plans.TempTableScanPlan; @@ -492,6 +493,12 @@ public Ordering visitInUnionOnKeyExpressionPlan(@Nonnull final RecordQueryInUnio return Ordering.empty(); } + @Nonnull + @Override + public Ordering visitMultiIntersectionOnValuesPlan(@Nonnull final RecordQueryMultiIntersectionOnValuesPlan element) { + return Ordering.empty(); // TODO + } + @Nonnull @Override public Ordering visitInParameterJoinPlan(@Nonnull final RecordQueryInParameterJoinPlan inParameterJoinPlan) { diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/PrimaryKeyProperty.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/PrimaryKeyProperty.java index cd714cfb76..27358ed5c0 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/PrimaryKeyProperty.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/PrimaryKeyProperty.java @@ -47,6 +47,7 @@ import com.apple.foundationdb.record.query.plan.plans.RecordQueryInValuesJoinPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryInsertPlan; +import com.apple.foundationdb.record.query.plan.plans.RecordQueryMultiIntersectionOnValuesPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryRecursiveUnionPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryTableFunctionPlan; import com.apple.foundationdb.record.query.plan.plans.TempTableScanPlan; @@ -313,6 +314,12 @@ public Optional> visitInUnionOnKeyExpressionPlan(@Nonnull final Reco return primaryKeyFromSingleChild(inUnionOnKeyExpressionPlan); } + @Nonnull + @Override + public Optional> visitMultiIntersectionOnValuesPlan(@Nonnull final RecordQueryMultiIntersectionOnValuesPlan element) { + return Optional.empty(); + } + @Nonnull @Override public Optional> visitInParameterJoinPlan(@Nonnull final RecordQueryInParameterJoinPlan inParameterJoinPlan) { diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/StoredRecordProperty.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/StoredRecordProperty.java index 8a82cd5b34..04640f60cc 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/StoredRecordProperty.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/StoredRecordProperty.java @@ -44,6 +44,7 @@ import com.apple.foundationdb.record.query.plan.plans.RecordQueryInValuesJoinPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryInsertPlan; +import com.apple.foundationdb.record.query.plan.plans.RecordQueryMultiIntersectionOnValuesPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryRecursiveUnionPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryTableFunctionPlan; import com.apple.foundationdb.record.query.plan.plans.TempTableInsertPlan; @@ -299,6 +300,12 @@ public Boolean visitInUnionOnKeyExpressionPlan(@Nonnull final RecordQueryInUnion return true; } + @Nonnull + @Override + public Boolean visitMultiIntersectionOnValuesPlan(@Nonnull final RecordQueryMultiIntersectionOnValuesPlan element) { + return false; + } + @Nonnull @Override public Boolean visitInParameterJoinPlan(@Nonnull final RecordQueryInParameterJoinPlan inParameterJoinPlan) { diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java index 66f41769c6..50d32ab54f 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java @@ -21,9 +21,11 @@ package com.apple.foundationdb.record.query.plan.cascades.rules; import com.apple.foundationdb.annotation.API; +import com.apple.foundationdb.record.query.plan.cascades.AggregateIndexMatchCandidate; import com.apple.foundationdb.record.query.plan.cascades.AliasMap; import com.apple.foundationdb.record.query.plan.cascades.CascadesPlanner; import com.apple.foundationdb.record.query.plan.cascades.CascadesRuleCall; +import com.apple.foundationdb.record.query.plan.cascades.Column; import com.apple.foundationdb.record.query.plan.cascades.ComparisonRange; import com.apple.foundationdb.record.query.plan.cascades.Compensation; import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier; @@ -39,12 +41,18 @@ import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression; import com.apple.foundationdb.record.query.plan.cascades.expressions.SelectExpression; import com.apple.foundationdb.record.query.plan.cascades.matching.structure.BindingMatcher; +import com.apple.foundationdb.record.query.plan.cascades.typing.Type; +import com.apple.foundationdb.record.query.plan.cascades.values.QuantifiedObjectValue; +import com.apple.foundationdb.record.query.plan.cascades.values.RecordConstructorValue; import com.apple.foundationdb.record.query.plan.cascades.values.Value; -import com.apple.foundationdb.record.query.plan.plans.RecordQueryIntersectionPlan; +import com.apple.foundationdb.record.query.plan.cascades.values.Values; +import com.apple.foundationdb.record.query.plan.cascades.values.translation.TranslationMap; +import com.apple.foundationdb.record.query.plan.plans.RecordQueryMultiIntersectionOnValuesPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQuerySetPlan; import com.apple.foundationdb.record.util.pair.NonnullPair; import com.apple.foundationdb.record.util.pair.Pair; +import com.google.common.base.Verify; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; @@ -62,8 +70,8 @@ import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.MatchPartitionMatchers.ofExpressionAndMatches; import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.MultiMatcher.some; -import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.PartialMatchMatchers.matchingAggregateIndexMatchCandidate; import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.PartialMatchMatchers.completeMatch; +import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.PartialMatchMatchers.matchingAggregateIndexMatchCandidate; import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.RelationalExpressionMatchers.anyExpression; /** @@ -246,19 +254,31 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me RecordQuerySetPlan.resolveComparisonDirection(comparisonOrderingParts); comparisonOrderingParts = RecordQuerySetPlan.adjustFixedBindings(comparisonOrderingParts, comparisonIsReverse); - final var newQuantifiers = - partition - .stream() - .map(pair -> Objects.requireNonNull(matchToPlanMap.get(pair.getElement().getPartialMatch()))) - .map(memoizer::memoizePlans) - .map(Quantifier::physical) - .collect(ImmutableList.toImmutableList()); + final var newQuantifiersBuilder = ImmutableList.builder(); + final var candidateTopAliasesBuilder = ImmutableList.builder(); + for (final var singleMatchedAccessWithIndex : partition) { + final var singleMatchedAccess = singleMatchedAccessWithIndex.getElement(); + final var plan = Objects.requireNonNull(matchToPlanMap.get( + singleMatchedAccess.getPartialMatch())); + final var reference = memoizer.memoizePlans(plan); + newQuantifiersBuilder.add(Quantifier.physical(reference)); + candidateTopAliasesBuilder.add(singleMatchedAccess.getCandidateTopAlias()); + } + final var newQuantifiers = newQuantifiersBuilder.build(); + final var commonAndPickUpValues = + computeCommonAndPickUpValues(partition, commonPrimaryKeyValues.size()); + final var intersectionResultValue = + computeIntersectionResultValue(newQuantifiers, commonAndPickUpValues.getLeft(), commonAndPickUpValues.getRight()); final var intersectionPlan = - RecordQueryIntersectionPlan.fromQuantifiers(newQuantifiers, - comparisonOrderingParts, comparisonIsReverse); + RecordQueryMultiIntersectionOnValuesPlan.intersection(newQuantifiers, + comparisonOrderingParts, intersectionResultValue, comparisonIsReverse); final var compensatedIntersection = - compensation.applyAllNeededCompensations(memoizer, intersectionPlan); + compensation.applyAllNeededCompensations(memoizer, intersectionPlan, + baseAlias -> computeTranslationMap(baseAlias, + newQuantifiers, candidateTopAliasesBuilder.build(), + (Type.Record)intersectionResultValue.getResultType(), + commonPrimaryKeyValues.size())); expressionsBuilder.add(compensatedIntersection); } } @@ -267,4 +287,79 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me return IntersectionResult.of(hasCommonOrdering ? intersectionOrdering : null, compensation, expressionsBuilder.build()); } + + @Nonnull + private static NonnullPair, List> computeCommonAndPickUpValues(@Nonnull final List> partition, + final int numGrouped) { + final var commonValuesAndPickUpValueByAccess = + partition + .stream() + .map(singleMatchedAccessWithIndex -> + singleMatchedAccessWithIndex.getElement() + .getPartialMatch() + .getMatchCandidate()) + .map(matchCandidate -> (AggregateIndexMatchCandidate)matchCandidate) + .map(AggregateIndexMatchCandidate::getGroupingAndAggregateAccessors) + .collect(ImmutableList.toImmutableList()); + + final var pickUpValuesBuilder = ImmutableList.builder(); + for (int i = 0; i < commonValuesAndPickUpValueByAccess.size(); i++) { + final var commonAndPickUpValuePair = commonValuesAndPickUpValueByAccess.get(i); + final var commonValues = commonAndPickUpValuePair.getLeft(); + Verify.verify(commonValues.size() == numGrouped); + final var pickUpValue = commonAndPickUpValuePair.getRight(); + pickUpValuesBuilder.add(pickUpValue); + } + return NonnullPair.of(commonValuesAndPickUpValueByAccess.get(0).getLeft(), pickUpValuesBuilder.build()); + } + + @Nonnull + private static Value computeIntersectionResultValue(@Nonnull final List quantifiers, + @Nonnull final List commonValues, + @Nonnull final List pickUpValues) { + final var columnBuilder = ImmutableList.>builder(); + + // grab the common values from the first quantifier + final var commonTranslationMap = + TranslationMap.ofAliases(Quantifier.current(), quantifiers.get(0).getAlias()); + for (final var commonValue : commonValues) { + columnBuilder.add(Column.unnamedOf(commonValue.translateCorrelations(commonTranslationMap))); + } + + for (int i = 0; i < quantifiers.size(); i++) { + final var quantifier = quantifiers.get(i); + final var pickUpTranslationMap = + TranslationMap.ofAliases(Quantifier.current(), quantifier.getAlias()); + columnBuilder.add(Column.unnamedOf(pickUpValues.get(i).translateCorrelations(pickUpTranslationMap))); + } + + return RecordConstructorValue.ofColumns(columnBuilder.build()); + } + + private static TranslationMap computeTranslationMap(@Nonnull final CorrelationIdentifier intersectionAlias, + @Nonnull final List quantifiers, + @Nonnull final List candidateTopAliases, + @Nonnull final Type.Record intersectionResultType, + final int numGrouped) { + final var builder = TranslationMap.builder(); + final var deconstructedIntersectionValues = + Values.deconstructRecord(QuantifiedObjectValue.of(intersectionAlias, intersectionResultType)); + for (int quantifierIndex = 0; quantifierIndex < quantifiers.size(); quantifierIndex++) { + final var quantifier = quantifiers.get(quantifierIndex); + final var quantifierFlowedObjectType = (Type.Record)quantifier.getFlowedObjectType(); + final var quantifierFields = quantifierFlowedObjectType.getFields(); + Verify.verify(quantifierFields.size() == numGrouped + 1); + final var columnBuilder = + ImmutableList.>builder(); + for (int columnIndex = 0; columnIndex < numGrouped; columnIndex++) { + columnBuilder.add(Column.of(quantifierFields.get(columnIndex), deconstructedIntersectionValues.get(columnIndex))); + } + columnBuilder.add(Column.of(quantifierFields.get(numGrouped), + deconstructedIntersectionValues.get(numGrouped + quantifierIndex))); + builder.when(candidateTopAliases.get(quantifierIndex)).then((alias, leaf) -> + RecordConstructorValue.ofColumns(columnBuilder.build())); + } + + return builder.build(); + } } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/explain/ExplainPlanVisitor.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/explain/ExplainPlanVisitor.java index d2ec7c1066..31174cd543 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/explain/ExplainPlanVisitor.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/explain/ExplainPlanVisitor.java @@ -52,6 +52,7 @@ import com.apple.foundationdb.record.query.plan.plans.RecordQueryIntersectionPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryLoadByKeysPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryMapPlan; +import com.apple.foundationdb.record.query.plan.plans.RecordQueryMultiIntersectionOnValuesPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryPlanVisitor; import com.apple.foundationdb.record.query.plan.plans.RecordQueryPlanWithExplain; @@ -329,6 +330,12 @@ public ExplainTokens visitInComparandJoinPlan(@Nonnull final RecordQueryInCompar return visitInJoinPlan(inComparandJoinPlan); } + @Nonnull + @Override + public ExplainTokens visitMultiIntersectionOnValuesPlan(@Nonnull final RecordQueryMultiIntersectionOnValuesPlan element) { + return new ExplainTokens().addToString("TODO"); // TODO + } + @Nonnull @Override public ExplainTokens visitInParameterJoinPlan(@Nonnull final RecordQueryInParameterJoinPlan inParameterJoinPlan) { diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryMultiIntersectionOnValuesPlan.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryMultiIntersectionOnValuesPlan.java index b76c20c7e6..a4addd5e0a 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryMultiIntersectionOnValuesPlan.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryMultiIntersectionOnValuesPlan.java @@ -31,20 +31,22 @@ import com.apple.foundationdb.record.planprotos.PRecordQueryPlan; import com.apple.foundationdb.record.provider.foundationdb.FDBRecordStoreBase; import com.apple.foundationdb.record.provider.foundationdb.cursors.IntersectionMultiCursor; -import com.apple.foundationdb.record.query.plan.cascades.Column; import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier; import com.apple.foundationdb.record.query.plan.cascades.Memoizer; import com.apple.foundationdb.record.query.plan.cascades.OrderingPart.ProvidedOrderingPart; import com.apple.foundationdb.record.query.plan.cascades.Quantifier; import com.apple.foundationdb.record.query.plan.cascades.Quantifiers; import com.apple.foundationdb.record.query.plan.cascades.Reference; +import com.apple.foundationdb.record.query.plan.cascades.explain.Attribute; +import com.apple.foundationdb.record.query.plan.cascades.explain.NodeInfo; +import com.apple.foundationdb.record.query.plan.cascades.explain.PlannerGraph; import com.apple.foundationdb.record.query.plan.cascades.typing.Type; -import com.apple.foundationdb.record.query.plan.cascades.values.RecordConstructorValue; import com.apple.foundationdb.record.query.plan.cascades.values.Value; import com.apple.foundationdb.record.query.plan.cascades.values.translation.TranslationMap; import com.google.auto.service.AutoService; import com.google.common.base.Verify; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.protobuf.Message; @@ -79,16 +81,6 @@ protected RecordQueryMultiIntersectionOnValuesPlan(@Nonnull final PlanSerializat recordQueryMultiIntersectionOnValuesPlanProto.getResultValue()); } - private RecordQueryMultiIntersectionOnValuesPlan(@Nonnull final List quantifiers, - @Nullable final List comparisonKeyOrderingParts, - @Nonnull final List comparisonKeyValues, - @Nonnull final List commonValues, - @Nonnull final List pickupValues, - final boolean reverse) { - this(quantifiers, comparisonKeyOrderingParts, comparisonKeyValues, - computeResultValue(quantifiers, commonValues, pickupValues), reverse); - } - private RecordQueryMultiIntersectionOnValuesPlan(@Nonnull final List quantifiers, @Nullable final List comparisonKeyOrderingParts, @Nonnull final List comparisonKeyValues, @@ -147,29 +139,6 @@ protected Value computeResultValue() { return resultValue; } - @Nonnull - private static Value computeResultValue(@Nonnull final List quantifiers, - @Nonnull final List commonValues, - @Nonnull final List pickupValues) { - final var columnBuilder = ImmutableList.>builder(); - - // grab the common values from the first quantifier - final var commonTranslationMap = - TranslationMap.ofAliases(Quantifier.current(), quantifiers.get(0).getAlias()); - for (final var commonValue : commonValues) { - columnBuilder.add(Column.unnamedOf(commonValue.translateCorrelations(commonTranslationMap))); - } - - for (int i = 0; i < quantifiers.size(); i++) { - final var quantifier = quantifiers.get(i); - final var pickUpTranslationMap = - TranslationMap.ofAliases(Quantifier.current(), quantifier.getAlias()); - columnBuilder.add(Column.unnamedOf(pickupValues.get(i).translateCorrelations(pickUpTranslationMap))); - } - - return RecordConstructorValue.ofColumns(columnBuilder.build()); - } - @Nonnull @Override @SuppressWarnings("resource") @@ -249,6 +218,18 @@ public PRecordQueryPlan toRecordQueryPlanProto(@Nonnull final PlanSerializationC .setMultiIntersectionOnValuesPlan(toProto(serializationContext)).build(); } + @Nonnull + @Override + public PlannerGraph rewritePlannerGraph(@Nonnull final List childGraphs) { + return PlannerGraph.fromNodeAndChildGraphs( + new PlannerGraph.OperatorNodeWithInfo(this, + NodeInfo.INTERSECTION_OPERATOR, + ImmutableList.of("COMPARE BY {{comparisonKeyFunction}}", "RESULT {{resultValue}}"), + ImmutableMap.of("comparisonKeyFunction", Attribute.gml(getComparisonKeyFunction().toString()), + "resultValue", Attribute.gml(resultValue.toString()))), + childGraphs); + } + @Nonnull public static RecordQueryMultiIntersectionOnValuesPlan fromProto(@Nonnull final PlanSerializationContext serializationContext, @Nonnull final PRecordQueryMultiIntersectionOnValuesPlan recordQueryMultiIntersectionOnValuesPlanProto) { @@ -258,14 +239,12 @@ public static RecordQueryMultiIntersectionOnValuesPlan fromProto(@Nonnull final @Nonnull public static RecordQueryMultiIntersectionOnValuesPlan intersection(@Nonnull final List quantifiers, @Nonnull final List comparisonKeyOrderingParts, - @Nonnull final List commonValues, - @Nonnull final List pickupValues, + @Nonnull final Value resultValue, final boolean isReverse) { return new RecordQueryMultiIntersectionOnValuesPlan(quantifiers, comparisonKeyOrderingParts, ProvidedOrderingPart.comparisonKeyValues(comparisonKeyOrderingParts, isReverse), - commonValues, - pickupValues, + resultValue, isReverse); } From 76e9b292e3df23c89db79097a8a98a00350644c2 Mon Sep 17 00:00:00 2001 From: Normen Seemann Date: Tue, 18 Mar 2025 23:30:23 +0100 Subject: [PATCH 10/20] basic aggregation queries using agg indexes intersections work --- .../query/plan/cascades/Compensation.java | 14 ++++---- .../plan/cascades/PredicateMultiMap.java | 24 +++++++++----- .../expressions/GroupByExpression.java | 4 +-- .../LogicalTypeFilterExpression.java | 5 +-- .../expressions/SelectExpression.java | 15 ++++----- .../predicates/LeafQueryPredicate.java | 7 +--- .../cascades/predicates/QueryPredicate.java | 9 ++---- .../plan/explain/ExplainPlanVisitor.java | 32 +++++++++++++++---- .../plan/plans/RecordQueryExplodePlan.java | 1 - ...ordQueryMultiIntersectionOnValuesPlan.java | 4 ++- 10 files changed, 64 insertions(+), 51 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java index ba5dc7bd97..49d66454b5 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java @@ -641,13 +641,15 @@ default Compensation intersect(@Nonnull Compensation otherCompensation) { final var combinedPredicateMap = new LinkedIdentityMap(); for (final var entry : getPredicateCompensationMap().entrySet()) { // if the other side does not have compensation for this key, we don't need compensation - if (otherCompensationMap.containsKey(entry.getKey())) { + final var otherPredicateCompensationFunction = otherCompensationMap.get(entry.getKey()); + if (otherPredicateCompensationFunction != null) { // Both compensations have a compensation for this particular predicate which is essentially - // reapplying the predicate. At this point it doesn't matter which side we take as both create - // the same compensating filter. If at any point in the future one data access has a better - // reapplication we need to generate plan variants with either compensation and let the planner - // figure out which one wins. - // We just pick one side here. + // reapplying the predicate. Three cases arise: + // 1. Both predicate compensation functions are needed and possible. At this point it doesn't + // matter which side we take as both create the same compensating filter. If at any point in the + // future one data access has a better reapplication we need to generate plan variants with + // either compensation and let the planner figure out which one wins. We just pick one side here. + // 2. TODO. combinedPredicateMap.put(entry.getKey(), entry.getValue().amend(unmatchedAggregateMap, newMatchedAggregateMap)); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PredicateMultiMap.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PredicateMultiMap.java index 2adc122dbb..97129016ee 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PredicateMultiMap.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PredicateMultiMap.java @@ -164,9 +164,14 @@ PredicateCompensationFunction amend(@Nonnull BiMap @Nonnull Set applyCompensationForPredicate(@Nonnull TranslationMap translationMap); + @Nonnull + static PredicateCompensationFunction ofPredicate(@Nonnull final QueryPredicate predicate) { + return ofPredicate(predicate, false); + } + @Nonnull static PredicateCompensationFunction ofPredicate(@Nonnull final QueryPredicate predicate, - @Nonnull final BiFunction> compensationFunction) { + final boolean shouldSimplifyValues) { final var isImpossible = predicateContainsUnmatchedValues(predicate); return new PredicateCompensationFunction() { @@ -189,13 +194,13 @@ public PredicateCompensationFunction amend(@Nonnull final BiMap applyCompensationForPredicate(@Nonnull final TranslationMap translationMap) { - return compensationFunction.apply(predicate, translationMap); + return LinkedIdentitySet.of(predicate.translateCorrelations(translationMap, shouldSimplifyValues)); } }; } @@ -369,8 +374,12 @@ ResultCompensationFunction amend(@Nonnull BiMap un Value applyCompensationForResult(@Nonnull TranslationMap translationMap); @Nonnull - static ResultCompensationFunction ofValue(@Nonnull final Value value, - @Nonnull final BiFunction compensationFunction) { + static ResultCompensationFunction ofValue(@Nonnull final Value value) { + return ofValue(value, false); + } + + @Nonnull + static ResultCompensationFunction ofValue(@Nonnull final Value value, final boolean shouldSimplifyValue) { final var isImpossible = valueContainsUnmatchedValues(value); return new ResultCompensationFunction() { @@ -390,14 +399,13 @@ public ResultCompensationFunction amend(@Nonnull final BiMap amendedMatchedAggregateMap) { final var amendedTranslatedQueryValue = amendValue(unmatchedAggregateMap, amendedMatchedAggregateMap, value); - - return ofValue(amendedTranslatedQueryValue, compensationFunction); + return ofValue(amendedTranslatedQueryValue, true); } @Nonnull @Override public Value applyCompensationForResult(@Nonnull final TranslationMap translationMap) { - return compensationFunction.apply(value, translationMap); + return value.translateCorrelations(translationMap, shouldSimplifyValue); } }; } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java index 6403bb78a8..e4a597344e 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java @@ -614,9 +614,7 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, final var pulledUpTranslatedResultValue = pulledUpTranslatedResultValueOptional.get(); resultCompensationFunction = - ResultCompensationFunction.ofValue(pulledUpTranslatedResultValue, - (value, translationMap) -> value.translateCorrelations(translationMap, - false)); + ResultCompensationFunction.ofValue(pulledUpTranslatedResultValue); isCompensationImpossible |= resultCompensationFunction.isImpossible(); pulledUpAggregateMappings = diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/LogicalTypeFilterExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/LogicalTypeFilterExpression.java index 3c75887181..dab99a25d9 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/LogicalTypeFilterExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/LogicalTypeFilterExpression.java @@ -219,10 +219,7 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, final var pulledUpTranslatedResultValue = pulledUpTranslatedResultValueOptional.get(); - resultCompensationFunction = - ResultCompensationFunction.ofValue(pulledUpTranslatedResultValue, - (value, translationMap) -> value.translateCorrelations(translationMap, - false)); + resultCompensationFunction = ResultCompensationFunction.ofValue(pulledUpTranslatedResultValue); isCompensationImpossible |= resultCompensationFunction.isImpossible(); aggregateMappings = diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java index 8b8a1408ea..0b092eec4a 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java @@ -842,11 +842,12 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, break; } + if (compensationFunction == null) { + compensationFunction = compensationFunctionForCandidatePredicate; + } + if (!compensationFunctionForCandidatePredicate.isImpossible()) { isCompensationFunctionImpossible = false; - if (compensationFunction == null) { - compensationFunction = compensationFunctionForCandidatePredicate; - } } } @@ -854,9 +855,8 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, isAnyCompensationFunctionNeeded = true; if (isCompensationFunctionImpossible) { isAnyCompensationFunctionImpossible = true; - } else { - predicateCompensationMap.put(predicate, Objects.requireNonNull(compensationFunction)); } + predicateCompensationMap.put(predicate, Objects.requireNonNull(compensationFunction)); } } } @@ -877,10 +877,7 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, final var pulledUpTranslatedResultValue = pulledUpTranslatedResultValueOptional.get(); - resultCompensationFunction = - ResultCompensationFunction.ofValue(pulledUpTranslatedResultValue, - (value, translationMap) -> value.translateCorrelations(translationMap, - false)); + resultCompensationFunction = ResultCompensationFunction.ofValue(pulledUpTranslatedResultValue); isAnyCompensationFunctionImpossible |= resultCompensationFunction.isImpossible(); aggregateMappings = diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/LeafQueryPredicate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/LeafQueryPredicate.java index f8568ab6f6..4640a89577 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/LeafQueryPredicate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/LeafQueryPredicate.java @@ -23,7 +23,6 @@ import com.apple.foundationdb.annotation.API; import com.apple.foundationdb.record.query.plan.cascades.ComparisonRange; import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier; -import com.apple.foundationdb.record.query.plan.cascades.LinkedIdentitySet; import com.apple.foundationdb.record.query.plan.cascades.PartialMatch; import com.apple.foundationdb.record.query.plan.cascades.PredicateMultiMap; import com.apple.foundationdb.record.query.plan.cascades.values.translation.PullUp; @@ -82,11 +81,7 @@ default PredicateMultiMap.PredicateCompensationFunction computeCompensationFunct default PredicateMultiMap.PredicateCompensationFunction computeCompensationFunctionForLeaf(@Nonnull final PullUp pullUp) { return toResidualPredicate() .replaceValuesMaybe(pullUp::pullUpMaybe) - .map(queryPredicate -> - PredicateMultiMap.PredicateCompensationFunction.ofPredicate(queryPredicate, - (pulledUpPredicate, translationMap) -> - LinkedIdentitySet.of(pulledUpPredicate.translateCorrelations(translationMap, - false)))) + .map(PredicateMultiMap.PredicateCompensationFunction::ofPredicate) .orElse(PredicateMultiMap.PredicateCompensationFunction.impossibleCompensation()); } } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/QueryPredicate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/QueryPredicate.java index cd70392d41..95ee0f349d 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/QueryPredicate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/QueryPredicate.java @@ -34,8 +34,6 @@ import com.apple.foundationdb.record.query.plan.cascades.ComparisonRange; import com.apple.foundationdb.record.query.plan.cascades.Correlated; import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier; -import com.apple.foundationdb.record.query.plan.explain.ExplainTokensWithPrecedence; -import com.apple.foundationdb.record.query.plan.cascades.LinkedIdentitySet; import com.apple.foundationdb.record.query.plan.cascades.Narrowable; import com.apple.foundationdb.record.query.plan.cascades.PartialMatch; import com.apple.foundationdb.record.query.plan.cascades.PredicateMultiMap.PredicateCompensation; @@ -48,6 +46,7 @@ import com.apple.foundationdb.record.query.plan.cascades.values.Value; import com.apple.foundationdb.record.query.plan.cascades.values.translation.PullUp; import com.apple.foundationdb.record.query.plan.cascades.values.translation.TranslationMap; +import com.apple.foundationdb.record.query.plan.explain.ExplainTokensWithPrecedence; import com.apple.foundationdb.record.query.plan.serialization.PlanSerialization; import com.google.common.base.Verify; import com.google.common.collect.ImmutableList; @@ -250,11 +249,7 @@ default PredicateCompensationFunction computeCompensationFunction(@Nonnull final return toResidualPredicate() .replaceValuesMaybe(pullUp::pullUpMaybe) - .map(queryPredicate -> - PredicateCompensationFunction.ofPredicate(queryPredicate, - (pulledUpPredicate, translationMap) -> - LinkedIdentitySet.of(pulledUpPredicate.translateCorrelations(translationMap, - false)))) + .map(PredicateCompensationFunction::ofPredicate) .orElse(PredicateCompensationFunction.impossibleCompensation()); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/explain/ExplainPlanVisitor.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/explain/ExplainPlanVisitor.java index 31174cd543..5db2b30765 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/explain/ExplainPlanVisitor.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/explain/ExplainPlanVisitor.java @@ -28,6 +28,7 @@ import com.apple.foundationdb.record.query.plan.TextScan; import com.apple.foundationdb.record.query.plan.bitmap.ComposedBitmapIndexQueryPlan; import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier; +import com.apple.foundationdb.record.query.plan.cascades.Quantifier; import com.apple.foundationdb.record.query.plan.plans.RecordQueryAggregateIndexPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryComparatorPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryCoveringIndexPlan; @@ -82,6 +83,7 @@ import javax.annotation.Nonnull; import java.util.Arrays; +import java.util.List; import java.util.function.Supplier; /** @@ -332,8 +334,26 @@ public ExplainTokens visitInComparandJoinPlan(@Nonnull final RecordQueryInCompar @Nonnull @Override - public ExplainTokens visitMultiIntersectionOnValuesPlan(@Nonnull final RecordQueryMultiIntersectionOnValuesPlan element) { - return new ExplainTokens().addToString("TODO"); // TODO + public ExplainTokens visitMultiIntersectionOnValuesPlan(@Nonnull final RecordQueryMultiIntersectionOnValuesPlan multiIntersectionOnValuesPlan) { + visitAndJoin(() -> new ExplainTokens().addWhitespace().addToString("∩").addWhitespace(), + multiIntersectionOnValuesPlan.getChildren()); + final var compareByExplainTokens = new ExplainTokens().addWhitespace().addKeyword("COMPARE") + .addWhitespace().addKeyword("BY").addWhitespace() + .addNested(multiIntersectionOnValuesPlan.getComparisonKeyFunction().explain().getExplainTokens()); + addNested(ExplainLevel.SOME_DETAILS, compareByExplainTokens); + + final List quantifiers = multiIntersectionOnValuesPlan.getQuantifiers(); + final var withExplainTokens = + new ExplainTokens().addWhitespace().addKeyword("WITH").addWhitespace() + .addSequence(() -> new ExplainTokens().addCommaAndWhiteSpace(), + () -> quantifiers.stream() + .map(quantifier -> new ExplainTokens() + .addAliasDefinition(quantifier.getAlias())) + .iterator()); + addNested(ExplainLevel.SOME_DETAILS, withExplainTokens); + final var returnExplainTokens = new ExplainTokens().addWhitespace().addKeyword("RETURN") + .addWhitespace().addNested(multiIntersectionOnValuesPlan.getResultValue().explain().getExplainTokens()); + return addNested(ExplainLevel.SOME_DETAILS, returnExplainTokens); } @Nonnull @@ -443,10 +463,10 @@ public ExplainTokens visitTempTableInsertPlan(@Nonnull final TempTableInsertPlan private ExplainTokens visitIntersectionPlan(@Nonnull final RecordQueryIntersectionPlan intersectionPlan) { visitAndJoin(() -> new ExplainTokens().addWhitespace().addToString("∩").addWhitespace(), intersectionPlan.getChildren()); - final var comparyByExplainTokens = new ExplainTokens().addWhitespace().addKeyword("COMPARE") + final var compareByExplainTokens = new ExplainTokens().addWhitespace().addKeyword("COMPARE") .addWhitespace().addKeyword("BY").addWhitespace() .addNested(intersectionPlan.getComparisonKeyFunction().explain().getExplainTokens()); - return addNested(ExplainLevel.SOME_DETAILS, comparyByExplainTokens); + return addNested(ExplainLevel.SOME_DETAILS, compareByExplainTokens); } @Nonnull @@ -584,10 +604,10 @@ private ExplainTokens visitUnionPlan(@Nonnull final RecordQueryUnionPlan unionPl visitAndJoin(() -> new ExplainTokens().addWhitespace().addToString("∪").addWhitespace(), unionPlan.getChildren()); - final var comparyByExplainTokens = new ExplainTokens().addWhitespace().addKeyword("COMPARE") + final var compareByExplainTokens = new ExplainTokens().addWhitespace().addKeyword("COMPARE") .addWhitespace().addKeyword("BY").addWhitespace() .addNested(unionPlan.getComparisonKeyFunction().explain().getExplainTokens()); - return addNested(ExplainLevel.SOME_DETAILS, comparyByExplainTokens); + return addNested(ExplainLevel.SOME_DETAILS, compareByExplainTokens); } @Nonnull diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryExplodePlan.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryExplodePlan.java index 2935edd3b9..29b2ec654a 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryExplodePlan.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryExplodePlan.java @@ -167,7 +167,6 @@ public Set getDynamicTypes() { return collectionValue.getDynamicTypes(); } - @Nonnull @Override public String toString() { diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryMultiIntersectionOnValuesPlan.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryMultiIntersectionOnValuesPlan.java index a4addd5e0a..c62ae39dec 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryMultiIntersectionOnValuesPlan.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryMultiIntersectionOnValuesPlan.java @@ -48,6 +48,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Streams; import com.google.protobuf.Message; import javax.annotation.Nonnull; @@ -57,6 +58,7 @@ import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.Stream; /** * Intersection plan that compares using a {@link Value}. @@ -128,7 +130,7 @@ public List getComparisonKeyValues() { @Nonnull @Override public Set getDynamicTypes() { - return getComparisonKeyValues().stream() + return Streams.concat(getComparisonKeyValues().stream(), Stream.of(resultValue)) .flatMap(comparisonKeyValue -> comparisonKeyValue.getDynamicTypes().stream()).collect(ImmutableSet.toImmutableSet()); } From 620a43545c5dc437b0617825029080f2fe1ac90b Mon Sep 17 00:00:00 2001 From: Normen Seemann Date: Fri, 21 Mar 2025 11:26:47 +0100 Subject: [PATCH 11/20] more agg queriers work --- .../combinatorics/EnumeratingIterable.java | 17 ++++++++++++++--- .../query/combinatorics/TopologicalSort.java | 12 +++++++----- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/combinatorics/EnumeratingIterable.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/combinatorics/EnumeratingIterable.java index 2ba9c3cff0..084c704916 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/combinatorics/EnumeratingIterable.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/combinatorics/EnumeratingIterable.java @@ -44,6 +44,10 @@ static EnumeratingIterable singleIterable(@Nonnull final T singleElement) return new SingleIterable<>(singleElement); } + static EnumeratingIterable emptyOnEmptyIterable() { + return new SingleIterable<>(); + } + /** * An implementation of {@link EnumeratingIterable} that is optimized to work for empty * input sets. @@ -84,13 +88,17 @@ public EnumeratingIterator iterator() { * @param type */ class SingleIterable implements EnumeratingIterable { - @Nonnull + @Nullable private final T singleElement; private SingleIterable(@Nonnull final T singleElement) { this.singleElement = singleElement; } + private SingleIterable() { + this.singleElement = null; + } + @Nonnull @Override public EnumeratingIterator iterator() { @@ -103,12 +111,12 @@ public EnumeratingIterator iterator() { * @param type of the element */ class SingleIterator extends AbstractIterator> implements EnumeratingIterator { - @Nonnull + @Nullable private final T singleElement; boolean atFirst = true; - private SingleIterator(@Nonnull final T singleElement) { + private SingleIterator(@Nullable final T singleElement) { this.singleElement = singleElement; } @@ -128,6 +136,9 @@ protected List computeNext() { atFirst = false; + if (singleElement == null) { + return ImmutableList.of(); + } return ImmutableList.of(singleElement); } } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/combinatorics/TopologicalSort.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/combinatorics/TopologicalSort.java index a61714e859..45b9df5d48 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/combinatorics/TopologicalSort.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/combinatorics/TopologicalSort.java @@ -537,9 +537,9 @@ public static Iterable> satisfyingPermutations(@Nonnull final Par @Nonnull final List

targetPermutation, @Nonnull final Function domainMapper, @Nonnull final Function, Integer> satisfiabilityFunction) { - if (partiallyOrderedSet.isEmpty()) { - return ImmutableList.of(); - } +// if (partiallyOrderedSet.isEmpty()) { +// return ImmutableList.of(); +// } if (partiallyOrderedSet.size() < targetPermutation.size()) { return ImmutableList.of(); @@ -565,9 +565,11 @@ protected Iterator domain(final int t) { } } }; - } else { - Verify.verify(partiallyOrderedSet.size() == 1); + } else if (partiallyOrderedSet.size() == 1) { enumeratingIterator = EnumeratingIterable.singleIterable(Iterables.getOnlyElement(partiallyOrderedSet.getSet())).iterator(); + } else { + Verify.verify(partiallyOrderedSet.isEmpty()); + enumeratingIterator = EnumeratingIterable.emptyOnEmptyIterable().iterator(); } return () -> new AbstractIterator<>() { From df87707624cf1a7e0990126188108ca9c0267116 Mon Sep 17 00:00:00 2001 From: Normen Seemann Date: Mon, 24 Mar 2025 09:24:38 +0100 Subject: [PATCH 12/20] rebased; regular intersections work; pre rollup --- .../rules/AbstractDataAccessRule.java | 8 +-- .../plan/cascades/MacroFunctionTest.java | 6 +- .../src/test/java/YamlIntegrationTests.java | 6 ++ .../composite-aggregates.metrics.binpb | Bin 0 -> 3133 bytes .../composite-aggregates.metrics.yaml | 13 ++++ .../resources/composite-aggregates.yamsql | 57 ++++++++++++++++++ 6 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 yaml-tests/src/test/resources/composite-aggregates.metrics.binpb create mode 100644 yaml-tests/src/test/resources/composite-aggregates.metrics.yaml create mode 100644 yaml-tests/src/test/resources/composite-aggregates.yamsql diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java index 5b8f54df4c..07902fa50e 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java @@ -983,10 +983,10 @@ private static Ordering orderingFromOrderingParts(final @Nonnull List comparisonKeyValues, @Nonnull List commonPrimaryKeyValues, @Nonnull ImmutableSet equalityBoundKeyValues) { - if (comparisonKeyValues.isEmpty()) { - // everything is in one row - return true; - } +// if (comparisonKeyValues.isEmpty()) { +// // everything is in one row +// return true; +// } return commonPrimaryKeyValues .stream() diff --git a/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/query/plan/cascades/MacroFunctionTest.java b/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/query/plan/cascades/MacroFunctionTest.java index 0ff371ca33..c1659f958a 100644 --- a/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/query/plan/cascades/MacroFunctionTest.java +++ b/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/query/plan/cascades/MacroFunctionTest.java @@ -43,7 +43,7 @@ void testColumnProjection() { Type.Record.Field.of(Type.primitiveType(Type.TypeCode.STRING), Optional.of("name")), Type.Record.Field.of(Type.primitiveType(Type.TypeCode.LONG), Optional.of("id"))); Type record = Type.Record.fromFields(false, fields); - QuantifiedObjectValue param = QuantifiedObjectValue.of(CorrelationIdentifier.uniqueID(), record); + QuantifiedObjectValue param = QuantifiedObjectValue.of(CorrelationIdentifier.uniqueId(), record); FieldValue bodyValue = FieldValue.ofFieldName(param, "name"); MacroFunction macroFunction = new MacroFunction("getName", ImmutableList.of(param), bodyValue); @@ -60,8 +60,8 @@ void testAdd() { ImmutableList fields = ImmutableList.of( Type.Record.Field.of(Type.primitiveType(Type.TypeCode.LONG), Optional.of("id"))); Type record = Type.Record.fromFields(false, fields); - QuantifiedObjectValue param1 = QuantifiedObjectValue.of(CorrelationIdentifier.uniqueID(), record); - QuantifiedObjectValue param2 = QuantifiedObjectValue.of(CorrelationIdentifier.uniqueID(), record); + QuantifiedObjectValue param1 = QuantifiedObjectValue.of(CorrelationIdentifier.uniqueId(), record); + QuantifiedObjectValue param2 = QuantifiedObjectValue.of(CorrelationIdentifier.uniqueId(), record); ArithmeticValue bodyValue = new ArithmeticValue(ArithmeticValue.PhysicalOperator.ADD_LL, param1, param2); MacroFunction macroFunction = new MacroFunction("add", ImmutableList.of(param1, param2), bodyValue); diff --git a/yaml-tests/src/test/java/YamlIntegrationTests.java b/yaml-tests/src/test/java/YamlIntegrationTests.java index c2d1e54e78..0c66dad5dc 100644 --- a/yaml-tests/src/test/java/YamlIntegrationTests.java +++ b/yaml-tests/src/test/java/YamlIntegrationTests.java @@ -263,4 +263,10 @@ public void uuidTest(YamlTest.Runner runner) throws Exception { public void tableFunctionsTest(YamlTest.Runner runner) throws Exception { runner.runYamsql("table-functions.yamsql"); } + + @TestTemplate + //@MaintainYamlTestConfig(YamlTestConfigFilters.CORRECT_EXPLAIN_AND_METRICS) + public void compositeAggregates(YamlTest.Runner runner) throws Exception { + runner.runYamsql("composite-aggregates.yamsql"); + } } diff --git a/yaml-tests/src/test/resources/composite-aggregates.metrics.binpb b/yaml-tests/src/test/resources/composite-aggregates.metrics.binpb new file mode 100644 index 0000000000000000000000000000000000000000..e10761c2e60000de3455822cb7e3433b52da34a6 GIT binary patch literal 3133 zcmeHJOK;Oa5C%jg)KgWdqHr4Rp-QBL#CfSr;)t|FB_d6tJPK7+MeBIuSlxIXdm{*s zdw)ea^9v9{ocRxk11elO@DJE^lE#%%RXrs1fRu;7-5KxroAG?}d3||*c?}yznDlHu z40Ehe66VC^?y6dNQ7z?*WpD{4Z4U0B7icpY3ql0iY+&&*>Nun45-9SA0>)X=i%HvzBKX2!Y^__e<(1^8)DaeL$uzk?l ztyP*;2?Kr4y)(pljo{X&L9+Hr90yZ=zh5JL0PYrlw)3h>{LRxqVCr z1a?@@9&pS}W@RH>&xs#tJHy_4+2;q8*(*qvntQW*(|PWg?h8p5Vg1!_ZOo?(`wvGPEai9yWc<0K?s85 zEX3!Z1)aQtdK+I=ysj_-KD0^tyyN&No0S6bh8n_pgYr!H?Bp~g`p@Zx!81O$8^m=4$;F42lwnChna#&!nwSG2DS5JNunRvq UCQtSag5wHFO*4^NbRypU1&^BSi2wiq literal 0 HcmV?d00001 diff --git a/yaml-tests/src/test/resources/composite-aggregates.metrics.yaml b/yaml-tests/src/test/resources/composite-aggregates.metrics.yaml new file mode 100644 index 0000000000..c2bf2e5021 --- /dev/null +++ b/yaml-tests/src/test/resources/composite-aggregates.metrics.yaml @@ -0,0 +1,13 @@ +agg-empty-table-tests: +- query: EXPLAIN select sum(col2) / count(col2) from T2 group by col1; + explain: 'AISCAN(T2_I6 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 + <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0._0) WITH q0, + q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 / _._2 AS _0)' + task_count: 317 + task_total_time_ms: 11 + transform_count: 115 + transform_time_ms: 10 + transform_yield_count: 51 + insert_time_ms: 0 + insert_new_count: 16 + insert_reused_count: 0 diff --git a/yaml-tests/src/test/resources/composite-aggregates.yamsql b/yaml-tests/src/test/resources/composite-aggregates.yamsql new file mode 100644 index 0000000000..d0230fae2f --- /dev/null +++ b/yaml-tests/src/test/resources/composite-aggregates.yamsql @@ -0,0 +1,57 @@ +# +# composite-aggregates.yamsql +# +# This source file is part of the FoundationDB open source project +# +# Copyright 2021-2025 Apple Inc. and the FoundationDB project authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +schema_template: + create table t1(id bigint, col1 bigint, col2 bigint, primary key(id)) + create table t2(id bigint, col1 bigint, col2 bigint, primary key(id)) + create table t3(id bigint, col1 bigint, col2 bigint, primary key(id)) + create index t2_i1 as select count(*) from t2 + create index t2_i2 as select count(*) from t2 group by col1 + create index t2_i3 as select count(col2) from t2 + create index t2_i4 as select count(col2) from t2 group by col1 + create index t2_i5 as select sum(col1) from t2 + create index t2_i6 as select sum(col2) from t2 group by col1 + create index t2_i7 as select count(*) from t2 group by col1, col2 + create index t3_i1 as select col1 from t3 + create index t3_i2 as select col2 from t3 + +--- +test_block: + name: agg-empty-table-tests + preset: single_repetition_ordered + tests: + #- + # - query: select count(*) from T2 group by col1, col2; + # - explain: "AISCAN(T2_I7 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | MAP (_._2 AS _0)" + # - result: [] + #- + # - query: select count(*) from T2 group by col2, col1; + # - explain: "AISCAN(T2_I7 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | MAP (_._2 AS _0)" + # - result: [] + #- + # - query: select count(*) from T2 where col1 = 3 group by col2; + # - explain: "AISCAN(T2_I7 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | MAP (_._2 AS _0)" + # - result: [] + - + - query: select sum(col2) / count(col2) from T2 group by col1; + - explain: "AISCAN(T2_I6 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 / _._2 AS _0)" + - result: [] +... + From f2b9502f3dcbdab3e91e928c931b2235daae50b6 Mon Sep 17 00:00:00 2001 From: Normen Seemann Date: Wed, 26 Mar 2025 19:44:25 +0100 Subject: [PATCH 13/20] roll ups work --- .../AggregateIndexExpansionVisitor.java | 40 +++++++- .../AggregateIndexMatchCandidate.java | 91 +++++++++++++++--- .../BitmapAggregateIndexExpansionVisitor.java | 2 - .../query/plan/cascades/MatchCandidate.java | 8 ++ .../record/query/plan/cascades/MatchInfo.java | 72 +++++++++++--- .../query/plan/cascades/PartialMatch.java | 28 +++++- .../WithPrimaryKeyMatchCandidate.java | 29 ------ .../expressions/GroupByExpression.java | 95 ++++++++++++------- .../LogicalTypeFilterExpression.java | 12 ++- .../expressions/SelectExpression.java | 15 +-- .../predicates/LeafQueryPredicate.java | 2 +- .../cascades/predicates/QueryPredicate.java | 2 +- .../rules/AbstractDataAccessRule.java | 66 +++++++++++-- .../rules/AggregateDataAccessRule.java | 14 +-- .../query/plan/cascades/typing/Type.java | 2 +- .../query/plan/cascades/values/Values.java | 2 +- .../cascades/values/translation/PullUp.java | 86 +++++++++++++---- .../plans/RecordQueryAggregateIndexPlan.java | 2 +- .../plan/plans/RecordQueryIndexPlan.java | 13 ++- .../resources/composite-aggregates.yamsql | 54 ++++++++++- 20 files changed, 489 insertions(+), 146 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexExpansionVisitor.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexExpansionVisitor.java index f19d481ce0..27d5ecf9a4 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexExpansionVisitor.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexExpansionVisitor.java @@ -33,6 +33,7 @@ import com.apple.foundationdb.record.query.plan.cascades.expressions.SelectExpression; import com.apple.foundationdb.record.query.plan.cascades.predicates.Placeholder; import com.apple.foundationdb.record.query.plan.cascades.predicates.PredicateWithValueAndRanges; +import com.apple.foundationdb.record.query.plan.cascades.values.AggregateValue; import com.apple.foundationdb.record.query.plan.cascades.values.ArithmeticValue; import com.apple.foundationdb.record.query.plan.cascades.values.CountValue; import com.apple.foundationdb.record.query.plan.cascades.values.EmptyValue; @@ -60,6 +61,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.function.Supplier; import java.util.stream.Stream; @@ -71,7 +73,12 @@ public class AggregateIndexExpansionVisitor extends KeyExpressionExpansionVisitor implements ExpansionVisitor { @Nonnull - static final Supplier>> aggregateMap = Suppliers.memoize(AggregateIndexExpansionVisitor::computeAggregateMap); + static final Supplier>> aggregateMap = + Suppliers.memoize(AggregateIndexExpansionVisitor::computeAggregateMap); + + @Nonnull + static final Supplier>> rollUpAggregateMap = + Suppliers.memoize(AggregateIndexExpansionVisitor::computeRollUpAggregateMap); @Nonnull protected final Index index; @@ -91,7 +98,8 @@ public class AggregateIndexExpansionVisitor extends KeyExpressionExpansionVisito * @param recordTypes The indexed record types. */ public AggregateIndexExpansionVisitor(@Nonnull final Index index, @Nonnull final Collection recordTypes) { - Preconditions.checkArgument(IndexTypes.BITMAP_VALUE.equals(index.getType()) || aggregateMap.get().containsKey(index.getType())); + Preconditions.checkArgument(IndexTypes.BITMAP_VALUE.equals(index.getType()) || + aggregateMap.get().containsKey(index.getType())); Preconditions.checkArgument(index.getRootExpression() instanceof GroupingKeyExpression); this.index = index; this.groupingKeyExpression = ((GroupingKeyExpression)index.getRootExpression()); @@ -334,6 +342,12 @@ private ConstructSelectHavingResult constructSelectHaving(@Nonnull final Quantif finalPlaceholders, currentGroupingValues); } + @Nonnull + public static Optional aggregateValue(@Nonnull final Index index, @Nonnull final Value argument) { + return Optional.of((AggregateValue)aggregateMap.get() + .get(index.getType()).encapsulate(ImmutableList.of(argument))); + } + @Nonnull private static Map> computeAggregateMap() { final ImmutableMap.Builder> mapBuilder = ImmutableMap.builder(); @@ -349,6 +363,28 @@ private static Map> computeAggregateMap return mapBuilder.build(); } + @Nonnull + public static Optional rollUpAggregateValueMaybe(@Nonnull final Index index, @Nonnull final Value argument) { + return Optional.ofNullable(rollUpAggregateMap.get() + .get(index.getType())) + .map(fn -> (AggregateValue)fn.encapsulate(ImmutableList.of(argument))); + } + + @Nonnull + private static Map> computeRollUpAggregateMap() { + final ImmutableMap.Builder> mapBuilder = ImmutableMap.builder(); + mapBuilder.put(IndexTypes.MAX_EVER_LONG, new NumericAggregationValue.MaxFn()); + mapBuilder.put(IndexTypes.MIN_EVER_LONG, new NumericAggregationValue.MinFn()); + // mapBuilder.put(IndexTypes.MAX_EVER_TUPLE, TODO); + // mapBuilder.put(IndexTypes.MIN_EVER_TUPLE, TODO); + mapBuilder.put(IndexTypes.SUM, new NumericAggregationValue.SumFn()); + mapBuilder.put(IndexTypes.COUNT, new NumericAggregationValue.SumFn()); + mapBuilder.put(IndexTypes.COUNT_NOT_NULL, new NumericAggregationValue.SumFn()); + mapBuilder.put(IndexTypes.PERMUTED_MAX, new NumericAggregationValue.MaxFn()); + mapBuilder.put(IndexTypes.PERMUTED_MIN, new NumericAggregationValue.MinFn()); + return mapBuilder.build(); + } + private static class ConstructSelectHavingResult { @Nonnull private final SelectExpression selectExpression; diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java index ac895f3c07..2da52a01ab 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java @@ -42,13 +42,16 @@ import com.apple.foundationdb.record.query.plan.cascades.typing.TypeRepository; import com.apple.foundationdb.record.query.plan.cascades.values.FieldValue; import com.apple.foundationdb.record.query.plan.cascades.values.QuantifiedObjectValue; +import com.apple.foundationdb.record.query.plan.cascades.values.RecordConstructorValue; import com.apple.foundationdb.record.query.plan.cascades.values.Value; import com.apple.foundationdb.record.query.plan.cascades.values.Values; import com.apple.foundationdb.record.query.plan.cascades.values.simplification.OrderingValueComputationRuleSet; +import com.apple.foundationdb.record.query.plan.cascades.values.translation.PullUp; import com.apple.foundationdb.record.query.plan.plans.RecordQueryAggregateIndexPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryFetchFromPartialRecordPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan; +import com.apple.foundationdb.record.query.plan.plans.RecordQueryStreamingAggregationPlan; import com.apple.foundationdb.record.util.pair.NonnullPair; import com.google.common.base.Preconditions; import com.google.common.base.Verify; @@ -171,7 +174,7 @@ public KeyExpression getFullKeyExpression() { @Override public String toString() { - return "Agg[" + getName() + "; " + index.getType() + "]"; + return "AGG[" + getName() + "; " + index.getType() + "]"; } @Override @@ -359,6 +362,33 @@ public Ordering computeOrderingFromScanComparisons(@Nonnull final ScanComparison return Ordering.ofOrderingSequence(bindingMapBuilder.build(), orderingSequenceBuilder.build(), isDistinct); } + @Nullable + @Override + public PullUp.UnificationPullUp prepareForUnification(@Nonnull final PartialMatch partialMatch, + @Nonnull final CorrelationIdentifier topAlias, + @Nonnull final CorrelationIdentifier topCandidateAlias) { + final var regularMatchInfo = partialMatch.getRegularMatchInfo(); + if (regularMatchInfo.getRollUpToGroupingValues() != null) { + final var groupingAndAggregateAccessors = + getGroupingAndAggregateAccessors(topCandidateAlias); + final var groupingAccessorValues = groupingAndAggregateAccessors.getLeft(); + final var aggregateAccessorValue = groupingAndAggregateAccessors.getRight(); + final var allFields = + ((Type.Record)selectHavingExpression.getResultValue().getResultType()).getFields(); + final var rollUpColumnsBuilder = + ImmutableList.>builder(); + final var numGroupings = regularMatchInfo.getRollUpToGroupingValues().size(); + for (int i = 0; i < numGroupings; i++) { + final var field = allFields.get(i); + rollUpColumnsBuilder.add(Column.of(field, groupingAccessorValues.get(i))); + } + rollUpColumnsBuilder.add(Column.of(allFields.get(allFields.size() - 1), aggregateAccessorValue)); + return PullUp.forUnification(topAlias, RecordConstructorValue.ofColumns(rollUpColumnsBuilder.build()), + ImmutableSet.of(topCandidateAlias)); + } + return null; + } + @Nonnull @Override public RecordQueryPlan toEquivalentPlan(@Nonnull final PartialMatch partialMatch, @@ -369,13 +399,14 @@ public RecordQueryPlan toEquivalentPlan(@Nonnull final PartialMatch partialMatch final var baseRecordType = Type.Record.fromFieldDescriptorsMap(RecordMetaData.getFieldDescriptorMapFromTypes(recordTypes)); final var selectHavingResultValue = selectHavingExpression.getResultValue(); - final var resultType = selectHavingResultValue.getResultType(); + final var resultType = (Type.Record)selectHavingResultValue.getResultType(); final var messageDescriptor = Objects.requireNonNull(TypeRepository.newBuilder() .addTypeIfNeeded(resultType) .build() .getMessageDescriptor(resultType)); - final var constraintMaybe = partialMatch.getRegularMatchInfo().getConstraint(); + final var regularMatchInfo = partialMatch.getRegularMatchInfo(); + final var constraintMaybe = regularMatchInfo.getConstraint(); final var indexEntryConverter = createIndexEntryConverter(messageDescriptor); final var aggregateIndexScan = new RecordQueryIndexPlan(index.getName(), @@ -389,12 +420,45 @@ public RecordQueryPlan toEquivalentPlan(@Nonnull final PartialMatch partialMatch baseRecordType, QueryPlanConstraint.tautology()); - return new RecordQueryAggregateIndexPlan(aggregateIndexScan, + var plan = new RecordQueryAggregateIndexPlan(aggregateIndexScan, recordTypes.get(0).getName(), indexEntryConverter, selectHavingResultValue, groupByResultValue, constraintMaybe); + if (regularMatchInfo.getRollUpToGroupingValues() != null) { + // + // We need to perform a roll up. + // + final var aggregateIndexScanReference = memoizer.memoizePlans(plan); + final var aggregateIndexScanAlias = Quantifier.uniqueId(); + + //final var recordValues = Values.deconstructRecord(recordValue); + final var groupingAndAggregateAccessors = + getGroupingAndAggregateAccessors(regularMatchInfo.getRollUpToGroupingValues().size(), + aggregateIndexScanAlias); + final var groupingAccessorValues = groupingAndAggregateAccessors.getLeft(); + final var aggregateAccessorValue = groupingAndAggregateAccessors.getRight(); + final var allFields = resultType.getFields(); + final var rollUpGroupingColumnsBuilder = + ImmutableList.>builder(); + for (int i = 0; i < groupingAccessorValues.size(); i++) { + final var field = allFields.get(i); + rollUpGroupingColumnsBuilder.add(Column.of(field, groupingAccessorValues.get(i))); + } + + final var rollUpAggregateValueOptional = + AggregateIndexExpansionVisitor.rollUpAggregateValueMaybe(index, + aggregateAccessorValue); + + final var aggregateIndexScanQuantifier = + Quantifier.physical(aggregateIndexScanReference, aggregateIndexScanAlias); + + return RecordQueryStreamingAggregationPlan.ofFlattened(aggregateIndexScanQuantifier, + RecordConstructorValue.ofColumns(rollUpGroupingColumnsBuilder.build(), resultType.isNullable()), + rollUpAggregateValueOptional.orElseThrow(() -> new RecordCoreException("unknown rollup operation"))); + } + return plan; } @Nonnull @@ -411,19 +475,22 @@ protected int getGroupingCount() { } @Nonnull - public NonnullPair, Value> getGroupingAndAggregateAccessors() { + public NonnullPair, Value> getGroupingAndAggregateAccessors(@Nonnull final CorrelationIdentifier alias) { + return getGroupingAndAggregateAccessors(getGroupingCount(), alias); + } + + @Nonnull + public NonnullPair, Value> getGroupingAndAggregateAccessors(final int numGroupings, + @Nonnull final CorrelationIdentifier alias) { final var selectHavingResultValue = selectHavingExpression.getResultValue(); final var selectHavingResultType = (Type.Record)selectHavingResultValue.getResultType(); final var unbasedResultValue = - QuantifiedObjectValue.of(Quantifier.current(), selectHavingResultType); - - final var groupingCount = getGroupingCount(); - Verify.verify(selectHavingResultType.getFields().size() >= groupingCount); - + QuantifiedObjectValue.of(alias, selectHavingResultType); final var deconstructedRecord = Values.deconstructRecord(unbasedResultValue); + Verify.verify(deconstructedRecord.size() > numGroupings); final var groupingAccessorValues = - ImmutableList.copyOf(deconstructedRecord.subList(0, groupingCount)); - final var aggregateAccessorValue = deconstructedRecord.get(groupingCount); + ImmutableList.copyOf(deconstructedRecord.subList(0, numGroupings)); + final var aggregateAccessorValue = deconstructedRecord.get(deconstructedRecord.size() - 1); return NonnullPair.of(groupingAccessorValues, aggregateAccessorValue); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/BitmapAggregateIndexExpansionVisitor.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/BitmapAggregateIndexExpansionVisitor.java index 17f30b609c..4e47ec83bd 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/BitmapAggregateIndexExpansionVisitor.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/BitmapAggregateIndexExpansionVisitor.java @@ -85,7 +85,6 @@ protected NonnullPair> constructGroupBy(@Nonnull f throw new UnsupportedOperationException("unable to plan group by with non-field value " + groupedValue); } - final var bitmapConstructAggFunc = FunctionCatalog.getFunctionSingleton(NumericAggregationValue.BitmapConstructAggFn.class).orElseThrow(); final var bitmapBitPositionFunc = FunctionCatalog.getFunctionSingleton(ArithmeticValue.BitmapBitPositionFn.class).orElseThrow(); final String sizeArgument = index.getOption(IndexOptions.BITMAP_VALUE_ENTRY_SIZE_OPTION); @@ -96,7 +95,6 @@ protected NonnullPair> constructGroupBy(@Nonnull f // add an RCV column representing the grouping columns as the first result set column // also, make sure to set the field type names correctly for each field value in the grouping keys RCV. - final var groupingValues = baseExpansion.getResultColumns().subList(0, groupingKeyExpression.getGroupingCount()) .stream() .map(Column::getValue) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchCandidate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchCandidate.java index 3d3a0b9632..3cec221751 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchCandidate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchCandidate.java @@ -36,6 +36,7 @@ import com.apple.foundationdb.record.query.plan.cascades.typing.Type; import com.apple.foundationdb.record.query.plan.cascades.values.Value; import com.apple.foundationdb.record.query.plan.cascades.values.simplification.OrderingValueComputationRuleSet; +import com.apple.foundationdb.record.query.plan.cascades.values.translation.PullUp; import com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan; import com.apple.foundationdb.record.util.pair.NonnullPair; import com.google.common.base.Verify; @@ -181,6 +182,13 @@ Ordering computeOrderingFromScanComparisons(@Nonnull ScanComparisons scanCompari boolean isReverse, boolean isDistinct); + @Nullable + default PullUp.UnificationPullUp prepareForUnification(@Nonnull final PartialMatch partialMatch, + @Nonnull final CorrelationIdentifier topAlias, + @Nonnull final CorrelationIdentifier topCandidateAlias) { + return null; + } + /** * Creates a {@link RecordQueryPlan} that represents a scan over the materialized candidate data. * @param partialMatch the match to be used diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchInfo.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchInfo.java index 7711e3a70e..bd04e6e6f7 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchInfo.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchInfo.java @@ -152,6 +152,9 @@ class RegularMatchInfo implements MatchInfo { @Nonnull private final AggregateMappings aggregateMappings; + @Nullable + private final List rollUpToGroupingValues; + /** * Field to hold additional query plan constraints that need to be imposed on the potentially realized match. */ @@ -165,6 +168,7 @@ private RegularMatchInfo(@Nonnull final Map matchedOrderingParts, @Nonnull final MaxMatchMap maxMatchMap, @Nonnull final AggregateMappings aggregateMappings, + @Nullable final List rollUpToGroupingValues, @Nonnull final QueryPlanConstraint additionalPlanConstraint) { this.parameterBindingMap = ImmutableMap.copyOf(parameterBindingMap); this.bindingAliasMap = bindingAliasMap; @@ -179,6 +183,8 @@ private RegularMatchInfo(@Nonnull final Map getRollUpToGroupingValues() { + return rollUpToGroupingValues; + } + @Nonnull public QueryPlanConstraint getAdditionalPlanConstraint() { return additionalPlanConstraint; @@ -284,7 +295,7 @@ private QueryPlanConstraint computeConstraints() { ImmutableList.builder() .addAll(constraints) .addAll(childConstraints) - .add(additionalPlanConstraint) + .add(getAdditionalPlanConstraint()) .build(); return QueryPlanConstraint.composeConstraints(allConstraints); } @@ -294,7 +305,8 @@ public static Optional tryFromMatchMap(@Nonnull final AliasMap bindin @Nonnull final IdentityBiMap partialMatchMap, @Nonnull final MaxMatchMap maxMatchMap) { return tryMerge(bindingAliasMap, partialMatchMap, ImmutableMap.of(), PredicateMap.empty(), - maxMatchMap, AggregateMappings.empty(), maxMatchMap.getQueryPlanConstraint()); + maxMatchMap, AggregateMappings.empty(), null, + maxMatchMap.getQueryPlanConstraint()); } @Nonnull @@ -304,6 +316,7 @@ public static Optional tryMerge(@Nonnull final AliasMap bindingAliasM @Nonnull final PredicateMultiMap predicateMap, @Nonnull final MaxMatchMap maxMatchMap, @Nonnull final AggregateMappings additionalAggregateMappings, + @Nullable final List rollUpToGroupingValues, @Nonnull final QueryPlanConstraint additionalPlanConstraint) { final var parameterMapsBuilder = ImmutableList.>builder(); final var matchInfos = PartialMatch.matchInfosFromMap(partialMatchMap); @@ -333,6 +346,31 @@ public static Optional tryMerge(@Nonnull final AliasMap bindingAliasM pullUpAndMergeAggregateMappings(bindingAliasMap, partialMatchMap, additionalAggregateMappings); + final List resolvedRollUpToGroupingValues; + if (rollUpToGroupingValues != null) { + for (final var regularQuantifier : regularQuantifiers) { + final var partialMatch = Objects.requireNonNull(partialMatchMap.getUnwrapped(regularQuantifier)); + if (partialMatch.getRegularMatchInfo().getRollUpToGroupingValues() != null) { + return Optional.empty(); + } + } + resolvedRollUpToGroupingValues = rollUpToGroupingValues; + } else { + List onlyRollUpToGroupingValues = null; + for (final var regularQuantifier : regularQuantifiers) { + final var partialMatch = Objects.requireNonNull(partialMatchMap.getUnwrapped(regularQuantifier)); + final var currentRollUpToGroupingValues = partialMatch.getRegularMatchInfo().getRollUpToGroupingValues(); + if (currentRollUpToGroupingValues != null) { + if (onlyRollUpToGroupingValues == null) { + onlyRollUpToGroupingValues = currentRollUpToGroupingValues; + } else { + return Optional.empty(); + } + } + } + resolvedRollUpToGroupingValues = onlyRollUpToGroupingValues; + } + return mergedParameterBindingsOptional .map(mergedParameterBindings -> new RegularMatchInfo(mergedParameterBindings, bindingAliasMap, @@ -341,6 +379,7 @@ public static Optional tryMerge(@Nonnull final AliasMap bindingAliasM orderingParts, maxMatchMap, matchedAggregateValueMap, + resolvedRollUpToGroupingValues, additionalPlanConstraint)); } @@ -392,9 +431,22 @@ private static AggregateMappings pullUpAndMergeAggregateMappings(@Nonnull final } @Nonnull - public static AggregateMappings pullUpAggregateMappings(@Nonnull final PartialMatch partialMatch, - @Nonnull final CorrelationIdentifier candidateAlias) { - return pullUpAggregateMappings(partialMatch, null, candidateAlias); + public static AggregateMappings pullUpAggregateCandidateMappings(@Nonnull final PartialMatch partialMatch, + @Nonnull final PullUp pullUp) { + final var matchInfo = partialMatch.getMatchInfo(); + final var aggregateMappings = matchInfo.getAggregateMappings(); + final var matchedAggregateMapBuilder = ImmutableMap.builder(); + for (final var matchedAggregateMapEntry : aggregateMappings.getMatchedAggregateMap().entrySet()) { + final var candidateAggregateValue = matchedAggregateMapEntry.getValue(); + final var pulledUpCandidateAggregateValueOptional = + pullUp.pullUpCandidateValueMaybe(candidateAggregateValue); + if (pulledUpCandidateAggregateValueOptional.isEmpty()) { + return AggregateMappings.empty(); + } + matchedAggregateMapBuilder.put(matchedAggregateMapEntry.getKey(), pulledUpCandidateAggregateValueOptional.get()); + } + + return AggregateMappings.of(matchedAggregateMapBuilder.build(), aggregateMappings.getUnmatchedAggregateMap()); } @Nonnull @@ -560,7 +612,7 @@ public Map collectPulledUpPredicateMappings(@N final var originalQueryPredicate = childPredicateMappingEntry.getKey(); final var childPredicateMapping = childPredicateMappingEntry.getValue(); final var pulledUpPredicateOptional = - childPredicateMapping.getTranslatedQueryPredicate().replaceValuesMaybe(pullUp::pullUpMaybe); + childPredicateMapping.getTranslatedQueryPredicate().replaceValuesMaybe(pullUp::pullUpValueMaybe); pulledUpPredicateOptional.ifPresent(queryPredicate -> resultsMap.put(originalQueryPredicate, childPredicateMapping.withTranslatedQueryPredicate(queryPredicate))); @@ -581,9 +633,6 @@ class AdjustedBuilder { @Nonnull private List matchedOrderingParts; - @Nonnull - private AggregateMappings aggregateMappings; - /** * A map of maximum matches between the query result {@code Value} and the corresponding candidate's result * {@code Value}. @@ -591,6 +640,9 @@ class AdjustedBuilder { @Nonnull private MaxMatchMap maxMatchMap; + @Nonnull + private AggregateMappings aggregateMappings; + private AdjustedBuilder(@Nonnull final MatchInfo underlying, @Nonnull final List matchedOrderingParts, @Nonnull final MaxMatchMap maxMatchMap, @@ -628,8 +680,6 @@ public AdjustedBuilder setMaxMatchMap(@Nonnull final MaxMatchMap maxMatchMap) { return this; } - - @Nonnull public AggregateMappings getAggregateMappings() { return aggregateMappings; diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PartialMatch.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PartialMatch.java index 43d5b4de9c..be6a1e5ea1 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PartialMatch.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PartialMatch.java @@ -26,6 +26,7 @@ import com.apple.foundationdb.record.query.plan.cascades.predicates.Placeholder; import com.apple.foundationdb.record.query.plan.cascades.predicates.QueryPredicate; import com.apple.foundationdb.record.query.plan.cascades.values.translation.PullUp; +import com.apple.foundationdb.record.util.pair.Pair; import com.google.common.base.Equivalence; import com.google.common.base.Suppliers; import com.google.common.base.Verify; @@ -328,7 +329,7 @@ public Map pullUpToParent(@Nonnull final Corre final var originalQueryPredicate = childPredicateMappingEntry.getKey(); final var childPredicateMapping = childPredicateMappingEntry.getValue(); final var pulledUpPredicateOptional = - childPredicateMapping.getTranslatedQueryPredicate().replaceValuesMaybe(pullUp::pullUpMaybe); + childPredicateMapping.getTranslatedQueryPredicate().replaceValuesMaybe(pullUp::pullUpValueMaybe); pulledUpPredicateOptional.ifPresent(queryPredicate -> resultsMap.put(originalQueryPredicate, childPredicateMapping.withTranslatedQueryPredicate(queryPredicate))); @@ -369,7 +370,13 @@ public Map getPulledUpPredicateMappings(@Nonnu @Nonnull public Compensation compensateCompleteMatch(@Nonnull final CorrelationIdentifier candidateTopAlias) { - return queryExpression.compensate(this, getBoundParameterPrefixMap(), null, candidateTopAlias); + return compensateCompleteMatch(null, candidateTopAlias); + } + + @Nonnull + public Compensation compensateCompleteMatch(@Nullable PullUp unificationPullUp, + @Nonnull final CorrelationIdentifier candidateTopAlias) { + return queryExpression.compensate(this, getBoundParameterPrefixMap(), unificationPullUp, candidateTopAlias); } @Nonnull @@ -384,13 +391,21 @@ public Compensation compensateExistential(@Nonnull final Map nestPullUp(@Nullable final PullUp pullUp, + @Nonnull final CorrelationIdentifier candidateAlias) { + PullUp rootOfMatchPullUp = null; var currentMatchInfo = getMatchInfo(); var currentCandidateRef = candidateRef; var currentPullUp = pullUp; @@ -400,6 +415,9 @@ public PullUp nestPullUp(@Nullable final PullUp pullUp, @Nonnull final Correlati PullUp.visitor(currentPullUp, currentCandidateAlias); final var currentCandidateExpression = currentCandidateRef.get(); currentPullUp = nestingVisitor.visit(currentCandidateRef.get()); + if (!(pullUp instanceof PullUp.MatchPullUp) && rootOfMatchPullUp == null) { + rootOfMatchPullUp = currentPullUp; + } if (!currentMatchInfo.isAdjusted()) { break; } @@ -412,7 +430,7 @@ public PullUp nestPullUp(@Nullable final PullUp pullUp, @Nonnull final Correlati currentMatchInfo = ((MatchInfo.AdjustedMatchInfo)currentMatchInfo).getUnderlying(); } - return currentPullUp; + return Pair.of(rootOfMatchPullUp, currentPullUp); } /** diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/WithPrimaryKeyMatchCandidate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/WithPrimaryKeyMatchCandidate.java index 8a6d3b9a07..2759d701fe 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/WithPrimaryKeyMatchCandidate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/WithPrimaryKeyMatchCandidate.java @@ -32,33 +32,4 @@ public interface WithPrimaryKeyMatchCandidate extends MatchCandidate { @Nonnull Optional> getPrimaryKeyValuesMaybe(); - - @Nonnull - static Optional> commonRecordKeyValuesMaybe(@Nonnull Iterable matchCandidates) { - List common = null; - var first = true; - for (final var matchCandidate : matchCandidates) { - final List key; - if (matchCandidate instanceof WithPrimaryKeyMatchCandidate) { - final var withPrimaryKeyMatchCandidate = (WithPrimaryKeyMatchCandidate)matchCandidate; - final var keyMaybe = withPrimaryKeyMatchCandidate.getPrimaryKeyValuesMaybe(); - if (keyMaybe.isEmpty()) { - return Optional.empty(); - } - key = keyMaybe.get(); - } else if (matchCandidate instanceof AggregateIndexMatchCandidate) { - final var aggregateIndexMatchCandidate = (AggregateIndexMatchCandidate)matchCandidate; - key = aggregateIndexMatchCandidate.getGroupByValues(); - } else { - return Optional.empty(); - } - if (first) { - common = key; - first = false; - } else if (!common.equals(key)) { - return Optional.empty(); - } - } - return Optional.ofNullable(common); // common can only be null if we didn't have any match candidates to start with - } } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java index e4a597344e..439e5301f6 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java @@ -25,6 +25,7 @@ import com.apple.foundationdb.record.PlanSerializationContext; import com.apple.foundationdb.record.planprotos.PValue; import com.apple.foundationdb.record.query.expressions.Comparisons; +import com.apple.foundationdb.record.query.plan.cascades.AggregateMappings; import com.apple.foundationdb.record.query.plan.cascades.AliasMap; import com.apple.foundationdb.record.query.plan.cascades.BooleanWithConstraint; import com.apple.foundationdb.record.query.plan.cascades.Column; @@ -34,7 +35,6 @@ import com.apple.foundationdb.record.query.plan.cascades.IdentityBiMap; import com.apple.foundationdb.record.query.plan.cascades.LinkedIdentityMap; import com.apple.foundationdb.record.query.plan.cascades.MatchInfo; -import com.apple.foundationdb.record.query.plan.cascades.AggregateMappings; import com.apple.foundationdb.record.query.plan.cascades.MatchInfo.RegularMatchInfo; import com.apple.foundationdb.record.query.plan.cascades.OrderingPart.RequestedOrderingPart; import com.apple.foundationdb.record.query.plan.cascades.OrderingPart.RequestedSortOrder; @@ -64,6 +64,7 @@ import com.apple.foundationdb.record.query.plan.cascades.values.translation.TranslationMap; import com.apple.foundationdb.record.query.plan.explain.ExplainTokens; import com.apple.foundationdb.record.query.plan.explain.ExplainTokensWithPrecedence; +import com.apple.foundationdb.record.util.pair.Pair; import com.google.common.base.Suppliers; import com.google.common.base.Verify; import com.google.common.collect.ImmutableBiMap; @@ -114,7 +115,8 @@ public class GroupByExpression implements RelationalExpressionWithChildren, Inte /** * Creates a new instance of {@link GroupByExpression}. * - * @param groupingValue The grouping {@code Value} used to determine individual groups, can be {@code null} indicating no grouping. + * @param groupingValue The grouping {@code Value} used to determine individual groups, can be {@code null} + * indicating no grouping. * @param aggregateValue The aggregation {@code Value} applied to each group. * @param resultValueFunction a bi-function that allows us to create the actual result value of this expression * @param innerQuantifier The underlying source of tuples to be grouped. @@ -360,11 +362,20 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid } } - final var subsumedGroupings = - subsumedAggregations - .compose(ignored -> groupingSubsumedBy(candidateInnerQuantifier, - Objects.requireNonNull(partialMatchMap.getUnwrapped(innerQuantifier)), - candidateGroupingValue, translationMap, valueEquivalence)); + final BooleanWithConstraint subsumedGroupings; + final List rollUpToGroupingValues; + if (subsumedAggregations.isTrue()) { + final var groupingSubSubsumedByPair = + groupingSubsumedBy(candidateInnerQuantifier, + Objects.requireNonNull(partialMatchMap.getUnwrapped(innerQuantifier)), + candidateGroupingValue, translationMap, valueEquivalence); + subsumedGroupings = Objects.requireNonNull(groupingSubSubsumedByPair.getLeft()); + rollUpToGroupingValues = groupingSubSubsumedByPair.getRight(); + Verify.verify(subsumedGroupings.isTrue() || rollUpToGroupingValues == null); + } else { + subsumedGroupings = falseValue(); + rollUpToGroupingValues = null; + } if (subsumedGroupings.isFalse()) { return ImmutableList.of(); @@ -383,7 +394,7 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid return RegularMatchInfo.tryMerge(bindingAliasMap, partialMatchMap, ImmutableMap.of(), PredicateMap.empty(), maxMatchMap, AggregateMappings.of(matchedAggregateMapBuilder.build(), unmatchedAggregateMapBuilder.build()), - queryPlanConstraint) + rollUpToGroupingValues, queryPlanConstraint) .map(ImmutableList::of) .orElse(ImmutableList.of()); } @@ -399,19 +410,19 @@ private Optional onUnmatchedValue(@Nonnull final Map> groupingSubsumedBy(@Nonnull final Quantifier candidateInnerQuantifier, + @Nonnull final PartialMatch childMatch, + @Nullable final Value candidateGroupingValue, + @Nonnull final TranslationMap translationMap, + @Nonnull final ValueEquivalence valueEquivalence) { if (groupingValue == null && candidateGroupingValue == null) { - return alwaysTrue(); + return Pair.of(alwaysTrue(), ImmutableList.of()); } if (candidateGroupingValue == null) { - return falseValue(); + return Pair.of(falseValue(), null); } - final Set translatedGroupingValues; + final List translatedGroupingValues; if (groupingValue != null) { final var translatedGroupingValue = groupingValue.translateCorrelations(translationMap, true); translatedGroupingValues = @@ -419,23 +430,25 @@ private BooleanWithConstraint groupingSubsumedBy(@Nonnull final Quantifier candi () -> translatedGroupingValue).stream() .map(primitiveGroupingValue -> primitiveGroupingValue.simplify(AliasMap.emptyMap(), ImmutableSet.of())) - .collect(ImmutableSet.toImmutableSet()); + .collect(ImmutableList.toImmutableList()); } else { - translatedGroupingValues = ImmutableSet.of(); + translatedGroupingValues = ImmutableList.of(); } + final Set translatedGroupingValuesSet = ImmutableSet.copyOf(translatedGroupingValues); final var candidateGroupingValues = Values.primitiveAccessorsForType(candidateGroupingValue.getResultType(), () -> candidateGroupingValue).stream() .map(primitiveGroupingValue -> primitiveGroupingValue.simplify(AliasMap.emptyMap(), ImmutableSet.of())) - .collect(ImmutableSet.toImmutableSet()); + .collect(ImmutableList.toImmutableList()); // // If there are more groupingValues than candidateGroupingValues, we cannot match the index. // - if (translatedGroupingValues.size() > candidateGroupingValues.size()) { - return falseValue(); + final var unmatchedCandidateValues = new LinkedHashSet<>(candidateGroupingValues); + if (translatedGroupingValuesSet.size() > unmatchedCandidateValues.size()) { + return Pair.of(falseValue(), null); } // @@ -451,15 +464,14 @@ private BooleanWithConstraint groupingSubsumedBy(@Nonnull final Quantifier candi // 3. For each candidate grouping value in the set of (yet) unmatched candidate group values, try to find a // predicate that binds that groupingValue. // - final var unmatchedCandidateValues = new LinkedHashSet<>(candidateGroupingValues); var booleanWithConstraint = alwaysTrue(); - for (final var groupingPartValue : translatedGroupingValues) { + for (final var translatedGroupingValue : translatedGroupingValuesSet) { var found = false; for (final var iterator = unmatchedCandidateValues.iterator(); iterator.hasNext(); ) { final var candidateGroupingPartValue = iterator.next(); final var semanticEquals = - groupingPartValue.semanticEquals(candidateGroupingPartValue, valueEquivalence); + translatedGroupingValue.semanticEquals(candidateGroupingPartValue, valueEquivalence); if (semanticEquals.isTrue()) { found = true; booleanWithConstraint = booleanWithConstraint.composeWithOther(semanticEquals); @@ -472,7 +484,7 @@ private BooleanWithConstraint groupingSubsumedBy(@Nonnull final Quantifier candi } } if (!found) { - return falseValue(); + return Pair.of(falseValue(), null); } if (unmatchedCandidateValues.isEmpty()) { break; @@ -481,7 +493,7 @@ private BooleanWithConstraint groupingSubsumedBy(@Nonnull final Quantifier candi if (unmatchedCandidateValues.isEmpty()) { // return with a positive result if sets where in fact semantically equal - return booleanWithConstraint; + return Pair.of(booleanWithConstraint, null); } // @@ -538,7 +550,23 @@ private BooleanWithConstraint groupingSubsumedBy(@Nonnull final Quantifier candi } } - return unmatchedCandidateValues.isEmpty() ? booleanWithConstraint : falseValue(); + if (!unmatchedCandidateValues.isEmpty()) { + Verify.verify(candidateGroupingValues.size() > translatedGroupingValues.size()); + // + // This is a potential roll-up case, but only if the query side's groupings are completely subsumed + // by the prefix of the candidate side. Iterate up to the smaller query side's grouping values to + // find out. + // + for (int i = 0; i < translatedGroupingValues.size(); i++) { + if (unmatchedCandidateValues.contains(candidateGroupingValues.get(i))) { + return Pair.of(falseValue(), null); + } + } + + return Pair.of(booleanWithConstraint, translatedGroupingValues); + } + + return Pair.of(booleanWithConstraint, null); } @Nonnull @@ -571,7 +599,11 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, final var regularMatchInfo = partialMatch.getRegularMatchInfo(); final var quantifier = Iterables.getOnlyElement(getQuantifiers()); - final var adjustedPullUp = partialMatch.nestPullUp(pullUp, candidateAlias); + final var nestedPullUpPair = + partialMatch.nestPullUp(pullUp, candidateAlias); + final var rootOfMatchPullUp = nestedPullUpPair.getKey(); + final var adjustedPullUp = Objects.requireNonNull(nestedPullUpPair.getRight()); + // if the match requires, for the moment, any, compensation, we reject it. final Optional childCompensationOptional = regularMatchInfo.getChildPartialMatchMaybe(quantifier) @@ -599,14 +631,13 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, boolean isCompensationImpossible = false; final ResultCompensationFunction resultCompensationFunction; final AggregateMappings pulledUpAggregateMappings; - if (pullUp != null) { + if (rootOfMatchPullUp == null) { resultCompensationFunction = ResultCompensationFunction.noCompensationNeeded(); pulledUpAggregateMappings = AggregateMappings.empty(); } else { - final var rootPullUp = adjustedPullUp.getRootPullUp(); final var maxMatchMap = matchInfo.getMaxMatchMap(); final var pulledUpTranslatedResultValueOptional = - rootPullUp.pullUpMaybe(maxMatchMap.getQueryValue()); + rootOfMatchPullUp.pullUpValueMaybe(maxMatchMap.getQueryValue()); if (pulledUpTranslatedResultValueOptional.isEmpty()) { return Compensation.impossibleCompensation(); } @@ -618,7 +649,7 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, isCompensationImpossible |= resultCompensationFunction.isImpossible(); pulledUpAggregateMappings = - RegularMatchInfo.pullUpAggregateMappings(partialMatch, candidateAlias); + RegularMatchInfo.pullUpAggregateCandidateMappings(partialMatch, rootOfMatchPullUp); } final var unmatchedQuantifiers = partialMatch.getUnmatchedQuantifiers(); diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/LogicalTypeFilterExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/LogicalTypeFilterExpression.java index dab99a25d9..84e8ac69c1 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/LogicalTypeFilterExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/LogicalTypeFilterExpression.java @@ -186,7 +186,10 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, @Nonnull final CorrelationIdentifier candidateAlias) { final var matchInfo = partialMatch.getMatchInfo(); final var regularMatchInfo = partialMatch.getRegularMatchInfo(); - final var adjustedPullUp = partialMatch.nestPullUp(pullUp, candidateAlias); + final var nestedPullUpPair = + partialMatch.nestPullUp(pullUp, candidateAlias); + final var rootOfMatchPullUp = nestedPullUpPair.getKey(); + final var adjustedPullUp = Objects.requireNonNull(nestedPullUpPair.getRight()); final var bindingAliasMap = regularMatchInfo.getBindingAliasMap(); final PartialMatch childPartialMatch = @@ -205,14 +208,13 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, boolean isCompensationImpossible = false; final ResultCompensationFunction resultCompensationFunction; final AggregateMappings aggregateMappings; - if (pullUp != null) { + if (rootOfMatchPullUp == null) { resultCompensationFunction = ResultCompensationFunction.noCompensationNeeded(); aggregateMappings = AggregateMappings.empty(); } else { - final var rootPullUp = adjustedPullUp.getRootPullUp(); final var maxMatchMap = matchInfo.getMaxMatchMap(); final var pulledUpTranslatedResultValueOptional = - rootPullUp.pullUpMaybe(maxMatchMap.getQueryValue()); + rootOfMatchPullUp.pullUpValueMaybe(maxMatchMap.getQueryValue()); if (pulledUpTranslatedResultValueOptional.isEmpty()) { return Compensation.impossibleCompensation(); } @@ -223,7 +225,7 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, isCompensationImpossible |= resultCompensationFunction.isImpossible(); aggregateMappings = - RegularMatchInfo.pullUpAggregateMappings(partialMatch, candidateAlias); + RegularMatchInfo.pullUpAggregateCandidateMappings(partialMatch, rootOfMatchPullUp); } final var unmatchedQuantifiers = partialMatch.getUnmatchedQuantifiers(); diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java index 0b092eec4a..af5db496ea 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java @@ -464,7 +464,7 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid MaxMatchMap.compute(translatedResultValue, candidateExpression.getResultValue(), Quantifiers.aliases(candidateExpression.getQuantifiers()), bindingValueEquivalence); return RegularMatchInfo.tryMerge(bindingAliasMap, partialMatchMap, mergedParameterBindingMap, - PredicateMap.empty(), maxMatchMap, AggregateMappings.empty(), + PredicateMap.empty(), maxMatchMap, AggregateMappings.empty(), null, maxMatchMap.getQueryPlanConstraint()) .map(ImmutableList::of) .orElse(ImmutableList.of()); @@ -584,7 +584,7 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid bindingValueEquivalence); return RegularMatchInfo.tryMerge(bindingAliasMap, partialMatchMap, allParameterBindingMap, predicateMap, - maxMatchMap, AggregateMappings.empty(), + maxMatchMap, AggregateMappings.empty(), null, maxMatchMap.getQueryPlanConstraint()); }) .map(ImmutableList::of) @@ -775,8 +775,10 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, final var regularMatchInfo = partialMatch.getRegularMatchInfo(); final var quantifiers = getQuantifiers(); - final var adjustedPullUp = + final var nestedPullUpPair = partialMatch.nestPullUp(pullUp, candidateAlias); + final var rootOfMatchPullUp = nestedPullUpPair.getKey(); + final var adjustedPullUp = Objects.requireNonNull(nestedPullUpPair.getRight()); // // The partial match we are called with here has child matches that have compensations on their own. @@ -863,14 +865,13 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, final ResultCompensationFunction resultCompensationFunction; final AggregateMappings aggregateMappings; - if (pullUp != null) { + if (rootOfMatchPullUp == null) { resultCompensationFunction = ResultCompensationFunction.noCompensationNeeded(); aggregateMappings = AggregateMappings.empty(); } else { - final var rootPullUp = adjustedPullUp.getRootPullUp(); final var maxMatchMap = matchInfo.getMaxMatchMap(); final var pulledUpTranslatedResultValueOptional = - rootPullUp.pullUpMaybe(maxMatchMap.getQueryValue()); + rootOfMatchPullUp.pullUpValueMaybe(maxMatchMap.getQueryValue()); if (pulledUpTranslatedResultValueOptional.isEmpty()) { return Compensation.impossibleCompensation(); } @@ -881,7 +882,7 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, isAnyCompensationFunctionImpossible |= resultCompensationFunction.isImpossible(); aggregateMappings = - RegularMatchInfo.pullUpAggregateMappings(partialMatch, candidateAlias); + RegularMatchInfo.pullUpAggregateCandidateMappings(partialMatch, rootOfMatchPullUp); } final var isCompensationNeeded = diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/LeafQueryPredicate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/LeafQueryPredicate.java index 4640a89577..c7d33ebfbe 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/LeafQueryPredicate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/LeafQueryPredicate.java @@ -80,7 +80,7 @@ default PredicateMultiMap.PredicateCompensationFunction computeCompensationFunct @Nonnull default PredicateMultiMap.PredicateCompensationFunction computeCompensationFunctionForLeaf(@Nonnull final PullUp pullUp) { return toResidualPredicate() - .replaceValuesMaybe(pullUp::pullUpMaybe) + .replaceValuesMaybe(pullUp::pullUpValueMaybe) .map(PredicateMultiMap.PredicateCompensationFunction::ofPredicate) .orElse(PredicateMultiMap.PredicateCompensationFunction.impossibleCompensation()); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/QueryPredicate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/QueryPredicate.java index 95ee0f349d..ffc2363b32 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/QueryPredicate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/QueryPredicate.java @@ -248,7 +248,7 @@ default PredicateCompensationFunction computeCompensationFunction(@Nonnull final Verify.verify(childrenResults.isEmpty()); return toResidualPredicate() - .replaceValuesMaybe(pullUp::pullUpMaybe) + .replaceValuesMaybe(pullUp::pullUpValueMaybe) .map(PredicateCompensationFunction::ofPredicate) .orElse(PredicateCompensationFunction.impossibleCompensation()); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java index 07902fa50e..374f21b21a 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java @@ -23,6 +23,7 @@ import com.apple.foundationdb.annotation.API; import com.apple.foundationdb.record.RecordCoreException; import com.apple.foundationdb.record.query.combinatorics.ChooseK; +import com.apple.foundationdb.record.query.plan.cascades.AggregateIndexMatchCandidate; import com.apple.foundationdb.record.query.plan.cascades.CascadesPlanner; import com.apple.foundationdb.record.query.plan.cascades.CascadesRule; import com.apple.foundationdb.record.query.plan.cascades.CascadesRuleCall; @@ -286,9 +287,10 @@ protected Set dataAccessForMatchPartition(@Nonnu distinctMatchToScanMap(call, bestMatchToPlanMap); final var commonPrimaryKeyValuesOptional = - WithPrimaryKeyMatchCandidate.commonRecordKeyValuesMaybe( + commonRecordKeyValuesMaybe( bestMaximumCoverageMatches.stream() - .map(singleMatchedAccessVectored -> singleMatchedAccessVectored.getElement().getPartialMatch().getMatchCandidate()) + .map(singleMatchedAccessVectored -> + singleMatchedAccessVectored.getElement().getPartialMatch()) .collect(ImmutableList.toImmutableList())); if (commonPrimaryKeyValuesOptional.isEmpty() || bestMaximumCoverageMatches.size() == 1) { return intersectionInfoMapToExpressions(intersectionInfoMap); @@ -420,6 +422,52 @@ protected Set dataAccessForMatchPartition(@Nonnu return intersectionInfoMapToExpressions(intersectionInfoMap); } + @Nonnull + private static Optional> commonRecordKeyValuesMaybe(@Nonnull Iterable partialMatches) { + List common = null; + var first = true; + for (final var partialMatch : partialMatches) { + final var matchCandidate = partialMatch.getMatchCandidate(); + final var regularMatchInfo = partialMatch.getRegularMatchInfo(); + + final List key; + if (matchCandidate instanceof WithPrimaryKeyMatchCandidate) { + final var withPrimaryKeyMatchCandidate = (WithPrimaryKeyMatchCandidate)matchCandidate; + final var keyMaybe = withPrimaryKeyMatchCandidate.getPrimaryKeyValuesMaybe(); + if (keyMaybe.isEmpty()) { + return Optional.empty(); + } + key = keyMaybe.get(); + } else if (matchCandidate instanceof AggregateIndexMatchCandidate) { + final var aggregateIndexMatchCandidate = (AggregateIndexMatchCandidate)matchCandidate; + final var rollUpToGroupingValues = regularMatchInfo.getRollUpToGroupingValues(); + if (rollUpToGroupingValues == null) { + key = aggregateIndexMatchCandidate.getGroupByValues(); + } else { + key = aggregateIndexMatchCandidate.getGroupByValues().subList(0, rollUpToGroupingValues.size()); + } + +// final var aggregateIndexMatchCandidate = (AggregateIndexMatchCandidate)matchCandidate; +// final var rollUpToGroupingValues = regularMatchInfo.getRollUpToGroupingValues(); +// if (rollUpToGroupingValues == null) { +// key = aggregateIndexMatchCandidate.getGroupingAndAggregateAccessors(Quantifier.current()).getLeft(); +// } else { +// key = aggregateIndexMatchCandidate.getGroupingAndAggregateAccessors(rollUpToGroupingValues.size(), +// Quantifier.current()).getLeft(); +// } + } else { + return Optional.empty(); + } + if (first) { + common = key; + first = false; + } else if (!common.equals(key)) { + return Optional.empty(); + } + } + return Optional.ofNullable(common); // common can only be null if we didn't have any match candidates to start with + } + @Nonnull private static BitSet[] newSquareBitMatrix(final int size) { BitSet[] matrix = new BitSet[size]; @@ -551,12 +599,17 @@ private static List prepareMatchesAndCompensations(final @N Verify.verify(scanDirection == ScanDirection.FORWARD || scanDirection == ScanDirection.REVERSE || scanDirection == ScanDirection.BOTH); + final var topAlias = Quantifier.uniqueId(); final var candidateTopAlias = Quantifier.uniqueId(); - final var compensation = partialMatch.compensateCompleteMatch(candidateTopAlias); + final var unificationPullUp = + partialMatch.prepareForUnification(topAlias, candidateTopAlias); + final var compensation = + partialMatch.compensateCompleteMatch(unificationPullUp, + unificationPullUp == null ? topAlias : candidateTopAlias); if (scanDirection == ScanDirection.FORWARD || scanDirection == ScanDirection.BOTH) { partialMatchesWithCompensation.add(new SingleMatchedAccess(partialMatch, compensation, - candidateTopAlias, false, satisfyingOrderingsPair.getRight())); + topAlias, false, satisfyingOrderingsPair.getRight())); } // @@ -569,7 +622,7 @@ private static List prepareMatchesAndCompensations(final @N // if (scanDirection == ScanDirection.REVERSE /* || scanDirection == ScanDirection.BOTH */) { partialMatchesWithCompensation.add(new SingleMatchedAccess(partialMatch, compensation, - candidateTopAlias, true, satisfyingOrderingsPair.getRight())); + topAlias, true, satisfyingOrderingsPair.getRight())); } } @@ -728,7 +781,8 @@ private static Map createScansForMatches(@Nonnull final var singleMatchedAccess = singleMatchedAccessVectored.getElement(); final var partialMatch = singleMatchedAccess.getPartialMatch(); return partialMatch.getMatchCandidate() - .toEquivalentPlan(partialMatch, planContext, memoizer, singleMatchedAccess.isReverseScanOrder()); + .toEquivalentPlan(partialMatch, planContext, memoizer, + singleMatchedAccess.isReverseScanOrder()); })); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java index 50d32ab54f..0358356f1d 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java @@ -145,14 +145,17 @@ public void onMatch(@Nonnull final CascadesRuleCall call) { // loop through all compensated alias sets and their associated match partitions for (final var matchPartitionByMatchAliasEntry : matchPartitionByMatchAliasMap.entrySet()) { final var matchedAlias = matchPartitionByMatchAliasEntry.getKey(); - final var matchPartitionForMatchedAlias = matchPartitionByMatchAliasEntry.getValue(); + final var matchPartitionForMatchedAlias = + matchPartitionByMatchAliasEntry.getValue(); // // Pull down the requested orderings along the matchedAlias // final var pushedRequestedOrderings = requestedOrderings.stream() - .map(requestedOrdering -> requestedOrdering.pushDown(expression.getResultValue(), matchedAlias, AliasMap.emptyMap(), correlatedTo)) + .map(requestedOrdering -> + requestedOrdering.pushDown(expression.getResultValue(), matchedAlias, + AliasMap.emptyMap(), correlatedTo)) .collect(ImmutableSet.toImmutableSet()); // @@ -290,7 +293,7 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me @Nonnull private static NonnullPair, List> computeCommonAndPickUpValues(@Nonnull final List> partition, - final int numGrouped) { + final int numGroupings) { final var commonValuesAndPickUpValueByAccess = partition .stream() @@ -299,14 +302,13 @@ private static NonnullPair, List> computeCommonAndPickUpValue .getPartialMatch() .getMatchCandidate()) .map(matchCandidate -> (AggregateIndexMatchCandidate)matchCandidate) - .map(AggregateIndexMatchCandidate::getGroupingAndAggregateAccessors) + .map(aggregateIndexMatchCandidate -> + aggregateIndexMatchCandidate.getGroupingAndAggregateAccessors(numGroupings, Quantifier.current())) .collect(ImmutableList.toImmutableList()); final var pickUpValuesBuilder = ImmutableList.builder(); for (int i = 0; i < commonValuesAndPickUpValueByAccess.size(); i++) { final var commonAndPickUpValuePair = commonValuesAndPickUpValueByAccess.get(i); - final var commonValues = commonAndPickUpValuePair.getLeft(); - Verify.verify(commonValues.size() == numGrouped); final var pickUpValue = commonAndPickUpValuePair.getRight(); pickUpValuesBuilder.add(pickUpValue); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/typing/Type.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/typing/Type.java index f7b57e3850..6b54bfed48 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/typing/Type.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/typing/Type.java @@ -2108,7 +2108,7 @@ public ExplainTokens describe() { } if (i + 1 < getFields().size()) { - return resultExplainTokens.addCommaAndWhiteSpace(); + resultExplainTokens.addCommaAndWhiteSpace(); } i ++; } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/Values.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/Values.java index 2440c99e55..3ee19ad972 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/Values.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/Values.java @@ -46,7 +46,7 @@ public class Values { * @return a list of field values */ @Nonnull - public static List deconstructRecord(@Nonnull Value recordValue) { + public static List deconstructRecord(@Nonnull final Value recordValue) { final var resultType = recordValue.getResultType(); Verify.verify(resultType.isRecord()); Verify.verify(resultType instanceof Type.Record); diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/translation/PullUp.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/translation/PullUp.java index 8c7db7845d..a055d5e788 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/translation/PullUp.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/translation/PullUp.java @@ -30,7 +30,9 @@ import com.apple.foundationdb.record.query.plan.cascades.typing.Type; import com.apple.foundationdb.record.query.plan.cascades.values.QuantifiedObjectValue; import com.apple.foundationdb.record.query.plan.cascades.values.Value; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -49,7 +51,6 @@ public class PullUp { private final Value pullThroughValue; @Nonnull private final Set rangedOverAliases; - @Nonnull private final PullUp rootPullUp; @@ -94,26 +95,28 @@ public Set getRangedOverAliases() { } @Nonnull - public CorrelationIdentifier getTopAlias() { - return getRootPullUp().getCandidateAlias(); + private static PullUp forMatch(@Nullable final PullUp parentPullUp, + @Nonnull final CorrelationIdentifier candidateAlias, + @Nonnull final CorrelationIdentifier lowerAlias, + @Nonnull final Type lowerType, + @Nonnull final Set rangedOverAliases) { + return forMatch(parentPullUp, candidateAlias, QuantifiedObjectValue.of(lowerAlias, lowerType), + rangedOverAliases); } @Nonnull - private static PullUp of(@Nullable final PullUp parentPullUp, - @Nonnull final CorrelationIdentifier candidateAlias, - @Nonnull final CorrelationIdentifier lowerAlias, - @Nonnull final Type lowerType, - @Nonnull final Set rangedOverAliases) { - return of(parentPullUp, candidateAlias, QuantifiedObjectValue.of(lowerAlias, lowerType), - rangedOverAliases); + private static PullUp forMatch(@Nullable final PullUp parentPullUp, + @Nonnull final CorrelationIdentifier candidateAlias, + @Nonnull final Value lowerPullThroughValue, + @Nonnull final Set rangedOverAliases) { + return new MatchPullUp(parentPullUp, candidateAlias, lowerPullThroughValue, rangedOverAliases); } @Nonnull - private static PullUp of(@Nullable final PullUp parentPullUp, - @Nonnull final CorrelationIdentifier candidateAlias, - @Nonnull final Value lowerPullThroughValue, - @Nonnull final Set rangedOverAliases) { - return new PullUp(parentPullUp, candidateAlias, lowerPullThroughValue, rangedOverAliases); + public static UnificationPullUp forUnification(@Nonnull final CorrelationIdentifier candidateAlias, + @Nonnull final Value lowerPullThroughValue, + @Nonnull final Set rangedOverAliases) { + return new UnificationPullUp(null, candidateAlias, lowerPullThroughValue, rangedOverAliases); } /** @@ -130,7 +133,7 @@ private static PullUp of(@Nullable final PullUp parentPullUp, * {@code value} could not be pulled up. */ @Nonnull - public Optional pullUpMaybe(@Nonnull final Value value) { + public Optional pullUpValueMaybe(@Nonnull final Value value) { // // The following loop would probably be more self-explanatory if it were written as a recursion but // this unrolled version probably performs better as this may prove to be a tight loop. @@ -154,6 +157,35 @@ public Optional pullUpMaybe(@Nonnull final Value value) { } } + @Nonnull + public Optional pullUpCandidateValueMaybe(@Nonnull final Value value) { + // + // The following loop would probably be more self-explanatory if it were written as a recursion but + // this unrolled version probably performs better as this may prove to be a tight loop. + // + var currentValue = value; + for (var currentPullUp = this; ; currentPullUp = currentPullUp.getParentPullUp()) { + final var currentPullThroughValue = currentPullUp.getPullThroughValue(); + final var currentRangedOverAliases = currentPullUp.getRangedOverAliases(); + final var currentCandidateAlias = currentPullUp.getCandidateAlias(); + final var candidatePullUpMap = + currentPullThroughValue.pullUp(ImmutableList.of(currentValue), + AliasMap.emptyMap(), + Sets.difference(currentValue.getCorrelatedToWithoutChildren(), + currentRangedOverAliases), + currentCandidateAlias); + final var pulledUpCandidateAggregateValue = candidatePullUpMap.get(currentValue); + if (pulledUpCandidateAggregateValue == null) { + return Optional.empty(); + } + currentValue = pulledUpCandidateAggregateValue; + + if (currentPullUp.getParentPullUp() == null) { + return Optional.of(currentValue); + } + } + } + @Nonnull public static RelationalExpressionVisitor visitor(@Nullable final PullUp parentPullUp, @Nonnull final CorrelationIdentifier candidateAlias) { @@ -175,7 +207,7 @@ public PullUpVisitor(@Nullable final PullUp parentPullUp, @Nonnull @Override public PullUp visitLogicalTypeFilterExpression(@Nonnull final LogicalTypeFilterExpression logicalTypeFilterExpression) { - return of(parentPullUp, candidateAlias, logicalTypeFilterExpression.getInnerQuantifier().getAlias(), + return forMatch(parentPullUp, candidateAlias, logicalTypeFilterExpression.getInnerQuantifier().getAlias(), logicalTypeFilterExpression.getInnerQuantifier().getFlowedObjectType(), Quantifiers.aliases(logicalTypeFilterExpression.getQuantifiers())); } @@ -183,8 +215,26 @@ public PullUp visitLogicalTypeFilterExpression(@Nonnull final LogicalTypeFilterE @Nonnull @Override public PullUp visitDefault(@Nonnull final RelationalExpression relationalExpression) { - return of(parentPullUp, candidateAlias, relationalExpression.getResultValue(), + return forMatch(parentPullUp, candidateAlias, relationalExpression.getResultValue(), Quantifiers.aliases(relationalExpression.getQuantifiers())); } } + + public static class MatchPullUp extends PullUp { + public MatchPullUp(@Nullable final PullUp parentPullUp, + @Nonnull final CorrelationIdentifier candidateAlias, + @Nonnull final Value pullThroughValue, + @Nonnull final Set rangedOverAliases) { + super(parentPullUp, candidateAlias, pullThroughValue, rangedOverAliases); + } + } + + public static class UnificationPullUp extends PullUp { + public UnificationPullUp(@Nullable final PullUp parentPullUp, + @Nonnull final CorrelationIdentifier candidateAlias, + @Nonnull final Value pullThroughValue, + @Nonnull final Set rangedOverAliases) { + super(parentPullUp, candidateAlias, pullThroughValue, rangedOverAliases); + } + } } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryAggregateIndexPlan.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryAggregateIndexPlan.java index 8bd4189af8..1828a4b1f6 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryAggregateIndexPlan.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryAggregateIndexPlan.java @@ -39,7 +39,6 @@ import com.apple.foundationdb.record.provider.foundationdb.FDBStoreTimer; import com.apple.foundationdb.record.query.plan.AvailableFields; import com.apple.foundationdb.record.query.plan.IndexKeyValueToPartialRecord; -import com.apple.foundationdb.record.query.plan.explain.ExplainPlanVisitor; import com.apple.foundationdb.record.query.plan.QueryPlanConstraint; import com.apple.foundationdb.record.query.plan.ScanComparisons; import com.apple.foundationdb.record.query.plan.cascades.AliasMap; @@ -54,6 +53,7 @@ import com.apple.foundationdb.record.query.plan.cascades.typing.TypeRepository; import com.apple.foundationdb.record.query.plan.cascades.values.Value; import com.apple.foundationdb.record.query.plan.cascades.values.translation.TranslationMap; +import com.apple.foundationdb.record.query.plan.explain.ExplainPlanVisitor; import com.google.auto.service.AutoService; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryIndexPlan.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryIndexPlan.java index 157efd4d04..17ecc4299e 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryIndexPlan.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/plans/RecordQueryIndexPlan.java @@ -60,6 +60,7 @@ import com.apple.foundationdb.record.provider.foundationdb.MultidimensionalIndexScanComparisons; import com.apple.foundationdb.record.provider.foundationdb.UnsupportedRemoteFetchIndexException; import com.apple.foundationdb.record.query.plan.AvailableFields; +import com.apple.foundationdb.record.query.plan.cascades.AggregateIndexMatchCandidate; import com.apple.foundationdb.record.query.plan.explain.ExplainPlanVisitor; import com.apple.foundationdb.record.query.plan.QueryPlanConstraint; import com.apple.foundationdb.record.query.plan.ScanComparisons; @@ -652,6 +653,16 @@ public PlannerGraph createIndexPlannerGraph(@Nonnull RecordQueryPlan identity, attributeMapBuilder.put("direction", Attribute.gml("reversed")); } + final var matchCandidateOptional = getMatchCandidateMaybe(); + final String extendedIndexName; + if (matchCandidateOptional.isPresent() && + matchCandidateOptional.get() instanceof AggregateIndexMatchCandidate) { + final var aggregateIndexMatchCandidate = (AggregateIndexMatchCandidate)matchCandidateOptional.get(); + extendedIndexName = aggregateIndexMatchCandidate.toString(); + } else { + extendedIndexName = getIndexName(); + } + return PlannerGraph.fromNodeAndChildGraphs( new PlannerGraph.OperatorNodeWithInfo(identity, nodeInfo, @@ -659,7 +670,7 @@ public PlannerGraph createIndexPlannerGraph(@Nonnull RecordQueryPlan identity, attributeMapBuilder.build()), ImmutableList.of( PlannerGraph.fromNodeAndChildGraphs( - new PlannerGraph.DataNodeWithInfo(NodeInfo.INDEX_DATA, getResultType(), ImmutableList.copyOf(getUsedIndexes())), + new PlannerGraph.DataNodeWithInfo(NodeInfo.INDEX_DATA, getResultType(), ImmutableList.of(extendedIndexName)), ImmutableList.of()))); } diff --git a/yaml-tests/src/test/resources/composite-aggregates.yamsql b/yaml-tests/src/test/resources/composite-aggregates.yamsql index d0230fae2f..957e18e65e 100644 --- a/yaml-tests/src/test/resources/composite-aggregates.yamsql +++ b/yaml-tests/src/test/resources/composite-aggregates.yamsql @@ -19,9 +19,11 @@ --- schema_template: - create table t1(id bigint, col1 bigint, col2 bigint, primary key(id)) + create table t1(id bigint, col1 bigint, col2 bigint, col3 bigint, primary key(id)) create table t2(id bigint, col1 bigint, col2 bigint, primary key(id)) create table t3(id bigint, col1 bigint, col2 bigint, primary key(id)) + create index t1_i1 as select sum(col1) from t1 group by col2, col3 + create index t1_i2 as select count(*) from t1 group by col2 create index t2_i1 as select count(*) from t2 create index t2_i2 as select count(*) from t2 group by col1 create index t2_i3 as select count(col2) from t2 @@ -29,8 +31,34 @@ schema_template: create index t2_i5 as select sum(col1) from t2 create index t2_i6 as select sum(col2) from t2 group by col1 create index t2_i7 as select count(*) from t2 group by col1, col2 - create index t3_i1 as select col1 from t3 - create index t3_i2 as select col2 from t3 + +--- +setup: + steps: + - query: INSERT INTO T1 + VALUES (1, 10, 1, 1), + (2, 10, 1, 1), + (3, 10, 1, 2), + (4, 10, 1, 2), + (5, 10, 1, 2), + (6, 20, 6, 1), + (7, 20, 7, 2), + (8, 20, 7, 2), + (9, 20, 7, 3), + (10, 20, 7, 3), + (11, 20, 8, 0), + (12, 20, 8, 0), + (13, 20, 10, 1) + - query: INSERT INTO T2(ID, COL1, COL2, COL3) + VALUES (1, 1, 1, 100), + (2, 1, 1, 1), + (3, 1, 5, 2), + (4, 1, 10, 200), + (5, 2, 10, 200), + (6, 2, 20, 3), + (7, 2, 30, 400), + (8, 2, 40, 400), + (9, 2, 60, 400) --- test_block: @@ -49,9 +77,25 @@ test_block: # - query: select count(*) from T2 where col1 = 3 group by col2; # - explain: "AISCAN(T2_I7 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | MAP (_._2 AS _0)" # - result: [] + #- + # - query: select sum(col2) / count(col2) from T2 group by col1; + # - explain: "AISCAN(T2_I6 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 / _._2 AS _0)" + # - result: [{!l 4}, {!l 32}] + #- + # - query: select sum(col2), count(col2) from T2 where col1 < 2 group by col1; + # - explain: "AISCAN(T2_I6 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 AS _0, _._2 AS _1)" + # - result: [{!l 17, !l 4}] + #- + # - query: select sum(col2), count(col2) from T2 group by col1 having sum(col2) = 17; + # - explain: "AISCAN(T2_I6 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | FILTER _._1 EQUALS promote(@c22 AS LONG) | MAP (_._1 AS _0, _._2 AS _1)" + # - result: [{!l 17, !l 4}] + #- + # - query: select sum(col2), count(col2) from T2 where col1 < 2 group by col1 having sum(col2) = 17; + # - explain: "AISCAN(T2_I6 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | FILTER _._1 EQUALS promote(@c26 AS LONG) | MAP (_._1 AS _0, _._2 AS _1)" + # - result: [{!l 17, !l 4}] - - - query: select sum(col2) / count(col2) from T2 group by col1; + - query: select sum(col1) / count(*) from T1 group by col2; - explain: "AISCAN(T2_I6 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 / _._2 AS _0)" - result: [] -... +... From 45040e4683352654428f7b519ec88c4db8df3b69 Mon Sep 17 00:00:00 2001 From: Normen Seemann Date: Sat, 29 Mar 2025 16:56:00 +0100 Subject: [PATCH 14/20] rollups work --- .../AggregateIndexMatchCandidate.java | 2 +- .../plan/cascades/RequestedOrdering.java | 16 ++++++++++++ .../composite-aggregates.metrics.binpb | Bin 3133 -> 1640 bytes .../composite-aggregates.metrics.yaml | 23 +++++++++--------- .../resources/composite-aggregates.yamsql | 21 +++++++++++----- 5 files changed, 43 insertions(+), 19 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java index 2da52a01ab..e3f67a04f0 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java @@ -490,7 +490,7 @@ public NonnullPair, Value> getGroupingAndAggregateAccessors(final in Verify.verify(deconstructedRecord.size() > numGroupings); final var groupingAccessorValues = ImmutableList.copyOf(deconstructedRecord.subList(0, numGroupings)); - final var aggregateAccessorValue = deconstructedRecord.get(deconstructedRecord.size() - 1); + final var aggregateAccessorValue = deconstructedRecord.get(numGroupings); return NonnullPair.of(groupingAccessorValues, aggregateAccessorValue); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/RequestedOrdering.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/RequestedOrdering.java index 58881d1f4b..628d0bc9fb 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/RequestedOrdering.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/RequestedOrdering.java @@ -28,6 +28,7 @@ import com.apple.foundationdb.record.query.plan.cascades.values.Values; import com.apple.foundationdb.record.query.plan.cascades.values.simplification.OrderingValueComputationRuleSet; import com.apple.foundationdb.record.query.plan.cascades.values.simplification.RequestedOrderingValueSimplificationRuleSet; +import com.apple.foundationdb.record.query.plan.cascades.values.translation.TranslationMap; import com.google.common.base.Suppliers; import com.google.common.base.Verify; import com.google.common.collect.ImmutableList; @@ -87,6 +88,7 @@ private RequestedOrdering(@Nonnull final List orderingPar this.valueRequestedSortOrderMapSupplier = Suppliers.memoize(this::computeValueSortOrderMap); } + @Nonnull public Distinctness getDistinctness() { return distinctness; } @@ -218,6 +220,20 @@ public RequestedOrdering pushDown(@Nonnull Value value, return new RequestedOrdering(pushedDownOrderingPartsBuilder.build(), Distinctness.PRESERVE_DISTINCTNESS, isExhaustive()); } + @Nonnull + public RequestedOrdering translate(@Nonnull TranslationMap translationMap) { + // + // Need to push every participating value of this requested ordering through the value. + // + final var pushedDownOrderingPartsBuilder = ImmutableList.builder(); + for (final var orderingPart : orderingParts) { + final var orderingValue = orderingPart.getValue(); + final var translatedOrderingValue = orderingValue.translateCorrelations(translationMap); + pushedDownOrderingPartsBuilder.add(new RequestedOrderingPart(translatedOrderingValue, orderingPart.getSortOrder())); + } + return new RequestedOrdering(pushedDownOrderingPartsBuilder.build(), Distinctness.PRESERVE_DISTINCTNESS, isExhaustive()); + } + @Nonnull private Map computeValueSortOrderMap() { return getOrderingParts() diff --git a/yaml-tests/src/test/resources/composite-aggregates.metrics.binpb b/yaml-tests/src/test/resources/composite-aggregates.metrics.binpb index e10761c2e60000de3455822cb7e3433b52da34a6..df8548f2a01d31aac6203b397b5f0160c15f0d5a 100644 GIT binary patch delta 385 zcmdlh@q(xR84p(omuO;ox^8N2K}n@j(0F*Sg7V72UlIB>%EYR6C(MVz< zqe9o7Su&qY!Uor2ys_ z#>Q$Y)F}8m1}JF6>%|)=I0h>?`}+VL0puBhc=3jsQmx#R6B+M`A;}h+!KEkrF?9<- z^!WJuxkL0!zRi?9`3%c{F@%tg0-S9$IgurA@(B)k2}gJLXt49F6$(;|a!X56Q{sW% ykDct#WIp*HdyE-O52^(~o)N-4AkSD+Ng>vnOF_X{LDx>fX!35ZlF2K%rvLyDQ*kW- delta 631 zcmaFCvsa>iw**%hmuO;ox^8N2K}n@jga(-!E36z&sl%J~*Vx*8>lwVq)kW>kj%rUeUdLYgv$+4G7;N$V_ ztP;fv^LM^w(J(f6a*NeMz=1*NF{7hrurr6FpGJsLyr2!Pd1rs$0LLI#1*b>_jd;Cy10d2=2=@%}P$)FeQ7AN22yzVx4f0da zCqzJ|V`lv?1*D(NWlp)Y}KogB1dNif(h^Azw7bO;COnh}+ z03=yxhLD}?$J{fyh$)+^B(1czEvB(wHyix WrXaP(lM`4=*vvpolg$aN9E<>Ftg`w5 diff --git a/yaml-tests/src/test/resources/composite-aggregates.metrics.yaml b/yaml-tests/src/test/resources/composite-aggregates.metrics.yaml index c2bf2e5021..47e678966f 100644 --- a/yaml-tests/src/test/resources/composite-aggregates.metrics.yaml +++ b/yaml-tests/src/test/resources/composite-aggregates.metrics.yaml @@ -1,13 +1,12 @@ agg-empty-table-tests: -- query: EXPLAIN select sum(col2) / count(col2) from T2 group by col1; - explain: 'AISCAN(T2_I6 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 - <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0._0) WITH q0, - q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 / _._2 AS _0)' - task_count: 317 - task_total_time_ms: 11 - transform_count: 115 - transform_time_ms: 10 - transform_yield_count: 51 - insert_time_ms: 0 - insert_new_count: 16 - insert_reused_count: 0 +- query: EXPLAIN select col1, min(col2) from T3 group by col1, col3; + explain: 'AISCAN(T3_I2 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) + | MAP (_._0 AS COL1, _._2 AS _1)' + task_count: 418 + task_total_time_ms: 105 + transform_count: 145 + transform_time_ms: 82 + transform_yield_count: 50 + insert_time_ms: 3 + insert_new_count: 50 + insert_reused_count: 4 diff --git a/yaml-tests/src/test/resources/composite-aggregates.yamsql b/yaml-tests/src/test/resources/composite-aggregates.yamsql index 957e18e65e..0fc54e44ab 100644 --- a/yaml-tests/src/test/resources/composite-aggregates.yamsql +++ b/yaml-tests/src/test/resources/composite-aggregates.yamsql @@ -21,9 +21,9 @@ schema_template: create table t1(id bigint, col1 bigint, col2 bigint, col3 bigint, primary key(id)) create table t2(id bigint, col1 bigint, col2 bigint, primary key(id)) - create table t3(id bigint, col1 bigint, col2 bigint, primary key(id)) - create index t1_i1 as select sum(col1) from t1 group by col2, col3 - create index t1_i2 as select count(*) from t1 group by col2 + create table t3(id bigint, col1 bigint, col2 bigint, col3 bigint, primary key(id)) + create index t1_i1 as select count(col1) from t1 group by col2, col3 + create index t1_i2 as select col2, sum(col1) from t1 group by col2 create index t2_i1 as select count(*) from t2 create index t2_i2 as select count(*) from t2 group by col1 create index t2_i3 as select count(col2) from t2 @@ -31,6 +31,8 @@ schema_template: create index t2_i5 as select sum(col1) from t2 create index t2_i6 as select sum(col2) from t2 group by col1 create index t2_i7 as select count(*) from t2 group by col1, col2 + create index t3_i1 as select col1, max(col2), col3 from T3 group by col1, col3 order by col1, max(col2), col3 + create index t3_i2 as select col1, min(col2), col3 from T3 group by col1, col3 order by col1, min(col2), col3 --- setup: @@ -93,9 +95,16 @@ test_block: # - query: select sum(col2), count(col2) from T2 where col1 < 2 group by col1 having sum(col2) = 17; # - explain: "AISCAN(T2_I6 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | FILTER _._1 EQUALS promote(@c26 AS LONG) | MAP (_._1 AS _0, _._2 AS _1)" # - result: [{!l 17, !l 4}] + #- + # - query: select sum(col1) / count(col1) from T1 group by col2; + # - explain: "AISCAN(T2_I6 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 / _._2 AS _0)" + # - result: [] + #- + # - query: select col2, sum(col1) / count(col1) from T1 where col2 < 2 group by col2 having sum(col1) = 17; + # - explain: "AISCAN(T1_I2 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T1_I1 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | AGG sum_l(_._1) GROUP BY (_._0 AS _0) COMPARE BY (_._0._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | FILTER _._1 EQUALS promote(@c26 AS LONG) | MAP (_._1 / _._2 AS _0)" + # - result: [] - - - query: select sum(col1) / count(*) from T1 group by col2; - - explain: "AISCAN(T2_I6 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 / _._2 AS _0)" + - query: select col1, min(col2), max(col2) from T3 group by col1, col3; + - explain: "AISCAN(T3_I2 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._0 AS COL1, _._2 AS _1)" - result: [] - ... From 186ddb49843ae46d5b9a230851f6004a3f7bed97 Mon Sep 17 00:00:00 2001 From: Normen Seemann Date: Wed, 2 Apr 2025 20:09:16 +0200 Subject: [PATCH 15/20] ordering sort of works --- .../query/plan/QueryPlanConstraint.java | 4 + .../AggregateIndexMatchCandidate.java | 9 +- .../plan/cascades/AggregateMappings.java | 63 ----- .../query/plan/cascades/Compensation.java | 68 +++-- .../query/plan/cascades/GroupByMappings.java | 73 ++++++ .../record/query/plan/cascades/MatchInfo.java | 243 ++++++++++-------- .../query/plan/cascades/Quantifier.java | 8 +- .../plan/cascades/RequestedOrdering.java | 4 +- .../expressions/GroupByExpression.java | 172 +++++++++---- .../LogicalTypeFilterExpression.java | 10 +- .../expressions/MatchableSortExpression.java | 2 +- .../expressions/SelectExpression.java | 16 +- .../rules/AbstractDataAccessRule.java | 84 +++--- .../rules/AggregateDataAccessRule.java | 70 +++-- .../rules/WithPrimaryKeyDataAccessRule.java | 28 +- .../values/translation/MaxMatchMap.java | 11 + .../foundationdb/UnnestedRecordTypeTest.java | 2 +- .../cascades/values/ValueTranslationTest.java | 4 +- .../lucene/search/BooleanPointsConfig.java | 2 +- .../api/metrics/NoOpMetricRegistry.java | 2 +- .../resources/composite-aggregates.yamsql | 14 +- 21 files changed, 544 insertions(+), 345 deletions(-) delete mode 100644 fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateMappings.java create mode 100644 fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/GroupByMappings.java diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/QueryPlanConstraint.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/QueryPlanConstraint.java index 59725061fe..ec26798415 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/QueryPlanConstraint.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/QueryPlanConstraint.java @@ -62,6 +62,10 @@ public QueryPredicate getPredicate() { return predicate; } + public boolean isTautology() { + return predicate.isTautology(); + } + @Override public boolean equals(final Object o) { if (this == o) { diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java index e3f67a04f0..0f488b2a75 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java @@ -215,9 +215,9 @@ public List computeMatchedOrderingParts(@Nonnull final Matc final var candidateParameterIds = getOrderingAliases(); final var normalizedValues = Sets.newHashSetWithExpectedSize(normalizedKeyExpressions.size()); - final var selectHavingResultValue = selectHavingExpression.getResultValue(); - final var deconstructedValue = Values.deconstructRecord(selectHavingResultValue); - final var aliasMap = AliasMap.ofAliases(Iterables.getOnlyElement(selectHavingResultValue.getCorrelatedTo()), Quantifier.current()); + final var selectHavingResultType = selectHavingExpression.getResultValue().getResultType(); + final var deconstructedValues = + Values.deconstructRecord(QuantifiedObjectValue.of(Quantifier.current(), selectHavingResultType)); // Compute the ordering for this index by collecting the result values of the selectHaving statement // associated with each sortParameterId. Note that for most aggregate indexes, the aggregate value is @@ -248,7 +248,7 @@ public List computeMatchedOrderingParts(@Nonnull final Matc } // Grab the value for this sortParameterID from the selectHaving result columns - final var value = deconstructedValue.get(permutedIndex).rebase(aliasMap); + final var value = deconstructedValues.get(permutedIndex); if (normalizedValues.add(value)) { final var matchedOrderingPart = @@ -286,7 +286,6 @@ public Ordering computeOrderingFromScanComparisons(@Nonnull final ScanComparison final int groupingCount = ((GroupingKeyExpression)index.getRootExpression()).getGroupingCount(); if (!isPermuted() && groupingCount == 0) { - // TODO this should be something like anything-order. return Ordering.empty(); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateMappings.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateMappings.java deleted file mode 100644 index 744f622ca1..0000000000 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateMappings.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * AggregateMappings.java - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2015-2025 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.apple.foundationdb.record.query.plan.cascades; - -import com.apple.foundationdb.record.query.plan.cascades.values.Value; -import com.google.common.collect.BiMap; -import com.google.common.collect.ImmutableBiMap; -import com.google.common.collect.ImmutableMap; - -import javax.annotation.Nonnull; -import java.util.Map; - -public class AggregateMappings { - @Nonnull - private final Map matchedAggregateMap; - - @Nonnull - private final BiMap unmatchedAggregateMap; - - private AggregateMappings(@Nonnull final Map matchedAggregateMap, - @Nonnull final BiMap unmatchedAggregateMap) { - this.matchedAggregateMap = matchedAggregateMap; - this.unmatchedAggregateMap = unmatchedAggregateMap; - } - - @Nonnull - public Map getMatchedAggregateMap() { - return matchedAggregateMap; - } - - @Nonnull - public BiMap getUnmatchedAggregateMap() { - return unmatchedAggregateMap; - } - - public static AggregateMappings empty() { - return of(ImmutableBiMap.of(), ImmutableBiMap.of()); - } - - @Nonnull - public static AggregateMappings of(@Nonnull final Map matchedAggregateMap, - @Nonnull final BiMap unmatchedAggregateMap) { - return new AggregateMappings(ImmutableMap.copyOf(matchedAggregateMap), ImmutableBiMap.copyOf(unmatchedAggregateMap)); - } -} diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java index 49d66454b5..c4d58f1e18 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java @@ -32,7 +32,6 @@ import com.google.common.base.Verify; import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; @@ -43,7 +42,6 @@ import java.util.Set; import java.util.function.Function; import java.util.function.Supplier; -import java.util.stream.Stream; /** * Interface for all kinds of compensation. A compensation is the byproduct of expression DAG matching. @@ -410,7 +408,7 @@ default ForMatch derived(final boolean isImpossible, @Nonnull final Set unmatchedQuantifiers, @Nonnull final Set compensatedAliases, @Nonnull final ResultCompensationFunction resultCompensationFunction, - @Nonnull final AggregateMappings aggregateMappings) { + @Nonnull final GroupByMappings groupByMappings) { // // At least one of these conditions must be true: // - it is an impossible compensation (in which case the predicate compensation map may be empty) @@ -423,7 +421,7 @@ default ForMatch derived(final boolean isImpossible, !predicateCompensationMap.isEmpty() || resultCompensationFunction.isNeeded() || isNeededForFiltering()); return new ForMatch(isImpossible, this, predicateCompensationMap, matchedQuantifiers, - unmatchedQuantifiers, compensatedAliases, resultCompensationFunction, aggregateMappings); + unmatchedQuantifiers, compensatedAliases, resultCompensationFunction, groupByMappings); } /** @@ -474,7 +472,7 @@ default boolean isFinalNeeded() { ResultCompensationFunction getResultCompensationFunction(); @Nonnull - AggregateMappings getAggregateMappings(); + GroupByMappings getGroupByMappings(); /** * Specific implementation of union-ing two compensations both of type {@link WithSelectCompensation}. @@ -570,7 +568,7 @@ default Compensation union(@Nonnull Compensation otherCompensation) { ImmutableSet.of(), Sets.union(getCompensatedAliases(), otherWithSelectCompensation.getCompensatedAliases()), newResultResultCompensationFunction, - AggregateMappings.empty()); + GroupByMappings.empty()); } /** @@ -601,26 +599,40 @@ default Compensation intersect(@Nonnull Compensation otherCompensation) { return Compensation.impossibleCompensation(); } - final var newMatchedAggregateMap = - Stream.concat(getAggregateMappings().getMatchedAggregateMap().entrySet().stream(), - otherWithSelectCompensation.getAggregateMappings().getMatchedAggregateMap().entrySet().stream()) - .collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, - Map.Entry::getValue, - (l, r) -> l)); - final var newUnmatchedAggregateMapBuilder = + final var newMatchedGroupingsMapBuilder = ImmutableBiMap.builder(); + final var matchedGroupingsMap = getGroupByMappings().getMatchedGroupingsMap(); + newMatchedGroupingsMapBuilder.putAll(matchedGroupingsMap); + for (final var entry : otherWithSelectCompensation.getGroupByMappings().getMatchedGroupingsMap().entrySet()) { + if (!matchedGroupingsMap.containsKey(entry.getKey())) { + newMatchedGroupingsMapBuilder.put(entry); + } + } + + final var newMatchedAggregatesMapBuilder = ImmutableBiMap.builder(); + final var matchedAggregatesMap = getGroupByMappings().getMatchedAggregatesMap(); + newMatchedAggregatesMapBuilder.putAll(matchedAggregatesMap); + for (final var entry : otherWithSelectCompensation.getGroupByMappings().getMatchedAggregatesMap().entrySet()) { + if (!matchedAggregatesMap.containsKey(entry.getKey())) { + newMatchedAggregatesMapBuilder.put(entry); + } + } + final var newMatchedAggregatesMap = newMatchedAggregatesMapBuilder.build(); + final var newUnmatchedAggregatesMapBuilder = ImmutableBiMap.builder(); - final var unmatchedAggregateMap = getAggregateMappings().getUnmatchedAggregateMap(); + final var unmatchedAggregateMap = getGroupByMappings().getUnmatchedAggregatesMap(); for (final var entry : unmatchedAggregateMap.entrySet()) { - if (!newMatchedAggregateMap.containsKey(entry.getValue())) { - newUnmatchedAggregateMapBuilder.put(entry); + if (!newMatchedAggregatesMap.containsKey(entry.getValue())) { + newUnmatchedAggregatesMapBuilder.put(entry); } } - for (final var entry : otherWithSelectCompensation.getAggregateMappings().getUnmatchedAggregateMap().entrySet()) { - if (!newMatchedAggregateMap.containsKey(entry.getValue())) { - newUnmatchedAggregateMapBuilder.put(entry); + for (final var entry : otherWithSelectCompensation.getGroupByMappings().getUnmatchedAggregatesMap().entrySet()) { + if (!newMatchedAggregatesMap.containsKey(entry.getValue()) && + !unmatchedAggregateMap.inverse().containsKey(entry.getValue())) { + newUnmatchedAggregatesMapBuilder.put(entry); } } - final var newAggregateMappings = AggregateMappings.of(newMatchedAggregateMap, newUnmatchedAggregateMapBuilder.build()); + final var newGroupByMappings = GroupByMappings.of(newMatchedGroupingsMapBuilder.build(), + newMatchedAggregatesMap, newUnmatchedAggregatesMapBuilder.build()); final ResultCompensationFunction newResultResultCompensationFunction; final var resultCompensationFunction = getResultCompensationFunction(); @@ -633,7 +645,7 @@ default Compensation intersect(@Nonnull Compensation otherCompensation) { Verify.verify(otherResultCompensationFunction.isNeeded()); // pick the one from this side -- it does not matter as both candidates have the same shape newResultResultCompensationFunction = - resultCompensationFunction.amend(unmatchedAggregateMap, newMatchedAggregateMap); + resultCompensationFunction.amend(unmatchedAggregateMap, newMatchedAggregatesMap); } final var otherCompensationMap = @@ -651,7 +663,7 @@ default Compensation intersect(@Nonnull Compensation otherCompensation) { // either compensation and let the planner figure out which one wins. We just pick one side here. // 2. TODO. combinedPredicateMap.put(entry.getKey(), - entry.getValue().amend(unmatchedAggregateMap, newMatchedAggregateMap)); + entry.getValue().amend(unmatchedAggregateMap, newMatchedAggregatesMap)); } } @@ -685,7 +697,7 @@ default Compensation intersect(@Nonnull Compensation otherCompensation) { intersectedUnmatchedQuantifiers, getCompensatedAliases(), // both compensated aliases must be identical, but too expensive to check newResultResultCompensationFunction, - newAggregateMappings); + newGroupByMappings); } } @@ -715,7 +727,7 @@ class ForMatch implements WithSelectCompensation { @Nonnull private final ResultCompensationFunction resultCompensationFunction; @Nonnull - private final AggregateMappings aggregateMappings; + private final GroupByMappings groupByMappings; @Nonnull private final Supplier> unmatchedForEachQuantifiersSupplier; @@ -727,7 +739,7 @@ private ForMatch(final boolean isImpossible, @Nonnull final Collection unmatchedQuantifiers, @Nonnull final Set compensatedAliases, @Nonnull final ResultCompensationFunction resultCompensationFunction, - @Nonnull final AggregateMappings aggregateMappings) { + @Nonnull final GroupByMappings groupByMappings) { this.isImpossible = isImpossible; this.childCompensation = childCompensation; this.predicateCompensationMap = new LinkedIdentityMap<>(); @@ -738,7 +750,7 @@ private ForMatch(final boolean isImpossible, this.unmatchedQuantifiers.addAll(unmatchedQuantifiers); this.compensatedAliases = ImmutableSet.copyOf(compensatedAliases); this.resultCompensationFunction = resultCompensationFunction; - this.aggregateMappings = aggregateMappings; + this.groupByMappings = groupByMappings; this.unmatchedForEachQuantifiersSupplier = Suppliers.memoize(this::computeUnmatchedForEachQuantifiers); } @@ -798,8 +810,8 @@ public ResultCompensationFunction getResultCompensationFunction() { @Nonnull @Override - public AggregateMappings getAggregateMappings() { - return aggregateMappings; + public GroupByMappings getGroupByMappings() { + return groupByMappings; } /** diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/GroupByMappings.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/GroupByMappings.java new file mode 100644 index 0000000000..d5999287d0 --- /dev/null +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/GroupByMappings.java @@ -0,0 +1,73 @@ +/* + * GroupByMappings.java + * + * This source file is part of the FoundationDB open source project + * + * Copyright 2015-2025 Apple Inc. and the FoundationDB project authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.apple.foundationdb.record.query.plan.cascades; + +import com.apple.foundationdb.record.query.plan.cascades.values.Value; +import com.google.common.collect.BiMap; +import com.google.common.collect.ImmutableBiMap; + +import javax.annotation.Nonnull; + +public class GroupByMappings { + @Nonnull + private final BiMap matchedGroupingsMap; + @Nonnull + private final BiMap matchedAggregatesMap; + + @Nonnull + private final BiMap unmatchedAggregatesMap; + + private GroupByMappings(@Nonnull final BiMap matchedGroupingsMap, + @Nonnull final BiMap matchedAggregatesMap, + @Nonnull final BiMap unmatchedAggregatesMap) { + this.matchedGroupingsMap = matchedGroupingsMap; + this.matchedAggregatesMap = matchedAggregatesMap; + this.unmatchedAggregatesMap = unmatchedAggregatesMap; + } + + @Nonnull + public BiMap getMatchedGroupingsMap() { + return matchedGroupingsMap; + } + + @Nonnull + public BiMap getMatchedAggregatesMap() { + return matchedAggregatesMap; + } + + @Nonnull + public BiMap getUnmatchedAggregatesMap() { + return unmatchedAggregatesMap; + } + + public static GroupByMappings empty() { + return of(ImmutableBiMap.of(), ImmutableBiMap.of(), ImmutableBiMap.of()); + } + + @Nonnull + public static GroupByMappings of(@Nonnull final BiMap matchedGroupingsMap, + @Nonnull final BiMap matchedAggregateMap, + @Nonnull final BiMap unmatchedAggregatesMap) { + return new GroupByMappings(ImmutableBiMap.copyOf(matchedGroupingsMap), + ImmutableBiMap.copyOf(matchedAggregateMap), + ImmutableBiMap.copyOf(unmatchedAggregatesMap)); + } +} diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchInfo.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchInfo.java index bd04e6e6f7..1b35507a56 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchInfo.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/MatchInfo.java @@ -30,6 +30,7 @@ import com.apple.foundationdb.record.query.plan.cascades.values.translation.PullUp; import com.google.common.base.Equivalence; import com.google.common.base.Suppliers; +import com.google.common.collect.BiMap; import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -72,43 +73,57 @@ Map collectPulledUpPredicateMappings(@Nonnull @Nonnull Set interestingPredicates); @Nonnull - AggregateMappings getAggregateMappings(); + GroupByMappings getGroupByMappings(); @Nonnull default AdjustedBuilder adjustedBuilder() { return new AdjustedBuilder(this, getMatchedOrderingParts(), getMaxMatchMap(), - getAggregateMappings()); + getGroupByMappings()); } @Nonnull - default AggregateMappings adjustAggregateMappings(@Nonnull final PartialMatch partialMatch, - @Nonnull final Quantifier candidateQuantifier) { - final var adjustedMatchedAggregateMapBuilder = ImmutableMap.builder(); - final var aggregateMappings = getAggregateMappings(); - final var matchedAggregateMap = aggregateMappings.getMatchedAggregateMap(); - for (final var matchedAggregateMapEntry : matchedAggregateMap.entrySet()) { + default GroupByMappings adjustGroupByMappings(@Nonnull final Quantifier candidateQuantifier) { + return adjustGroupByMappings(candidateQuantifier.getAlias(), candidateQuantifier.getRangesOver().get()); + } + + @Nonnull + default GroupByMappings adjustGroupByMappings(@Nonnull final CorrelationIdentifier candidateAlias, + @Nonnull final RelationalExpression candidateLowerExpression) { + final var groupByMappings = getGroupByMappings(); + + final var matchedGroupingsMap = groupByMappings.getMatchedGroupingsMap(); + final var adjustedMatchedGroupingsMap = + adjustMatchedValueMap(candidateAlias, candidateLowerExpression, matchedGroupingsMap); + final var matchedAggregatesMap = groupByMappings.getMatchedAggregatesMap(); + final var adjustedMatchedAggregatesMap = + adjustMatchedValueMap(candidateAlias, candidateLowerExpression, matchedAggregatesMap); + return GroupByMappings.of(adjustedMatchedGroupingsMap, adjustedMatchedAggregatesMap, + groupByMappings.getUnmatchedAggregatesMap()); + } + + @Nonnull + static ImmutableBiMap adjustMatchedValueMap(@Nonnull final CorrelationIdentifier candidateAlias, + @Nonnull final RelationalExpression candidateLowerExpression, + @Nonnull final Map matchedValueMap) { + final var adjustedMatchedAggregateMapBuilder = ImmutableBiMap.builder(); + for (final var matchedAggregateMapEntry : matchedValueMap.entrySet()) { final var queryAggregateValue = matchedAggregateMapEntry.getKey(); final var candidateAggregateValue = matchedAggregateMapEntry.getValue(); - final var candidateLowerExpression = - Iterables.getOnlyElement(partialMatch.getCandidateRef().getMembers()); final var candidateLowerResultValue = candidateLowerExpression.getResultValue(); final var candidatePullUpMap = candidateLowerResultValue.pullUp(ImmutableList.of(candidateAggregateValue), AliasMap.emptyMap(), Sets.difference(candidateAggregateValue.getCorrelatedToWithoutChildren(), candidateLowerExpression.getCorrelatedTo()), - candidateQuantifier.getAlias()); + candidateAlias); final var pulledUpCandidateAggregateValue = candidatePullUpMap.get(candidateAggregateValue); - if (pulledUpCandidateAggregateValue == null) { - return AggregateMappings.empty(); + if (pulledUpCandidateAggregateValue != null) { + adjustedMatchedAggregateMapBuilder.put(queryAggregateValue, pulledUpCandidateAggregateValue); } - adjustedMatchedAggregateMapBuilder.put(queryAggregateValue, pulledUpCandidateAggregateValue); } - - return AggregateMappings.of(adjustedMatchedAggregateMapBuilder.build(), - aggregateMappings.getUnmatchedAggregateMap()); + return adjustedMatchedAggregateMapBuilder.build(); } /** @@ -150,7 +165,7 @@ class RegularMatchInfo implements MatchInfo { private final MaxMatchMap maxMatchMap; @Nonnull - private final AggregateMappings aggregateMappings; + private final GroupByMappings groupByMappings; @Nullable private final List rollUpToGroupingValues; @@ -167,7 +182,7 @@ private RegularMatchInfo(@Nonnull final Map matchedOrderingParts, @Nonnull final MaxMatchMap maxMatchMap, - @Nonnull final AggregateMappings aggregateMappings, + @Nonnull final GroupByMappings groupByMappings, @Nullable final List rollUpToGroupingValues, @Nonnull final QueryPlanConstraint additionalPlanConstraint) { this.parameterBindingMap = ImmutableMap.copyOf(parameterBindingMap); @@ -182,7 +197,7 @@ private RegularMatchInfo(@Nonnull final Map tryFromMatchMap(@Nonnull final AliasMap bindin @Nonnull final IdentityBiMap partialMatchMap, @Nonnull final MaxMatchMap maxMatchMap) { return tryMerge(bindingAliasMap, partialMatchMap, ImmutableMap.of(), PredicateMap.empty(), - maxMatchMap, AggregateMappings.empty(), null, + maxMatchMap, GroupByMappings.empty(), null, maxMatchMap.getQueryPlanConstraint()); } @@ -315,7 +330,7 @@ public static Optional tryMerge(@Nonnull final AliasMap bindingAliasM @Nonnull final Map parameterBindingMap, @Nonnull final PredicateMultiMap predicateMap, @Nonnull final MaxMatchMap maxMatchMap, - @Nonnull final AggregateMappings additionalAggregateMappings, + @Nonnull final GroupByMappings additionalGroupByMappings, @Nullable final List rollUpToGroupingValues, @Nonnull final QueryPlanConstraint additionalPlanConstraint) { final var parameterMapsBuilder = ImmutableList.>builder(); @@ -343,8 +358,8 @@ public static Optional tryMerge(@Nonnull final AliasMap bindingAliasM tryMergeParameterBindings(parameterMapsBuilder.build()); final var matchedAggregateValueMap = - pullUpAndMergeAggregateMappings(bindingAliasMap, partialMatchMap, - additionalAggregateMappings); + pullUpAndMergeGroupByMappings(bindingAliasMap, partialMatchMap, + additionalGroupByMappings); final List resolvedRollUpToGroupingValues; if (rollUpToGroupingValues != null) { @@ -406,74 +421,115 @@ public static Optional> tryMergePara } @Nonnull - private static AggregateMappings pullUpAndMergeAggregateMappings(@Nonnull final AliasMap bindingAliasMap, - @Nonnull final IdentityBiMap partialMatchMap, - @Nonnull final AggregateMappings additionalAggregateMappings) { - final var matchedAggregateMapBuilder = ImmutableMap.builder(); - matchedAggregateMapBuilder.putAll(additionalAggregateMappings.getMatchedAggregateMap()); + private static GroupByMappings pullUpAndMergeGroupByMappings(@Nonnull final AliasMap bindingAliasMap, + @Nonnull final IdentityBiMap partialMatchMap, + @Nonnull final GroupByMappings additionalGroupByMappings) { + final var matchedGroupingsMapBuilder = ImmutableBiMap.builder(); + matchedGroupingsMapBuilder.putAll(additionalGroupByMappings.getMatchedGroupingsMap()); + final var matchedAggregateMapBuilder = ImmutableBiMap.builder(); + matchedAggregateMapBuilder.putAll(additionalGroupByMappings.getMatchedAggregatesMap()); final var unatchedAggregateMapBuilder = ImmutableBiMap.builder(); - unatchedAggregateMapBuilder.putAll(additionalAggregateMappings.getUnmatchedAggregateMap()); + unatchedAggregateMapBuilder.putAll(additionalGroupByMappings.getUnmatchedAggregatesMap()); for (final var partialMatchMapEntry : partialMatchMap.entrySet()) { final var partialMatchMapEntryKey = partialMatchMapEntry.getKey(); final var quantifier = partialMatchMapEntryKey.get(); if (quantifier instanceof Quantifier.ForEach) { final var partialMatch = partialMatchMapEntry.getValue().get(); - final var pulledUpAggregateMappings = - pullUpAggregateMappings(partialMatch, + final var pulledUpGroupByMappings = + pullUpGroupByMappings(partialMatch, quantifier.getAlias(), Objects.requireNonNull(bindingAliasMap.getTarget(quantifier.getAlias()))); - matchedAggregateMapBuilder.putAll(pulledUpAggregateMappings.getMatchedAggregateMap()); - unatchedAggregateMapBuilder.putAll(pulledUpAggregateMappings.getUnmatchedAggregateMap()); + matchedGroupingsMapBuilder.putAll(pulledUpGroupByMappings.getMatchedGroupingsMap()); + matchedAggregateMapBuilder.putAll(pulledUpGroupByMappings.getMatchedAggregatesMap()); + unatchedAggregateMapBuilder.putAll(pulledUpGroupByMappings.getUnmatchedAggregatesMap()); } } - return AggregateMappings.of(matchedAggregateMapBuilder.build(), unatchedAggregateMapBuilder.build()); + return GroupByMappings.of(matchedGroupingsMapBuilder.build(), + matchedAggregateMapBuilder.build(), unatchedAggregateMapBuilder.build()); } @Nonnull - public static AggregateMappings pullUpAggregateCandidateMappings(@Nonnull final PartialMatch partialMatch, - @Nonnull final PullUp pullUp) { + public static GroupByMappings pullUpAggregateCandidateMappings(@Nonnull final PartialMatch partialMatch, + @Nonnull final PullUp pullUp) { final var matchInfo = partialMatch.getMatchInfo(); - final var aggregateMappings = matchInfo.getAggregateMappings(); - final var matchedAggregateMapBuilder = ImmutableMap.builder(); - for (final var matchedAggregateMapEntry : aggregateMappings.getMatchedAggregateMap().entrySet()) { - final var candidateAggregateValue = matchedAggregateMapEntry.getValue(); + final var groupByMappings = matchInfo.getGroupByMappings(); + + final var matchedGroupingsMapBuilder = ImmutableBiMap.builder(); + for (final var matchedGroupingsMapEntry : groupByMappings.getMatchedGroupingsMap().entrySet()) { + final var candidateGroupingValue = matchedGroupingsMapEntry.getValue(); + final var pulledUpCandidateGroupingValueOptional = + pullUp.pullUpCandidateValueMaybe(candidateGroupingValue); + pulledUpCandidateGroupingValueOptional.ifPresent( + value -> matchedGroupingsMapBuilder.put(matchedGroupingsMapEntry.getKey(), value)); + } + + final var matchedAggregatesMapBuilder = ImmutableBiMap.builder(); + for (final var matchedAggregatesMapEntry : groupByMappings.getMatchedAggregatesMap().entrySet()) { + final var candidateAggregateValue = matchedAggregatesMapEntry.getValue(); final var pulledUpCandidateAggregateValueOptional = pullUp.pullUpCandidateValueMaybe(candidateAggregateValue); - if (pulledUpCandidateAggregateValueOptional.isEmpty()) { - return AggregateMappings.empty(); - } - matchedAggregateMapBuilder.put(matchedAggregateMapEntry.getKey(), pulledUpCandidateAggregateValueOptional.get()); + pulledUpCandidateAggregateValueOptional.ifPresent( + value -> matchedAggregatesMapBuilder.put(matchedAggregatesMapEntry.getKey(), value)); } - return AggregateMappings.of(matchedAggregateMapBuilder.build(), aggregateMappings.getUnmatchedAggregateMap()); + return GroupByMappings.of(matchedGroupingsMapBuilder.build(), + matchedAggregatesMapBuilder.build(), groupByMappings.getUnmatchedAggregatesMap()); } @Nonnull - public static AggregateMappings pullUpAggregateMappings(@Nonnull final PartialMatch partialMatch, - @Nullable final CorrelationIdentifier queryAlias, - @Nonnull final CorrelationIdentifier candidateAlias) { + public static GroupByMappings pullUpGroupByMappings(@Nonnull final PartialMatch partialMatch, + @Nonnull final CorrelationIdentifier queryAlias, + @Nonnull final CorrelationIdentifier candidateAlias) { final var matchInfo = partialMatch.getMatchInfo(); final var queryExpression = partialMatch.getQueryExpression(); final var resultValue = queryExpression.getResultValue(); - final var aggregateMappings = matchInfo.getAggregateMappings(); - final var matchedAggregateMapBuilder = ImmutableMap.builder(); - for (final var matchedAggregateMapEntry : aggregateMappings.getMatchedAggregateMap().entrySet()) { - final var queryAggregateValue = matchedAggregateMapEntry.getKey(); - final Value pulledUpQueryAggregateValue; - if (queryAlias != null) { - final var pullUpMap = - resultValue.pullUp(ImmutableList.of(queryAggregateValue), AliasMap.emptyMap(), - Sets.difference(queryAggregateValue.getCorrelatedToWithoutChildren(), - queryExpression.getCorrelatedTo()), queryAlias); - pulledUpQueryAggregateValue = pullUpMap.get(queryAggregateValue); - if (pulledUpQueryAggregateValue == null) { - return AggregateMappings.empty(); - } - } else { - pulledUpQueryAggregateValue = queryAggregateValue; + final var groupByMappings = matchInfo.getGroupByMappings(); + final var constantAliases = Sets.difference(resultValue.getCorrelatedTo(), + queryExpression.getCorrelatedTo()); + final var matchedGroupingsMap = + pullUpMatchedValueMap(partialMatch, groupByMappings.getMatchedGroupingsMap(), resultValue, + queryAlias, candidateAlias, constantAliases); + + final var matchedAggregatesMap = + pullUpMatchedValueMap(partialMatch, groupByMappings.getMatchedAggregatesMap(), resultValue, + queryAlias, candidateAlias, constantAliases); + + final var unmatchedAggregateMapBuilder = ImmutableBiMap.builder(); + for (final var unmatchedAggregateMapEntry : groupByMappings.getUnmatchedAggregatesMap().entrySet()) { + final var queryAggregateValue = unmatchedAggregateMapEntry.getValue(); + final var pullUpMap = + resultValue.pullUp(ImmutableList.of(queryAggregateValue), AliasMap.emptyMap(), + Sets.difference(queryAggregateValue.getCorrelatedToWithoutChildren(), + queryExpression.getCorrelatedTo()), queryAlias); + final var pulledUpQueryAggregateValue = pullUpMap.get(queryAggregateValue); + if (pulledUpQueryAggregateValue == null) { + return GroupByMappings.empty(); + } + unmatchedAggregateMapBuilder.put(unmatchedAggregateMapEntry.getKey(), pulledUpQueryAggregateValue); + } + + return GroupByMappings.of(matchedGroupingsMap, matchedAggregatesMap, unmatchedAggregateMapBuilder.build()); + } + + private static ImmutableBiMap pullUpMatchedValueMap(@Nonnull final PartialMatch partialMatch, + @Nonnull final BiMap matchedValueMap, + @Nonnull final Value queryResultValue, + @Nonnull final CorrelationIdentifier queryAlias, + @Nonnull final CorrelationIdentifier candidateAlias, + @Nonnull final Set constantAliases) { + final var matchedAggregatesMapBuilder = ImmutableBiMap.builder(); + for (final var entry : matchedValueMap.entrySet()) { + final var queryValue = entry.getKey(); + final var pullUpMap = + queryResultValue.pullUp(ImmutableList.of(queryValue), AliasMap.emptyMap(), constantAliases, + queryAlias); + final Value pulledUpQueryValue = pullUpMap.get(queryValue); + if (pulledUpQueryValue == null) { + continue; } - final var candidateAggregateValue = matchedAggregateMapEntry.getValue(); + + final var candidateAggregateValue = entry.getValue(); final var candidateLowerExpression = Iterables.getOnlyElement(partialMatch.getCandidateRef().getMembers()); final var candidateLowerResultValue = candidateLowerExpression.getResultValue(); @@ -485,30 +541,11 @@ public static AggregateMappings pullUpAggregateMappings(@Nonnull final PartialMa candidateAlias); final var pulledUpCandidateAggregateValue = candidatePullUpMap.get(candidateAggregateValue); if (pulledUpCandidateAggregateValue == null) { - return AggregateMappings.empty(); - } - matchedAggregateMapBuilder.put(pulledUpQueryAggregateValue, pulledUpCandidateAggregateValue); - } - - final var unmatchedAggregateMapBuilder = ImmutableBiMap.builder(); - if (queryAlias != null) { - for (final var unmatchedAggregateMapEntry : aggregateMappings.getUnmatchedAggregateMap().entrySet()) { - final var queryAggregateValue = unmatchedAggregateMapEntry.getValue(); - final var pullUpMap = - resultValue.pullUp(ImmutableList.of(queryAggregateValue), AliasMap.emptyMap(), - Sets.difference(queryAggregateValue.getCorrelatedToWithoutChildren(), - queryExpression.getCorrelatedTo()), queryAlias); - final var pulledUpQueryAggregateValue = pullUpMap.get(queryAggregateValue); - if (pulledUpQueryAggregateValue == null) { - return AggregateMappings.empty(); - } - unmatchedAggregateMapBuilder.put(unmatchedAggregateMapEntry.getKey(), pulledUpQueryAggregateValue); + continue; } - } else { - unmatchedAggregateMapBuilder.putAll(aggregateMappings.getUnmatchedAggregateMap()); + matchedAggregatesMapBuilder.put(pulledUpQueryValue, pulledUpCandidateAggregateValue); } - - return AggregateMappings.of(matchedAggregateMapBuilder.build(), unmatchedAggregateMapBuilder.build()); + return matchedAggregatesMapBuilder.build(); } } @@ -545,16 +582,16 @@ class AdjustedMatchInfo implements MatchInfo { private final MaxMatchMap maxMatchMap; @Nonnull - private final AggregateMappings aggregateMappings; + private final GroupByMappings groupByMappings; private AdjustedMatchInfo(@Nonnull final MatchInfo underlying, @Nonnull final List matchedOrderingParts, @Nonnull final MaxMatchMap maxMatchMap, - @Nonnull final AggregateMappings aggregateMappings) { + @Nonnull final GroupByMappings groupByMappings) { this.underlying = underlying; this.matchedOrderingParts = matchedOrderingParts; this.maxMatchMap = maxMatchMap; - this.aggregateMappings = aggregateMappings; + this.groupByMappings = groupByMappings; } @Nonnull @@ -576,8 +613,8 @@ public MaxMatchMap getMaxMatchMap() { @Nonnull @Override - public AggregateMappings getAggregateMappings() { - return aggregateMappings; + public GroupByMappings getGroupByMappings() { + return groupByMappings; } @Override @@ -641,16 +678,16 @@ class AdjustedBuilder { private MaxMatchMap maxMatchMap; @Nonnull - private AggregateMappings aggregateMappings; + private GroupByMappings groupByMappings; private AdjustedBuilder(@Nonnull final MatchInfo underlying, @Nonnull final List matchedOrderingParts, @Nonnull final MaxMatchMap maxMatchMap, - @Nonnull final AggregateMappings aggregateMappings) { + @Nonnull final GroupByMappings groupByMappings) { this.underlying = underlying; this.matchedOrderingParts = matchedOrderingParts; this.maxMatchMap = maxMatchMap; - this.aggregateMappings = aggregateMappings; + this.groupByMappings = groupByMappings; } @Nonnull @@ -664,8 +701,8 @@ public AdjustedBuilder setMatchedOrderingParts(@Nonnull final List> computeFlowedColumns() { @Nonnull public Optional pullUpMaxMatchMapMaybe(@Nonnull final MaxMatchMap maxMatchMap, @Nonnull final CorrelationIdentifier candidateAlias) { - final var translatedQueryValueOptional = maxMatchMap.translateQueryValueMaybe(candidateAlias); - return translatedQueryValueOptional - .map(translatedQueryValue -> - TranslationMap.builder() - .when(getAlias()).then(TranslationFunction.adjustValueType(translatedQueryValue)) - .build()); + return maxMatchMap.pullUpMaybe(getAlias(), candidateAlias); } @SuppressWarnings("PMD.CompareObjectsWithEquals") diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/RequestedOrdering.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/RequestedOrdering.java index 628d0bc9fb..427d6e686f 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/RequestedOrdering.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/RequestedOrdering.java @@ -221,14 +221,14 @@ public RequestedOrdering pushDown(@Nonnull Value value, } @Nonnull - public RequestedOrdering translate(@Nonnull TranslationMap translationMap) { + public RequestedOrdering translateCorrelations(@Nonnull TranslationMap translationMap, final boolean shouldSimplify) { // // Need to push every participating value of this requested ordering through the value. // final var pushedDownOrderingPartsBuilder = ImmutableList.builder(); for (final var orderingPart : orderingParts) { final var orderingValue = orderingPart.getValue(); - final var translatedOrderingValue = orderingValue.translateCorrelations(translationMap); + final var translatedOrderingValue = orderingValue.translateCorrelations(translationMap, shouldSimplify); pushedDownOrderingPartsBuilder.add(new RequestedOrderingPart(translatedOrderingValue, orderingPart.getSortOrder())); } return new RequestedOrdering(pushedDownOrderingPartsBuilder.build(), Distinctness.PRESERVE_DISTINCTNESS, isExhaustive()); diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java index 439e5301f6..d8ad48c130 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java @@ -25,13 +25,13 @@ import com.apple.foundationdb.record.PlanSerializationContext; import com.apple.foundationdb.record.planprotos.PValue; import com.apple.foundationdb.record.query.expressions.Comparisons; -import com.apple.foundationdb.record.query.plan.cascades.AggregateMappings; import com.apple.foundationdb.record.query.plan.cascades.AliasMap; import com.apple.foundationdb.record.query.plan.cascades.BooleanWithConstraint; import com.apple.foundationdb.record.query.plan.cascades.Column; import com.apple.foundationdb.record.query.plan.cascades.ComparisonRange; import com.apple.foundationdb.record.query.plan.cascades.Compensation; import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier; +import com.apple.foundationdb.record.query.plan.cascades.GroupByMappings; import com.apple.foundationdb.record.query.plan.cascades.IdentityBiMap; import com.apple.foundationdb.record.query.plan.cascades.LinkedIdentityMap; import com.apple.foundationdb.record.query.plan.cascades.MatchInfo; @@ -64,9 +64,9 @@ import com.apple.foundationdb.record.query.plan.cascades.values.translation.TranslationMap; import com.apple.foundationdb.record.query.plan.explain.ExplainTokens; import com.apple.foundationdb.record.query.plan.explain.ExplainTokensWithPrecedence; -import com.apple.foundationdb.record.util.pair.Pair; import com.google.common.base.Suppliers; import com.google.common.base.Verify; +import com.google.common.collect.BiMap; import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -340,10 +340,10 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid return ImmutableList.of(); } final var otherPrimitiveAggregateValue = Iterables.getOnlyElement(otherAggregateValues); - final var matchedAggregateMapBuilder = ImmutableBiMap.builder(); - final var unmatchedAggregateMapBuilder = + final var matchedAggregatesMapBuilder = ImmutableBiMap.builder(); + final var unmatchedAggregatesMapBuilder = ImmutableBiMap.builder(); - final var unmatchedTranslatedAggregateValueMapBuilder = + final var unmatchedTranslatedAggregatesValueMapBuilder = ImmutableMap.builder(); var subsumedAggregations = BooleanWithConstraint.falseValue(); for (final var primitiveAggregateValue : aggregateValues) { @@ -353,47 +353,45 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid final var semanticEquals = translatedPrimitiveAggregateValue.semanticEquals(otherPrimitiveAggregateValue, valueEquivalence); if (semanticEquals.isTrue()) { - matchedAggregateMapBuilder.put(primitiveAggregateValue, otherPrimitiveAggregateValue); + matchedAggregatesMapBuilder.put(primitiveAggregateValue, otherPrimitiveAggregateValue); subsumedAggregations = semanticEquals; } else { final var unmatchedId = UnmatchedAggregateValue.uniqueId(); - unmatchedAggregateMapBuilder.put(unmatchedId, primitiveAggregateValue); - unmatchedTranslatedAggregateValueMapBuilder.put(translatedPrimitiveAggregateValue, unmatchedId); + unmatchedAggregatesMapBuilder.put(unmatchedId, primitiveAggregateValue); + unmatchedTranslatedAggregatesValueMapBuilder.put(translatedPrimitiveAggregateValue, unmatchedId); } } - final BooleanWithConstraint subsumedGroupings; - final List rollUpToGroupingValues; - if (subsumedAggregations.isTrue()) { - final var groupingSubSubsumedByPair = - groupingSubsumedBy(candidateInnerQuantifier, - Objects.requireNonNull(partialMatchMap.getUnwrapped(innerQuantifier)), - candidateGroupingValue, translationMap, valueEquivalence); - subsumedGroupings = Objects.requireNonNull(groupingSubSubsumedByPair.getLeft()); - rollUpToGroupingValues = groupingSubSubsumedByPair.getRight(); - Verify.verify(subsumedGroupings.isTrue() || rollUpToGroupingValues == null); - } else { - subsumedGroupings = falseValue(); - rollUpToGroupingValues = null; + if (subsumedAggregations.isFalse()) { + return ImmutableList.of(); } + final var subsumedGroupingsResult = + subsumedGroupings(candidateInnerQuantifier, + Objects.requireNonNull(partialMatchMap.getUnwrapped(innerQuantifier)), + candidateGroupingValue, translationMap, valueEquivalence); + final var subsumedGroupings = Objects.requireNonNull(subsumedGroupingsResult.getSubsumedGroups()); if (subsumedGroupings.isFalse()) { return ImmutableList.of(); } + final var matchedGroupingsMap = subsumedGroupingsResult.getMatchedGroupingsMap(); + final var rollUpToGroupingValues = subsumedGroupingsResult.getRollUpToValues(); final var unmatchedTranslatedAggregateValueMap = - unmatchedTranslatedAggregateValueMapBuilder.buildKeepingLast(); + unmatchedTranslatedAggregatesValueMapBuilder.buildKeepingLast(); final var translatedResultValue = getResultValue().translateCorrelations(translationMap, true); final var maxMatchMap = MaxMatchMap.compute(translatedResultValue, candidateExpression.getResultValue(), Quantifiers.aliases(candidateExpression.getQuantifiers()), valueEquivalence, - translatedUnmatchedValue -> onUnmatchedValue(unmatchedTranslatedAggregateValueMap, translatedUnmatchedValue)); + translatedUnmatchedValue -> onUnmatchedValue(unmatchedTranslatedAggregateValueMap, + translatedUnmatchedValue)); final var queryPlanConstraint = subsumedGroupings.getConstraint().compose(maxMatchMap.getQueryPlanConstraint()); return RegularMatchInfo.tryMerge(bindingAliasMap, partialMatchMap, ImmutableMap.of(), PredicateMap.empty(), maxMatchMap, - AggregateMappings.of(matchedAggregateMapBuilder.build(), unmatchedAggregateMapBuilder.build()), + GroupByMappings.of(matchedGroupingsMap, matchedAggregatesMapBuilder.build(), + unmatchedAggregatesMapBuilder.build()), rollUpToGroupingValues, queryPlanConstraint) .map(ImmutableList::of) .orElse(ImmutableList.of()); @@ -410,30 +408,42 @@ private Optional onUnmatchedValue(@Nonnull final Map> groupingSubsumedBy(@Nonnull final Quantifier candidateInnerQuantifier, - @Nonnull final PartialMatch childMatch, - @Nullable final Value candidateGroupingValue, - @Nonnull final TranslationMap translationMap, - @Nonnull final ValueEquivalence valueEquivalence) { + private SubsumedGroupingsResult subsumedGroupings(@Nonnull final Quantifier candidateInnerQuantifier, + @Nonnull final PartialMatch childMatch, + @Nullable final Value candidateGroupingValue, + @Nonnull final TranslationMap translationMap, + @Nonnull final ValueEquivalence valueEquivalence) { if (groupingValue == null && candidateGroupingValue == null) { - return Pair.of(alwaysTrue(), ImmutableList.of()); + return SubsumedGroupingsResult.withoutRollUp(alwaysTrue(), ImmutableBiMap.of()); } if (candidateGroupingValue == null) { - return Pair.of(falseValue(), null); + return SubsumedGroupingsResult.noSubsumption(); } - final List translatedGroupingValues; + final List translatedGroupingValues; // with duplicate groupings if present + final BiMap matchedGroupingsMap; if (groupingValue != null) { - final var translatedGroupingValue = groupingValue.translateCorrelations(translationMap, true); - translatedGroupingValues = - Values.primitiveAccessorsForType(translatedGroupingValue.getResultType(), - () -> translatedGroupingValue).stream() + final var translatedGroupingsValuesBuilder = ImmutableList.builder(); + final var matchedGroupingsMapBuilder = ImmutableBiMap.builder(); + final var groupingValues = + Values.primitiveAccessorsForType(groupingValue.getResultType(), () -> groupingValue).stream() .map(primitiveGroupingValue -> primitiveGroupingValue.simplify(AliasMap.emptyMap(), ImmutableSet.of())) .collect(ImmutableList.toImmutableList()); + for (final var primitiveGroupingValue : groupingValues) { + final var translatedPrimitiveGroupingValue = + primitiveGroupingValue.translateCorrelations(translationMap, true) + .simplify(AliasMap.emptyMap(), ImmutableSet.of()); + translatedGroupingsValuesBuilder.add(translatedPrimitiveGroupingValue); + matchedGroupingsMapBuilder.put(primitiveGroupingValue, translatedPrimitiveGroupingValue); + } + translatedGroupingValues = translatedGroupingsValuesBuilder.build(); + matchedGroupingsMap = matchedGroupingsMapBuilder.build(); } else { translatedGroupingValues = ImmutableList.of(); + matchedGroupingsMap = ImmutableBiMap.of(); } + final Set translatedGroupingValuesSet = ImmutableSet.copyOf(translatedGroupingValues); final var candidateGroupingValues = @@ -448,7 +458,7 @@ private Pair> groupingSubsumedBy(@Nonnull fin // final var unmatchedCandidateValues = new LinkedHashSet<>(candidateGroupingValues); if (translatedGroupingValuesSet.size() > unmatchedCandidateValues.size()) { - return Pair.of(falseValue(), null); + return SubsumedGroupingsResult.noSubsumption(); } // @@ -484,7 +494,7 @@ private Pair> groupingSubsumedBy(@Nonnull fin } } if (!found) { - return Pair.of(falseValue(), null); + return SubsumedGroupingsResult.noSubsumption(); } if (unmatchedCandidateValues.isEmpty()) { break; @@ -493,7 +503,7 @@ private Pair> groupingSubsumedBy(@Nonnull fin if (unmatchedCandidateValues.isEmpty()) { // return with a positive result if sets where in fact semantically equal - return Pair.of(booleanWithConstraint, null); + return SubsumedGroupingsResult.withoutRollUp(booleanWithConstraint, matchedGroupingsMap); } // @@ -559,14 +569,14 @@ private Pair> groupingSubsumedBy(@Nonnull fin // for (int i = 0; i < translatedGroupingValues.size(); i++) { if (unmatchedCandidateValues.contains(candidateGroupingValues.get(i))) { - return Pair.of(falseValue(), null); + return SubsumedGroupingsResult.noSubsumption(); } } - return Pair.of(booleanWithConstraint, translatedGroupingValues); + return SubsumedGroupingsResult.of(booleanWithConstraint, matchedGroupingsMap, translatedGroupingValues); } - return Pair.of(booleanWithConstraint, null); + return SubsumedGroupingsResult.withoutRollUp(booleanWithConstraint, matchedGroupingsMap); } @Nonnull @@ -619,21 +629,28 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, final var childCompensation = childCompensationOptional.get(); - if (childCompensation.isImpossible() || - // - // TODO This needs some improvement as GB a, b, c WHERE a= AND c= needs to reapply the - // predicate on c which is currently refused here. - // - childCompensation.isNeededForFiltering()) { + if (childCompensation.isImpossible() +// || +// // +// // TODO This needs some improvement as GB a, b, c WHERE a= AND c= needs to reapply the +// // predicate on c which is currently refused here. +// // +// childCompensation.isNeededForFiltering() + ) { + // + // Note that it may be better to just return the child compensation verbatim as that compensation + // may be combinable with something else to make it possible while the statically impossible compensation + // can never combine into anything that is possible. + // return Compensation.impossibleCompensation(); } boolean isCompensationImpossible = false; final ResultCompensationFunction resultCompensationFunction; - final AggregateMappings pulledUpAggregateMappings; + final GroupByMappings pulledUpGroupByMappings; if (rootOfMatchPullUp == null) { resultCompensationFunction = ResultCompensationFunction.noCompensationNeeded(); - pulledUpAggregateMappings = AggregateMappings.empty(); + pulledUpGroupByMappings = GroupByMappings.empty(); } else { final var maxMatchMap = matchInfo.getMaxMatchMap(); final var pulledUpTranslatedResultValueOptional = @@ -648,7 +665,7 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, ResultCompensationFunction.ofValue(pulledUpTranslatedResultValue); isCompensationImpossible |= resultCompensationFunction.isImpossible(); - pulledUpAggregateMappings = + pulledUpGroupByMappings = RegularMatchInfo.pullUpAggregateCandidateMappings(partialMatch, rootOfMatchPullUp); } @@ -665,7 +682,7 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, unmatchedQuantifiers, partialMatch.getCompensatedAliases(), resultCompensationFunction, - pulledUpAggregateMappings); + pulledUpGroupByMappings); } @Nonnull @@ -780,4 +797,55 @@ public static CorrelationIdentifier uniqueId() { return CorrelationIdentifier.uniqueId(UnmatchedAggregateValue.class); } } + + private static class SubsumedGroupingsResult { + @Nonnull + private final BooleanWithConstraint subsumedGroups; + @Nonnull + private final BiMap matchedGroupingsMap; + @Nullable + private final List rollUpToValues; + + private SubsumedGroupingsResult(@Nonnull final BooleanWithConstraint subsumedGroups, + @Nonnull final BiMap matchedGroupingsMap, + @Nullable final List rollUpToValues) { + this.subsumedGroups = subsumedGroups; + this.matchedGroupingsMap = matchedGroupingsMap; + this.rollUpToValues = rollUpToValues; + } + + @Nonnull + public BooleanWithConstraint getSubsumedGroups() { + return subsumedGroups; + } + + @Nonnull + public BiMap getMatchedGroupingsMap() { + return matchedGroupingsMap; + } + + @Nullable + public List getRollUpToValues() { + return rollUpToValues; + } + + @Nonnull + public static SubsumedGroupingsResult noSubsumption() { + return of(falseValue(), ImmutableBiMap.of(), null); + } + + @Nonnull + public static SubsumedGroupingsResult withoutRollUp(@Nonnull final BooleanWithConstraint subsumedGroups, + @Nonnull final BiMap matchedGroupingsMap) { + return of(subsumedGroups, matchedGroupingsMap, null); + } + + @Nonnull + public static SubsumedGroupingsResult of(@Nonnull final BooleanWithConstraint subsumedGroups, + @Nonnull final BiMap matchedGroupingsMap, + @Nullable final List rollUpToValues) { + return new SubsumedGroupingsResult(subsumedGroups, ImmutableBiMap.copyOf(matchedGroupingsMap), + rollUpToValues == null ? null : ImmutableList.copyOf(rollUpToValues)); + } + } } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/LogicalTypeFilterExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/LogicalTypeFilterExpression.java index 84e8ac69c1..6b1cf30d25 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/LogicalTypeFilterExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/LogicalTypeFilterExpression.java @@ -30,7 +30,7 @@ import com.apple.foundationdb.record.query.plan.cascades.IdentityBiMap; import com.apple.foundationdb.record.query.plan.cascades.LinkedIdentityMap; import com.apple.foundationdb.record.query.plan.cascades.MatchInfo; -import com.apple.foundationdb.record.query.plan.cascades.AggregateMappings; +import com.apple.foundationdb.record.query.plan.cascades.GroupByMappings; import com.apple.foundationdb.record.query.plan.cascades.MatchInfo.RegularMatchInfo; import com.apple.foundationdb.record.query.plan.cascades.PartialMatch; import com.apple.foundationdb.record.query.plan.cascades.PredicateMultiMap.ResultCompensationFunction; @@ -207,10 +207,10 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, boolean isCompensationImpossible = false; final ResultCompensationFunction resultCompensationFunction; - final AggregateMappings aggregateMappings; + final GroupByMappings groupByMappings; if (rootOfMatchPullUp == null) { resultCompensationFunction = ResultCompensationFunction.noCompensationNeeded(); - aggregateMappings = AggregateMappings.empty(); + groupByMappings = GroupByMappings.empty(); } else { final var maxMatchMap = matchInfo.getMaxMatchMap(); final var pulledUpTranslatedResultValueOptional = @@ -224,7 +224,7 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, resultCompensationFunction = ResultCompensationFunction.ofValue(pulledUpTranslatedResultValue); isCompensationImpossible |= resultCompensationFunction.isImpossible(); - aggregateMappings = + groupByMappings = RegularMatchInfo.pullUpAggregateCandidateMappings(partialMatch, rootOfMatchPullUp); } @@ -241,7 +241,7 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, unmatchedQuantifiers, partialMatch.getCompensatedAliases(), resultCompensationFunction, - aggregateMappings); + groupByMappings); } @Nonnull diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/MatchableSortExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/MatchableSortExpression.java index 0221c03f52..0a29ef8962 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/MatchableSortExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/MatchableSortExpression.java @@ -224,7 +224,7 @@ public Optional adjustMatch(@Nonnull final PartialMatch partialMatch, childMatchInfo.adjustedBuilder() .setMaxMatchMap(adjustedMaxMatchMap) .setMatchedOrderingParts(forPartialMatch(partialMatch)) - .setAggregateMappings(childMatchInfo.adjustAggregateMappings(partialMatch, candidateQuantifier)) + .setGroupByMappings(childMatchInfo.adjustGroupByMappings(candidateQuantifier)) .build()); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java index af5db496ea..533d351454 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/SelectExpression.java @@ -32,7 +32,7 @@ import com.apple.foundationdb.record.query.plan.cascades.IterableHelpers; import com.apple.foundationdb.record.query.plan.cascades.LinkedIdentityMap; import com.apple.foundationdb.record.query.plan.cascades.MatchInfo; -import com.apple.foundationdb.record.query.plan.cascades.AggregateMappings; +import com.apple.foundationdb.record.query.plan.cascades.GroupByMappings; import com.apple.foundationdb.record.query.plan.cascades.MatchInfo.RegularMatchInfo; import com.apple.foundationdb.record.query.plan.cascades.PartialMatch; import com.apple.foundationdb.record.query.plan.cascades.PredicateMap; @@ -464,7 +464,7 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid MaxMatchMap.compute(translatedResultValue, candidateExpression.getResultValue(), Quantifiers.aliases(candidateExpression.getQuantifiers()), bindingValueEquivalence); return RegularMatchInfo.tryMerge(bindingAliasMap, partialMatchMap, mergedParameterBindingMap, - PredicateMap.empty(), maxMatchMap, AggregateMappings.empty(), null, + PredicateMap.empty(), maxMatchMap, GroupByMappings.empty(), null, maxMatchMap.getQueryPlanConstraint()) .map(ImmutableList::of) .orElse(ImmutableList.of()); @@ -584,7 +584,7 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid bindingValueEquivalence); return RegularMatchInfo.tryMerge(bindingAliasMap, partialMatchMap, allParameterBindingMap, predicateMap, - maxMatchMap, AggregateMappings.empty(), null, + maxMatchMap, GroupByMappings.empty(), null, maxMatchMap.getQueryPlanConstraint()); }) .map(ImmutableList::of) @@ -621,7 +621,7 @@ public Optional adjustMatch(@Nonnull final PartialMatch partialMatch, .map(adjustedMaxMatchMap -> childMatchInfo.adjustedBuilder() .setMaxMatchMap(adjustedMaxMatchMap) - .setAggregateMappings(childMatchInfo.adjustAggregateMappings(partialMatch, candidateQuantifier)) + .setGroupByMappings(childMatchInfo.adjustGroupByMappings(candidateQuantifier)) .build()); } @@ -864,10 +864,10 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, } final ResultCompensationFunction resultCompensationFunction; - final AggregateMappings aggregateMappings; + final GroupByMappings groupByMappings; if (rootOfMatchPullUp == null) { resultCompensationFunction = ResultCompensationFunction.noCompensationNeeded(); - aggregateMappings = AggregateMappings.empty(); + groupByMappings = GroupByMappings.empty(); } else { final var maxMatchMap = matchInfo.getMaxMatchMap(); final var pulledUpTranslatedResultValueOptional = @@ -881,7 +881,7 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, resultCompensationFunction = ResultCompensationFunction.ofValue(pulledUpTranslatedResultValue); isAnyCompensationFunctionImpossible |= resultCompensationFunction.isImpossible(); - aggregateMappings = + groupByMappings = RegularMatchInfo.pullUpAggregateCandidateMappings(partialMatch, rootOfMatchPullUp); } @@ -914,6 +914,6 @@ public Compensation compensate(@Nonnull final PartialMatch partialMatch, partialMatch.getUnmatchedQuantifiers(), partialMatch.getCompensatedAliases(), resultCompensationFunction, - aggregateMappings); + groupByMappings); } } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java index 374f21b21a..dfb34dba34 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java @@ -30,6 +30,7 @@ import com.apple.foundationdb.record.query.plan.cascades.ComparisonRange; import com.apple.foundationdb.record.query.plan.cascades.Compensation; import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier; +import com.apple.foundationdb.record.query.plan.cascades.GroupByMappings; import com.apple.foundationdb.record.query.plan.cascades.LinkedIdentitySet; import com.apple.foundationdb.record.query.plan.cascades.MatchCandidate; import com.apple.foundationdb.record.query.plan.cascades.MatchPartition; @@ -61,6 +62,7 @@ import com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryUnorderedPrimaryKeyDistinctPlan; import com.apple.foundationdb.record.util.pair.NonnullPair; +import com.google.common.base.Suppliers; import com.google.common.base.Verify; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -84,6 +86,7 @@ import java.util.Optional; import java.util.Set; import java.util.function.Function; +import java.util.function.Supplier; /** * A rule that utilizes index matching information compiled by {@link CascadesPlanner} to create one or more @@ -283,19 +286,12 @@ protected Set dataAccessForMatchPartition(@Nonnu addToIntersectionInfoMap(intersectionInfoMap, bestMatchWithIndex, compensatedSingleAccessExpressionOptional); } - final var bestMatchToDistinctPlanMap = - distinctMatchToScanMap(call, bestMatchToPlanMap); - - final var commonPrimaryKeyValuesOptional = - commonRecordKeyValuesMaybe( - bestMaximumCoverageMatches.stream() - .map(singleMatchedAccessVectored -> - singleMatchedAccessVectored.getElement().getPartialMatch()) - .collect(ImmutableList.toImmutableList())); - if (commonPrimaryKeyValuesOptional.isEmpty() || bestMaximumCoverageMatches.size() == 1) { + if (bestMaximumCoverageMatches.size() == 1) { return intersectionInfoMapToExpressions(intersectionInfoMap); } - final var commonPrimaryKeyValues = commonPrimaryKeyValuesOptional.get(); + + final var bestMatchToDistinctPlanMap = + distinctMatchToScanMap(call, bestMatchToPlanMap); // // Create all combinations of scans for all best matches and intersect them. @@ -339,7 +335,6 @@ protected Set dataAccessForMatchPartition(@Nonnu createIntersectionAndCompensation( call, intersectionInfoMap, - commonPrimaryKeyValues, bestMatchToDistinctPlanMap, binaryPartition, requestedOrderings); @@ -397,7 +392,6 @@ protected Set dataAccessForMatchPartition(@Nonnu createIntersectionAndCompensation( call, intersectionInfoMap, - commonPrimaryKeyValues, bestMatchToDistinctPlanMap, kPartition, requestedOrderings); @@ -423,7 +417,7 @@ protected Set dataAccessForMatchPartition(@Nonnu } @Nonnull - private static Optional> commonRecordKeyValuesMaybe(@Nonnull Iterable partialMatches) { + protected static Optional> commonRecordKeyValuesMaybe(@Nonnull Iterable partialMatches) { List common = null; var first = true; for (final var partialMatch : partialMatches) { @@ -439,22 +433,22 @@ private static Optional> commonRecordKeyValuesMaybe(@Nonnull Iterabl } key = keyMaybe.get(); } else if (matchCandidate instanceof AggregateIndexMatchCandidate) { - final var aggregateIndexMatchCandidate = (AggregateIndexMatchCandidate)matchCandidate; - final var rollUpToGroupingValues = regularMatchInfo.getRollUpToGroupingValues(); - if (rollUpToGroupingValues == null) { - key = aggregateIndexMatchCandidate.getGroupByValues(); - } else { - key = aggregateIndexMatchCandidate.getGroupByValues().subList(0, rollUpToGroupingValues.size()); - } - // final var aggregateIndexMatchCandidate = (AggregateIndexMatchCandidate)matchCandidate; // final var rollUpToGroupingValues = regularMatchInfo.getRollUpToGroupingValues(); // if (rollUpToGroupingValues == null) { -// key = aggregateIndexMatchCandidate.getGroupingAndAggregateAccessors(Quantifier.current()).getLeft(); +// key = aggregateIndexMatchCandidate.getGroupByValues(); // } else { -// key = aggregateIndexMatchCandidate.getGroupingAndAggregateAccessors(rollUpToGroupingValues.size(), -// Quantifier.current()).getLeft(); +// key = aggregateIndexMatchCandidate.getGroupByValues().subList(0, rollUpToGroupingValues.size()); // } + + final var aggregateIndexMatchCandidate = (AggregateIndexMatchCandidate)matchCandidate; + final var rollUpToGroupingValues = regularMatchInfo.getRollUpToGroupingValues(); + if (rollUpToGroupingValues == null) { + key = aggregateIndexMatchCandidate.getGroupingAndAggregateAccessors(Quantifier.current()).getLeft(); + } else { + key = aggregateIndexMatchCandidate.getGroupingAndAggregateAccessors(rollUpToGroupingValues.size(), + Quantifier.current()).getLeft(); + } } else { return Optional.empty(); } @@ -589,7 +583,8 @@ private static List prepareMatchesAndCompensations(final @N final @Nonnull Set requestedOrderings) { final var partialMatchesWithCompensation = new ArrayList(); for (final var partialMatch: partialMatches) { - final var satisfyingOrderingsPairOptional = satisfiesAnyRequestedOrderings(partialMatch, requestedOrderings); + final var satisfyingOrderingsPairOptional = + satisfiesAnyRequestedOrderings(partialMatch, requestedOrderings); if (satisfyingOrderingsPairOptional.isEmpty()) { continue; } @@ -645,14 +640,25 @@ private static List prepareMatchesAndCompensations(final @N @SuppressWarnings("java:S135") private static Optional>> satisfiesAnyRequestedOrderings(@Nonnull final PartialMatch partialMatch, @Nonnull final Set requestedOrderings) { + final var maxMatchMap = partialMatch.getMatchInfo().getMaxMatchMap(); + final var translationMapOptional = + maxMatchMap.pullUpMaybe(Quantifier.current(), Quantifier.current()); + if (translationMapOptional.isEmpty()) { + return Optional.empty(); + } + final var translationMap = translationMapOptional.get(); + boolean seenForward = false; boolean seenReverse = false; final var satisfyingRequestedOrderings = ImmutableSet.builder(); for (final var requestedOrdering : requestedOrderings) { + final var translatedRequestedOrdering = + requestedOrdering.translateCorrelations(translationMap, true); + final var scanDirectionForRequestedOrderingOptional = - satisfiesRequestedOrdering(partialMatch, requestedOrdering); + satisfiesRequestedOrdering(partialMatch, translatedRequestedOrdering); if (scanDirectionForRequestedOrderingOptional.isPresent()) { - satisfyingRequestedOrderings.add(requestedOrdering); + satisfyingRequestedOrderings.add(translatedRequestedOrdering); // Note, that a match may satisfy one requested ordering using a forward scan and another requested // ordering using a reverse scan. final var scanDirectionForRequestedOrdering = scanDirectionForRequestedOrderingOptional.get(); @@ -848,7 +854,6 @@ private static Optional applyCompensationForSingleDataAcce * before using the resulting {@link Compensation} to compute the compensating expression for the entire * intersection. * @param memoizer the memoizer - * @param commonPrimaryKeyValues normalized common primary key * @param matchToPlanMap a map from match to single data access expression * @param partition a partition (i.e. a list of {@link SingleMatchedAccess}es that the caller would like to compute * and intersected data access for @@ -859,7 +864,6 @@ private static Optional applyCompensationForSingleDataAcce @Nonnull protected abstract IntersectionResult createIntersectionAndCompensation(@Nonnull final Memoizer memoizer, @Nonnull final Map intersectionInfoMap, - @Nonnull final List commonPrimaryKeyValues, @Nonnull final Map matchToPlanMap, @Nonnull final List> partition, @Nonnull final Set requestedOrderings); @@ -948,7 +952,7 @@ private static Optional compensationMaybe(@ private static Optional> unmatchedIdsMaybe(@Nonnull final IntersectionInfo intersectionInfo) { final var compensationOptional = compensationMaybe(intersectionInfo); return compensationOptional.map(compensation -> - compensation.getAggregateMappings().getUnmatchedAggregateMap().keySet()); + compensation.getGroupByMappings().getUnmatchedAggregatesMap().keySet()); } @Nonnull @@ -1134,6 +1138,8 @@ protected static class SingleMatchedAccess { private final boolean reverseScanOrder; @Nonnull private final Set satisfyingRequestedOrderings; + @Nonnull + private final Supplier pulledUpGroupByMappingsSupplier; public SingleMatchedAccess(@Nonnull final PartialMatch partialMatch, @Nonnull final Compensation compensation, @@ -1145,6 +1151,9 @@ public SingleMatchedAccess(@Nonnull final PartialMatch partialMatch, this.candidateTopAlias = candidateTopAlias; this.reverseScanOrder = reverseScanOrder; this.satisfyingRequestedOrderings = ImmutableSet.copyOf(satisfyingRequestedOrderings); + this.pulledUpGroupByMappingsSupplier = + Suppliers.memoize(() -> partialMatch.getMatchInfo() + .adjustGroupByMappings(Quantifier.current(), partialMatch.getCandidateRef().get())); } @Nonnull @@ -1170,6 +1179,19 @@ public boolean isReverseScanOrder() { public Set getSatisfyingRequestedOrderings() { return satisfyingRequestedOrderings; } + + @Nonnull + public GroupByMappings getPulledUpGroupByMappingsForOrdering() { + return pulledUpGroupByMappingsSupplier.get(); + } + + @Override + public String toString() { + return "[" + partialMatch + ", " + compensation + + ", " + candidateTopAlias + + ", " + (reverseScanOrder ? "forward" : "reverse") + + ", " + satisfyingRequestedOrderings + ']'; + } } protected static class Vectored { diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java index 0358356f1d..8434e9ebb4 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java @@ -22,7 +22,6 @@ import com.apple.foundationdb.annotation.API; import com.apple.foundationdb.record.query.plan.cascades.AggregateIndexMatchCandidate; -import com.apple.foundationdb.record.query.plan.cascades.AliasMap; import com.apple.foundationdb.record.query.plan.cascades.CascadesPlanner; import com.apple.foundationdb.record.query.plan.cascades.CascadesRuleCall; import com.apple.foundationdb.record.query.plan.cascades.Column; @@ -38,6 +37,7 @@ import com.apple.foundationdb.record.query.plan.cascades.Quantifiers; import com.apple.foundationdb.record.query.plan.cascades.RequestedOrdering; import com.apple.foundationdb.record.query.plan.cascades.RequestedOrderingConstraint; +import com.apple.foundationdb.record.query.plan.cascades.ValueEquivalence; import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression; import com.apple.foundationdb.record.query.plan.cascades.expressions.SelectExpression; import com.apple.foundationdb.record.query.plan.cascades.matching.structure.BindingMatcher; @@ -105,7 +105,6 @@ public void onMatch(@Nonnull final CascadesRuleCall call) { } final var expression = bindings.get(getExpressionMatcher()); - final var correlatedTo = expression.getCorrelatedTo(); // // return if there is no pre-determined interesting ordering @@ -144,20 +143,9 @@ public void onMatch(@Nonnull final CascadesRuleCall call) { // loop through all compensated alias sets and their associated match partitions for (final var matchPartitionByMatchAliasEntry : matchPartitionByMatchAliasMap.entrySet()) { - final var matchedAlias = matchPartitionByMatchAliasEntry.getKey(); final var matchPartitionForMatchedAlias = matchPartitionByMatchAliasEntry.getValue(); - // - // Pull down the requested orderings along the matchedAlias - // - final var pushedRequestedOrderings = - requestedOrderings.stream() - .map(requestedOrdering -> - requestedOrdering.pushDown(expression.getResultValue(), matchedAlias, - AliasMap.emptyMap(), correlatedTo)) - .collect(ImmutableSet.toImmutableSet()); - // // We do know that local predicates (which includes predicates only using the matchedAlias quantifier) // are definitely handled by the logic expressed by the partial matches of the current match partition. @@ -191,7 +179,7 @@ public void onMatch(@Nonnull final CascadesRuleCall call) { // final var dataAccessExpressions = dataAccessForMatchPartition(call, - pushedRequestedOrderings, + requestedOrderings, matchPartition); call.yieldExpression(dataAccessExpressions); } @@ -202,10 +190,21 @@ public void onMatch(@Nonnull final CascadesRuleCall call) { @Override protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Memoizer memoizer, @Nonnull final Map intersectionInfoMap, - @Nonnull final List commonPrimaryKeyValues, @Nonnull final Map matchToPlanMap, @Nonnull final List> partition, @Nonnull final Set requestedOrderings) { + Verify.verify(partition.size() > 1); + final var commonRecordKeyValuesOptional = + commonRecordKeyValuesMaybe( + partition.stream() + .map(singleMatchedAccessVectored -> + singleMatchedAccessVectored.getElement().getPartialMatch()) + .collect(ImmutableList.toImmutableList())); + if (commonRecordKeyValuesOptional.isEmpty()) { + return IntersectionResult.noCommonOrdering(); + } + final var commonRecordKeyValues = commonRecordKeyValuesOptional.get(); + final var partitionOrderings = partition.stream() .map(Vectored::getElement) @@ -243,11 +242,15 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me intersectionOrdering.enumerateSatisfyingComparisonKeyValues(requestedOrdering); for (final var comparisonKeyValues : comparisonKeyValuesIterable) { if (!isCompatibleComparisonKey(comparisonKeyValues, - commonPrimaryKeyValues, + commonRecordKeyValues, equalityBoundKeyValues)) { continue; } + if (!isCompatibleDerivationAcrossMatches(partition, comparisonKeyValues)) { + continue; + } + hasCommonOrdering = true; if (!compensation.isImpossible()) { var comparisonOrderingParts = @@ -270,7 +273,7 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me final var newQuantifiers = newQuantifiersBuilder.build(); final var commonAndPickUpValues = - computeCommonAndPickUpValues(partition, commonPrimaryKeyValues.size()); + computeCommonAndPickUpValues(partition, commonRecordKeyValues.size()); final var intersectionResultValue = computeIntersectionResultValue(newQuantifiers, commonAndPickUpValues.getLeft(), commonAndPickUpValues.getRight()); final var intersectionPlan = @@ -281,7 +284,7 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me baseAlias -> computeTranslationMap(baseAlias, newQuantifiers, candidateTopAliasesBuilder.build(), (Type.Record)intersectionResultValue.getResultType(), - commonPrimaryKeyValues.size())); + commonRecordKeyValues.size())); expressionsBuilder.add(compensatedIntersection); } } @@ -291,6 +294,37 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me expressionsBuilder.build()); } + private static boolean isCompatibleDerivationAcrossMatches(@Nonnull final List> partition, + @Nonnull final List comparisonKeyValues) { + for (final var comparisonKeyValue : comparisonKeyValues) { + Value queryComparisonKeyValue = null; + for (final var singleMatchedAccessWithIndex : partition) { + final var singledMatchedAccess = singleMatchedAccessWithIndex.getElement(); + final var groupByMappings = singledMatchedAccess.getPulledUpGroupByMappingsForOrdering(); + final var inverseMatchedGroupingsMap = + groupByMappings.getMatchedGroupingsMap().inverse(); + final var currentQueryComparisonKeyValue = inverseMatchedGroupingsMap.get(comparisonKeyValue); + if (currentQueryComparisonKeyValue == null) { + return false; + } + if (queryComparisonKeyValue == null) { + queryComparisonKeyValue = currentQueryComparisonKeyValue; + } else { + final var semanticEquals = + queryComparisonKeyValue.semanticEquals(currentQueryComparisonKeyValue, + ValueEquivalence.empty()); + if (semanticEquals.isFalse()) { + return false; + } + if (!semanticEquals.getConstraint().isTautology()) { + return false; + } + } + } + } + return true; + } + @Nonnull private static NonnullPair, List> computeCommonAndPickUpValues(@Nonnull final List> partition, final int numGroupings) { diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/WithPrimaryKeyDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/WithPrimaryKeyDataAccessRule.java index ad9e678491..04297ef436 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/WithPrimaryKeyDataAccessRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/WithPrimaryKeyDataAccessRule.java @@ -21,7 +21,6 @@ package com.apple.foundationdb.record.query.plan.cascades.rules; import com.apple.foundationdb.annotation.API; -import com.apple.foundationdb.record.query.plan.cascades.AliasMap; import com.apple.foundationdb.record.query.plan.cascades.CascadesPlanner; import com.apple.foundationdb.record.query.plan.cascades.CascadesRuleCall; import com.apple.foundationdb.record.query.plan.cascades.ComparisonRange; @@ -39,13 +38,13 @@ import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression; import com.apple.foundationdb.record.query.plan.cascades.expressions.SelectExpression; import com.apple.foundationdb.record.query.plan.cascades.matching.structure.BindingMatcher; -import com.apple.foundationdb.record.query.plan.cascades.values.Value; import com.apple.foundationdb.record.query.plan.cascades.values.translation.TranslationMap; import com.apple.foundationdb.record.query.plan.plans.RecordQueryIntersectionPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQuerySetPlan; import com.apple.foundationdb.record.util.pair.NonnullPair; import com.apple.foundationdb.record.util.pair.Pair; +import com.google.common.base.Verify; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; @@ -138,17 +137,8 @@ public void onMatch(@Nonnull final CascadesRuleCall call) { // loop through all compensated alias sets and their associated match partitions for (final var matchPartitionByMatchAliasEntry : matchPartitionByMatchAliasMap.entrySet()) { - final var matchedAlias = matchPartitionByMatchAliasEntry.getKey(); final var matchPartitionForMatchedAlias = matchPartitionByMatchAliasEntry.getValue(); - // - // Pull down the requested orderings along the matchedAlias - // - final var pushedRequestedOrderings = - requestedOrderings.stream() - .map(requestedOrdering -> requestedOrdering.pushDown(expression.getResultValue(), matchedAlias, AliasMap.emptyMap(), correlatedTo)) - .collect(ImmutableSet.toImmutableSet()); - // // We do know that local predicates (which includes predicates only using the matchedAlias quantifier) // are definitely handled by the logic expressed by the partial matches of the current match partition. @@ -182,7 +172,7 @@ public void onMatch(@Nonnull final CascadesRuleCall call) { // final var dataAccessExpressions = dataAccessForMatchPartition(call, - pushedRequestedOrderings, + requestedOrderings, matchPartition); call.yieldExpression(dataAccessExpressions); } @@ -193,10 +183,22 @@ public void onMatch(@Nonnull final CascadesRuleCall call) { @Override protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Memoizer memoizer, @Nonnull final Map intersectionInfoMap, - @Nonnull final List commonPrimaryKeyValues, @Nonnull final Map matchToPlanMap, @Nonnull final List> partition, @Nonnull final Set requestedOrderings) { + Verify.verify(partition.size() > 1); + final var commonRecordKeyValuesOptional = + commonRecordKeyValuesMaybe( + partition.stream() + .map(singleMatchedAccessVectored -> + singleMatchedAccessVectored.getElement().getPartialMatch()) + .collect(ImmutableList.toImmutableList())); + if (commonRecordKeyValuesOptional.isEmpty()) { + return IntersectionResult.noCommonOrdering(); + } + + final var commonPrimaryKeyValues = commonRecordKeyValuesOptional.get(); + final var partitionOrderings = partition.stream() .map(Vectored::getElement) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/translation/MaxMatchMap.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/translation/MaxMatchMap.java index a9c01df03f..97a6ca9551 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/translation/MaxMatchMap.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/translation/MaxMatchMap.java @@ -289,6 +289,17 @@ public Optional adjustMaybe(@Nonnull final CorrelationIdentifier up rangedOverAliases)); } + @Nonnull + public Optional pullUpMaybe(@Nonnull final CorrelationIdentifier queryAlias, + @Nonnull final CorrelationIdentifier candidateAlias) { + final var translatedQueryValueOptional = translateQueryValueMaybe(candidateAlias); + return translatedQueryValueOptional + .map(translatedQueryValue -> + TranslationMap.builder() + .when(queryAlias).then(TranslationMap.TranslationFunction.adjustValueType(translatedQueryValue)) + .build()); + } + @Override public String toString() { return "M³(" + diff --git a/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/UnnestedRecordTypeTest.java b/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/UnnestedRecordTypeTest.java index 73bcc1ca9e..9f2b354e1c 100644 --- a/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/UnnestedRecordTypeTest.java +++ b/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/UnnestedRecordTypeTest.java @@ -2318,7 +2318,7 @@ void deleteWhereOnMultiTypeFailsWithAmbiguousParent() { void deleteWhereOnMultiTypeFailsWithRecordTypePrefix() { // Create a multi-type index on two different unnested types. Each one has a parent constituent named and an inner constituent, so the index is well-defined. // The multi-type index in this case has a record type prefix. In theory, we actually could perform the delete records where, but the record type key in the - // index matches the synthetic type's record type key, not the base type. This means we'd need to translate the record type key before deleting data from the + // index matches the synthetic type's record type key, not the base type. This means we'd need to translateCorrelations the record type key before deleting data from the // index. Until we get that working, just assert that this fails. final RecordMetaDataHook hook = addMultiTypeDoubleUnnestedIndex(concat(recordType(), field(PARENT_CONSTITUENT).nest(field("middle").nest("other_int")), field("inner").nest("foo"))) .andThen(setOuterAndMiddlePrimaryKey(concat(recordType(), field("middle").nest("other_int"), field("rec_no")))); diff --git a/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/query/plan/cascades/values/ValueTranslationTest.java b/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/query/plan/cascades/values/ValueTranslationTest.java index b4bbb1132b..dd2fc6b2a9 100644 --- a/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/query/plan/cascades/values/ValueTranslationTest.java +++ b/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/query/plan/cascades/values/ValueTranslationTest.java @@ -722,7 +722,7 @@ translation of (t.a.q, t.a.r, (t.b.t), t.j.s) with correlation mapping of t -> t Assertions.assertEquals(expectedL1TranslatedQueryNValue, l1m3ForNValue.getQueryValue()); Assertions.assertEquals(n_v, l1m3ForNValue.getCandidateValue()); - // translate a complex join condition, each quantifier in the join condition is assumed to match a corresponding + // translateCorrelations a complex join condition, each quantifier in the join condition is assumed to match a corresponding // quantifier in a non-joined index candidate. /* @@ -952,7 +952,7 @@ translation of (t.a.q, t.a.r, (t.b.t), t.j.s) with correlation mapping of t -> t final var l1m3ForMValue = calculate(l1TranslatedQueryMValue, m_v); final var l1m3ForNValue = calculate(l1TranslatedQueryNValue, n_v); - // translate a complex join condition, each quantifier in the join condition is assumed to match a corresponding + // translateCorrelations a complex join condition, each quantifier in the join condition is assumed to match a corresponding // quantifier in a non-joined index candidate. /* diff --git a/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/search/BooleanPointsConfig.java b/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/search/BooleanPointsConfig.java index 3b1187ea8a..b0d7fdd907 100644 --- a/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/search/BooleanPointsConfig.java +++ b/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/search/BooleanPointsConfig.java @@ -26,7 +26,7 @@ import java.text.NumberFormat; /** - * A subclass of PointsConfig to allow the Parser the ability to translate boolean terms to binary ones. + * A subclass of PointsConfig to allow the Parser the ability to translateCorrelations boolean terms to binary ones. */ public class BooleanPointsConfig extends PointsConfig { diff --git a/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/api/metrics/NoOpMetricRegistry.java b/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/api/metrics/NoOpMetricRegistry.java index 7296c260cb..ceeae4ef02 100644 --- a/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/api/metrics/NoOpMetricRegistry.java +++ b/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/api/metrics/NoOpMetricRegistry.java @@ -31,7 +31,7 @@ *

* NOTE(stack): Consider NOT using codahale but prometheus metrics. If server is exporting metrics * on an prometheus endpoint, codahale will require translation (there are translators but better not - * to translate at all). What is the story for clients? RL is codahale? + * to translateCorrelations at all). What is the story for clients? RL is codahale? */ @API(API.Status.EXPERIMENTAL) public final class NoOpMetricRegistry { diff --git a/yaml-tests/src/test/resources/composite-aggregates.yamsql b/yaml-tests/src/test/resources/composite-aggregates.yamsql index 0fc54e44ab..1daef5c819 100644 --- a/yaml-tests/src/test/resources/composite-aggregates.yamsql +++ b/yaml-tests/src/test/resources/composite-aggregates.yamsql @@ -24,6 +24,8 @@ schema_template: create table t3(id bigint, col1 bigint, col2 bigint, col3 bigint, primary key(id)) create index t1_i1 as select count(col1) from t1 group by col2, col3 create index t1_i2 as select col2, sum(col1) from t1 group by col2 + create index t1_i3 as select col3, col2, sum(col1) from t1 group by col3, col2 + create index t1_i4 as select col2, col3, sum(col1) from t1 group by col2, col3 create index t2_i1 as select count(*) from t2 create index t2_i2 as select count(*) from t2 group by col1 create index t2_i3 as select count(col2) from t2 @@ -100,11 +102,15 @@ test_block: # - explain: "AISCAN(T2_I6 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 / _._2 AS _0)" # - result: [] #- - # - query: select col2, sum(col1) / count(col1) from T1 where col2 < 2 group by col2 having sum(col1) = 17; + # - query: select col2, sum(col1) / count(col1) from T1 where col2 < 2 group by col2 having sum(col1) = 17 order by col2; # - explain: "AISCAN(T1_I2 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T1_I1 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | AGG sum_l(_._1) GROUP BY (_._0 AS _0) COMPARE BY (_._0._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | FILTER _._1 EQUALS promote(@c26 AS LONG) | MAP (_._1 / _._2 AS _0)" # - result: [] - - - query: select col1, min(col2), max(col2) from T3 group by col1, col3; - - explain: "AISCAN(T3_I2 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._0 AS COL1, _._2 AS _1)" - - result: [] + - query: select col2, sum(col1) / count(col1) from T1 where col2 < 2 group by col2, col3 having sum(col1) = 17; + - explain: "AISCAN(T1_I2 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T1_I1 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | AGG sum_l(_._1) GROUP BY (_._0 AS _0) COMPARE BY (_._0._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | FILTER _._1 EQUALS promote(@c26 AS LONG) | MAP (_._1 / _._2 AS _0)" + - result: [] + #- + # - query: select col1, min(col2), max(col2) from T3 group by col1, col3; + # - explain: "AISCAN(T3_I2 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._0 AS COL1, _._2 AS _1)" + # - result: [] ... From 8ab570979cdd89b4910e2977427d548eb71070dd Mon Sep 17 00:00:00 2001 From: Normen Seemann Date: Sat, 5 Apr 2025 21:36:46 +0200 Subject: [PATCH 16/20] agg testcases run --- .../AggregateIndexMatchCandidate.java | 16 ++- .../query/plan/cascades/Compensation.java | 24 ++-- .../cascades/properties/OrderingProperty.java | 6 +- .../rules/AbstractDataAccessRule.java | 63 +++++----- .../rules/AggregateDataAccessRule.java | 112 +++++++++++++----- .../rules/WithPrimaryKeyDataAccessRule.java | 17 ++- .../composite-aggregates.metrics.binpb | 22 ++-- .../composite-aggregates.metrics.yaml | 18 +-- .../resources/composite-aggregates.yamsql | 40 +++---- 9 files changed, 195 insertions(+), 123 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java index 0f488b2a75..6df5c91d18 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java @@ -206,8 +206,8 @@ private int getPermutedCount() { public List computeMatchedOrderingParts(@Nonnull final MatchInfo matchInfo, @Nonnull final List sortParameterIds, final boolean isReverse) { - final var parameterBindingMap = - matchInfo.getRegularMatchInfo().getParameterBindingMap(); + final var regularMatchInfo = matchInfo.getRegularMatchInfo(); + final var parameterBindingMap = regularMatchInfo.getParameterBindingMap(); final var normalizedKeyExpressions = getFullKeyExpression().normalizeKeyForPositions(); @@ -219,13 +219,17 @@ public List computeMatchedOrderingParts(@Nonnull final Matc final var deconstructedValues = Values.deconstructRecord(QuantifiedObjectValue.of(Quantifier.current(), selectHavingResultType)); + final var rollUpToGroupingValues = regularMatchInfo.getRollUpToGroupingValues(); + final int orderSize = rollUpToGroupingValues != null ? rollUpToGroupingValues.size() : sortParameterIds.size(); + // Compute the ordering for this index by collecting the result values of the selectHaving statement // associated with each sortParameterId. Note that for most aggregate indexes, the aggregate value is // in the FDB value, and so it does not contribute to the ordering of the index, so there is no sortParameterId // corresponding to it. For the PERMUTED_MIN and PERMUTED_MAX indexes, the aggregate _does_ have a corresponding // sortParameterId. Its position is determined by the permutedSize option, handled below by adjusting the // sortParameterId's index before looking it up in the original key expression - for (final var parameterId : sortParameterIds) { + for (int i = 0; i < orderSize; i++) { + final var parameterId = sortParameterIds.get(i); final var ordinalInCandidate = candidateParameterIds.indexOf(parameterId); Verify.verify(ordinalInCandidate >= 0); int permutedIndex = indexWithPermutation(ordinalInCandidate); @@ -425,6 +429,7 @@ public RecordQueryPlan toEquivalentPlan(@Nonnull final PartialMatch partialMatch selectHavingResultValue, groupByResultValue, constraintMaybe); + if (regularMatchInfo.getRollUpToGroupingValues() != null) { // // We need to perform a roll up. @@ -434,14 +439,13 @@ public RecordQueryPlan toEquivalentPlan(@Nonnull final PartialMatch partialMatch //final var recordValues = Values.deconstructRecord(recordValue); final var groupingAndAggregateAccessors = - getGroupingAndAggregateAccessors(regularMatchInfo.getRollUpToGroupingValues().size(), - aggregateIndexScanAlias); + getGroupingAndAggregateAccessors(getGroupingCount(), aggregateIndexScanAlias); final var groupingAccessorValues = groupingAndAggregateAccessors.getLeft(); final var aggregateAccessorValue = groupingAndAggregateAccessors.getRight(); final var allFields = resultType.getFields(); final var rollUpGroupingColumnsBuilder = ImmutableList.>builder(); - for (int i = 0; i < groupingAccessorValues.size(); i++) { + for (int i = 0; i < regularMatchInfo.getRollUpToGroupingValues().size(); i++) { final var field = allFields.get(i); rollUpGroupingColumnsBuilder.add(Column.of(field, groupingAccessorValues.get(i))); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java index c4d58f1e18..77508fdb1c 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/Compensation.java @@ -634,6 +634,8 @@ default Compensation intersect(@Nonnull Compensation otherCompensation) { final var newGroupByMappings = GroupByMappings.of(newMatchedGroupingsMapBuilder.build(), newMatchedAggregatesMap, newUnmatchedAggregatesMapBuilder.build()); + boolean isImpossible = false; + final ResultCompensationFunction newResultResultCompensationFunction; final var resultCompensationFunction = getResultCompensationFunction(); final var otherResultCompensationFunction = otherWithSelectCompensation.getResultCompensationFunction(); @@ -646,6 +648,7 @@ default Compensation intersect(@Nonnull Compensation otherCompensation) { // pick the one from this side -- it does not matter as both candidates have the same shape newResultResultCompensationFunction = resultCompensationFunction.amend(unmatchedAggregateMap, newMatchedAggregatesMap); + isImpossible |= newResultResultCompensationFunction.isImpossible(); } final var otherCompensationMap = @@ -656,14 +659,17 @@ default Compensation intersect(@Nonnull Compensation otherCompensation) { final var otherPredicateCompensationFunction = otherCompensationMap.get(entry.getKey()); if (otherPredicateCompensationFunction != null) { // Both compensations have a compensation for this particular predicate which is essentially - // reapplying the predicate. Three cases arise: + // reapplying the predicate. Two cases arise: // 1. Both predicate compensation functions are needed and possible. At this point it doesn't // matter which side we take as both create the same compensating filter. If at any point in the // future one data access has a better reapplication we need to generate plan variants with // either compensation and let the planner figure out which one wins. We just pick one side here. - // 2. TODO. - combinedPredicateMap.put(entry.getKey(), - entry.getValue().amend(unmatchedAggregateMap, newMatchedAggregatesMap)); + // 2. Either one or both compensation functions are impossible, but thee intersection is possible. + // We take the compensation function from this side and amend it with the compensation function + // from the other side. + final var newPredicateCompensationFunction = entry.getValue().amend(unmatchedAggregateMap, newMatchedAggregatesMap); + combinedPredicateMap.put(entry.getKey(), newPredicateCompensationFunction); + isImpossible |= newPredicateCompensationFunction.isImpossible(); } } @@ -686,10 +692,12 @@ default Compensation intersect(@Nonnull Compensation otherCompensation) { final var unmatchedQuantifiers = Sets.intersection(this.getUnmatchedQuantifiers(), otherWithSelectCompensation.getUnmatchedQuantifiers()); final var unmatchedQuantifierAliases = unmatchedQuantifiers.stream().map(Quantifier::getAlias).collect(ImmutableList.toImmutableList()); - final var isImpossible = combinedPredicateMap.keySet() - .stream() - .flatMap(queryPredicate -> queryPredicate.getCorrelatedTo().stream()) - .anyMatch(unmatchedQuantifierAliases::contains); + if (!isImpossible) { + isImpossible = combinedPredicateMap.keySet() + .stream() + .flatMap(queryPredicate -> queryPredicate.getCorrelatedTo().stream()) + .anyMatch(unmatchedQuantifierAliases::contains); + } return intersectedChildCompensation.derived(isImpossible, combinedPredicateMap, diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/OrderingProperty.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/OrderingProperty.java index 1bb5d784b2..3f745ffdd0 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/OrderingProperty.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/OrderingProperty.java @@ -495,8 +495,10 @@ public Ordering visitInUnionOnKeyExpressionPlan(@Nonnull final RecordQueryInUnio @Nonnull @Override - public Ordering visitMultiIntersectionOnValuesPlan(@Nonnull final RecordQueryMultiIntersectionOnValuesPlan element) { - return Ordering.empty(); // TODO + public Ordering visitMultiIntersectionOnValuesPlan(@Nonnull final RecordQueryMultiIntersectionOnValuesPlan multiIntersectionOnValuesPlan) { + final var orderings = orderingsFromChildren(multiIntersectionOnValuesPlan); + return deriveForDistinctSetOperationFromOrderings(orderings, + multiIntersectionOnValuesPlan.getComparisonKeyOrderingParts(), Ordering.INTERSECTION); } @Nonnull diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java index dfb34dba34..2d9242523d 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java @@ -338,7 +338,7 @@ protected Set dataAccessForMatchPartition(@Nonnu bestMatchToDistinctPlanMap, binaryPartition, requestedOrderings); - if (binaryIntersections.hasCommonIntersectionOrdering()) { + if (binaryIntersections.hasViableIntersection()) { updateIntersectionInfoMap(intersectionInfoMap, binaryPartition, binaryIntersections); } else { if (sieveBitMatrix != null) { @@ -396,7 +396,10 @@ protected Set dataAccessForMatchPartition(@Nonnu kPartition, requestedOrderings); - Verify.verify(intersectionResult.hasCommonIntersectionOrdering()); + if (!intersectionResult.hasViableIntersection()) { + continue; + } + hasCommonOrderingForK = true; updateIntersectionInfoMap(intersectionInfoMap, kPartition, intersectionResult); @@ -433,14 +436,6 @@ protected static Optional> commonRecordKeyValuesMaybe(@Nonnull Itera } key = keyMaybe.get(); } else if (matchCandidate instanceof AggregateIndexMatchCandidate) { -// final var aggregateIndexMatchCandidate = (AggregateIndexMatchCandidate)matchCandidate; -// final var rollUpToGroupingValues = regularMatchInfo.getRollUpToGroupingValues(); -// if (rollUpToGroupingValues == null) { -// key = aggregateIndexMatchCandidate.getGroupByValues(); -// } else { -// key = aggregateIndexMatchCandidate.getGroupByValues().subList(0, rollUpToGroupingValues.size()); -// } - final var aggregateIndexMatchCandidate = (AggregateIndexMatchCandidate)matchCandidate; final var rollUpToGroupingValues = regularMatchInfo.getRollUpToGroupingValues(); if (rollUpToGroupingValues == null) { @@ -583,8 +578,13 @@ private static List prepareMatchesAndCompensations(final @N final @Nonnull Set requestedOrderings) { final var partialMatchesWithCompensation = new ArrayList(); for (final var partialMatch: partialMatches) { + final var topToTopTranslationMapOptional = computeTopToTopTranslationMapMaybe(partialMatch); + if (topToTopTranslationMapOptional.isEmpty()) { + continue; + } + final var topToTopTranslationMap = topToTopTranslationMapOptional.get(); final var satisfyingOrderingsPairOptional = - satisfiesAnyRequestedOrderings(partialMatch, requestedOrderings); + satisfiesAnyRequestedOrderings(partialMatch, topToTopTranslationMap, requestedOrderings); if (satisfyingOrderingsPairOptional.isEmpty()) { continue; } @@ -604,7 +604,7 @@ private static List prepareMatchesAndCompensations(final @N if (scanDirection == ScanDirection.FORWARD || scanDirection == ScanDirection.BOTH) { partialMatchesWithCompensation.add(new SingleMatchedAccess(partialMatch, compensation, - topAlias, false, satisfyingOrderingsPair.getRight())); + topAlias, false, topToTopTranslationMap, satisfyingOrderingsPair.getRight())); } // @@ -617,7 +617,7 @@ private static List prepareMatchesAndCompensations(final @N // if (scanDirection == ScanDirection.REVERSE /* || scanDirection == ScanDirection.BOTH */) { partialMatchesWithCompensation.add(new SingleMatchedAccess(partialMatch, compensation, - topAlias, true, satisfyingOrderingsPair.getRight())); + topAlias, true, topToTopTranslationMap, satisfyingOrderingsPair.getRight())); } } @@ -627,6 +627,12 @@ private static List prepareMatchesAndCompensations(final @N return partialMatchesWithCompensation; } + @Nonnull + private static Optional computeTopToTopTranslationMapMaybe(final PartialMatch partialMatch) { + final var maxMatchMap = partialMatch.getMatchInfo().getMaxMatchMap(); + return maxMatchMap.pullUpMaybe(Quantifier.current(), Quantifier.current()); + } + /** * Private helper method to compute the subset of orderings passed in that would be satisfied by a scan * if the given {@link PartialMatch} were to be planned. @@ -639,21 +645,14 @@ private static List prepareMatchesAndCompensations(final @N @Nonnull @SuppressWarnings("java:S135") private static Optional>> satisfiesAnyRequestedOrderings(@Nonnull final PartialMatch partialMatch, + @Nonnull final TranslationMap topToTopTranslationMap, @Nonnull final Set requestedOrderings) { - final var maxMatchMap = partialMatch.getMatchInfo().getMaxMatchMap(); - final var translationMapOptional = - maxMatchMap.pullUpMaybe(Quantifier.current(), Quantifier.current()); - if (translationMapOptional.isEmpty()) { - return Optional.empty(); - } - final var translationMap = translationMapOptional.get(); - boolean seenForward = false; boolean seenReverse = false; final var satisfyingRequestedOrderings = ImmutableSet.builder(); for (final var requestedOrdering : requestedOrderings) { final var translatedRequestedOrdering = - requestedOrdering.translateCorrelations(translationMap, true); + requestedOrdering.translateCorrelations(topToTopTranslationMap, true); final var scanDirectionForRequestedOrderingOptional = satisfiesRequestedOrdering(partialMatch, translatedRequestedOrdering); @@ -1041,11 +1040,6 @@ private static Ordering orderingFromOrderingParts(final @Nonnull List comparisonKeyValues, @Nonnull List commonPrimaryKeyValues, @Nonnull ImmutableSet equalityBoundKeyValues) { -// if (comparisonKeyValues.isEmpty()) { -// // everything is in one row -// return true; -// } - return commonPrimaryKeyValues .stream() .filter(commonPrimaryKeyValue -> !equalityBoundKeyValues.contains(commonPrimaryKeyValue)) @@ -1085,7 +1079,7 @@ private static void updateIntersectionInfoMap(@Nonnull final Map= 2); final var cacheKey = intersectionInfoKey(partition); - if (intersectionResult.hasCommonIntersectionOrdering()) { + if (intersectionResult.hasViableIntersection()) { if (!intersectionResult.getExpressions().isEmpty()) { // This loop loops partition.size() times for (final var subPartition : ChooseK.chooseK(partition, partition.size() - 1)) { @@ -1137,6 +1131,8 @@ protected static class SingleMatchedAccess { private final CorrelationIdentifier candidateTopAlias; private final boolean reverseScanOrder; @Nonnull + private final TranslationMap topToTopTranslationMap; + @Nonnull private final Set satisfyingRequestedOrderings; @Nonnull private final Supplier pulledUpGroupByMappingsSupplier; @@ -1145,12 +1141,14 @@ public SingleMatchedAccess(@Nonnull final PartialMatch partialMatch, @Nonnull final Compensation compensation, @Nonnull final CorrelationIdentifier candidateTopAlias, final boolean reverseScanOrder, + @Nonnull final TranslationMap topToTopTranslationMap, @Nonnull final Set satisfyingRequestedOrderings) { this.partialMatch = partialMatch; this.compensation = compensation; this.candidateTopAlias = candidateTopAlias; this.reverseScanOrder = reverseScanOrder; this.satisfyingRequestedOrderings = ImmutableSet.copyOf(satisfyingRequestedOrderings); + this.topToTopTranslationMap = topToTopTranslationMap; this.pulledUpGroupByMappingsSupplier = Suppliers.memoize(() -> partialMatch.getMatchInfo() .adjustGroupByMappings(Quantifier.current(), partialMatch.getCandidateRef().get())); @@ -1175,6 +1173,11 @@ public boolean isReverseScanOrder() { return reverseScanOrder; } + @Nonnull + public TranslationMap getTopToTopTranslationMap() { + return topToTopTranslationMap; + } + @Nonnull public Set getSatisfyingRequestedOrderings() { return satisfyingRequestedOrderings; @@ -1262,7 +1265,7 @@ public List getExpressions() { return Objects.requireNonNull(expressions); } - public boolean hasCommonIntersectionOrdering() { + public boolean hasViableIntersection() { return commonIntersectionOrdering != null; } @@ -1277,7 +1280,7 @@ public Compensation getCompensation() { } @Nonnull - public static IntersectionResult noCommonOrdering() { + public static IntersectionResult noViableIntersection() { return new IntersectionResult(null, Compensation.noCompensation(), ImmutableList.of()); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java index 8434e9ebb4..1540e03c40 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java @@ -64,6 +64,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -201,7 +202,7 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me singleMatchedAccessVectored.getElement().getPartialMatch()) .collect(ImmutableList.toImmutableList())); if (commonRecordKeyValuesOptional.isEmpty()) { - return IntersectionResult.noCommonOrdering(); + return IntersectionResult.noViableIntersection(); } final var commonRecordKeyValues = commonRecordKeyValuesOptional.get(); @@ -226,7 +227,7 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me final var isPartitionRedundant = isPartitionRedundant(intersectionInfoMap, partition, equalityBoundKeyValues); if (isPartitionRedundant) { - return IntersectionResult.noCommonOrdering(); + return IntersectionResult.noViableIntersection(); } final var compensation = @@ -235,26 +236,37 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me .map(pair -> pair.getElement().getCompensation()) .reduce(Compensation.impossibleCompensation(), Compensation::intersect); + // + // Grab the first matched access from the partition in order to translate to the required ordering + // to the candidate's top. + // + final var firstMatchedAccess = partition.get(0).getElement(); + final var topToTopTranslationMap = firstMatchedAccess.getTopToTopTranslationMap(); + boolean hasCommonOrdering = false; final var expressionsBuilder = ImmutableList.builder(); for (final var requestedOrdering : requestedOrderings) { + final var translatedRequestedOrdering = + requestedOrdering.translateCorrelations(topToTopTranslationMap, true); + if (!areRequestedOrderingsDerivationsCompatibleAcrossMatches(partition, translatedRequestedOrdering)) { + continue; + } + final var comparisonKeyValuesIterable = - intersectionOrdering.enumerateSatisfyingComparisonKeyValues(requestedOrdering); + intersectionOrdering.enumerateSatisfyingComparisonKeyValues(translatedRequestedOrdering); for (final var comparisonKeyValues : comparisonKeyValuesIterable) { - if (!isCompatibleComparisonKey(comparisonKeyValues, - commonRecordKeyValues, - equalityBoundKeyValues)) { + if (!isCompatibleComparisonKey(comparisonKeyValues, commonRecordKeyValues, equalityBoundKeyValues)) { continue; } - if (!isCompatibleDerivationAcrossMatches(partition, comparisonKeyValues)) { + if (!areComparisonKeyDerivationsCompatibleAcrossMatches(partition, comparisonKeyValues)) { continue; } hasCommonOrdering = true; if (!compensation.isImpossible()) { var comparisonOrderingParts = - intersectionOrdering.directionalOrderingParts(comparisonKeyValues, requestedOrdering, + intersectionOrdering.directionalOrderingParts(comparisonKeyValues, translatedRequestedOrdering, OrderingPart.ProvidedSortOrder.FIXED); final var comparisonIsReverse = RecordQuerySetPlan.resolveComparisonDirection(comparisonOrderingParts); @@ -294,37 +306,75 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me expressionsBuilder.build()); } - private static boolean isCompatibleDerivationAcrossMatches(@Nonnull final List> partition, - @Nonnull final List comparisonKeyValues) { + private static boolean areRequestedOrderingsDerivationsCompatibleAcrossMatches(@Nonnull final List> partition, + @Nonnull final RequestedOrdering requestedOrdering) { + for (final var orderingPart : requestedOrdering.getOrderingParts()) { + if (isAggregateQueryValue(partition, orderingPart.getValue())) { + return false; + } + } + return true; + } + + private static boolean areComparisonKeyDerivationsCompatibleAcrossMatches(@Nonnull final List> partition, + @Nonnull final List comparisonKeyValues) { for (final var comparisonKeyValue : comparisonKeyValues) { - Value queryComparisonKeyValue = null; - for (final var singleMatchedAccessWithIndex : partition) { - final var singledMatchedAccess = singleMatchedAccessWithIndex.getElement(); - final var groupByMappings = singledMatchedAccess.getPulledUpGroupByMappingsForOrdering(); - final var inverseMatchedGroupingsMap = - groupByMappings.getMatchedGroupingsMap().inverse(); - final var currentQueryComparisonKeyValue = inverseMatchedGroupingsMap.get(comparisonKeyValue); - if (currentQueryComparisonKeyValue == null) { + if (consistentQueryValueForGroupingValueMaybe(partition, comparisonKeyValue).isEmpty()) { + if (!isAggregateQueryValue(partition, comparisonKeyValue)) { return false; } - if (queryComparisonKeyValue == null) { - queryComparisonKeyValue = currentQueryComparisonKeyValue; - } else { - final var semanticEquals = - queryComparisonKeyValue.semanticEquals(currentQueryComparisonKeyValue, - ValueEquivalence.empty()); - if (semanticEquals.isFalse()) { - return false; - } - if (!semanticEquals.getConstraint().isTautology()) { - return false; - } - } } } return true; } + @Nonnull + private static Optional consistentQueryValueForGroupingValueMaybe(@Nonnull final List> partition, + @Nonnull final Value comparisonKeyValue) { + Value queryComparisonKeyValue = null; + for (final var singleMatchedAccessWithIndex : partition) { + final var singledMatchedAccess = singleMatchedAccessWithIndex.getElement(); + final var groupByMappings = singledMatchedAccess.getPulledUpGroupByMappingsForOrdering(); + final var inverseMatchedGroupingsMap = + groupByMappings.getMatchedGroupingsMap().inverse(); + final var currentQueryComparisonKeyValue = inverseMatchedGroupingsMap.get(comparisonKeyValue); + if (currentQueryComparisonKeyValue == null) { + return Optional.empty(); + } + if (queryComparisonKeyValue == null) { + queryComparisonKeyValue = currentQueryComparisonKeyValue; + } else { + final var semanticEquals = + queryComparisonKeyValue.semanticEquals(currentQueryComparisonKeyValue, + ValueEquivalence.empty()); + if (semanticEquals.isFalse()) { + return Optional.empty(); + } + if (!semanticEquals.getConstraint().isTautology()) { + return Optional.empty(); + } + } + } + + return Optional.of(Objects.requireNonNull(queryComparisonKeyValue)); + } + + private static boolean isAggregateQueryValue(@Nonnull final List> partition, + @Nonnull final Value comparisonKeyValue) { + for (final var singleMatchedAccessWithIndex : partition) { + final var singledMatchedAccess = singleMatchedAccessWithIndex.getElement(); + final var groupByMappings = singledMatchedAccess.getPulledUpGroupByMappingsForOrdering(); + final var inverseMatchedGroupingsMap = + groupByMappings.getMatchedAggregatesMap().inverse(); + final var currentQueryComparisonKeyValue = inverseMatchedGroupingsMap.get(comparisonKeyValue); + if (currentQueryComparisonKeyValue != null) { + return true; + } + } + + return false; + } + @Nonnull private static NonnullPair, List> computeCommonAndPickUpValues(@Nonnull final List> partition, final int numGroupings) { diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/WithPrimaryKeyDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/WithPrimaryKeyDataAccessRule.java index 04297ef436..2feedb20b1 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/WithPrimaryKeyDataAccessRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/WithPrimaryKeyDataAccessRule.java @@ -194,7 +194,7 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me singleMatchedAccessVectored.getElement().getPartialMatch()) .collect(ImmutableList.toImmutableList())); if (commonRecordKeyValuesOptional.isEmpty()) { - return IntersectionResult.noCommonOrdering(); + return IntersectionResult.noViableIntersection(); } final var commonPrimaryKeyValues = commonRecordKeyValuesOptional.get(); @@ -220,7 +220,7 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me final var isPartitionRedundant = isPartitionRedundant(intersectionInfoMap, partition, equalityBoundKeyValues); if (isPartitionRedundant) { - return IntersectionResult.noCommonOrdering(); + return IntersectionResult.noViableIntersection(); } final var compensation = @@ -231,11 +231,20 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me final Function matchedToRealizedTranslationMapFunction = realizedAlias -> matchedToRealizedTranslationMap(partition, realizedAlias); + // + // Grab the first matched access from the partition in order to translate to the required ordering + // to the candidate's top. + // + final var firstMatchedAccess = partition.get(0).getElement(); + final var topToTopTranslationMap = firstMatchedAccess.getTopToTopTranslationMap(); + boolean hasCommonOrdering = false; final var expressionsBuilder = ImmutableList.builder(); for (final var requestedOrdering : requestedOrderings) { + final var translatedRequestedOrdering = + requestedOrdering.translateCorrelations(topToTopTranslationMap, true); final var comparisonKeyValuesIterable = - intersectionOrdering.enumerateSatisfyingComparisonKeyValues(requestedOrdering); + intersectionOrdering.enumerateSatisfyingComparisonKeyValues(translatedRequestedOrdering); for (final var comparisonKeyValues : comparisonKeyValuesIterable) { if (!isCompatibleComparisonKey(comparisonKeyValues, commonPrimaryKeyValues, @@ -246,7 +255,7 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me hasCommonOrdering = true; if (!compensation.isImpossible()) { var comparisonOrderingParts = - intersectionOrdering.directionalOrderingParts(comparisonKeyValues, requestedOrdering, + intersectionOrdering.directionalOrderingParts(comparisonKeyValues, translatedRequestedOrdering, OrderingPart.ProvidedSortOrder.FIXED); final var comparisonIsReverse = RecordQuerySetPlan.resolveComparisonDirection(comparisonOrderingParts); diff --git a/yaml-tests/src/test/resources/composite-aggregates.metrics.binpb b/yaml-tests/src/test/resources/composite-aggregates.metrics.binpb index df8548f2a0..cf0976e361 100644 --- a/yaml-tests/src/test/resources/composite-aggregates.metrics.binpb +++ b/yaml-tests/src/test/resources/composite-aggregates.metrics.binpb @@ -1,13 +1,19 @@ - -T -agg-empty-table-tests;EXPLAIN select col1, min(col2) from T3 group by col1, col3; -2 '(20Ĩ82@fAISCAN(T3_I2 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._0 AS COL1, _._2 AS _1) digraph G { + +_ +agg-empty-table-testsFEXPLAIN select col1, min(col2), max(col2) from T3 group by col1, col3; +8 -(7086@AISCAN(T3_I2 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) ∩ AISCAN(T3_I1 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) COMPARE BY (_._0, _._2, _._1) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q0._2 AS _2, q1._2 AS _3) | MAP (_._0 AS COL1, _._2 AS _1, _._3 AS _2)digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
Value Computation
MAP (q6._0 AS COL1, q6._2 AS _1)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS _1)" ]; - 2 [ label=<
Index Scan
scan type: BY_GROUP
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1, LONG AS _2)" ]; - 3 [ label=<
Index
AGG[T3_I2; permuted_min]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; - 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 1 [ label=<
Value Computation
MAP (q6._0 AS COL1, q6._2 AS _1, q6._3 AS _2)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS _1, LONG AS _2)" ]; + 2 [ label=<
Intersection
COMPARE BY (_._0, _._2, _._1)
RESULT (q91._0 AS _0, q91._1 AS _1, q91._2 AS _2, q93._2 AS _3)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1, LONG AS _2, LONG AS _3)" ]; + 3 [ label=<
Index Scan
scan type: BY_GROUP
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1, LONG AS _2)" ]; + 4 [ label=<
Index Scan
scan type: BY_GROUP
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1, LONG AS _2)" ]; + 5 [ label=<
Index
AGG[T3_I2; permuted_min]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; + 6 [ label=<
Index
AGG[T3_I1; permuted_max]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; + 3 -> 2 [ label=< q91> label="q91" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 2 [ label=< q93> label="q93" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; } \ No newline at end of file diff --git a/yaml-tests/src/test/resources/composite-aggregates.metrics.yaml b/yaml-tests/src/test/resources/composite-aggregates.metrics.yaml index 47e678966f..39a0ae3946 100644 --- a/yaml-tests/src/test/resources/composite-aggregates.metrics.yaml +++ b/yaml-tests/src/test/resources/composite-aggregates.metrics.yaml @@ -1,12 +1,14 @@ agg-empty-table-tests: -- query: EXPLAIN select col1, min(col2) from T3 group by col1, col3; +- query: EXPLAIN select col1, min(col2), max(col2) from T3 group by col1, col3; explain: 'AISCAN(T3_I2 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) - | MAP (_._0 AS COL1, _._2 AS _1)' - task_count: 418 - task_total_time_ms: 105 - transform_count: 145 - transform_time_ms: 82 - transform_yield_count: 50 + ∩ AISCAN(T3_I1 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) COMPARE + BY (_._0, _._2, _._1) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q0._2 + AS _2, q1._2 AS _3) | MAP (_._0 AS COL1, _._2 AS _1, _._3 AS _2)' + task_count: 468 + task_total_time_ms: 118 + transform_count: 154 + transform_time_ms: 96 + transform_yield_count: 55 insert_time_ms: 3 - insert_new_count: 50 + insert_new_count: 54 insert_reused_count: 4 diff --git a/yaml-tests/src/test/resources/composite-aggregates.yamsql b/yaml-tests/src/test/resources/composite-aggregates.yamsql index 1daef5c819..4617f0aaf5 100644 --- a/yaml-tests/src/test/resources/composite-aggregates.yamsql +++ b/yaml-tests/src/test/resources/composite-aggregates.yamsql @@ -69,48 +69,36 @@ test_block: name: agg-empty-table-tests preset: single_repetition_ordered tests: - #- - # - query: select count(*) from T2 group by col1, col2; - # - explain: "AISCAN(T2_I7 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | MAP (_._2 AS _0)" - # - result: [] - #- - # - query: select count(*) from T2 group by col2, col1; - # - explain: "AISCAN(T2_I7 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | MAP (_._2 AS _0)" - # - result: [] - #- - # - query: select count(*) from T2 where col1 = 3 group by col2; - # - explain: "AISCAN(T2_I7 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | MAP (_._2 AS _0)" - # - result: [] #- # - query: select sum(col2) / count(col2) from T2 group by col1; - # - explain: "AISCAN(T2_I6 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 / _._2 AS _0)" + # - explain: "AISCAN(T2_I6 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 / _._2 AS _0)" # - result: [{!l 4}, {!l 32}] #- # - query: select sum(col2), count(col2) from T2 where col1 < 2 group by col1; - # - explain: "AISCAN(T2_I6 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 AS _0, _._2 AS _1)" + # - explain: "AISCAN(T2_I6 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 AS _0, _._2 AS _1)" # - result: [{!l 17, !l 4}] #- # - query: select sum(col2), count(col2) from T2 group by col1 having sum(col2) = 17; - # - explain: "AISCAN(T2_I6 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | FILTER _._1 EQUALS promote(@c22 AS LONG) | MAP (_._1 AS _0, _._2 AS _1)" + # - explain: "AISCAN(T2_I6 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | FILTER _._1 EQUALS promote(@c22 AS LONG) | MAP (_._1 AS _0, _._2 AS _1)" # - result: [{!l 17, !l 4}] #- # - query: select sum(col2), count(col2) from T2 where col1 < 2 group by col1 having sum(col2) = 17; - # - explain: "AISCAN(T2_I6 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | FILTER _._1 EQUALS promote(@c26 AS LONG) | MAP (_._1 AS _0, _._2 AS _1)" + # - explain: "AISCAN(T2_I6 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | FILTER _._1 EQUALS promote(@c26 AS LONG) | MAP (_._1 AS _0, _._2 AS _1)" # - result: [{!l 17, !l 4}] #- - # - query: select sum(col1) / count(col1) from T1 group by col2; - # - explain: "AISCAN(T2_I6 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 / _._2 AS _0)" - # - result: [] + # - query: select sum(col1) / count(col1), col2 from T1 group by col2; + # - explain: "AISCAN(T1_I2 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T1_I1 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | AGG sum_l(_._2) GROUP BY (_._0 AS _0) COMPARE BY (_._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 / _._2 AS _0, _._0 AS COL2)" + # - result: [{!l 10, !l 1}, {!l 20, !l 6}, {!l 20, !l 7}, {!l 20, !l 8}, {!l 20, !l 10}] #- # - query: select col2, sum(col1) / count(col1) from T1 where col2 < 2 group by col2 having sum(col1) = 17 order by col2; - # - explain: "AISCAN(T1_I2 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T1_I1 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | AGG sum_l(_._1) GROUP BY (_._0 AS _0) COMPARE BY (_._0._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | FILTER _._1 EQUALS promote(@c26 AS LONG) | MAP (_._1 / _._2 AS _0)" + # - explain: "AISCAN(T1_I2 [[LESS_THAN promote(@c18 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T1_I1 [[LESS_THAN promote(@c18 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | AGG sum_l(_._2) GROUP BY (_._0 AS _0) COMPARE BY (_._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | FILTER _._1 EQUALS promote(@c28 AS LONG) | MAP (_._0 AS COL2, _._1 / _._2 AS _1)" # - result: [] - - - - query: select col2, sum(col1) / count(col1) from T1 where col2 < 2 group by col2, col3 having sum(col1) = 17; - - explain: "AISCAN(T1_I2 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T1_I1 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | AGG sum_l(_._1) GROUP BY (_._0 AS _0) COMPARE BY (_._0._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | FILTER _._1 EQUALS promote(@c26 AS LONG) | MAP (_._1 / _._2 AS _0)" - - result: [] #- - # - query: select col1, min(col2), max(col2) from T3 group by col1, col3; - # - explain: "AISCAN(T3_I2 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._0 AS COL1, _._2 AS _1)" + # - query: select col2, sum(col1) / count(col1) from T1 where col2 < 2 group by col2, col3 having sum(col1) = 17; + # - explain: "AISCAN(T1_I4 [[LESS_THAN promote(@c18 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) ∩ AISCAN(T1_I1 [[LESS_THAN promote(@c18 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) COMPARE BY (_._0, _._1) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q0._2 AS _2, q1._2 AS _3) | FILTER _._2 EQUALS promote(@c30 AS LONG) | MAP (_._0 AS COL2, _._2 / _._3 AS _1)" # - result: [] + - + - query: select col1, min(col2), max(col2) from T3 group by col1, col3; + - explain: "AISCAN(T3_I2 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) ∩ AISCAN(T3_I1 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) COMPARE BY (_._0, _._2, _._1) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q0._2 AS _2, q1._2 AS _3) | MAP (_._0 AS COL1, _._2 AS _1, _._3 AS _2)" + - result: [] ... From 349dec00c5ed456265e71d1fddd34d77be78d4f1 Mon Sep 17 00:00:00 2001 From: Normen Seemann Date: Sun, 6 Apr 2025 19:20:25 +0200 Subject: [PATCH 17/20] cleaning up --- .../rules/AggregateDataAccessRule.java | 9 +- .../rules/WithPrimaryKeyDataAccessRule.java | 1 - .../composite-aggregates.metrics.binpb | Bin 3472 -> 30660 bytes .../composite-aggregates.metrics.yaml | 105 +++++++++++++++++- .../resources/composite-aggregates.yamsql | 56 +++++----- 5 files changed, 132 insertions(+), 39 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java index 1540e03c40..f9493e8b5e 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java @@ -39,7 +39,6 @@ import com.apple.foundationdb.record.query.plan.cascades.RequestedOrderingConstraint; import com.apple.foundationdb.record.query.plan.cascades.ValueEquivalence; import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression; -import com.apple.foundationdb.record.query.plan.cascades.expressions.SelectExpression; import com.apple.foundationdb.record.query.plan.cascades.matching.structure.BindingMatcher; import com.apple.foundationdb.record.query.plan.cascades.typing.Type; import com.apple.foundationdb.record.query.plan.cascades.values.QuantifiedObjectValue; @@ -76,12 +75,8 @@ import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.RelationalExpressionMatchers.anyExpression; /** - * A rule that utilizes index matching information compiled by {@link CascadesPlanner} to create one or more - * expressions for data access specifically for a {@link SelectExpression}. A {@link SelectExpression} behaves - * different compared to essentially all other expressions in a way that we can conceptually deconstruct such an expression - * on the fly and only replace the matched part of the original expression with the scan over the materialized view. - * That allows us to relax restrictions (.e.g. to match all quantifiers the select expression owns) while matching - * select expressions. + * A rule that utilizes index matching information compiled by {@link CascadesPlanner} to create a multitude of + * expressions for data access involving {@link AggregateIndexMatchCandidate}. */ @API(API.Status.EXPERIMENTAL) @SuppressWarnings("PMD.TooManyStaticImports") diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/WithPrimaryKeyDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/WithPrimaryKeyDataAccessRule.java index 2feedb20b1..920612cc82 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/WithPrimaryKeyDataAccessRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/WithPrimaryKeyDataAccessRule.java @@ -98,7 +98,6 @@ public void onMatch(@Nonnull final CascadesRuleCall call) { } final var expression = bindings.get(getExpressionMatcher()); - final var correlatedTo = expression.getCorrelatedTo(); // // return if there is no pre-determined interesting ordering diff --git a/yaml-tests/src/test/resources/composite-aggregates.metrics.binpb b/yaml-tests/src/test/resources/composite-aggregates.metrics.binpb index cf0976e36188980c3e84aec56b8b0b7a71b89fc6..80227e341c4074ea0e1cd31a9fb71eec8fde6a5f 100644 GIT binary patch literal 30660 zcmeI5U1%fM702t{P#iT&jr-;GlHH3M7Adv6nvo+*mSt9Pv|bU#c5Qjn;2JTKW@WMC z8F@5L*J<`CZ8i^WHnfG5K$bQkkbXhf*AhryLPJYqN}3kZKu9SxNhvgtZ68|bxp%(q z*dxnYYeqBLd04NmJTn@dd*|NsJO6X8ZyXO@2z`O8)yDaahO#}baAkoXSNNvV9M0sv zzF5fS=TVav_=TN{yzB(PC*234djQPEl#WoZKySyYpytp+M@!!HFUJ^ZJU(DA`n zj|~0dyUVlgO+l|m8E$U*^I%jP<9!W@cYnUNQ1!#=?$>ON(NTx4&4e*JQ4-j^@y}LI_=yL`CE__zW0NuJdvl-jg};QnfB;?l0n2vmw+)zL{xA z!Zv<|-(%1!61XxiWTvM{@1U|IS9v)Tj)hT$7X-b@sLf`BtJKAs@#_Xxt&(;!JTtAx z@UMzEpgl8^r!WNHarH#gx!YOr0oIayeXW$1u*5-KfbvF~(1ZNQbU;o0? zd1uI-&dlJUAi=Gc1+H=_jGF6QgU^H;0#_HIrECk(YDz-A8b%lEf?z$`uvb_!7#sv9 zY}Oxxvyx$?NRpt`8=3G@u8=L}7v>{{h50$n`eC$&t;afTy}YRKauXhp_J-Rt>?niT z8G0$VyizE_Kuk^2BN4aEp_oePEjCJBujd^whK$aDC&qZqMzxNKJKr%?{xVvwaP7u( z6AnSjc7vZXW+2Ltb{zu`Z4Hh-Ehy>n_n*2x2J_MN(={bco#rX~>o%VVZ0_i!LydDr zxA}dp*qj=9b^|s$H@8aG*)(3n*QldA8K-!L=B+a|tRw468P*SVY9^~&$Fp_*0n>1^ z3k7PrfR-^~B)nwEiL~kgl|)G?iCco;Pn*WEt3@r5r^Rx!k%skVMsqpB@EY6-brA<& zW}5}4LtD4Yl7I(;?$osCc21V1Z?5xPH4_#kd4m(eh`gn6bpgL6!qCAEP`E59>)P5d z(c-pJ)NQ5QzpeZ5ZQ*sx-X6Li=MM?fNIP_>(CYR2v})vnLX6cf^&~M?=+C z%<^C>W*Ji-*j>m1BU9$FRT(r555g{jdH1+VFfaf5wa)^<{Nd&A9Rq^-^LI`Xf_do( zg&;6Htrl|2%cbJ^>^y1!5lIRkIa^^8*dN92Pjqd~@Gr1YJ0zU$UVe`&+ARXoaLK?R zCOZ1;m--!pbVf8-i1Dl|uDd1Fr0)z>23%whrlzY?q8y!);pX_6iz*O9;N*H!5}Q*8 znGbK#57igit_BR~e$gKiKl4(*^+mu@ZKGZRM_HnXF0yIBQJvsjz)_iLFL2biPlhhF z;;5z0ILZP}Xq|f$6bDK#${=PkJ^aJF0jJ(QGIaCf=Z}qCMmrxqcV}cG_VK?TNPZp! zp=Yc(*3ucHAu349M#Bs-_jadKLe z`D(qwDLgt?7eHL1ykxuB?!)JEAZ4n0+6S9SkQ1=#6qZdn%*StDZHozYGOKc<%v_F$68S^*BJ%xrzW<7 zVt{Z0#lQdLg+YMg>%ZCgG(hp+pZpww;vFj#cUJ`5lSSFx%Xe90+#jk!-g(inT-ZQo>@eLv=nLC~eJTv-O$hIkluu9b zxSsETcA4vh}Jb9CrGzkBnpk!u6!gJ<6uj4-ilSMN>U1LE_G24^#+JlkP8A>$U#ONu>ZOWWbsOq3T-%p0!tH4i7AeFSeWmZw z*;3F5g`SYnOC&t<{k;i$bd8MT+O#W(ryHHr-KL;LRXZm2R#5F|DdKgID*P&&IxbZ& zD>Bb*;7q4%ttRs|NZFvK2)nQnJgbG=Y*CxvH4VGe^;TJ_N7O73$9L4>UPTY znnO+Aru-{i-cFh_atijOu$NSwE0s04+Wv#}>^&!IQmsUvq=-J*gCbobZsS?fb%S`Z zRQ4zLgsu&=0_#V2fi>pmF+FR0H(ncHZHU}}$-7Es*)enDpud)38 zLb+)-N+>rNmk_^YA0sH>{mZHTR?Mkyzjs?BFO~9Q)HfGRGg*;ZmYgZ(?P^N8IRYu~ zJy6eG39SU``7NmDhvxhgB>Q*5`S|#N^R?~i9E@xoBzM7_t=4XJk00F$cf4NR&%uFy z=?iLoHp-bi6*TCdSXk0Cr3JTHEQSij^ePfVZIhx!VuBop7Q3k#IS$r9O^PajNcEup zp?6gXNnHOBgoxDL_O85wLRVXch{Udkh)9}7+&)m09)9r@R71RZWawZ2{Nr6C61w@T zo1w^f?4#eR)euk8ks*-x>~~zFJ+?MGuC)x^>`Ccx@UwQOa;Pzwj`yU74XV|Rm?1=f zH>g${alApb84+Ul?ne+Oq_KNH0xBj#_HrXTTgOTE2}Fec+vkZO)VEhRxK{H*^zZMT zxP|{BLi>+E?^qTmpBTGVTckkheM6R|+!1FYaEFKvY4ZtXTDvp@W3%x|ONRl8P84dk`@&0vWEScJwY*;l-qq zr%!}Rt#V4v?F|@!^9)I{>c;EvlDll#gFSAk)PQ55bK~jZpN)o248C=A===YB>Db6~ z18C>98+S$~V^^Q}@jxa$wKg~t86{*n}2>AD*ylh delta 41 zcmV+^0M`G+?*Wh-1dbaDUy>RalTd0<672fMI2f7%Am;t-EhslIq>A9PvT70yS|brB diff --git a/yaml-tests/src/test/resources/composite-aggregates.metrics.yaml b/yaml-tests/src/test/resources/composite-aggregates.metrics.yaml index 39a0ae3946..4c62af23ee 100644 --- a/yaml-tests/src/test/resources/composite-aggregates.metrics.yaml +++ b/yaml-tests/src/test/resources/composite-aggregates.metrics.yaml @@ -1,14 +1,113 @@ agg-empty-table-tests: +- query: EXPLAIN select sum(col2) / count(col2) from T2 group by col1; + explain: 'AISCAN(T2_I6 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 + <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0) WITH q0, q1 + RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 / _._2 AS _0)' + task_count: 317 + task_total_time_ms: 95 + transform_count: 115 + transform_time_ms: 81 + transform_yield_count: 51 + insert_time_ms: 0 + insert_new_count: 16 + insert_reused_count: 0 +- query: EXPLAIN select sum(col2), count(col2) from T2 where col1 < 2 group by col1; + explain: 'AISCAN(T2_I6 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], + _1: VALUE:[0]]) ∩ AISCAN(T2_I4 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP + -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0) WITH q0, q1 RETURN (q0._0 + AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 AS _0, _._2 AS _1)' + task_count: 317 + task_total_time_ms: 32 + transform_count: 115 + transform_time_ms: 27 + transform_yield_count: 51 + insert_time_ms: 0 + insert_new_count: 16 + insert_reused_count: 0 +- query: EXPLAIN select sum(col2), count(col2) from T2 group by col1 having sum(col2) + = 17; + explain: 'AISCAN(T2_I6 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 + <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0) WITH q0, q1 + RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | FILTER _._1 EQUALS promote(@c22 + AS LONG) | MAP (_._1 AS _0, _._2 AS _1)' + task_count: 349 + task_total_time_ms: 27 + transform_count: 120 + transform_time_ms: 19 + transform_yield_count: 52 + insert_time_ms: 1 + insert_new_count: 20 + insert_reused_count: 0 +- query: EXPLAIN select sum(col2), count(col2) from T2 where col1 < 2 group by col1 + having sum(col2) = 17; + explain: 'AISCAN(T2_I6 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], + _1: VALUE:[0]]) ∩ AISCAN(T2_I4 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP + -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0) WITH q0, q1 RETURN (q0._0 + AS _0, q0._1 AS _1, q1._1 AS _2) | FILTER _._1 EQUALS promote(@c26 AS LONG) + | MAP (_._1 AS _0, _._2 AS _1)' + task_count: 349 + task_total_time_ms: 17 + transform_count: 120 + transform_time_ms: 13 + transform_yield_count: 52 + insert_time_ms: 0 + insert_new_count: 20 + insert_reused_count: 0 +- query: EXPLAIN select sum(col1) / count(col1), col2 from T1 group by col2; + explain: 'AISCAN(T1_I2 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T1_I1 + <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | AGG sum_l(_._2) + GROUP BY (_._0 AS _0) COMPARE BY (_._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 + AS _1, q1._1 AS _2) | MAP (_._1 / _._2 AS _0, _._0 AS COL2)' + task_count: 475 + task_total_time_ms: 26 + transform_count: 143 + transform_time_ms: 17 + transform_yield_count: 49 + insert_time_ms: 0 + insert_new_count: 36 + insert_reused_count: 0 +- query: EXPLAIN select col2, sum(col1) / count(col1) from T1 where col2 < 2 group + by col2 having sum(col1) = 17 order by col2; + explain: 'AISCAN(T1_I2 [[LESS_THAN promote(@c18 AS LONG)]] BY_GROUP -> [_0: KEY:[0], + _1: VALUE:[0]]) ∩ AISCAN(T1_I1 [[LESS_THAN promote(@c18 AS LONG)]] BY_GROUP + -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | AGG sum_l(_._2) GROUP BY (_._0 + AS _0) COMPARE BY (_._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 + AS _2) | FILTER _._1 EQUALS promote(@c28 AS LONG) | MAP (_._0 AS COL2, _._1 + / _._2 AS _1)' + task_count: 528 + task_total_time_ms: 23 + transform_count: 152 + transform_time_ms: 18 + transform_yield_count: 51 + insert_time_ms: 0 + insert_new_count: 43 + insert_reused_count: 0 +- query: EXPLAIN select col2, sum(col1) / count(col1) from T1 where col2 < 2 group + by col2, col3 having sum(col1) = 17; + explain: 'AISCAN(T1_I4 [[LESS_THAN promote(@c18 AS LONG)]] BY_GROUP -> [_0: KEY:[0], + _1: KEY:[1], _2: VALUE:[0]]) ∩ AISCAN(T1_I1 [[LESS_THAN promote(@c18 AS LONG)]] + BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) COMPARE BY (_._0, _._1) + WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q0._2 AS _2, q1._2 AS _3) | + FILTER _._2 EQUALS promote(@c30 AS LONG) | MAP (_._0 AS COL2, _._2 / _._3 + AS _1)' + task_count: 335 + task_total_time_ms: 26 + transform_count: 111 + transform_time_ms: 22 + transform_yield_count: 45 + insert_time_ms: 0 + insert_new_count: 20 + insert_reused_count: 0 - query: EXPLAIN select col1, min(col2), max(col2) from T3 group by col1, col3; explain: 'AISCAN(T3_I2 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) ∩ AISCAN(T3_I1 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) COMPARE BY (_._0, _._2, _._1) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q0._2 AS _2, q1._2 AS _3) | MAP (_._0 AS COL1, _._2 AS _1, _._3 AS _2)' task_count: 468 - task_total_time_ms: 118 + task_total_time_ms: 27 transform_count: 154 - transform_time_ms: 96 + transform_time_ms: 19 transform_yield_count: 55 - insert_time_ms: 3 + insert_time_ms: 2 insert_new_count: 54 insert_reused_count: 4 diff --git a/yaml-tests/src/test/resources/composite-aggregates.yamsql b/yaml-tests/src/test/resources/composite-aggregates.yamsql index 4617f0aaf5..29bc9f39ef 100644 --- a/yaml-tests/src/test/resources/composite-aggregates.yamsql +++ b/yaml-tests/src/test/resources/composite-aggregates.yamsql @@ -69,34 +69,34 @@ test_block: name: agg-empty-table-tests preset: single_repetition_ordered tests: - #- - # - query: select sum(col2) / count(col2) from T2 group by col1; - # - explain: "AISCAN(T2_I6 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 / _._2 AS _0)" - # - result: [{!l 4}, {!l 32}] - #- - # - query: select sum(col2), count(col2) from T2 where col1 < 2 group by col1; - # - explain: "AISCAN(T2_I6 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 AS _0, _._2 AS _1)" - # - result: [{!l 17, !l 4}] - #- - # - query: select sum(col2), count(col2) from T2 group by col1 having sum(col2) = 17; - # - explain: "AISCAN(T2_I6 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | FILTER _._1 EQUALS promote(@c22 AS LONG) | MAP (_._1 AS _0, _._2 AS _1)" - # - result: [{!l 17, !l 4}] - #- - # - query: select sum(col2), count(col2) from T2 where col1 < 2 group by col1 having sum(col2) = 17; - # - explain: "AISCAN(T2_I6 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | FILTER _._1 EQUALS promote(@c26 AS LONG) | MAP (_._1 AS _0, _._2 AS _1)" - # - result: [{!l 17, !l 4}] - #- - # - query: select sum(col1) / count(col1), col2 from T1 group by col2; - # - explain: "AISCAN(T1_I2 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T1_I1 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | AGG sum_l(_._2) GROUP BY (_._0 AS _0) COMPARE BY (_._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 / _._2 AS _0, _._0 AS COL2)" - # - result: [{!l 10, !l 1}, {!l 20, !l 6}, {!l 20, !l 7}, {!l 20, !l 8}, {!l 20, !l 10}] - #- - # - query: select col2, sum(col1) / count(col1) from T1 where col2 < 2 group by col2 having sum(col1) = 17 order by col2; - # - explain: "AISCAN(T1_I2 [[LESS_THAN promote(@c18 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T1_I1 [[LESS_THAN promote(@c18 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | AGG sum_l(_._2) GROUP BY (_._0 AS _0) COMPARE BY (_._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | FILTER _._1 EQUALS promote(@c28 AS LONG) | MAP (_._0 AS COL2, _._1 / _._2 AS _1)" - # - result: [] - #- - # - query: select col2, sum(col1) / count(col1) from T1 where col2 < 2 group by col2, col3 having sum(col1) = 17; - # - explain: "AISCAN(T1_I4 [[LESS_THAN promote(@c18 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) ∩ AISCAN(T1_I1 [[LESS_THAN promote(@c18 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) COMPARE BY (_._0, _._1) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q0._2 AS _2, q1._2 AS _3) | FILTER _._2 EQUALS promote(@c30 AS LONG) | MAP (_._0 AS COL2, _._2 / _._3 AS _1)" - # - result: [] + - + - query: select sum(col2) / count(col2) from T2 group by col1; + - explain: "AISCAN(T2_I6 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 / _._2 AS _0)" + - result: [{!l 4}, {!l 32}] + - + - query: select sum(col2), count(col2) from T2 where col1 < 2 group by col1; + - explain: "AISCAN(T2_I6 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 AS _0, _._2 AS _1)" + - result: [{!l 17, !l 4}] + - + - query: select sum(col2), count(col2) from T2 group by col1 having sum(col2) = 17; + - explain: "AISCAN(T2_I6 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | FILTER _._1 EQUALS promote(@c22 AS LONG) | MAP (_._1 AS _0, _._2 AS _1)" + - result: [{!l 17, !l 4}] + - + - query: select sum(col2), count(col2) from T2 where col1 < 2 group by col1 having sum(col2) = 17; + - explain: "AISCAN(T2_I6 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T2_I4 [[LESS_THAN promote(@c16 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | FILTER _._1 EQUALS promote(@c26 AS LONG) | MAP (_._1 AS _0, _._2 AS _1)" + - result: [{!l 17, !l 4}] + - + - query: select sum(col1) / count(col1), col2 from T1 group by col2; + - explain: "AISCAN(T1_I2 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T1_I1 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | AGG sum_l(_._2) GROUP BY (_._0 AS _0) COMPARE BY (_._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 / _._2 AS _0, _._0 AS COL2)" + - result: [{!l 10, !l 1}, {!l 20, !l 6}, {!l 20, !l 7}, {!l 20, !l 8}, {!l 20, !l 10}] + - + - query: select col2, sum(col1) / count(col1) from T1 where col2 < 2 group by col2 having sum(col1) = 17 order by col2; + - explain: "AISCAN(T1_I2 [[LESS_THAN promote(@c18 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) ∩ AISCAN(T1_I1 [[LESS_THAN promote(@c18 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | AGG sum_l(_._2) GROUP BY (_._0 AS _0) COMPARE BY (_._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | FILTER _._1 EQUALS promote(@c28 AS LONG) | MAP (_._0 AS COL2, _._1 / _._2 AS _1)" + - result: [] + - + - query: select col2, sum(col1) / count(col1) from T1 where col2 < 2 group by col2, col3 having sum(col1) = 17; + - explain: "AISCAN(T1_I4 [[LESS_THAN promote(@c18 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) ∩ AISCAN(T1_I1 [[LESS_THAN promote(@c18 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) COMPARE BY (_._0, _._1) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q0._2 AS _2, q1._2 AS _3) | FILTER _._2 EQUALS promote(@c30 AS LONG) | MAP (_._0 AS COL2, _._2 / _._3 AS _1)" + - result: [] - - query: select col1, min(col2), max(col2) from T3 group by col1, col3; - explain: "AISCAN(T3_I2 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) ∩ AISCAN(T3_I1 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) COMPARE BY (_._0, _._2, _._1) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q0._2 AS _2, q1._2 AS _3) | MAP (_._0 AS COL1, _._2 AS _1, _._3 AS _2)" From 99f2c4322baed65e36de879eb063ef35d904e748 Mon Sep 17 00:00:00 2001 From: Normen Seemann Date: Mon, 7 Apr 2025 17:26:13 +0200 Subject: [PATCH 18/20] build somewhat stable --- .../rules/AbstractDataAccessRule.java | 144 ++++++++---- .../rules/AggregateDataAccessRule.java | 208 +++++------------- .../rules/WithPrimaryKeyDataAccessRule.java | 158 ++++--------- .../src/test/java/YamlIntegrationTests.java | 1 + .../composite-aggregates.metrics.binpb | Bin 30660 -> 30041 bytes .../composite-aggregates.metrics.yaml | 49 ++--- .../resources/composite-aggregates.yamsql | 2 +- 7 files changed, 236 insertions(+), 326 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java index 2d9242523d..353f5a6fb9 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java @@ -23,7 +23,6 @@ import com.apple.foundationdb.annotation.API; import com.apple.foundationdb.record.RecordCoreException; import com.apple.foundationdb.record.query.combinatorics.ChooseK; -import com.apple.foundationdb.record.query.plan.cascades.AggregateIndexMatchCandidate; import com.apple.foundationdb.record.query.plan.cascades.CascadesPlanner; import com.apple.foundationdb.record.query.plan.cascades.CascadesRule; import com.apple.foundationdb.record.query.plan.cascades.CascadesRuleCall; @@ -43,12 +42,12 @@ import com.apple.foundationdb.record.query.plan.cascades.PlanContext; import com.apple.foundationdb.record.query.plan.cascades.PrimaryScanMatchCandidate; import com.apple.foundationdb.record.query.plan.cascades.Quantifier; +import com.apple.foundationdb.record.query.plan.cascades.Quantifiers; import com.apple.foundationdb.record.query.plan.cascades.Reference; import com.apple.foundationdb.record.query.plan.cascades.ReferencedFieldsConstraint; import com.apple.foundationdb.record.query.plan.cascades.RequestedOrdering; import com.apple.foundationdb.record.query.plan.cascades.RequestedOrderingConstraint; import com.apple.foundationdb.record.query.plan.cascades.ValueIndexScanMatchCandidate; -import com.apple.foundationdb.record.query.plan.cascades.WithPrimaryKeyMatchCandidate; import com.apple.foundationdb.record.query.plan.cascades.debug.Debugger; import com.apple.foundationdb.record.query.plan.cascades.expressions.LogicalDistinctExpression; import com.apple.foundationdb.record.query.plan.cascades.expressions.LogicalIntersectionExpression; @@ -62,12 +61,14 @@ import com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryUnorderedPrimaryKeyDistinctPlan; import com.apple.foundationdb.record.util.pair.NonnullPair; +import com.apple.foundationdb.record.util.pair.Pair; import com.google.common.base.Suppliers; import com.google.common.base.Verify; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSetMultimap; +import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.slf4j.Logger; @@ -79,6 +80,8 @@ import java.util.BitSet; import java.util.Collection; import java.util.Comparator; +import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @@ -87,6 +90,8 @@ import java.util.Set; import java.util.function.Function; import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * A rule that utilizes index matching information compiled by {@link CascadesPlanner} to create one or more @@ -129,6 +134,97 @@ protected BindingMatcher getExpressionMatcher() { return expressionMatcher; } + @Override + public void onMatch(@Nonnull final CascadesRuleCall call) { + final var bindings = call.getBindings(); + final var completeMatches = bindings.getAll(getCompleteMatchMatcher()); + if (completeMatches.isEmpty()) { + return; + } + + final var expression = bindings.get(getExpressionMatcher()); + + // + // return if there is no pre-determined interesting ordering + // + final var requestedOrderingsOptional = call.getPlannerConstraint(RequestedOrderingConstraint.REQUESTED_ORDERING); + if (requestedOrderingsOptional.isEmpty()) { + return; + } + + final var requestedOrderings = requestedOrderingsOptional.get(); + final var aliasToQuantifierMap = Quantifiers.aliasToQuantifierMap(expression.getQuantifiers()); + final var aliases = aliasToQuantifierMap.keySet(); + + // group all successful matches by their sets of compensated aliases + final var matchPartitionByMatchAliasMap = + completeMatches + .stream() + .flatMap(match -> { + final var compensatedAliases = match.getCompensatedAliases(); + if (!compensatedAliases.containsAll(aliases)) { + return Stream.empty(); + } + final Set matchedForEachAliases = + compensatedAliases.stream() + .filter(matchedAlias -> + Objects.requireNonNull(aliasToQuantifierMap.get(matchedAlias)) instanceof Quantifier.ForEach) + .collect(ImmutableSet.toImmutableSet()); + if (matchedForEachAliases.size() == 1) { + return Stream.of(NonnullPair.of(Iterables.getOnlyElement(matchedForEachAliases), match)); + } + return Stream.empty(); + }) + .collect(Collectors.groupingBy( + Pair::getLeft, + LinkedHashMap::new, + Collectors.mapping(Pair::getRight, ImmutableList.toImmutableList()))); + + // loop through all compensated alias sets and their associated match partitions + for (final var matchPartitionByMatchAliasEntry : matchPartitionByMatchAliasMap.entrySet()) { + final var matchPartitionForMatchedAlias = + matchPartitionByMatchAliasEntry.getValue(); + + // + // We do know that local predicates (which includes predicates only using the matchedAlias quantifier) + // are definitely handled by the logic expressed by the partial matches of the current match partition. + // Join predicates are different in a sense that there will be matches that handle those predicates and + // there will be matches where these predicates will not be handled. We further need to sub-partition the + // current match partition, by the predicates that are being handled by the matches. + // + // TODO this should just be exactly one key + final var matchPartitionsForAliasesByPredicates = + matchPartitionForMatchedAlias + .stream() + .collect(Collectors.groupingBy(match -> + new LinkedIdentitySet<>(match.getRegularMatchInfo().getPredicateMap().keySet()), + HashMap::new, + ImmutableList.toImmutableList())); + + // + // Note that this works because there is only one for-each and potentially 0 - n existential quantifiers + // that are covered by the match partition. Even though that logically forms a join, the existential + // quantifiers do not mutate the result of the join, they only cause filtering, that is, the resulting + // record is exactly what the for each quantifier produced filtered by the predicates expressed on the + // existential quantifiers. + // + for (final var matchPartitionEntry : matchPartitionsForAliasesByPredicates.entrySet()) { + final var matchPartition = matchPartitionEntry.getValue(); + + // + // The current match partition covers all matches that match the aliases in matchedAliases + // as well as all predicates in matchedPredicates. In other words we now have to compensate + // for all the remaining quantifiers and all remaining predicates. + // + final var dataAccessExpressions = + dataAccessForMatchPartition(call, + requestedOrderings, + matchPartition); + call.yieldExpression(dataAccessExpressions); + } + } + } + /** * Method that does the leg work to create the appropriate expression dag for data access using value indexes or * value index-like scans (primary scans). @@ -419,44 +515,6 @@ protected Set dataAccessForMatchPartition(@Nonnu return intersectionInfoMapToExpressions(intersectionInfoMap); } - @Nonnull - protected static Optional> commonRecordKeyValuesMaybe(@Nonnull Iterable partialMatches) { - List common = null; - var first = true; - for (final var partialMatch : partialMatches) { - final var matchCandidate = partialMatch.getMatchCandidate(); - final var regularMatchInfo = partialMatch.getRegularMatchInfo(); - - final List key; - if (matchCandidate instanceof WithPrimaryKeyMatchCandidate) { - final var withPrimaryKeyMatchCandidate = (WithPrimaryKeyMatchCandidate)matchCandidate; - final var keyMaybe = withPrimaryKeyMatchCandidate.getPrimaryKeyValuesMaybe(); - if (keyMaybe.isEmpty()) { - return Optional.empty(); - } - key = keyMaybe.get(); - } else if (matchCandidate instanceof AggregateIndexMatchCandidate) { - final var aggregateIndexMatchCandidate = (AggregateIndexMatchCandidate)matchCandidate; - final var rollUpToGroupingValues = regularMatchInfo.getRollUpToGroupingValues(); - if (rollUpToGroupingValues == null) { - key = aggregateIndexMatchCandidate.getGroupingAndAggregateAccessors(Quantifier.current()).getLeft(); - } else { - key = aggregateIndexMatchCandidate.getGroupingAndAggregateAccessors(rollUpToGroupingValues.size(), - Quantifier.current()).getLeft(); - } - } else { - return Optional.empty(); - } - if (first) { - common = key; - first = false; - } else if (!common.equals(key)) { - return Optional.empty(); - } - } - return Optional.ofNullable(common); // common can only be null if we didn't have any match candidates to start with - } - @Nonnull private static BitSet[] newSquareBitMatrix(final int size) { BitSet[] matrix = new BitSet[size]; @@ -1033,14 +1091,14 @@ private static Ordering orderingFromOrderingParts(final @Nonnull List comparisonKeyValues, - @Nonnull List commonPrimaryKeyValues, + @Nonnull List commonRecordKeyValues, @Nonnull ImmutableSet equalityBoundKeyValues) { - return commonPrimaryKeyValues + return commonRecordKeyValues .stream() .filter(commonPrimaryKeyValue -> !equalityBoundKeyValues.contains(commonPrimaryKeyValue)) .allMatch(comparisonKeyValues::contains); diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java index f9493e8b5e..3a527f2207 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java @@ -23,20 +23,16 @@ import com.apple.foundationdb.annotation.API; import com.apple.foundationdb.record.query.plan.cascades.AggregateIndexMatchCandidate; import com.apple.foundationdb.record.query.plan.cascades.CascadesPlanner; -import com.apple.foundationdb.record.query.plan.cascades.CascadesRuleCall; import com.apple.foundationdb.record.query.plan.cascades.Column; import com.apple.foundationdb.record.query.plan.cascades.ComparisonRange; import com.apple.foundationdb.record.query.plan.cascades.Compensation; import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier; -import com.apple.foundationdb.record.query.plan.cascades.LinkedIdentitySet; import com.apple.foundationdb.record.query.plan.cascades.MatchPartition; import com.apple.foundationdb.record.query.plan.cascades.Memoizer; import com.apple.foundationdb.record.query.plan.cascades.OrderingPart; import com.apple.foundationdb.record.query.plan.cascades.PartialMatch; import com.apple.foundationdb.record.query.plan.cascades.Quantifier; -import com.apple.foundationdb.record.query.plan.cascades.Quantifiers; import com.apple.foundationdb.record.query.plan.cascades.RequestedOrdering; -import com.apple.foundationdb.record.query.plan.cascades.RequestedOrderingConstraint; import com.apple.foundationdb.record.query.plan.cascades.ValueEquivalence; import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression; import com.apple.foundationdb.record.query.plan.cascades.matching.structure.BindingMatcher; @@ -50,23 +46,17 @@ import com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQuerySetPlan; import com.apple.foundationdb.record.util.pair.NonnullPair; -import com.apple.foundationdb.record.util.pair.Pair; import com.google.common.base.Verify; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; import javax.annotation.Nonnull; import java.util.BitSet; -import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.MatchPartitionMatchers.ofExpressionAndMatches; import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.MultiMatcher.some; @@ -76,7 +66,7 @@ /** * A rule that utilizes index matching information compiled by {@link CascadesPlanner} to create a multitude of - * expressions for data access involving {@link AggregateIndexMatchCandidate}. + * expressions for data access involving only {@link AggregateIndexMatchCandidate}. */ @API(API.Status.EXPERIMENTAL) @SuppressWarnings("PMD.TooManyStaticImports") @@ -92,96 +82,6 @@ public AggregateDataAccessRule() { super(rootMatcher, completeMatchMatcher, expressionMatcher); } - @Override - public void onMatch(@Nonnull final CascadesRuleCall call) { - final var bindings = call.getBindings(); - final var completeMatches = bindings.getAll(getCompleteMatchMatcher()); - if (completeMatches.isEmpty()) { - return; - } - - final var expression = bindings.get(getExpressionMatcher()); - - // - // return if there is no pre-determined interesting ordering - // - final var requestedOrderingsOptional = call.getPlannerConstraint(RequestedOrderingConstraint.REQUESTED_ORDERING); - if (requestedOrderingsOptional.isEmpty()) { - return; - } - - final var requestedOrderings = requestedOrderingsOptional.get(); - final var aliasToQuantifierMap = Quantifiers.aliasToQuantifierMap(expression.getQuantifiers()); - final var aliases = aliasToQuantifierMap.keySet(); - - // group all successful matches by their sets of compensated aliases - final var matchPartitionByMatchAliasMap = - completeMatches - .stream() - .flatMap(match -> { - final var compensatedAliases = match.getCompensatedAliases(); - if (!compensatedAliases.containsAll(aliases)) { - return Stream.empty(); - } - final Set matchedForEachAliases = - compensatedAliases.stream() - .filter(matchedAlias -> Objects.requireNonNull(aliasToQuantifierMap.get(matchedAlias)) instanceof Quantifier.ForEach) - .collect(ImmutableSet.toImmutableSet()); - if (matchedForEachAliases.size() == 1) { - return Stream.of(NonnullPair.of(Iterables.getOnlyElement(matchedForEachAliases), match)); - } - return Stream.empty(); - }) - .collect(Collectors.groupingBy( - Pair::getLeft, - LinkedHashMap::new, - Collectors.mapping(Pair::getRight, ImmutableList.toImmutableList()))); - - // loop through all compensated alias sets and their associated match partitions - for (final var matchPartitionByMatchAliasEntry : matchPartitionByMatchAliasMap.entrySet()) { - final var matchPartitionForMatchedAlias = - matchPartitionByMatchAliasEntry.getValue(); - - // - // We do know that local predicates (which includes predicates only using the matchedAlias quantifier) - // are definitely handled by the logic expressed by the partial matches of the current match partition. - // Join predicates are different in a sense that there will be matches that handle those predicates and - // there will be matches where these predicates will not be handled. We further need to sub-partition the - // current match partition, by the predicates that are being handled by the matches. - // - // TODO this should just be exactly one key - final var matchPartitionsForAliasesByPredicates = - matchPartitionForMatchedAlias - .stream() - .collect(Collectors.groupingBy(match -> - new LinkedIdentitySet<>(match.getRegularMatchInfo().getPredicateMap().keySet()), - HashMap::new, - ImmutableList.toImmutableList())); - - // - // Note that this works because there is only one for-each and potentially 0 - n existential quantifiers - // that are covered by the match partition. Even though that logically forms a join, the existential - // quantifiers do not mutate the result of the join, they only cause filtering, that is, the resulting - // record is exactly what the for each quantifier produced filtered by the predicates expressed on the - // existential quantifiers. - // - for (final var matchPartitionEntry : matchPartitionsForAliasesByPredicates.entrySet()) { - final var matchPartition = matchPartitionEntry.getValue(); - - // - // The current match partition covers all matches that match the aliases in matchedAliases - // as well as all predicates in matchedPredicates. In other words we now have to compensate - // for all the remaining quantifiers and all remaining predicates. - // - final var dataAccessExpressions = - dataAccessForMatchPartition(call, - requestedOrderings, - matchPartition); - call.yieldExpression(dataAccessExpressions); - } - } - } - @Nonnull @Override protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Memoizer memoizer, @@ -190,20 +90,23 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me @Nonnull final List> partition, @Nonnull final Set requestedOrderings) { Verify.verify(partition.size() > 1); - final var commonRecordKeyValuesOptional = - commonRecordKeyValuesMaybe( - partition.stream() - .map(singleMatchedAccessVectored -> - singleMatchedAccessVectored.getElement().getPartialMatch()) + + final var partitionAccesses = + partition.stream() + .map(Vectored::getElement) + .collect(ImmutableList.toImmutableList()); + final var commonGroupingKeyValuesOptional = + commonGroupingKeyValuesMaybe( + partitionAccesses.stream() + .map(SingleMatchedAccess::getPartialMatch) .collect(ImmutableList.toImmutableList())); - if (commonRecordKeyValuesOptional.isEmpty()) { + if (commonGroupingKeyValuesOptional.isEmpty()) { return IntersectionResult.noViableIntersection(); } - final var commonRecordKeyValues = commonRecordKeyValuesOptional.get(); + final var commonGroupingKeyValues = commonGroupingKeyValuesOptional.get(); final var partitionOrderings = - partition.stream() - .map(Vectored::getElement) + partitionAccesses.stream() .map(AbstractDataAccessRule::adjustMatchedOrderingParts) .collect(ImmutableList.toImmutableList()); final var intersectionOrdering = intersectOrderings(partitionOrderings); @@ -226,14 +129,15 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me } final var compensation = - partition + partitionAccesses .stream() - .map(pair -> pair.getElement().getCompensation()) + .map(SingleMatchedAccess::getCompensation) .reduce(Compensation.impossibleCompensation(), Compensation::intersect); // // Grab the first matched access from the partition in order to translate to the required ordering - // to the candidate's top. + // to the candidate's top. This is only correct as long as the derivations are consistent among the indexes. + // We check that a bit further down. // final var firstMatchedAccess = partition.get(0).getElement(); final var topToTopTranslationMap = firstMatchedAccess.getTopToTopTranslationMap(); @@ -243,18 +147,25 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me for (final var requestedOrdering : requestedOrderings) { final var translatedRequestedOrdering = requestedOrdering.translateCorrelations(topToTopTranslationMap, true); - if (!areRequestedOrderingsDerivationsCompatibleAcrossMatches(partition, translatedRequestedOrdering)) { - continue; - } final var comparisonKeyValuesIterable = intersectionOrdering.enumerateSatisfyingComparisonKeyValues(translatedRequestedOrdering); for (final var comparisonKeyValues : comparisonKeyValuesIterable) { - if (!isCompatibleComparisonKey(comparisonKeyValues, commonRecordKeyValues, equalityBoundKeyValues)) { + // + // We need to ensure that the common record key, that is the key that is used to identify the + // entire record is part of the comparison key (unless it's equality-bound). + // + if (!isCompatibleComparisonKey(comparisonKeyValues, commonGroupingKeyValues, equalityBoundKeyValues)) { continue; } - if (!areComparisonKeyDerivationsCompatibleAcrossMatches(partition, comparisonKeyValues)) { + // + // We need to ensure that the comparison key has consistent translations to all participating + // candidates. For grouping values (and we only allow grouping values) that is rather straightforward. + // We map the grouping values from each match candidate one-by-one to the query side grouping values + // and see if they match across candidates. + // + if (!isConsistentComparisonKeyDerivations(partition, comparisonKeyValues)) { continue; } @@ -280,7 +191,7 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me final var newQuantifiers = newQuantifiersBuilder.build(); final var commonAndPickUpValues = - computeCommonAndPickUpValues(partition, commonRecordKeyValues.size()); + computeCommonAndPickUpValues(partition, commonGroupingKeyValues.size()); final var intersectionResultValue = computeIntersectionResultValue(newQuantifiers, commonAndPickUpValues.getLeft(), commonAndPickUpValues.getRight()); final var intersectionPlan = @@ -291,7 +202,7 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me baseAlias -> computeTranslationMap(baseAlias, newQuantifiers, candidateTopAliasesBuilder.build(), (Type.Record)intersectionResultValue.getResultType(), - commonRecordKeyValues.size())); + commonGroupingKeyValues.size())); expressionsBuilder.add(compensatedIntersection); } } @@ -301,23 +212,42 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me expressionsBuilder.build()); } - private static boolean areRequestedOrderingsDerivationsCompatibleAcrossMatches(@Nonnull final List> partition, - @Nonnull final RequestedOrdering requestedOrdering) { - for (final var orderingPart : requestedOrdering.getOrderingParts()) { - if (isAggregateQueryValue(partition, orderingPart.getValue())) { - return false; + @Nonnull + protected static Optional> commonGroupingKeyValuesMaybe(@Nonnull Iterable partialMatches) { + List common = null; + var first = true; + for (final var partialMatch : partialMatches) { + final var matchCandidate = partialMatch.getMatchCandidate(); + final var regularMatchInfo = partialMatch.getRegularMatchInfo(); + + final List key; + if (matchCandidate instanceof AggregateIndexMatchCandidate) { + final var aggregateIndexMatchCandidate = (AggregateIndexMatchCandidate)matchCandidate; + final var rollUpToGroupingValues = regularMatchInfo.getRollUpToGroupingValues(); + if (rollUpToGroupingValues == null) { + key = aggregateIndexMatchCandidate.getGroupingAndAggregateAccessors(Quantifier.current()).getLeft(); + } else { + key = aggregateIndexMatchCandidate.getGroupingAndAggregateAccessors(rollUpToGroupingValues.size(), + Quantifier.current()).getLeft(); + } + } else { + return Optional.empty(); + } + if (first) { + common = key; + first = false; + } else if (!common.equals(key)) { + return Optional.empty(); } } - return true; + return Optional.ofNullable(common); // common can only be null if we didn't have any match candidates to start with } - private static boolean areComparisonKeyDerivationsCompatibleAcrossMatches(@Nonnull final List> partition, - @Nonnull final List comparisonKeyValues) { + private static boolean isConsistentComparisonKeyDerivations(@Nonnull final List> partition, + @Nonnull final List comparisonKeyValues) { for (final var comparisonKeyValue : comparisonKeyValues) { if (consistentQueryValueForGroupingValueMaybe(partition, comparisonKeyValue).isEmpty()) { - if (!isAggregateQueryValue(partition, comparisonKeyValue)) { - return false; - } + return false; } } return true; @@ -354,22 +284,6 @@ private static Optional consistentQueryValueForGroupingValueMaybe(@Nonnul return Optional.of(Objects.requireNonNull(queryComparisonKeyValue)); } - private static boolean isAggregateQueryValue(@Nonnull final List> partition, - @Nonnull final Value comparisonKeyValue) { - for (final var singleMatchedAccessWithIndex : partition) { - final var singledMatchedAccess = singleMatchedAccessWithIndex.getElement(); - final var groupByMappings = singledMatchedAccess.getPulledUpGroupByMappingsForOrdering(); - final var inverseMatchedGroupingsMap = - groupByMappings.getMatchedAggregatesMap().inverse(); - final var currentQueryComparisonKeyValue = inverseMatchedGroupingsMap.get(comparisonKeyValue); - if (currentQueryComparisonKeyValue != null) { - return true; - } - } - - return false; - } - @Nonnull private static NonnullPair, List> computeCommonAndPickUpValues(@Nonnull final List> partition, final int numGroupings) { diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/WithPrimaryKeyDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/WithPrimaryKeyDataAccessRule.java index 920612cc82..a0cf2ecc61 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/WithPrimaryKeyDataAccessRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/WithPrimaryKeyDataAccessRule.java @@ -22,28 +22,24 @@ import com.apple.foundationdb.annotation.API; import com.apple.foundationdb.record.query.plan.cascades.CascadesPlanner; -import com.apple.foundationdb.record.query.plan.cascades.CascadesRuleCall; import com.apple.foundationdb.record.query.plan.cascades.ComparisonRange; import com.apple.foundationdb.record.query.plan.cascades.Compensation; import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier; -import com.apple.foundationdb.record.query.plan.cascades.LinkedIdentitySet; import com.apple.foundationdb.record.query.plan.cascades.MatchPartition; import com.apple.foundationdb.record.query.plan.cascades.Memoizer; import com.apple.foundationdb.record.query.plan.cascades.OrderingPart; import com.apple.foundationdb.record.query.plan.cascades.PartialMatch; import com.apple.foundationdb.record.query.plan.cascades.Quantifier; -import com.apple.foundationdb.record.query.plan.cascades.Quantifiers; import com.apple.foundationdb.record.query.plan.cascades.RequestedOrdering; -import com.apple.foundationdb.record.query.plan.cascades.RequestedOrderingConstraint; +import com.apple.foundationdb.record.query.plan.cascades.WithPrimaryKeyMatchCandidate; import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression; import com.apple.foundationdb.record.query.plan.cascades.expressions.SelectExpression; import com.apple.foundationdb.record.query.plan.cascades.matching.structure.BindingMatcher; +import com.apple.foundationdb.record.query.plan.cascades.values.Value; import com.apple.foundationdb.record.query.plan.cascades.values.translation.TranslationMap; import com.apple.foundationdb.record.query.plan.plans.RecordQueryIntersectionPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQuerySetPlan; -import com.apple.foundationdb.record.util.pair.NonnullPair; -import com.apple.foundationdb.record.util.pair.Pair; import com.google.common.base.Verify; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; @@ -51,15 +47,12 @@ import javax.annotation.Nonnull; import java.util.BitSet; -import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.MatchPartitionMatchers.ofExpressionAndMatches; import static com.apple.foundationdb.record.query.plan.cascades.matching.structure.MultiMatcher.some; @@ -89,95 +82,6 @@ public WithPrimaryKeyDataAccessRule() { super(rootMatcher, completeMatchMatcher, expressionMatcher); } - @Override - public void onMatch(@Nonnull final CascadesRuleCall call) { - final var bindings = call.getBindings(); - final var completeMatches = bindings.getAll(getCompleteMatchMatcher()); - if (completeMatches.isEmpty()) { - return; - } - - final var expression = bindings.get(getExpressionMatcher()); - - // - // return if there is no pre-determined interesting ordering - // - final var requestedOrderingsOptional = call.getPlannerConstraint(RequestedOrderingConstraint.REQUESTED_ORDERING); - if (requestedOrderingsOptional.isEmpty()) { - return; - } - - final var requestedOrderings = requestedOrderingsOptional.get(); - final var aliasToQuantifierMap = Quantifiers.aliasToQuantifierMap(expression.getQuantifiers()); - final var aliases = aliasToQuantifierMap.keySet(); - - // group all successful matches by their sets of compensated aliases - final var matchPartitionByMatchAliasMap = - completeMatches - .stream() - .flatMap(match -> { - final var compensatedAliases = match.getCompensatedAliases(); - if (!compensatedAliases.containsAll(aliases)) { - return Stream.empty(); - } - final Set matchedForEachAliases = - compensatedAliases.stream() - .filter(matchedAlias -> Objects.requireNonNull(aliasToQuantifierMap.get(matchedAlias)) instanceof Quantifier.ForEach) - .collect(ImmutableSet.toImmutableSet()); - if (matchedForEachAliases.size() == 1) { - return Stream.of(NonnullPair.of(Iterables.getOnlyElement(matchedForEachAliases), match)); - } - return Stream.empty(); - }) - .collect(Collectors.groupingBy( - Pair::getLeft, - LinkedHashMap::new, - Collectors.mapping(Pair::getRight, ImmutableList.toImmutableList()))); - - // loop through all compensated alias sets and their associated match partitions - for (final var matchPartitionByMatchAliasEntry : matchPartitionByMatchAliasMap.entrySet()) { - final var matchPartitionForMatchedAlias = matchPartitionByMatchAliasEntry.getValue(); - - // - // We do know that local predicates (which includes predicates only using the matchedAlias quantifier) - // are definitely handled by the logic expressed by the partial matches of the current match partition. - // Join predicates are different in a sense that there will be matches that handle those predicates and - // there will be matches where these predicates will not be handled. We further need to sub-partition the - // current match partition, by the predicates that are being handled by the matches. - // - // TODO this should just be exactly one key - final var matchPartitionsForAliasesByPredicates = - matchPartitionForMatchedAlias - .stream() - .collect(Collectors.groupingBy(match -> - new LinkedIdentitySet<>(match.getRegularMatchInfo().getPredicateMap().keySet()), - HashMap::new, - ImmutableList.toImmutableList())); - - // - // Note that this works because there is only one for-each and potentially 0 - n existential quantifiers - // that are covered by the match partition. Even though that logically forms a join, the existential - // quantifiers do not mutate the result of the join, they only cause filtering, that is, the resulting - // record is exactly what the for each quantifier produced filtered by the predicates expressed on the - // existential quantifiers. - // - for (final var matchPartitionEntry : matchPartitionsForAliasesByPredicates.entrySet()) { - final var matchPartition = matchPartitionEntry.getValue(); - - // - // The current match partition covers all matches that match the aliases in matchedAliases - // as well as all predicates in matchedPredicates. In other words we now have to compensate - // for all the remaining quantifiers and all remaining predicates. - // - final var dataAccessExpressions = - dataAccessForMatchPartition(call, - requestedOrderings, - matchPartition); - call.yieldExpression(dataAccessExpressions); - } - } - } - @Nonnull @Override protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Memoizer memoizer, @@ -186,21 +90,25 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me @Nonnull final List> partition, @Nonnull final Set requestedOrderings) { Verify.verify(partition.size() > 1); - final var commonRecordKeyValuesOptional = - commonRecordKeyValuesMaybe( - partition.stream() - .map(singleMatchedAccessVectored -> - singleMatchedAccessVectored.getElement().getPartialMatch()) + + final var partitionAccesses = + partition.stream() + .map(Vectored::getElement) + .collect(ImmutableList.toImmutableList()); + + final var commonPrimaryKeyValuesOptional = + commonPrimaryKeyValuesMaybe( + partitionAccesses.stream() + .map(SingleMatchedAccess::getPartialMatch) .collect(ImmutableList.toImmutableList())); - if (commonRecordKeyValuesOptional.isEmpty()) { + if (commonPrimaryKeyValuesOptional.isEmpty()) { return IntersectionResult.noViableIntersection(); } - final var commonPrimaryKeyValues = commonRecordKeyValuesOptional.get(); + final var commonPrimaryKeyValues = commonPrimaryKeyValuesOptional.get(); final var partitionOrderings = - partition.stream() - .map(Vectored::getElement) + partitionAccesses.stream() .map(AbstractDataAccessRule::adjustMatchedOrderingParts) .collect(ImmutableList.toImmutableList()); final var intersectionOrdering = intersectOrderings(partitionOrderings); @@ -223,9 +131,9 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me } final var compensation = - partition + partitionAccesses .stream() - .map(pair -> pair.getElement().getCompensation()) + .map(SingleMatchedAccess::getCompensation) .reduce(Compensation.impossibleCompensation(), Compensation::intersect); final Function matchedToRealizedTranslationMapFunction = realizedAlias -> matchedToRealizedTranslationMap(partition, realizedAlias); @@ -284,6 +192,36 @@ protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Me expressionsBuilder.build()); } + @Nonnull + protected static Optional> commonPrimaryKeyValuesMaybe(@Nonnull Iterable partialMatches) { + Verify.verify(!Iterables.isEmpty(partialMatches)); + List common = null; + var first = true; + for (final var partialMatch : partialMatches) { + final var matchCandidate = partialMatch.getMatchCandidate(); + + final List key; + if (matchCandidate instanceof WithPrimaryKeyMatchCandidate) { + final var withPrimaryKeyMatchCandidate = (WithPrimaryKeyMatchCandidate)matchCandidate; + final var keyMaybe = withPrimaryKeyMatchCandidate.getPrimaryKeyValuesMaybe(); + if (keyMaybe.isEmpty()) { + return Optional.empty(); + } + key = keyMaybe.get(); + } else { + return Optional.empty(); + } + if (first) { + common = key; + first = false; + } else if (!common.equals(key)) { + return Optional.empty(); + } + } + return Optional.of(Objects.requireNonNull(common)); + } + + @Nonnull private static TranslationMap matchedToRealizedTranslationMap(@Nonnull final List> partition, @Nonnull final CorrelationIdentifier realizedAlias) { final var translationMapBuilder = TranslationMap.builder(); diff --git a/yaml-tests/src/test/java/YamlIntegrationTests.java b/yaml-tests/src/test/java/YamlIntegrationTests.java index 0c66dad5dc..a10bbcb528 100644 --- a/yaml-tests/src/test/java/YamlIntegrationTests.java +++ b/yaml-tests/src/test/java/YamlIntegrationTests.java @@ -115,6 +115,7 @@ public void aggregateIndexTests(YamlTest.Runner runner) throws Exception { } @TestTemplate + @MaintainYamlTestConfig(YamlTestConfigFilters.SHOW_PLAN_ON_DIFF) public void aggregateEmptyTable(YamlTest.Runner runner) throws Exception { runner.runYamsql("aggregate-empty-table.yamsql"); } diff --git a/yaml-tests/src/test/resources/composite-aggregates.metrics.binpb b/yaml-tests/src/test/resources/composite-aggregates.metrics.binpb index 80227e341c4074ea0e1cd31a9fb71eec8fde6a5f..bd32f8769d9ea101a409a132eab8704eeed78aa4 100644 GIT binary patch delta 911 zcmX@|p7G`@#tF$1OE+&ckSJDIJfU4v!`PsEvVnzw1B1{5#>qWWCnvL8iEWNzoWeG_ zUhMefRUEyO>r5_Bt~YC#eBP9GvYxB(7UH?QX|V-)}RwwE7h)cW-=d4NXE zIU)%*YU$<$np}*V-S|EbV+^P?yK4Y)9QrAXpr8+*sess48+ z&o%0r{66^X zEQ`gs;wMQ-Ob*EMsNXNjCB<=oN#M8#;2z{38lVv86bUp6s>u+h2PR+)762-S*$Gk@ZvYYn+F_`p090rQ6^Ms( zA;uVKN<9&td_ViX5{iyOGgK{L{^X4|QzmEUwgO|q$^`0@LUUt~ZCLz*A!DdH*-=S; za+g21EL;=ZF9_AflLPtZbHMyK`Jk>C8^nK;3t2KJ-;FV2H-bn`o+#5jSwUQGa*Ycg zM2W%VTK!3r6OODU&CPtpzI7*p_i{VaZAi#RM>m+H3!fKSLP~g z?(>+&ws}KruEFcm z!kbq__3*RwNpr|*B&tPXqKaCLMcuyk*8y&mJ7d7Qoyj>%$qK#s86ylAn6u=zA*jP=4M;$8_;OZv_ zT59v5s+ssvga@ccFWv}D8cxpEGMs!WT3XlFF+f2BC~lzO7_8vz?_&s21>(g+*v4SC zk*3sB@yYY0@5v&mEHnce2vZ8;7*7`Pn>d*(w{^0*leHx=j2W17gZ4g1&*~s zL26NMX-R5Id~Rmm BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 / _._2 AS _0)' task_count: 317 - task_total_time_ms: 95 + task_total_time_ms: 101 transform_count: 115 - transform_time_ms: 81 + transform_time_ms: 86 transform_yield_count: 51 insert_time_ms: 0 insert_new_count: 16 @@ -17,9 +17,9 @@ agg-empty-table-tests: -> [_0: KEY:[0], _1: VALUE:[0]]) COMPARE BY (_._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 AS _0, _._2 AS _1)' task_count: 317 - task_total_time_ms: 32 + task_total_time_ms: 31 transform_count: 115 - transform_time_ms: 27 + transform_time_ms: 26 transform_yield_count: 51 insert_time_ms: 0 insert_new_count: 16 @@ -31,11 +31,11 @@ agg-empty-table-tests: RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | FILTER _._1 EQUALS promote(@c22 AS LONG) | MAP (_._1 AS _0, _._2 AS _1)' task_count: 349 - task_total_time_ms: 27 + task_total_time_ms: 23 transform_count: 120 - transform_time_ms: 19 + transform_time_ms: 17 transform_yield_count: 52 - insert_time_ms: 1 + insert_time_ms: 0 insert_new_count: 20 insert_reused_count: 0 - query: EXPLAIN select sum(col2), count(col2) from T2 where col1 < 2 group by col1 @@ -46,9 +46,9 @@ agg-empty-table-tests: AS _0, q0._1 AS _1, q1._1 AS _2) | FILTER _._1 EQUALS promote(@c26 AS LONG) | MAP (_._1 AS _0, _._2 AS _1)' task_count: 349 - task_total_time_ms: 17 + task_total_time_ms: 18 transform_count: 120 - transform_time_ms: 13 + transform_time_ms: 15 transform_yield_count: 52 insert_time_ms: 0 insert_new_count: 20 @@ -59,9 +59,9 @@ agg-empty-table-tests: GROUP BY (_._0 AS _0) COMPARE BY (_._0) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q1._1 AS _2) | MAP (_._1 / _._2 AS _0, _._0 AS COL2)' task_count: 475 - task_total_time_ms: 26 + task_total_time_ms: 25 transform_count: 143 - transform_time_ms: 17 + transform_time_ms: 19 transform_yield_count: 49 insert_time_ms: 0 insert_new_count: 36 @@ -75,9 +75,9 @@ agg-empty-table-tests: AS _2) | FILTER _._1 EQUALS promote(@c28 AS LONG) | MAP (_._0 AS COL2, _._1 / _._2 AS _1)' task_count: 528 - task_total_time_ms: 23 + task_total_time_ms: 29 transform_count: 152 - transform_time_ms: 18 + transform_time_ms: 22 transform_yield_count: 51 insert_time_ms: 0 insert_new_count: 43 @@ -91,23 +91,22 @@ agg-empty-table-tests: FILTER _._2 EQUALS promote(@c30 AS LONG) | MAP (_._0 AS COL2, _._2 / _._3 AS _1)' task_count: 335 - task_total_time_ms: 26 + task_total_time_ms: 32 transform_count: 111 - transform_time_ms: 22 + transform_time_ms: 26 transform_yield_count: 45 insert_time_ms: 0 insert_new_count: 20 insert_reused_count: 0 - query: EXPLAIN select col1, min(col2), max(col2) from T3 group by col1, col3; - explain: 'AISCAN(T3_I2 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) - ∩ AISCAN(T3_I1 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) COMPARE - BY (_._0, _._2, _._1) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q0._2 - AS _2, q1._2 AS _3) | MAP (_._0 AS COL1, _._2 AS _1, _._3 AS _2)' - task_count: 468 - task_total_time_ms: 27 - transform_count: 154 - transform_time_ms: 19 - transform_yield_count: 55 + explain: ISCAN(T3_I1 <,>) | MAP (_ AS _0) | AGG (min_l(_._0.COL2) AS _0, max_l(_._0.COL2) + AS _1) GROUP BY (_._0.COL1 AS _0, _._0.COL3 AS _1) | MAP (_._0._0 AS COL1, + _._1._0 AS _1, _._1._1 AS _2) + task_count: 320 + task_total_time_ms: 31 + transform_count: 115 + transform_time_ms: 25 + transform_yield_count: 48 insert_time_ms: 2 - insert_new_count: 54 + insert_new_count: 38 insert_reused_count: 4 diff --git a/yaml-tests/src/test/resources/composite-aggregates.yamsql b/yaml-tests/src/test/resources/composite-aggregates.yamsql index 29bc9f39ef..7adce8d4b4 100644 --- a/yaml-tests/src/test/resources/composite-aggregates.yamsql +++ b/yaml-tests/src/test/resources/composite-aggregates.yamsql @@ -99,6 +99,6 @@ test_block: - result: [] - - query: select col1, min(col2), max(col2) from T3 group by col1, col3; - - explain: "AISCAN(T3_I2 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) ∩ AISCAN(T3_I1 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) COMPARE BY (_._0, _._2, _._1) WITH q0, q1 RETURN (q0._0 AS _0, q0._1 AS _1, q0._2 AS _2, q1._2 AS _3) | MAP (_._0 AS COL1, _._2 AS _1, _._3 AS _2)" + - explain: "ISCAN(T3_I1 <,>) | MAP (_ AS _0) | AGG (min_l(_._0.COL2) AS _0, max_l(_._0.COL2) AS _1) GROUP BY (_._0.COL1 AS _0, _._0.COL3 AS _1) | MAP (_._0._0 AS COL1, _._1._0 AS _1, _._1._1 AS _2)" - result: [] ... From dd18b65c1ba958b4f391dfb142d79bfa3f1cffff Mon Sep 17 00:00:00 2001 From: Normen Seemann Date: Wed, 9 Apr 2025 08:22:52 +0200 Subject: [PATCH 19/20] some polishing --- .../query/combinatorics/TopologicalSort.java | 4 ---- .../AggregateIndexExpansionVisitor.java | 21 +++---------------- .../AggregateIndexMatchCandidate.java | 17 +-------------- .../plan/cascades/PredicateMultiMap.java | 10 ++++----- .../foundationdb/UnnestedRecordTypeTest.java | 9 ++++---- .../cascades/values/ValueTranslationTest.java | 4 ++-- .../lucene/search/BooleanPointsConfig.java | 2 +- .../api/metrics/NoOpMetricRegistry.java | 2 +- 8 files changed, 18 insertions(+), 51 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/combinatorics/TopologicalSort.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/combinatorics/TopologicalSort.java index 45b9df5d48..4bf630bac6 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/combinatorics/TopologicalSort.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/combinatorics/TopologicalSort.java @@ -537,10 +537,6 @@ public static Iterable> satisfyingPermutations(@Nonnull final Par @Nonnull final List

targetPermutation, @Nonnull final Function domainMapper, @Nonnull final Function, Integer> satisfiabilityFunction) { -// if (partiallyOrderedSet.isEmpty()) { -// return ImmutableList.of(); -// } - if (partiallyOrderedSet.size() < targetPermutation.size()) { return ImmutableList.of(); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexExpansionVisitor.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexExpansionVisitor.java index 27d5ecf9a4..52f2442ef9 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexExpansionVisitor.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexExpansionVisitor.java @@ -44,7 +44,6 @@ import com.apple.foundationdb.record.query.plan.cascades.values.RecordConstructorValue; import com.apple.foundationdb.record.query.plan.cascades.values.Value; import com.apple.foundationdb.record.query.plan.cascades.values.Values; -import com.apple.foundationdb.record.query.plan.cascades.values.translation.TranslationMap; import com.apple.foundationdb.record.util.pair.NonnullPair; import com.google.common.base.Preconditions; import com.google.common.base.Suppliers; @@ -162,8 +161,7 @@ public MatchCandidate expand(@Nonnull final Supplier baseQua recordTypes, baseQuantifier.getFlowedObjectType(), groupByQun.getRangesOver().get().getResultValue(), - selectHaving, - constructSelectHavingResult.getGroupByValues()); + selectHaving); } @Nonnull @@ -334,12 +332,8 @@ private ConstructSelectHavingResult constructSelectHaving(@Nonnull final Quantif finalPlaceholders = placeholderAliases.build(); } - final var currentGroupingValues = groupingValues.stream() - .map(groupingValue -> groupingValue.translateCorrelations(TranslationMap.ofAliases(groupByQun.getAlias(), Quantifier.current()))) - .collect(ImmutableList.toImmutableList()); - return new ConstructSelectHavingResult(selectHavingGraphExpansionBuilder.build().buildSelect(), - finalPlaceholders, currentGroupingValues); + finalPlaceholders); } @Nonnull @@ -390,15 +384,11 @@ private static class ConstructSelectHavingResult { private final SelectExpression selectExpression; @Nonnull private final List placeholderAliases; - @Nonnull - private final List groupByValues; private ConstructSelectHavingResult(@Nonnull final SelectExpression selectExpression, - @Nonnull final List placeholderAliases, - @Nonnull final List groupByValues) { + @Nonnull final List placeholderAliases) { this.selectExpression = selectExpression; this.placeholderAliases = placeholderAliases; - this.groupByValues = groupByValues; } @Nonnull @@ -410,10 +400,5 @@ public SelectExpression getSelectExpression() { public List getPlaceholderAliases() { return placeholderAliases; } - - @Nonnull - public List getGroupByValues() { - return groupByValues; - } } } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java index 6df5c91d18..112f46750d 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java @@ -99,9 +99,6 @@ public class AggregateIndexMatchCandidate implements MatchCandidate, WithBaseQua @Nonnull private final SelectExpression selectHavingExpression; - @Nonnull - private final List groupByValues; - /** * Creates a new instance of {@link AggregateIndexMatchCandidate}. * @@ -119,8 +116,7 @@ public AggregateIndexMatchCandidate(@Nonnull final Index index, @Nonnull final Collection recordTypes, @Nonnull final Type baseType, @Nonnull final Value groupByResultValue, - @Nonnull final SelectExpression selectHavingExpression, - @Nonnull final List groupByValues) { + @Nonnull final SelectExpression selectHavingExpression) { Preconditions.checkArgument(!recordTypes.isEmpty()); this.index = index; this.traversal = traversal; @@ -129,7 +125,6 @@ public AggregateIndexMatchCandidate(@Nonnull final Index index, this.baseType = baseType; this.groupByResultValue = groupByResultValue; this.selectHavingExpression = selectHavingExpression; - this.groupByValues = ImmutableList.copyOf(groupByValues); } @Nonnull @@ -156,16 +151,6 @@ public List getOrderingAliases() { return sargableAndOrderAliases; } - @Nonnull - public SelectExpression getSelectHavingExpression() { - return selectHavingExpression; - } - - @Nonnull - public List getGroupByValues() { - return groupByValues; - } - @Nonnull @Override public KeyExpression getFullKeyExpression() { diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PredicateMultiMap.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PredicateMultiMap.java index 97129016ee..a5f8f3ebb7 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PredicateMultiMap.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PredicateMultiMap.java @@ -66,9 +66,9 @@ public class PredicateMultiMap { private final ImmutableSetMultimap map; @Nonnull - private static Value amendValue(@Nonnull final BiMap unmatchedAggregateMap, - @Nonnull final Map amendedMatchedAggregateMap, - @Nonnull final Value rootValue) { + private static Value replaceNewlyMatchedValues(@Nonnull final BiMap unmatchedAggregateMap, + @Nonnull final Map amendedMatchedAggregateMap, + @Nonnull final Value rootValue) { return Objects.requireNonNull(rootValue.replace(currentValue -> { if (currentValue instanceof GroupByExpression.UnmatchedAggregateValue) { final var unmatchedId = @@ -191,7 +191,7 @@ public PredicateCompensationFunction amend(@Nonnull final BiMap amendedMatchedAggregateMap) { final var amendedTranslatedPredicateOptional = predicate.replaceValuesMaybe(rootValue -> - Optional.of(amendValue(unmatchedAggregateMap, amendedMatchedAggregateMap, + Optional.of(replaceNewlyMatchedValues(unmatchedAggregateMap, amendedMatchedAggregateMap, rootValue))); Verify.verify(amendedTranslatedPredicateOptional.isPresent()); return ofPredicate(amendedTranslatedPredicateOptional.get(), true); @@ -398,7 +398,7 @@ public boolean isImpossible() { public ResultCompensationFunction amend(@Nonnull final BiMap unmatchedAggregateMap, @Nonnull final Map amendedMatchedAggregateMap) { final var amendedTranslatedQueryValue = - amendValue(unmatchedAggregateMap, amendedMatchedAggregateMap, value); + replaceNewlyMatchedValues(unmatchedAggregateMap, amendedMatchedAggregateMap, value); return ofValue(amendedTranslatedQueryValue, true); } diff --git a/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/UnnestedRecordTypeTest.java b/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/UnnestedRecordTypeTest.java index 9f2b354e1c..f7cdb1986f 100644 --- a/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/UnnestedRecordTypeTest.java +++ b/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/UnnestedRecordTypeTest.java @@ -2316,10 +2316,11 @@ void deleteWhereOnMultiTypeFailsWithAmbiguousParent() { @Test void deleteWhereOnMultiTypeFailsWithRecordTypePrefix() { - // Create a multi-type index on two different unnested types. Each one has a parent constituent named and an inner constituent, so the index is well-defined. - // The multi-type index in this case has a record type prefix. In theory, we actually could perform the delete records where, but the record type key in the - // index matches the synthetic type's record type key, not the base type. This means we'd need to translateCorrelations the record type key before deleting data from the - // index. Until we get that working, just assert that this fails. + // Create a multi-type index on two different unnested types. Each one has a parent constituent named and an + // inner constituent, so the index is well-defined. The multi-type index in this case has a record type prefix. + // In theory, we actually could perform the delete records where, but the record type key in the index matches + // the synthetic type's record type key, not the base type. This means we'd need to translate the record type + // key before deleting data from the index. Until we get that working, just assert that this fails. final RecordMetaDataHook hook = addMultiTypeDoubleUnnestedIndex(concat(recordType(), field(PARENT_CONSTITUENT).nest(field("middle").nest("other_int")), field("inner").nest("foo"))) .andThen(setOuterAndMiddlePrimaryKey(concat(recordType(), field("middle").nest("other_int"), field("rec_no")))); final RecordMetaData metaData = doubleNestedMetaData(hook); diff --git a/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/query/plan/cascades/values/ValueTranslationTest.java b/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/query/plan/cascades/values/ValueTranslationTest.java index dd2fc6b2a9..b4bbb1132b 100644 --- a/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/query/plan/cascades/values/ValueTranslationTest.java +++ b/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/query/plan/cascades/values/ValueTranslationTest.java @@ -722,7 +722,7 @@ translation of (t.a.q, t.a.r, (t.b.t), t.j.s) with correlation mapping of t -> t Assertions.assertEquals(expectedL1TranslatedQueryNValue, l1m3ForNValue.getQueryValue()); Assertions.assertEquals(n_v, l1m3ForNValue.getCandidateValue()); - // translateCorrelations a complex join condition, each quantifier in the join condition is assumed to match a corresponding + // translate a complex join condition, each quantifier in the join condition is assumed to match a corresponding // quantifier in a non-joined index candidate. /* @@ -952,7 +952,7 @@ translation of (t.a.q, t.a.r, (t.b.t), t.j.s) with correlation mapping of t -> t final var l1m3ForMValue = calculate(l1TranslatedQueryMValue, m_v); final var l1m3ForNValue = calculate(l1TranslatedQueryNValue, n_v); - // translateCorrelations a complex join condition, each quantifier in the join condition is assumed to match a corresponding + // translate a complex join condition, each quantifier in the join condition is assumed to match a corresponding // quantifier in a non-joined index candidate. /* diff --git a/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/search/BooleanPointsConfig.java b/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/search/BooleanPointsConfig.java index b0d7fdd907..3b1187ea8a 100644 --- a/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/search/BooleanPointsConfig.java +++ b/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/search/BooleanPointsConfig.java @@ -26,7 +26,7 @@ import java.text.NumberFormat; /** - * A subclass of PointsConfig to allow the Parser the ability to translateCorrelations boolean terms to binary ones. + * A subclass of PointsConfig to allow the Parser the ability to translate boolean terms to binary ones. */ public class BooleanPointsConfig extends PointsConfig { diff --git a/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/api/metrics/NoOpMetricRegistry.java b/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/api/metrics/NoOpMetricRegistry.java index ceeae4ef02..7296c260cb 100644 --- a/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/api/metrics/NoOpMetricRegistry.java +++ b/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/api/metrics/NoOpMetricRegistry.java @@ -31,7 +31,7 @@ *

* NOTE(stack): Consider NOT using codahale but prometheus metrics. If server is exporting metrics * on an prometheus endpoint, codahale will require translation (there are translators but better not - * to translateCorrelations at all). What is the story for clients? RL is codahale? + * to translate at all). What is the story for clients? RL is codahale? */ @API(API.Status.EXPERIMENTAL) public final class NoOpMetricRegistry { From 55cd005aefea6a24a7cd30d3c091c415a8e57121 Mon Sep 17 00:00:00 2001 From: Normen Seemann Date: Thu, 10 Apr 2025 14:47:20 +0200 Subject: [PATCH 20/20] updating tests and writing documentation --- .../AggregateIndexExpansionVisitor.java | 12 +- .../AggregateIndexMatchCandidate.java | 2 +- .../query/plan/cascades/PlannerRuleSet.java | 2 - .../expressions/GroupByExpression.java | 49 +- .../properties/DerivationsProperty.java | 88 +- .../rules/AbstractDataAccessRule.java | 10 +- .../plan/cascades/rules/AdjustMatchRule.java | 2 +- .../rules/AggregateDataAccessRule.java | 25 + .../api/metrics/NoOpMetricRegistry.java | 2 +- .../jdbc/grpc/GrpcSQLExceptionUtil.java | 2 +- .../yamltests/YamlTestExtension.java | 2 +- .../src/test/java/YamlIntegrationTests.java | 3 +- .../aggregate-empty-table.metrics.binpb | 1221 ++++++++--------- .../aggregate-empty-table.metrics.yaml | 661 +++++---- .../resources/aggregate-empty-table.yamsql | 13 +- ...gate-index-tests-count-empty.metrics.binpb | Bin 18820 -> 19522 bytes ...egate-index-tests-count-empty.metrics.yaml | 62 +- .../aggregate-index-tests-count.metrics.binpb | Bin 18847 -> 19550 bytes .../aggregate-index-tests-count.metrics.yaml | 64 +- .../aggregate-index-tests.metrics.binpb | 582 ++++---- .../aggregate-index-tests.metrics.yaml | 304 ++-- .../resources/aggregate-index-tests.yamsql | 4 +- .../bitmap-aggregate-index.metrics.binpb | Bin 12565 -> 9538 bytes .../bitmap-aggregate-index.metrics.yaml | 66 +- .../resources/bitmap-aggregate-index.yamsql | 20 +- .../src/test/resources/catalog.metrics.binpb | 38 +- .../src/test/resources/catalog.metrics.yaml | 16 +- .../resources/composite-aggregates.yamsql | 3 + .../test/resources/create-drop.metrics.binpb | 52 +- .../test/resources/create-drop.metrics.yaml | 30 +- .../src/test/resources/cte.metrics.binpb | 50 +- .../src/test/resources/cte.metrics.yaml | 8 +- .../field-index-tests-proto.metrics.binpb | 46 +- .../field-index-tests-proto.metrics.yaml | 24 +- .../resources/groupby-tests.metrics.binpb | 140 +- .../test/resources/groupby-tests.metrics.yaml | 95 +- .../resources/indexed-functions.metrics.binpb | 50 +- .../resources/indexed-functions.metrics.yaml | 26 +- .../null-operator-tests.metrics.binpb | 22 +- .../null-operator-tests.metrics.yaml | 8 +- .../src/test/resources/orderby.metrics.binpb | 72 +- .../src/test/resources/orderby.metrics.yaml | 24 +- .../resources/primary-key-tests.metrics.binpb | 14 +- .../resources/primary-key-tests.metrics.yaml | 8 +- .../resources/recursive-cte.metrics.binpb | 172 +-- .../test/resources/recursive-cte.metrics.yaml | 20 +- .../resources/select-a-star.metrics.binpb | 54 +- .../test/resources/select-a-star.metrics.yaml | 24 +- .../standard-tests-metadata.metrics.binpb | 14 +- .../standard-tests-metadata.metrics.yaml | 8 +- .../standard-tests-proto.metrics.binpb | Bin 7052 -> 7331 bytes .../standard-tests-proto.metrics.yaml | 32 +- .../resources/standard-tests.metrics.binpb | 103 +- .../resources/standard-tests.metrics.yaml | 46 +- .../resources/subquery-tests.metrics.binpb | 149 +- .../resources/subquery-tests.metrics.yaml | 46 +- .../resources/table-functions.metrics.binpb | Bin 14400 -> 14947 bytes .../resources/table-functions.metrics.yaml | 36 +- .../union-empty-tables.metrics.binpb | 415 +++--- .../resources/union-empty-tables.metrics.yaml | 124 +- .../test/resources/union-empty-tables.yamsql | 2 +- .../src/test/resources/union.metrics.binpb | 160 ++- .../src/test/resources/union.metrics.yaml | 52 +- yaml-tests/src/test/resources/union.yamsql | 2 +- .../update-delete-returning.metrics.binpb | 132 +- .../update-delete-returning.metrics.yaml | 28 +- .../src/test/resources/uuid.metrics.binpb | 66 +- .../src/test/resources/uuid.metrics.yaml | 38 +- .../resources/versions-tests.metrics.binpb | 164 ++- .../resources/versions-tests.metrics.yaml | 78 +- 70 files changed, 2977 insertions(+), 2910 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexExpansionVisitor.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexExpansionVisitor.java index 52f2442ef9..838c5510c8 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexExpansionVisitor.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexExpansionVisitor.java @@ -357,10 +357,14 @@ private static Map> computeAggregateMap return mapBuilder.build(); } + public static boolean canBeRolledUp(@Nonnull final String indexType) { + return rollUpAggregateMap.get().containsKey(indexType); + } + @Nonnull - public static Optional rollUpAggregateValueMaybe(@Nonnull final Index index, @Nonnull final Value argument) { + public static Optional rollUpAggregateValueMaybe(@Nonnull final String indexType, @Nonnull final Value argument) { return Optional.ofNullable(rollUpAggregateMap.get() - .get(index.getType())) + .get(indexType)) .map(fn -> (AggregateValue)fn.encapsulate(ImmutableList.of(argument))); } @@ -369,8 +373,8 @@ private static Map> computeRollUpAggreg final ImmutableMap.Builder> mapBuilder = ImmutableMap.builder(); mapBuilder.put(IndexTypes.MAX_EVER_LONG, new NumericAggregationValue.MaxFn()); mapBuilder.put(IndexTypes.MIN_EVER_LONG, new NumericAggregationValue.MinFn()); - // mapBuilder.put(IndexTypes.MAX_EVER_TUPLE, TODO); - // mapBuilder.put(IndexTypes.MIN_EVER_TUPLE, TODO); + mapBuilder.put(IndexTypes.MAX_EVER_TUPLE, new NumericAggregationValue.MaxFn()); + mapBuilder.put(IndexTypes.MIN_EVER_TUPLE, new NumericAggregationValue.MinFn()); mapBuilder.put(IndexTypes.SUM, new NumericAggregationValue.SumFn()); mapBuilder.put(IndexTypes.COUNT, new NumericAggregationValue.SumFn()); mapBuilder.put(IndexTypes.COUNT_NOT_NULL, new NumericAggregationValue.SumFn()); diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java index 112f46750d..d884b3cb3f 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/AggregateIndexMatchCandidate.java @@ -436,7 +436,7 @@ public RecordQueryPlan toEquivalentPlan(@Nonnull final PartialMatch partialMatch } final var rollUpAggregateValueOptional = - AggregateIndexExpansionVisitor.rollUpAggregateValueMaybe(index, + AggregateIndexExpansionVisitor.rollUpAggregateValueMaybe(index.getType(), aggregateAccessorValue); final var aggregateIndexScanQuantifier = diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PlannerRuleSet.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PlannerRuleSet.java index 808b3fc0d6..efa9b4874b 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PlannerRuleSet.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/PlannerRuleSet.java @@ -41,10 +41,8 @@ import com.apple.foundationdb.record.query.plan.cascades.rules.ImplementIntersectionRule; import com.apple.foundationdb.record.query.plan.cascades.rules.ImplementNestedLoopJoinRule; import com.apple.foundationdb.record.query.plan.cascades.rules.ImplementPhysicalScanRule; -import com.apple.foundationdb.record.query.plan.cascades.rules.ImplementRecursiveUnionRule; import com.apple.foundationdb.record.query.plan.cascades.rules.ImplementSimpleSelectRule; import com.apple.foundationdb.record.query.plan.cascades.rules.ImplementStreamingAggregationRule; -import com.apple.foundationdb.record.query.plan.cascades.rules.ImplementTempTableInsertRule; import com.apple.foundationdb.record.query.plan.cascades.rules.ImplementTempTableScanRule; import com.apple.foundationdb.record.query.plan.cascades.rules.ImplementTypeFilterRule; import com.apple.foundationdb.record.query.plan.cascades.rules.ImplementUniqueRule; diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java index d8ad48c130..7c66965dc5 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/expressions/GroupByExpression.java @@ -25,6 +25,7 @@ import com.apple.foundationdb.record.PlanSerializationContext; import com.apple.foundationdb.record.planprotos.PValue; import com.apple.foundationdb.record.query.expressions.Comparisons; +import com.apple.foundationdb.record.query.plan.cascades.AggregateIndexExpansionVisitor; import com.apple.foundationdb.record.query.plan.cascades.AliasMap; import com.apple.foundationdb.record.query.plan.cascades.BooleanWithConstraint; import com.apple.foundationdb.record.query.plan.cascades.Column; @@ -85,9 +86,6 @@ import java.util.function.BiFunction; import java.util.function.Supplier; -import static com.apple.foundationdb.record.query.plan.cascades.BooleanWithConstraint.alwaysTrue; -import static com.apple.foundationdb.record.query.plan.cascades.BooleanWithConstraint.falseValue; - /** * A logical {@code group by} expression that represents grouping incoming tuples and aggregating each group. */ @@ -339,7 +337,7 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid if (otherAggregateValues.size() != 1) { return ImmutableList.of(); } - final var otherPrimitiveAggregateValue = Iterables.getOnlyElement(otherAggregateValues); + final var otherPrimitiveAggregateValue = (IndexableAggregateValue)Iterables.getOnlyElement(otherAggregateValues); final var matchedAggregatesMapBuilder = ImmutableBiMap.builder(); final var unmatchedAggregatesMapBuilder = ImmutableBiMap.builder(); @@ -377,6 +375,12 @@ public Iterable subsumedBy(@Nonnull final RelationalExpression candid final var matchedGroupingsMap = subsumedGroupingsResult.getMatchedGroupingsMap(); final var rollUpToGroupingValues = subsumedGroupingsResult.getRollUpToValues(); + if (rollUpToGroupingValues != null && + !AggregateIndexExpansionVisitor.canBeRolledUp(otherPrimitiveAggregateValue.getIndexTypeName())) { + // We determined we need a roll up, but we cannot do it base on the aggregations. + return ImmutableList.of(); + } + final var unmatchedTranslatedAggregateValueMap = unmatchedTranslatedAggregatesValueMapBuilder.buildKeepingLast(); final var translatedResultValue = getResultValue().translateCorrelations(translationMap, true); @@ -414,7 +418,7 @@ private SubsumedGroupingsResult subsumedGroupings(@Nonnull final Quantifier cand @Nonnull final TranslationMap translationMap, @Nonnull final ValueEquivalence valueEquivalence) { if (groupingValue == null && candidateGroupingValue == null) { - return SubsumedGroupingsResult.withoutRollUp(alwaysTrue(), ImmutableBiMap.of()); + return SubsumedGroupingsResult.withoutRollUp(BooleanWithConstraint.alwaysTrue(), ImmutableBiMap.of()); } if (candidateGroupingValue == null) { return SubsumedGroupingsResult.noSubsumption(); @@ -424,7 +428,7 @@ private SubsumedGroupingsResult subsumedGroupings(@Nonnull final Quantifier cand final BiMap matchedGroupingsMap; if (groupingValue != null) { final var translatedGroupingsValuesBuilder = ImmutableList.builder(); - final var matchedGroupingsMapBuilder = ImmutableBiMap.builder(); + final var matchedGroupingsMapBuilder = ImmutableMap.builder(); final var groupingValues = Values.primitiveAccessorsForType(groupingValue.getResultType(), () -> groupingValue).stream() .map(primitiveGroupingValue -> primitiveGroupingValue.simplify(AliasMap.emptyMap(), @@ -438,7 +442,14 @@ private SubsumedGroupingsResult subsumedGroupings(@Nonnull final Quantifier cand matchedGroupingsMapBuilder.put(primitiveGroupingValue, translatedPrimitiveGroupingValue); } translatedGroupingValues = translatedGroupingsValuesBuilder.build(); - matchedGroupingsMap = matchedGroupingsMapBuilder.build(); + + // + // We know that if there are duplicates, they will be on the query side. Immutable bi-maps do not support + // duplicated keys at all while regular maps do. The simplest and also the cheapest solution is to just + // use an immutable map builder (which then is de-duped when built) and then use that map to build the + // bi-map. + // + matchedGroupingsMap = ImmutableBiMap.copyOf(matchedGroupingsMapBuilder.buildKeepingLast()); } else { translatedGroupingValues = ImmutableList.of(); matchedGroupingsMap = ImmutableBiMap.of(); @@ -474,7 +485,7 @@ private SubsumedGroupingsResult subsumedGroupings(@Nonnull final Quantifier cand // 3. For each candidate grouping value in the set of (yet) unmatched candidate group values, try to find a // predicate that binds that groupingValue. // - var booleanWithConstraint = alwaysTrue(); + var booleanWithConstraint = BooleanWithConstraint.alwaysTrue(); for (final var translatedGroupingValue : translatedGroupingValuesSet) { var found = false; @@ -561,7 +572,8 @@ private SubsumedGroupingsResult subsumedGroupings(@Nonnull final Quantifier cand } if (!unmatchedCandidateValues.isEmpty()) { - Verify.verify(candidateGroupingValues.size() > translatedGroupingValues.size()); + Verify.verify(candidateGroupingValues.size() > translatedGroupingValuesSet.size()); + // // This is a potential roll-up case, but only if the query side's groupings are completely subsumed // 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, final var childCompensation = childCompensationOptional.get(); - if (childCompensation.isImpossible() -// || -// // -// // TODO This needs some improvement as GB a, b, c WHERE a= AND c= needs to reapply the -// // predicate on c which is currently refused here. -// // -// childCompensation.isNeededForFiltering() - ) { + if (childCompensation.isImpossible()) { // // Note that it may be better to just return the child compensation verbatim as that compensation // 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, return rcv.simplify(AliasMap.identitiesFor(rcv.getCorrelatedTo()), ImmutableSet.of()); } - public static class UnmatchedAggregateValue extends AbstractValue implements Value.NonEvaluableValue, IndexableAggregateValue { + public static class UnmatchedAggregateValue extends AbstractValue implements Value.NonEvaluableValue { @Nonnull private final CorrelationIdentifier unmatchedId; @@ -749,12 +754,6 @@ protected Iterable computeChildren() { return ImmutableList.of(); } - @Nonnull - @Override - public String getIndexTypeName() { - throw new UnsupportedOperationException(); - } - @Nonnull @Override public ExplainTokensWithPrecedence explain(@Nonnull final Iterable> explainSuppliers) { @@ -831,7 +830,7 @@ public List getRollUpToValues() { @Nonnull public static SubsumedGroupingsResult noSubsumption() { - return of(falseValue(), ImmutableBiMap.of(), null); + return of(BooleanWithConstraint.falseValue(), ImmutableBiMap.of(), null); } @Nonnull diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/DerivationsProperty.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/DerivationsProperty.java index c14d3dcac7..ac151d3fe8 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/DerivationsProperty.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/properties/DerivationsProperty.java @@ -23,24 +23,25 @@ import com.apple.foundationdb.annotation.API; import com.apple.foundationdb.annotation.SpotBugsSuppressWarnings; import com.apple.foundationdb.record.RecordCoreException; +import com.apple.foundationdb.record.query.combinatorics.CrossProduct; import com.apple.foundationdb.record.query.expressions.Comparisons; import com.apple.foundationdb.record.query.plan.bitmap.ComposedBitmapIndexQueryPlan; import com.apple.foundationdb.record.query.plan.cascades.AliasMap; -import com.apple.foundationdb.record.query.plan.cascades.Reference; import com.apple.foundationdb.record.query.plan.cascades.PlanProperty; import com.apple.foundationdb.record.query.plan.cascades.Quantifier; -import com.apple.foundationdb.record.query.plan.cascades.values.FirstOrDefaultStreamingValue; -import com.apple.foundationdb.record.query.plan.cascades.values.translation.TranslationMap; +import com.apple.foundationdb.record.query.plan.cascades.Reference; import com.apple.foundationdb.record.query.plan.cascades.TreeLike; import com.apple.foundationdb.record.query.plan.cascades.expressions.RelationalExpression; import com.apple.foundationdb.record.query.plan.cascades.predicates.PredicateWithComparisons; import com.apple.foundationdb.record.query.plan.cascades.predicates.PredicateWithValue; import com.apple.foundationdb.record.query.plan.cascades.predicates.QueryPredicate; import com.apple.foundationdb.record.query.plan.cascades.typing.Type; +import com.apple.foundationdb.record.query.plan.cascades.values.FirstOrDefaultStreamingValue; import com.apple.foundationdb.record.query.plan.cascades.values.FirstOrDefaultValue; import com.apple.foundationdb.record.query.plan.cascades.values.QueriedValue; import com.apple.foundationdb.record.query.plan.cascades.values.ThrowsValue; import com.apple.foundationdb.record.query.plan.cascades.values.Value; +import com.apple.foundationdb.record.query.plan.cascades.values.translation.TranslationMap; import com.apple.foundationdb.record.query.plan.plans.RecordQueryAggregateIndexPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryComparatorPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryCoveringIndexPlan; @@ -60,26 +61,24 @@ import com.apple.foundationdb.record.query.plan.plans.RecordQueryInValuesJoinPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryInsertPlan; -import com.apple.foundationdb.record.query.plan.plans.RecordQueryMultiIntersectionOnValuesPlan; -import com.apple.foundationdb.record.query.plan.plans.RecordQueryRecursiveUnionPlan; -import com.apple.foundationdb.record.query.plan.plans.RecordQueryTableFunctionPlan; -import com.apple.foundationdb.record.query.plan.plans.TempTableInsertPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryIntersectionOnKeyExpressionPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryIntersectionOnValuesPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryLoadByKeysPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryMapPlan; +import com.apple.foundationdb.record.query.plan.plans.RecordQueryMultiIntersectionOnValuesPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryPlanVisitor; import com.apple.foundationdb.record.query.plan.plans.RecordQueryPlanWithComparisonKeyValues; import com.apple.foundationdb.record.query.plan.plans.RecordQueryPlanWithComparisons; import com.apple.foundationdb.record.query.plan.plans.RecordQueryPredicatesFilterPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryRangePlan; +import com.apple.foundationdb.record.query.plan.plans.RecordQueryRecursiveUnionPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryScanPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryScoreForRankPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQuerySelectorPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQuerySetPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryStreamingAggregationPlan; -import com.apple.foundationdb.record.query.plan.plans.TempTableScanPlan; +import com.apple.foundationdb.record.query.plan.plans.RecordQueryTableFunctionPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryTextIndexPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryTypeFilterPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryUnionOnKeyExpressionPlan; @@ -88,12 +87,15 @@ import com.apple.foundationdb.record.query.plan.plans.RecordQueryUnorderedPrimaryKeyDistinctPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryUnorderedUnionPlan; import com.apple.foundationdb.record.query.plan.plans.RecordQueryUpdatePlan; +import com.apple.foundationdb.record.query.plan.plans.TempTableInsertPlan; +import com.apple.foundationdb.record.query.plan.plans.TempTableScanPlan; import com.apple.foundationdb.record.query.plan.sorting.RecordQueryDamPlan; import com.apple.foundationdb.record.query.plan.sorting.RecordQuerySortPlan; import com.google.common.base.Verify; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; +import com.google.common.collect.Streams; import javax.annotation.Nonnull; import java.util.List; @@ -235,8 +237,8 @@ public Derivations visitInComparandJoinPlan(@Nonnull final RecordQueryInComparan @Nonnull @Override public Derivations visitAggregateIndexPlan(@Nonnull final RecordQueryAggregateIndexPlan aggregateIndexPlan) { - final var matchCandidate = aggregateIndexPlan.getMatchCandidate(); - return visitPlanWithComparisons(aggregateIndexPlan, matchCandidate.getQueriedRecordTypeNames()); + final var localValues = localValuesForComparisons(aggregateIndexPlan.getComparisons()); + return new Derivations(ImmutableList.of(), localValues); } @Nonnull @@ -260,7 +262,7 @@ public Derivations visitIntersectionOnKeyExpressionPlan(@Nonnull final RecordQue @Nonnull @Override public Derivations visitMapPlan(@Nonnull final RecordQueryMapPlan mapPlan) { - final Quantifier rangesOver = Iterables.getOnlyElement(mapPlan.getQuantifiers()); + final var rangesOver = Iterables.getOnlyElement(mapPlan.getQuantifiers()); final var childDerivations = derivationsFromQuantifier(rangesOver); final var childResultValues = childDerivations.getResultValues(); final var resultValue = mapPlan.getResultValue(); @@ -382,17 +384,20 @@ public Derivations visitRecursiveUnionPlan(@Nonnull final RecordQueryRecursiveUn @Nonnull private Derivations visitPlanWithComparisons(@Nonnull final RecordQueryPlanWithComparisons planWithComparisons, @Nonnull final Iterable recordTypeNames) { - final var comparisons = planWithComparisons.getComparisons(); - final var comparisonValues = comparisons.stream() - .map(Comparisons.Comparison::getValue) - .filter(Objects::nonNull) - .collect(ImmutableList.toImmutableList()); + final var comparisonValues = localValuesForComparisons(planWithComparisons.getComparisons()); final var resultValueFromPlan = planWithComparisons.getResultValue(); final var resultValue = new QueriedValue(resultValueFromPlan.getResultType(), recordTypeNames); - return new Derivations(ImmutableList.of(resultValue), comparisonValues); } + @Nonnull + private List localValuesForComparisons(@Nonnull final Iterable comparisons) { + return Streams.stream(comparisons) + .map(Comparisons.Comparison::getValue) + .filter(Objects::nonNull) + .collect(ImmutableList.toImmutableList()); + } + @Nonnull @Override public Derivations visitFirstOrDefaultPlan(@Nonnull final RecordQueryFirstOrDefaultPlan firstOrDefaultPlan) { @@ -539,8 +544,40 @@ public Derivations visitInUnionOnKeyExpressionPlan(@Nonnull final RecordQueryInU @Nonnull @Override - public Derivations visitMultiIntersectionOnValuesPlan(@Nonnull final RecordQueryMultiIntersectionOnValuesPlan element) { - return null; //TODO + public Derivations visitMultiIntersectionOnValuesPlan(@Nonnull final RecordQueryMultiIntersectionOnValuesPlan multiIntersectionOnValuesPlan) { + final var intersectionResultValue = multiIntersectionOnValuesPlan.getResultValue(); + final var resultValuesBuilder = ImmutableList.builder(); + final var localValuesBuilder = ImmutableList.builder(); + + final var resultDerivationsBuilder = ImmutableList.>builder(); + + final var quantifiers = multiIntersectionOnValuesPlan.getQuantifiers(); + + for (final var quantifier : quantifiers) { + final var childDerivations = derivationsFromQuantifier(quantifier); + resultDerivationsBuilder.add(childDerivations.getResultValues()); + localValuesBuilder.addAll(childDerivations.getLocalValues()); + } + + final var crossProductIterable = + CrossProduct.crossProduct(resultDerivationsBuilder.build()); + + for (final var element : crossProductIterable) { + final var translationMapBuilder = TranslationMap.builder(); + for (int i = 0; i < quantifiers.size(); i++) { + final var quantifier = quantifiers.get(i); + final var derivationResultValue = element.get(i); + translationMapBuilder.when(quantifier.getAlias()) + .then((alias, leafValue) -> derivationResultValue); + } + resultValuesBuilder.add(intersectionResultValue.translateCorrelations(translationMapBuilder.build())); + } + final var resultValues = resultValuesBuilder.build(); + + localValuesBuilder.addAll(derivationsFromComparisonKeyValues(multiIntersectionOnValuesPlan, resultValues)); + + return new Derivations(resultValues, localValuesBuilder.build()); + } @Nonnull @@ -673,18 +710,25 @@ private Derivations visitSetPlan(@Nonnull final RecordQuerySetPlan setPlan) { final var resultValues = resultValuesBuilder.build(); + localValuesBuilder.addAll(derivationsFromComparisonKeyValues(setPlan, resultValues)); + + return new Derivations(resultValues, localValuesBuilder.build()); + } + + private static List derivationsFromComparisonKeyValues(@Nonnull final RecordQuerySetPlan setPlan, + @Nonnull final ImmutableList resultValues) { + final var resultBuilder = ImmutableList.builder(); if (setPlan instanceof RecordQueryPlanWithComparisonKeyValues) { for (final var comparisonKeyValue : ((RecordQueryPlanWithComparisonKeyValues)setPlan).getComparisonKeyValues()) { for (final var resultValue : resultValues) { final var translationMap = TranslationMap.builder() .when(Quantifier.current()).then((sourceAlias, leafValue) -> resultValue) .build(); - localValuesBuilder.add(comparisonKeyValue.translateCorrelations(translationMap, true)); + resultBuilder.add(comparisonKeyValue.translateCorrelations(translationMap, true)); } } } - - return new Derivations(resultValues, localValuesBuilder.build()); + return resultBuilder.build(); } @Nonnull diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java index 353f5a6fb9..f3b1f81148 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AbstractDataAccessRule.java @@ -919,11 +919,11 @@ private static Optional applyCompensationForSingleDataAcce * realized data access and its compensation. */ @Nonnull - protected abstract IntersectionResult createIntersectionAndCompensation(@Nonnull final Memoizer memoizer, - @Nonnull final Map intersectionInfoMap, - @Nonnull final Map matchToPlanMap, - @Nonnull final List> partition, - @Nonnull final Set requestedOrderings); + protected abstract IntersectionResult createIntersectionAndCompensation(@Nonnull Memoizer memoizer, + @Nonnull Map intersectionInfoMap, + @Nonnull Map matchToPlanMap, + @Nonnull List> partition, + @Nonnull Set requestedOrderings); protected static boolean isPartitionRedundant(@Nonnull final Map intersectionInfoMap, @Nonnull final List> partition, diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AdjustMatchRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AdjustMatchRule.java index b471a1a172..2f5c02b73f 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AdjustMatchRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AdjustMatchRule.java @@ -50,7 +50,7 @@ *

  • referencing the {@link MatchCandidate}'s traversal w.r.t. the (partially) matched query.
  • *
  • does not have a corresponding match on the query side.
  • * - * For more information, see {@link RelationalExpression#adjustMatch(PartialMatch)}. + * For more information, see {@link RelationalExpression#adjustMatch(PartialMatch, Quantifier)}. * Currently the only such expression that can be absorbed is * {@link com.apple.foundationdb.record.query.plan.cascades.expressions.MatchableSortExpression}. * TODO Maybe that expression should just be a generic property-defining expression or properties should be kept on quantifiers. diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java index 3a527f2207..da6c50e781 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/rules/AggregateDataAccessRule.java @@ -82,6 +82,31 @@ public AggregateDataAccessRule() { super(rootMatcher, completeMatchMatcher, expressionMatcher); } + /** + * Method to compute the intersection of multiple compatibly-ordered index scans of aggregate indexes. This method + * utilizes {@link RecordQueryMultiIntersectionOnValuesPlan} which intersects {@code n} compatibly-ordered data + * streams of records comprised of the groupings and the aggregates of the underlying indexes. In contrast to the + * simpler {@link com.apple.foundationdb.record.query.plan.plans.RecordQueryIntersectionOnValuesPlan} which is + * used to intersect value indexes, a multi intersection allows us to associate the current records of all data + * streams by the use of a common comparison key (that identifies the group) and then freely to pick any datum + * from any participating stream. In this way, we can access the different aggregates flowed in the individuals + * stream. + *
    + * For instance, if the partition we are trying to intersect, flows the result of an index scan over a + * {@code SUM} index ({@code q1 := (a, b, SUM(c)}) and another flows the result of a {@code COUNT} index using an + * identical grouping ({@code q2: = (a, b, COUNT_STAR}), we can form a multi intersection using a comparison key + * {@code _.1, _2}. We can then also access the aggregates in individually, e.g. + * ({@code (q1._0, q1._1, q1._2, q2._2}) would return the groupings comprised of {@code a} and {@code b} as well + * as the sum and the count. + * @param memoizer the memoizer + * @param intersectionInfoMap a map that allows us to access information about other intersections of degree + * {@code n-1}. + * @param matchToPlanMap a map from match to single data access expression + * @param partition a partition (i.e. a list of {@link SingleMatchedAccess}es that the caller would like to compute + * and intersected data access for + * @param requestedOrderings a set of ordering that have been requested by consuming expressions/plan operators + * @return a new {@link IntersectionResult} + */ @Nonnull @Override protected IntersectionResult createIntersectionAndCompensation(@Nonnull final Memoizer memoizer, diff --git a/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/api/metrics/NoOpMetricRegistry.java b/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/api/metrics/NoOpMetricRegistry.java index 7296c260cb..a663ba3618 100644 --- a/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/api/metrics/NoOpMetricRegistry.java +++ b/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/api/metrics/NoOpMetricRegistry.java @@ -30,7 +30,7 @@ * A utility for accessing a no-op {@link MetricRegistry}. *

    * NOTE(stack): Consider NOT using codahale but prometheus metrics. If server is exporting metrics - * on an prometheus endpoint, codahale will require translation (there are translators but better not + * on a prometheus endpoint, codahale will require translation (there are translators but better not * to translate at all). What is the story for clients? RL is codahale? */ @API(API.Status.EXPERIMENTAL) diff --git a/fdb-relational-grpc/src/main/java/com/apple/foundationdb/relational/jdbc/grpc/GrpcSQLExceptionUtil.java b/fdb-relational-grpc/src/main/java/com/apple/foundationdb/relational/jdbc/grpc/GrpcSQLExceptionUtil.java index 3cafaafc85..317d5255de 100644 --- a/fdb-relational-grpc/src/main/java/com/apple/foundationdb/relational/jdbc/grpc/GrpcSQLExceptionUtil.java +++ b/fdb-relational-grpc/src/main/java/com/apple/foundationdb/relational/jdbc/grpc/GrpcSQLExceptionUtil.java @@ -217,7 +217,7 @@ private static SQLException map(String message, ErrorInfo errorInfo) { } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { // Just fall through to plain-old sqlexception. - if (logger.isTraceEnabled()) { + if (logger.isTraceEnabled() && e.getMessage() != null) { logger.trace(e.getMessage()); } } diff --git a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlTestExtension.java b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlTestExtension.java index 1f5d8a6953..3224c7041a 100644 --- a/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlTestExtension.java +++ b/yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/YamlTestExtension.java @@ -69,7 +69,7 @@ public class YamlTestExtension implements TestTemplateInvocationContextProvider, private final boolean includeMethodInDescriptions; public YamlTestExtension() { - this(null, false); + this(null, true); } /** diff --git a/yaml-tests/src/test/java/YamlIntegrationTests.java b/yaml-tests/src/test/java/YamlIntegrationTests.java index a10bbcb528..596a9b9774 100644 --- a/yaml-tests/src/test/java/YamlIntegrationTests.java +++ b/yaml-tests/src/test/java/YamlIntegrationTests.java @@ -115,7 +115,7 @@ public void aggregateIndexTests(YamlTest.Runner runner) throws Exception { } @TestTemplate - @MaintainYamlTestConfig(YamlTestConfigFilters.SHOW_PLAN_ON_DIFF) + //@MaintainYamlTestConfig(YamlTestConfigFilters.SHOW_PLAN_ON_DIFF) public void aggregateEmptyTable(YamlTest.Runner runner) throws Exception { runner.runYamsql("aggregate-empty-table.yamsql"); } @@ -266,7 +266,6 @@ public void tableFunctionsTest(YamlTest.Runner runner) throws Exception { } @TestTemplate - //@MaintainYamlTestConfig(YamlTestConfigFilters.CORRECT_EXPLAIN_AND_METRICS) public void compositeAggregates(YamlTest.Runner runner) throws Exception { runner.runYamsql("composite-aggregates.yamsql"); } diff --git a/yaml-tests/src/test/resources/aggregate-empty-table.metrics.binpb b/yaml-tests/src/test/resources/aggregate-empty-table.metrics.binpb index 7d82373796..fe680d1113 100644 --- a/yaml-tests/src/test/resources/aggregate-empty-table.metrics.binpb +++ b/yaml-tests/src/test/resources/aggregate-empty-table.metrics.binpb @@ -1,71 +1,71 @@ - + 9 -agg-empty-table-tests EXPLAIN select count(*) from T1; -W ϔ(0"8@SCAN(<,>) | TFILTER T1 | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +agg-empty-table-tests EXPLAIN select count(*) from T1; +Z ܢZ(08@SCAN(<,>) | TFILTER T1 | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 6 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 7 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q27> label="q27" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q29> label="q29" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q19> label="q19" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q20> label="q20" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} H -agg-empty-table-tests/EXPLAIN select count(*) from T1 where col1 = 0; -вj ח(0/8@SCAN(<,>) | TFILTER T1 | FILTER _.COL1 EQUALS promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +agg-empty-table-tests/EXPLAIN select count(*) from T1 where col1 = 0; +m T(08@SCAN(<,>) | TFILTER T1 | FILTER _.COL1 EQUALS promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q23 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 EQUALS promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 4 [ label=<
    Value Computation
    MAP (q24 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 EQUALS promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 8 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q32> label="q32" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q34> label="q34" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q19> label="q19" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q20> label="q20" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} H -agg-empty-table-tests/EXPLAIN select count(*) from T1 where col1 > 0; -ɏj (088@SCAN(<,>) | TFILTER T1 | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +agg-empty-table-tests/EXPLAIN select count(*) from T1 where col1 > 0; +΋m f(08@SCAN(<,>) | TFILTER T1 | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q23 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 GREATER_THAN promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 4 [ label=<
    Value Computation
    MAP (q24 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 GREATER_THAN promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 8 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q32> label="q32" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q34> label="q34" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q19> label="q19" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q20> label="q20" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} 9 -agg-empty-table-tests EXPLAIN select count(*) from T2; - (20Ʀ8+@AISCAN(T2_I1 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +agg-empty-table-tests EXPLAIN select count(*) from T2; +  (G0/8z@AISCAN(T2_I1 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; @@ -73,260 +73,256 @@ H 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Value Computation
    MAP (q4 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 4 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 5 [ label=<
    Index
    T2_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 5 [ label=<
    Index
    AGG[T2_I1; count]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} H -agg-empty-table-tests/EXPLAIN select count(*) from T2 where col1 = 0; - - (<081@AISCAN(T2_I2 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +agg-empty-table-tests/EXPLAIN select count(*) from T2 where col1 = 0; + +(<0481@AISCAN(T2_I2 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Value Computation
    MAP ((q4._1 AS _0) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 5 [ label=<
    Index
    T2_I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 4 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 5 [ label=<
    Index
    AGG[T2_I2; count]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} H -agg-empty-table-tests/EXPLAIN select count(*) from T2 where col1 > 0; -Š (.0b8@SCAN(<,>) | TFILTER T2 | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +agg-empty-table-tests/EXPLAIN select count(*) from T2 where col1 > 0; + ֋ (<0B84@AISCAN(T2_I2 [[GREATER_THAN promote(@c11 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | AGG sum_l(_._1) GROUP BY () | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q77 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 GREATER_THAN promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Type Filter
    WHERE record IS [T2]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 8 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; + 3 [ label=<
    Value Computation
    MAP ((q4._1 AS _0) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Streaming Aggregate
    COLLECT sum_l(q94._1)
    GROUP BY ()
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; + 5 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 6 [ label=<
    Index
    AGG[T2_I2; count]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q86> label="q86" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q77> label="q77" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q73> label="q73" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q94> label="q94" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} G -agg-empty-table-tests.EXPLAIN select count(*) from T2 group by col1; -ܶ -a (*0 8 @MAISCAN(T2_I2 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0) +agg-empty-table-tests.EXPLAIN select count(*) from T2 group by col1; +Őf ܪ(*08 @MAISCAN(T2_I2 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0) digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    T2_I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 3 [ label=<
    Index
    AGG[T2_I2; count]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} V -agg-empty-table-tests=EXPLAIN select count(*) from T2 where col1 = 0 group by col1; - a (*08 @hAISCAN(T2_I2 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0) +agg-empty-table-tests=EXPLAIN select count(*) from T2 where col1 = 0 group by col1; + f (*0 +8 @hAISCAN(T2_I2 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0) digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    T2_I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 3 [ label=<
    Index
    AGG[T2_I2; count]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} V -agg-empty-table-tests=EXPLAIN select count(*) from T2 where col1 > 0 group by col1; -ĭ a վ(*08 @pAISCAN(T2_I2 [[GREATER_THAN promote(@c11 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0) +agg-empty-table-tests=EXPLAIN select count(*) from T2 where col1 > 0 group by col1; +f (*0Ų8 @pAISCAN(T2_I2 [[GREATER_THAN promote(@c11 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0) digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    T2_I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 3 [ label=<
    Index
    AGG[T2_I2; count]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} 9 -agg-empty-table-tests EXPLAIN select count(*) from T3; - (,0U8K@ISCAN(T3_I2 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +agg-empty-table-tests EXPLAIN select count(*) from T3; +ܬ (,0ٶ<8K@ISCAN(T3_I2 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    T3_I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index
    T3_I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q61> label="q61" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q67> label="q67" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} H -agg-empty-table-tests/EXPLAIN select count(*) from T3 where col1 = 0; -ӏ (20ޟ8g@ISCAN(T3_I1 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +agg-empty-table-tests/EXPLAIN select count(*) from T3 where col1 = 0; +  (20R8g@ISCAN(T3_I1 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q78> label="q78" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q84> label="q84" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} H -agg-empty-table-tests/EXPLAIN select count(*) from T3 where col1 > 0; -M /(508l@ISCAN(T3_I1 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +agg-empty-table-tests/EXPLAIN select count(*) from T3 where col1 > 0; +ӭ  (50_8l@ISCAN(T3_I1 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q78> label="q78" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q84> label="q84" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} G -agg-empty-table-tests.EXPLAIN select count(*) from T3 group by col1; -;H Ҳ((0}8@mISCAN(T3_I1 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0)digraph G { +agg-empty-table-tests.EXPLAIN select count(*) from T3 group by col1; +댲K ݛ(0 8@mISCAN(T3_I1 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    GROUP BY (q40._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, )" ]; - 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 4 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 5 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q40> label="q40" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    GROUP BY (q42._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, LONG AS _0 AS _1)" ]; + 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 4 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 5 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 -> 2 [ label=< q42> label="q42" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} V -agg-empty-table-tests=EXPLAIN select count(*) from T3 where col1 = 0 group by col1; -Ȣa (0ר8 @ISCAN(T3_I1 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (count_star(*) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0)digraph G { +agg-empty-table-tests=EXPLAIN select count(*) from T3 where col1 = 0 group by col1; +d (08 @ISCAN(T3_I1 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (count_star(*) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    GROUP BY (q48._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, )" ]; - 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 4 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 5 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q48> label="q48" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    GROUP BY (q50._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, LONG AS _0 AS _1)" ]; + 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 4 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 5 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 -> 2 [ label=< q50> label="q50" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} V -agg-empty-table-tests=EXPLAIN select count(*) from T3 where col1 > 0 group by col1; -a (0ڧ8 @ISCAN(T3_I1 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (count_star(*) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0)digraph G { +agg-empty-table-tests=EXPLAIN select count(*) from T3 where col1 > 0 group by col1; +۠d (08 @ISCAN(T3_I1 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (count_star(*) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    GROUP BY (q48._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, )" ]; - 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 4 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 5 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q48> label="q48" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    GROUP BY (q50._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, LONG AS _0 AS _1)" ]; + 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 4 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 5 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 -> 2 [ label=< q50> label="q50" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} < -agg-empty-table-tests#EXPLAIN select count(col2) from T1; -˯<W '(08@SCAN(<,>) | TFILTER T1 | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +agg-empty-table-tests#EXPLAIN select count(col2) from T1; +Z ۨO(08@SCAN(<,>) | TFILTER T1 | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q27._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q29._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 6 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 7 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q27> label="q27" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q29> label="q29" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q19> label="q19" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q20> label="q20" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} K -agg-empty-table-tests2EXPLAIN select count(col2) from T1 where col1 = 0; -j (008@SCAN(<,>) | TFILTER T1 | FILTER _.COL1 EQUALS promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +agg-empty-table-tests2EXPLAIN select count(col2) from T1 where col1 = 0; +m {(08@SCAN(<,>) | TFILTER T1 | FILTER _.COL1 EQUALS promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q32._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q23 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 EQUALS promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q34._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q24 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 EQUALS promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 8 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q32> label="q32" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q34> label="q34" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q19> label="q19" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q20> label="q20" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} K -agg-empty-table-tests2EXPLAIN select count(col2) from T1 where col1 > 0; -쉄j (028@SCAN(<,>) | TFILTER T1 | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +agg-empty-table-tests2EXPLAIN select count(col2) from T1 where col1 > 0; +m (0Ȏ8@SCAN(<,>) | TFILTER T1 | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q32._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q23 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 GREATER_THAN promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q34._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q24 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 GREATER_THAN promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 8 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q32> label="q32" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q34> label="q34" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q19> label="q19" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q20> label="q20" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} < -agg-empty-table-tests#EXPLAIN select count(col2) from T2; -п  (20[8+@AISCAN(T2_I3 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +agg-empty-table-tests#EXPLAIN select count(col2) from T2; + ΋ (G0D8z@AISCAN(T2_I3 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; @@ -334,305 +330,300 @@ K 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Value Computation
    MAP (q4 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 4 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 5 [ label=<
    Index
    T2_I3
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 5 [ label=<
    Index
    AGG[T2_I3; count_not_null]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} K -agg-empty-table-tests2EXPLAIN select count(col2) from T2 where col1 = 0; - ʒ(<0ూ81@AISCAN(T2_I4 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +agg-empty-table-tests2EXPLAIN select count(col2) from T2 where col1 = 0; +˺ (<0.81@AISCAN(T2_I4 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Value Computation
    MAP ((q4._1 AS _0) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 5 [ label=<
    Index
    T2_I4
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 4 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 5 [ label=<
    Index
    AGG[T2_I4; count_not_null]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} K -agg-empty-table-tests2EXPLAIN select count(col2) from T2 where col1 > 0; -  Ѷ(.0)8@SCAN(<,>) | TFILTER T2 | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +agg-empty-table-tests2EXPLAIN select count(col2) from T2 where col1 > 0; + ҄ (<0Q84@AISCAN(T2_I4 [[GREATER_THAN promote(@c11 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | AGG sum_l(_._1) GROUP BY () | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q86._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q77 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 GREATER_THAN promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Type Filter
    WHERE record IS [T2]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 8 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; + 3 [ label=<
    Value Computation
    MAP ((q4._1 AS _0) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Streaming Aggregate
    COLLECT sum_l(q94._1)
    GROUP BY ()
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; + 5 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 6 [ label=<
    Index
    AGG[T2_I4; count_not_null]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q86> label="q86" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q77> label="q77" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q73> label="q73" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q94> label="q94" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} J -agg-empty-table-tests1EXPLAIN select count(col2) from T2 group by col1; -՜8a +(*0&8 @MAISCAN(T2_I4 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0) +agg-empty-table-tests1EXPLAIN select count(col2) from T2 group by col1; +f (*08 @MAISCAN(T2_I4 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0) digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    T2_I4
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 3 [ label=<
    Index
    AGG[T2_I4; count_not_null]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} Y -agg-empty-table-tests@EXPLAIN select count(col2) from T2 where col1 = 0 group by col1; -ކa (*0 8 @hAISCAN(T2_I4 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0) +agg-empty-table-tests@EXPLAIN select count(col2) from T2 where col1 = 0 group by col1; +ɧf (*08 @hAISCAN(T2_I4 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0) digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    T2_I4
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 3 [ label=<
    Index
    AGG[T2_I4; count_not_null]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} Y -agg-empty-table-tests@EXPLAIN select count(col2) from T2 where col1 > 0 group by col1; -Ҩ a (*068 @pAISCAN(T2_I4 [[GREATER_THAN promote(@c11 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0) +agg-empty-table-tests@EXPLAIN select count(col2) from T2 where col1 > 0 group by col1; +f (*0 8 @pAISCAN(T2_I4 [[GREATER_THAN promote(@c11 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0) digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    T2_I4
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 3 [ label=<
    Index
    AGG[T2_I4; count_not_null]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} < -agg-empty-table-tests#EXPLAIN select count(col2) from T3; -  (,0ᤐ8K@ISCAN(T3_I1 <,>) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +agg-empty-table-tests#EXPLAIN select count(col2) from T3; + (,0J8K@ISCAN(T3_I1 <,>) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q59._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q65._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q59> label="q59" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q65> label="q65" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} K -agg-empty-table-tests2EXPLAIN select count(col2) from T3 where col1 = 0; - - (20U8g@ISCAN(T3_I1 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +agg-empty-table-tests2EXPLAIN select count(col2) from T3 where col1 = 0; +Ӷ  (20X8g@ISCAN(T3_I1 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q78._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q84._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q78> label="q78" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q84> label="q84" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} K -agg-empty-table-tests2EXPLAIN select count(col2) from T3 where col1 > 0; - - (50s8l@ISCAN(T3_I1 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +agg-empty-table-tests2EXPLAIN select count(col2) from T3 where col1 > 0; + + ڍ(50Y8l@ISCAN(T3_I1 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q78._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q84._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q78> label="q78" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q84> label="q84" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} J -agg-empty-table-tests1EXPLAIN select count(col2) from T3 group by col1; - -H (0n8@pISCAN(T3_I1 <,>) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0)digraph G { +agg-empty-table-tests1EXPLAIN select count(col2) from T3 group by col1; +K (0Ԑ 8@pISCAN(T3_I1 <,>) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Streaming Aggregate
    COLLECT (count(q40._0.COL2) AS _0)
    GROUP BY (q40._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, )" ]; - 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 4 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 5 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q40> label="q40" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 [ label=<
    Streaming Aggregate
    COLLECT (count(q42._0.COL2) AS _0)
    GROUP BY (q42._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, LONG AS _0 AS _1)" ]; + 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 4 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 5 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 -> 2 [ label=< q42> label="q42" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} Y -agg-empty-table-tests@EXPLAIN select count(col2) from T3 where col1 = 0 group by col1; -ʝa (0ի8 @ISCAN(T3_I1 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0)digraph G { +agg-empty-table-tests@EXPLAIN select count(col2) from T3 where col1 = 0 group by col1; +Ѹd (08 @ISCAN(T3_I1 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Streaming Aggregate
    COLLECT (count(q48._0.COL2) AS _0)
    GROUP BY (q48._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, )" ]; - 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 4 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 5 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q48> label="q48" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 [ label=<
    Streaming Aggregate
    COLLECT (count(q50._0.COL2) AS _0)
    GROUP BY (q50._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, LONG AS _0 AS _1)" ]; + 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 4 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 5 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 -> 2 [ label=< q50> label="q50" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} Y -agg-empty-table-tests@EXPLAIN select count(col2) from T3 where col1 > 0 group by col1; -ψ a (0"8 @ISCAN(T3_I1 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0)digraph G { +agg-empty-table-tests@EXPLAIN select count(col2) from T3 where col1 > 0 group by col1; +ǎd Ʌ(08 @ISCAN(T3_I1 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Streaming Aggregate
    COLLECT (count(q48._0.COL2) AS _0)
    GROUP BY (q48._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, )" ]; - 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 4 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 5 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q48> label="q48" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 [ label=<
    Streaming Aggregate
    COLLECT (count(q50._0.COL2) AS _0)
    GROUP BY (q50._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, LONG AS _0 AS _1)" ]; + 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 4 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 5 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 -> 2 [ label=< q50> label="q50" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} : -agg-empty-table-tests!EXPLAIN select sum(col1) from T1; -ᣲW ȸ(078@kSCAN(<,>) | TFILTER T1 | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +agg-empty-table-tests!EXPLAIN select sum(col1) from T1; +֋Z ȃf(08@kSCAN(<,>) | TFILTER T1 | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q27._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q29._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 6 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 7 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q27> label="q27" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q29> label="q29" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q19> label="q19" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q20> label="q20" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} I -agg-empty-table-tests0EXPLAIN select sum(col1) from T1 where col1 = 0; -j 绩(08@SCAN(<,>) | TFILTER T1 | FILTER _.COL1 EQUALS promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +agg-empty-table-tests0EXPLAIN select sum(col1) from T1 where col1 = 0; +m Ę(08@SCAN(<,>) | TFILTER T1 | FILTER _.COL1 EQUALS promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q32._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q23 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 EQUALS promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q34._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q24 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 EQUALS promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 8 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q32> label="q32" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q34> label="q34" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q19> label="q19" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q20> label="q20" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} I -agg-empty-table-tests0EXPLAIN select sum(col1) from T1 where col2 = 0; -j v(08@SCAN(<,>) | TFILTER T1 | FILTER _.COL2 EQUALS promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +agg-empty-table-tests0EXPLAIN select sum(col1) from T1 where col2 = 0; +m ߵ(0!8@SCAN(<,>) | TFILTER T1 | FILTER _.COL2 EQUALS promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q32._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q23 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q2.COL2 EQUALS promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q34._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q24 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Predicate Filter
    WHERE q2.COL2 EQUALS promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 8 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q32> label="q32" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q34> label="q34" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q19> label="q19" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q20> label="q20" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} I -agg-empty-table-tests0EXPLAIN select sum(col1) from T1 where col1 > 0; -j 覯(0,8@SCAN(<,>) | TFILTER T1 | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +agg-empty-table-tests0EXPLAIN select sum(col1) from T1 where col1 > 0; +՟m x(08@SCAN(<,>) | TFILTER T1 | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q32._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q23 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 GREATER_THAN promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q34._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q24 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 GREATER_THAN promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 8 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q32> label="q32" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q34> label="q34" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q19> label="q19" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q20> label="q20" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} I -agg-empty-table-tests0EXPLAIN select sum(col1) from T1 where col2 > 0; -j (0-8@SCAN(<,>) | TFILTER T1 | FILTER _.COL2 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +agg-empty-table-tests0EXPLAIN select sum(col1) from T1 where col2 > 0; +m D(08@SCAN(<,>) | TFILTER T1 | FILTER _.COL2 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q32._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q23 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q2.COL2 GREATER_THAN promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q34._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q24 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Predicate Filter
    WHERE q2.COL2 GREATER_THAN promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 8 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q32> label="q32" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q34> label="q34" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q19> label="q19" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q20> label="q20" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} : -agg-empty-table-tests!EXPLAIN select sum(col1) from T2; -E ߃1(20Ĕ8+@cAISCAN(T2_I5 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +agg-empty-table-tests!EXPLAIN select sum(col1) from T2; + +(G0D8z@cAISCAN(T2_I5 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; @@ -640,346 +631,342 @@ I 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Value Computation
    MAP (q4 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 4 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 5 [ label=<
    Index
    T2_I5
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 5 [ label=<
    Index
    AGG[T2_I5; sum]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} I -agg-empty-table-tests0EXPLAIN select sum(col1) from T2 where col1 = 0; -  (.0 8@SCAN(<,>) | TFILTER T2 | FILTER _.COL1 EQUALS promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +agg-empty-table-tests0EXPLAIN select sum(col1) from T2 where col1 = 0; + ʸ (608@SCAN(<,>) | TFILTER T2 | FILTER _.COL1 EQUALS promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q86._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q77 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 EQUALS promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Type Filter
    WHERE record IS [T2]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q88._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q78 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 EQUALS promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Type Filter
    WHERE record IS [T2]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 8 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q86> label="q86" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q77> label="q77" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q88> label="q88" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q78> label="q78" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q73> label="q73" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q74> label="q74" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} I -agg-empty-table-tests0EXPLAIN select sum(col1) from T2 where col2 = 0; - (<081@AISCAN(T2_I6 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +agg-empty-table-tests0EXPLAIN select sum(col1) from T2 where col2 = 0; + (<0<81@AISCAN(T2_I6 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Value Computation
    MAP ((q4._1 AS _0) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 5 [ label=<
    Index
    T2_I6
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 4 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 5 [ label=<
    Index
    AGG[T2_I6; sum]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} I -agg-empty-table-tests0EXPLAIN select sum(col1) from T2 where col1 > 0; - ܰ(.0&8@SCAN(<,>) | TFILTER T2 | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +agg-empty-table-tests0EXPLAIN select sum(col1) from T2 where col1 > 0; + Έ (608@SCAN(<,>) | TFILTER T2 | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q86._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q77 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 GREATER_THAN promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Type Filter
    WHERE record IS [T2]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q88._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q78 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 GREATER_THAN promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Type Filter
    WHERE record IS [T2]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 8 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q86> label="q86" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q77> label="q77" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q88> label="q88" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q78> label="q78" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q73> label="q73" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q74> label="q74" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} I -agg-empty-table-tests0EXPLAIN select sum(col1) from T2 where col2 > 0; -ʿ (.0ȼJ8@SCAN(<,>) | TFILTER T2 | FILTER _.COL2 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +agg-empty-table-tests0EXPLAIN select sum(col1) from T2 where col2 > 0; +  (<0184@AISCAN(T2_I6 [[GREATER_THAN promote(@c11 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | AGG sum_l(_._1) GROUP BY () | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q86._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q77 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q2.COL2 GREATER_THAN promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Type Filter
    WHERE record IS [T2]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 8 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; + 3 [ label=<
    Value Computation
    MAP ((q4._1 AS _0) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Streaming Aggregate
    COLLECT sum_l(q94._1)
    GROUP BY ()
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; + 5 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 6 [ label=<
    Index
    AGG[T2_I6; sum]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q86> label="q86" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q77> label="q77" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q73> label="q73" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q94> label="q94" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} W -agg-empty-table-tests>EXPLAIN select sum(col1) from T2 where col2 = 0 group by col2; -ߒ a (*0 8 @hAISCAN(T2_I6 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0) +agg-empty-table-tests>EXPLAIN select sum(col1) from T2 where col2 = 0 group by col2; +ͬ f (*08 @hAISCAN(T2_I6 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0) digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    T2_I6
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 3 [ label=<
    Index
    AGG[T2_I6; sum]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} W -agg-empty-table-tests>EXPLAIN select sum(col1) from T2 where col2 > 0 group by col2; - a (*0Ϛ8 @pAISCAN(T2_I6 [[GREATER_THAN promote(@c11 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0) +agg-empty-table-tests>EXPLAIN select sum(col1) from T2 where col2 > 0 group by col2; +f ٗ(*08 @pAISCAN(T2_I6 [[GREATER_THAN promote(@c11 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0) digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    T2_I6
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 3 [ label=<
    Index
    AGG[T2_I6; sum]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} : -agg-empty-table-tests!EXPLAIN select sum(col1) from T3; -  (,0{8K@eISCAN(T3_I1 <,>) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +agg-empty-table-tests!EXPLAIN select sum(col1) from T3; + (,0R8K@eISCAN(T3_I1 <,>) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q59._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q65._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q59> label="q59" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q65> label="q65" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} I -agg-empty-table-tests0EXPLAIN select sum(col1) from T3 where col1 = 0; - ȳ(20V8g@ISCAN(T3_I1 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +agg-empty-table-tests0EXPLAIN select sum(col1) from T3 where col1 = 0; +  (20T8g@ISCAN(T3_I1 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q78._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q84._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q78> label="q78" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q84> label="q84" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} I -agg-empty-table-tests0EXPLAIN select sum(col1) from T3 where col2 = 0; - դ(20ߊ8g@ISCAN(T3_I2 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +agg-empty-table-tests0EXPLAIN select sum(col1) from T3 where col2 = 0; + (20;8g@ISCAN(T3_I2 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q80._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    T3_I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q86._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index
    T3_I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q80> label="q80" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q86> label="q86" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} I -agg-empty-table-tests0EXPLAIN select sum(col1) from T3 where col1 > 0; -  (508l@ISCAN(T3_I1 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +agg-empty-table-tests0EXPLAIN select sum(col1) from T3 where col1 > 0; + + (50\8l@ISCAN(T3_I1 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q78._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q84._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q78> label="q78" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q84> label="q84" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} I -agg-empty-table-tests0EXPLAIN select sum(col1) from T3 where col2 > 0; -L ɜ.(508l@ISCAN(T3_I2 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +agg-empty-table-tests0EXPLAIN select sum(col1) from T3 where col2 > 0; +  (50f8l@ISCAN(T3_I2 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q80._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    T3_I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q86._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index
    T3_I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q80> label="q80" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q86> label="q86" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} W -agg-empty-table-tests>EXPLAIN select sum(col1) from T3 where col1 = 0 group by col2; -_ ׺(08@ISCAN(T3_I2 <,>) | FILTER _.COL1 EQUALS promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) GROUP BY (_._0.COL2 AS _0) | MAP (_._1._0 AS _0)digraph G { +agg-empty-table-tests>EXPLAIN select sum(col1) from T3 where col1 = 0 group by col2; +ʄb (08@ISCAN(T3_I2 <,>) | FILTER _.COL1 EQUALS promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) GROUP BY (_._0.COL2 AS _0) | MAP (_._1._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q46._0.COL1) AS _0)
    GROUP BY (q46._0.COL2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, )" ]; - 3 [ label=<
    Value Computation
    MAP (q35 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 4 [ label=<
    Predicate Filter
    WHERE q2.COL1 EQUALS promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 5 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    T3_I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q46> label="q46" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q35> label="q35" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q48._0.COL1) AS _0)
    GROUP BY (q48._0.COL2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, LONG AS _0 AS _1)" ]; + 3 [ label=<
    Value Computation
    MAP (q36 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 4 [ label=<
    Predicate Filter
    WHERE q2.COL1 EQUALS promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 5 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index
    T3_I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 -> 2 [ label=< q48> label="q48" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q36> label="q36" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} W -agg-empty-table-tests>EXPLAIN select sum(col1) from T3 where col2 = 0 group by col2; - -a (08 @ISCAN(T3_I2 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) GROUP BY (_._0.COL2 AS _0) | MAP (_._1._0 AS _0)digraph G { +agg-empty-table-tests>EXPLAIN select sum(col1) from T3 where col2 = 0 group by col2; +d (08 @ISCAN(T3_I2 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) GROUP BY (_._0.COL2 AS _0) | MAP (_._1._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q48._0.COL1) AS _0)
    GROUP BY (q48._0.COL2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, )" ]; - 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 4 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 5 [ label=<
    Index
    T3_I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q48> label="q48" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q50._0.COL1) AS _0)
    GROUP BY (q50._0.COL2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, LONG AS _0 AS _1)" ]; + 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 4 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 5 [ label=<
    Index
    T3_I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 -> 2 [ label=< q50> label="q50" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} W -agg-empty-table-tests>EXPLAIN select sum(col1) from T3 where col1 > 0 group by col2; -_ (0Ҋ8@ISCAN(T3_I2 <,>) | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) GROUP BY (_._0.COL2 AS _0) | MAP (_._1._0 AS _0)digraph G { +agg-empty-table-tests>EXPLAIN select sum(col1) from T3 where col1 > 0 group by col2; +b (0 8@ISCAN(T3_I2 <,>) | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) GROUP BY (_._0.COL2 AS _0) | MAP (_._1._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q46._0.COL1) AS _0)
    GROUP BY (q46._0.COL2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, )" ]; - 3 [ label=<
    Value Computation
    MAP (q35 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 4 [ label=<
    Predicate Filter
    WHERE q2.COL1 GREATER_THAN promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 5 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    T3_I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q46> label="q46" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q35> label="q35" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q48._0.COL1) AS _0)
    GROUP BY (q48._0.COL2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, LONG AS _0 AS _1)" ]; + 3 [ label=<
    Value Computation
    MAP (q36 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 4 [ label=<
    Predicate Filter
    WHERE q2.COL1 GREATER_THAN promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 5 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index
    T3_I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 -> 2 [ label=< q48> label="q48" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q36> label="q36" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} W -agg-empty-table-tests>EXPLAIN select sum(col1) from T3 where col2 > 0 group by col2; -빎a (08 @ISCAN(T3_I2 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) GROUP BY (_._0.COL2 AS _0) | MAP (_._1._0 AS _0)digraph G { +agg-empty-table-tests>EXPLAIN select sum(col1) from T3 where col2 > 0 group by col2; +d (08 @ISCAN(T3_I2 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) GROUP BY (_._0.COL2 AS _0) | MAP (_._1._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q48._0.COL1) AS _0)
    GROUP BY (q48._0.COL2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, )" ]; - 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 4 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 5 [ label=<
    Index
    T3_I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q48> label="q48" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q50._0.COL1) AS _0)
    GROUP BY (q50._0.COL2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, LONG AS _0 AS _1)" ]; + 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 4 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 5 [ label=<
    Index
    T3_I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 -> 2 [ label=< q50> label="q50" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} M -)agg-empty-table-tests-after-modifications EXPLAIN select count(*) from T1; -W ϔ(0"8@SCAN(<,>) | TFILTER T1 | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +)agg-empty-table-tests-after-modifications EXPLAIN select count(*) from T1; +Z ܢZ(08@SCAN(<,>) | TFILTER T1 | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 6 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 7 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q27> label="q27" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q29> label="q29" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q19> label="q19" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q20> label="q20" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} \ -)agg-empty-table-tests-after-modifications/EXPLAIN select count(*) from T1 where col1 = 0; -вj ח(0/8@SCAN(<,>) | TFILTER T1 | FILTER _.COL1 EQUALS promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +)agg-empty-table-tests-after-modifications/EXPLAIN select count(*) from T1 where col1 = 0; +m T(08@SCAN(<,>) | TFILTER T1 | FILTER _.COL1 EQUALS promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q23 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 EQUALS promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 4 [ label=<
    Value Computation
    MAP (q24 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 EQUALS promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 8 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q32> label="q32" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q34> label="q34" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q19> label="q19" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q20> label="q20" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} \ -)agg-empty-table-tests-after-modifications/EXPLAIN select count(*) from T1 where col1 > 0; -ɏj (088@SCAN(<,>) | TFILTER T1 | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +)agg-empty-table-tests-after-modifications/EXPLAIN select count(*) from T1 where col1 > 0; +΋m f(08@SCAN(<,>) | TFILTER T1 | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q23 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 GREATER_THAN promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 4 [ label=<
    Value Computation
    MAP (q24 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 GREATER_THAN promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 8 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q32> label="q32" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q34> label="q34" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q19> label="q19" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q20> label="q20" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} M -)agg-empty-table-tests-after-modifications EXPLAIN select count(*) from T2; - (20Ʀ8+@AISCAN(T2_I1 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +)agg-empty-table-tests-after-modifications EXPLAIN select count(*) from T2; +  (G0/8z@AISCAN(T2_I1 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; @@ -987,15 +974,15 @@ M 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Value Computation
    MAP (q4 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 4 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 5 [ label=<
    Index
    T2_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 5 [ label=<
    Index
    AGG[T2_I1; count]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} P -)agg-empty-table-tests-after-modifications#EXPLAIN select count(col2) from T2; -п  (20[8+@AISCAN(T2_I3 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +)agg-empty-table-tests-after-modifications#EXPLAIN select count(col2) from T2; + ΋ (G0D8z@AISCAN(T2_I3 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; @@ -1003,266 +990,261 @@ P 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Value Computation
    MAP (q4 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 4 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 5 [ label=<
    Index
    T2_I3
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 5 [ label=<
    Index
    AGG[T2_I3; count_not_null]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} _ -)agg-empty-table-tests-after-modifications2EXPLAIN select count(col2) from T2 where col1 = 0; - ʒ(<0ూ81@AISCAN(T2_I4 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +)agg-empty-table-tests-after-modifications2EXPLAIN select count(col2) from T2 where col1 = 0; +˺ (<0.81@AISCAN(T2_I4 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Value Computation
    MAP ((q4._1 AS _0) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 5 [ label=<
    Index
    T2_I4
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 4 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 5 [ label=<
    Index
    AGG[T2_I4; count_not_null]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} _ -)agg-empty-table-tests-after-modifications2EXPLAIN select count(col2) from T2 where col1 > 0; -  Ѷ(.0)8@SCAN(<,>) | TFILTER T2 | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +)agg-empty-table-tests-after-modifications2EXPLAIN select count(col2) from T2 where col1 > 0; + ҄ (<0Q84@AISCAN(T2_I4 [[GREATER_THAN promote(@c11 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | AGG sum_l(_._1) GROUP BY () | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q86._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q77 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 GREATER_THAN promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Type Filter
    WHERE record IS [T2]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 8 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; + 3 [ label=<
    Value Computation
    MAP ((q4._1 AS _0) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Streaming Aggregate
    COLLECT sum_l(q94._1)
    GROUP BY ()
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; + 5 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 6 [ label=<
    Index
    AGG[T2_I4; count_not_null]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q86> label="q86" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q77> label="q77" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q73> label="q73" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q94> label="q94" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} P -)agg-empty-table-tests-after-modifications#EXPLAIN select count(col2) from T3; -  (,0ᤐ8K@ISCAN(T3_I1 <,>) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +)agg-empty-table-tests-after-modifications#EXPLAIN select count(col2) from T3; + (,0J8K@ISCAN(T3_I1 <,>) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q59._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q65._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q59> label="q59" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q65> label="q65" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} _ -)agg-empty-table-tests-after-modifications2EXPLAIN select count(col2) from T3 where col1 = 0; - - (20U8g@ISCAN(T3_I1 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +)agg-empty-table-tests-after-modifications2EXPLAIN select count(col2) from T3 where col1 = 0; +Ӷ  (20X8g@ISCAN(T3_I1 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q78._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q84._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q78> label="q78" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q84> label="q84" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} _ -)agg-empty-table-tests-after-modifications2EXPLAIN select count(col2) from T3 where col1 > 0; - - (50s8l@ISCAN(T3_I1 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +)agg-empty-table-tests-after-modifications2EXPLAIN select count(col2) from T3 where col1 > 0; + + ڍ(50Y8l@ISCAN(T3_I1 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q78._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q84._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q78> label="q78" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q84> label="q84" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} ^ -)agg-empty-table-tests-after-modifications1EXPLAIN select count(col2) from T3 group by col1; - -H (0n8@pISCAN(T3_I1 <,>) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0)digraph G { +)agg-empty-table-tests-after-modifications1EXPLAIN select count(col2) from T3 group by col1; +K (0Ԑ 8@pISCAN(T3_I1 <,>) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Streaming Aggregate
    COLLECT (count(q40._0.COL2) AS _0)
    GROUP BY (q40._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, )" ]; - 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 4 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 5 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q40> label="q40" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 [ label=<
    Streaming Aggregate
    COLLECT (count(q42._0.COL2) AS _0)
    GROUP BY (q42._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, LONG AS _0 AS _1)" ]; + 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 4 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 5 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 -> 2 [ label=< q42> label="q42" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} m -)agg-empty-table-tests-after-modifications@EXPLAIN select count(col2) from T3 where col1 = 0 group by col1; -ʝa (0ի8 @ISCAN(T3_I1 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0)digraph G { +)agg-empty-table-tests-after-modifications@EXPLAIN select count(col2) from T3 where col1 = 0 group by col1; +Ѹd (08 @ISCAN(T3_I1 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Streaming Aggregate
    COLLECT (count(q48._0.COL2) AS _0)
    GROUP BY (q48._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, )" ]; - 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 4 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 5 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q48> label="q48" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 [ label=<
    Streaming Aggregate
    COLLECT (count(q50._0.COL2) AS _0)
    GROUP BY (q50._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, LONG AS _0 AS _1)" ]; + 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 4 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 5 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 -> 2 [ label=< q50> label="q50" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} m -)agg-empty-table-tests-after-modifications@EXPLAIN select count(col2) from T3 where col1 > 0 group by col1; -ψ a (0"8 @ISCAN(T3_I1 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0)digraph G { +)agg-empty-table-tests-after-modifications@EXPLAIN select count(col2) from T3 where col1 > 0 group by col1; +ǎd Ʌ(08 @ISCAN(T3_I1 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Streaming Aggregate
    COLLECT (count(q48._0.COL2) AS _0)
    GROUP BY (q48._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, )" ]; - 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 4 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 5 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q48> label="q48" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 [ label=<
    Streaming Aggregate
    COLLECT (count(q50._0.COL2) AS _0)
    GROUP BY (q50._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, LONG AS _0 AS _1)" ]; + 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 4 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 5 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 -> 2 [ label=< q50> label="q50" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} N -)agg-empty-table-tests-after-modifications!EXPLAIN select sum(col1) from T1; -ᣲW ȸ(078@kSCAN(<,>) | TFILTER T1 | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +)agg-empty-table-tests-after-modifications!EXPLAIN select sum(col1) from T1; +֋Z ȃf(08@kSCAN(<,>) | TFILTER T1 | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q27._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q29._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 6 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 7 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q27> label="q27" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q29> label="q29" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q19> label="q19" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q20> label="q20" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} ] -)agg-empty-table-tests-after-modifications0EXPLAIN select sum(col1) from T1 where col1 = 0; -j 绩(08@SCAN(<,>) | TFILTER T1 | FILTER _.COL1 EQUALS promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +)agg-empty-table-tests-after-modifications0EXPLAIN select sum(col1) from T1 where col1 = 0; +m Ę(08@SCAN(<,>) | TFILTER T1 | FILTER _.COL1 EQUALS promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q32._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q23 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 EQUALS promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q34._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q24 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 EQUALS promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 8 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q32> label="q32" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q34> label="q34" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q19> label="q19" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q20> label="q20" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} ] -)agg-empty-table-tests-after-modifications0EXPLAIN select sum(col1) from T1 where col2 = 0; -j v(08@SCAN(<,>) | TFILTER T1 | FILTER _.COL2 EQUALS promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +)agg-empty-table-tests-after-modifications0EXPLAIN select sum(col1) from T1 where col2 = 0; +m ߵ(0!8@SCAN(<,>) | TFILTER T1 | FILTER _.COL2 EQUALS promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q32._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q23 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q2.COL2 EQUALS promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q34._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q24 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Predicate Filter
    WHERE q2.COL2 EQUALS promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 8 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q32> label="q32" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q34> label="q34" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q19> label="q19" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q20> label="q20" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} ] -)agg-empty-table-tests-after-modifications0EXPLAIN select sum(col1) from T1 where col1 > 0; -j 覯(0,8@SCAN(<,>) | TFILTER T1 | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +)agg-empty-table-tests-after-modifications0EXPLAIN select sum(col1) from T1 where col1 > 0; +՟m x(08@SCAN(<,>) | TFILTER T1 | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q32._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q23 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 GREATER_THAN promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q34._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q24 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 GREATER_THAN promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 8 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q32> label="q32" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q34> label="q34" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q19> label="q19" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q20> label="q20" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} ] -)agg-empty-table-tests-after-modifications0EXPLAIN select sum(col1) from T1 where col2 > 0; -j (0-8@SCAN(<,>) | TFILTER T1 | FILTER _.COL2 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +)agg-empty-table-tests-after-modifications0EXPLAIN select sum(col1) from T1 where col2 > 0; +m D(08@SCAN(<,>) | TFILTER T1 | FILTER _.COL2 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q32._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q23 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q2.COL2 GREATER_THAN promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q34._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q24 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Predicate Filter
    WHERE q2.COL2 GREATER_THAN promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 8 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q32> label="q32" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q34> label="q34" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q19> label="q19" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q20> label="q20" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} N -)agg-empty-table-tests-after-modifications!EXPLAIN select sum(col1) from T2; -E ߃1(20Ĕ8+@cAISCAN(T2_I5 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +)agg-empty-table-tests-after-modifications!EXPLAIN select sum(col1) from T2; + +(G0D8z@cAISCAN(T2_I5 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; @@ -1270,140 +1252,137 @@ N 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Value Computation
    MAP (q4 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 4 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 5 [ label=<
    Index
    T2_I5
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 5 [ label=<
    Index
    AGG[T2_I5; sum]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} ] -)agg-empty-table-tests-after-modifications0EXPLAIN select sum(col1) from T2 where col2 = 0; - (<081@AISCAN(T2_I6 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +)agg-empty-table-tests-after-modifications0EXPLAIN select sum(col1) from T2 where col2 = 0; + (<0<81@AISCAN(T2_I6 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Value Computation
    MAP ((q4._1 AS _0) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 5 [ label=<
    Index
    T2_I6
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 4 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 5 [ label=<
    Index
    AGG[T2_I6; sum]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} ] -)agg-empty-table-tests-after-modifications0EXPLAIN select sum(col1) from T2 where col1 > 0; - ܰ(.0&8@SCAN(<,>) | TFILTER T2 | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +)agg-empty-table-tests-after-modifications0EXPLAIN select sum(col1) from T2 where col1 > 0; + Έ (608@SCAN(<,>) | TFILTER T2 | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q86._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q77 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 GREATER_THAN promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Type Filter
    WHERE record IS [T2]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q88._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q78 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Predicate Filter
    WHERE q2.COL1 GREATER_THAN promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Type Filter
    WHERE record IS [T2]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 8 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q86> label="q86" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q77> label="q77" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q88> label="q88" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q78> label="q78" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q73> label="q73" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q74> label="q74" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} ] -)agg-empty-table-tests-after-modifications0EXPLAIN select sum(col1) from T2 where col2 > 0; -ʿ (.0ȼJ8@SCAN(<,>) | TFILTER T2 | FILTER _.COL2 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +)agg-empty-table-tests-after-modifications0EXPLAIN select sum(col1) from T2 where col2 > 0; +  (<0184@AISCAN(T2_I6 [[GREATER_THAN promote(@c11 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | AGG sum_l(_._1) GROUP BY () | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q86._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q77 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q2.COL2 GREATER_THAN promote(@c11 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Type Filter
    WHERE record IS [T2]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 8 [ label=<
    Primary Storage
    record types: [T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; + 3 [ label=<
    Value Computation
    MAP ((q4._1 AS _0) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Streaming Aggregate
    COLLECT sum_l(q94._1)
    GROUP BY ()
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; + 5 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 6 [ label=<
    Index
    AGG[T2_I6; sum]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q86> label="q86" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q77> label="q77" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q73> label="q73" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q94> label="q94" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} ] -)agg-empty-table-tests-after-modifications0EXPLAIN select sum(col1) from T3 where col1 = 0; - ȳ(20V8g@ISCAN(T3_I1 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +)agg-empty-table-tests-after-modifications0EXPLAIN select sum(col1) from T3 where col1 = 0; +  (20T8g@ISCAN(T3_I1 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q78._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q84._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q78> label="q78" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q84> label="q84" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} ] -)agg-empty-table-tests-after-modifications0EXPLAIN select sum(col1) from T3 where col2 = 0; - դ(20ߊ8g@ISCAN(T3_I2 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +)agg-empty-table-tests-after-modifications0EXPLAIN select sum(col1) from T3 where col2 = 0; + (20;8g@ISCAN(T3_I2 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q80._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    T3_I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q86._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index
    T3_I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q80> label="q80" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q86> label="q86" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} ] -)agg-empty-table-tests-after-modifications0EXPLAIN select sum(col1) from T3 where col1 > 0; -  (508l@ISCAN(T3_I1 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +)agg-empty-table-tests-after-modifications0EXPLAIN select sum(col1) from T3 where col1 > 0; + + (50\8l@ISCAN(T3_I1 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q78._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q84._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index
    T3_I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q78> label="q78" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q84> label="q84" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} ] -)agg-empty-table-tests-after-modifications0EXPLAIN select sum(col1) from T3 where col2 > 0; -L ɜ.(508l@ISCAN(T3_I2 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +)agg-empty-table-tests-after-modifications0EXPLAIN select sum(col1) from T3 where col2 > 0; +  (50f8l@ISCAN(T3_I2 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q80._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    T3_I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q86._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c11 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index
    T3_I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q80> label="q80" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q86> label="q86" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; diff --git a/yaml-tests/src/test/resources/aggregate-empty-table.metrics.yaml b/yaml-tests/src/test/resources/aggregate-empty-table.metrics.yaml index beb48f13a9..4ac33e26d0 100644 --- a/yaml-tests/src/test/resources/aggregate-empty-table.metrics.yaml +++ b/yaml-tests/src/test/resources/aggregate-empty-table.metrics.yaml @@ -3,9 +3,9 @@ agg-empty-table-tests: explain: SCAN(<,>) | TFILTER T1 | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 263 - task_total_time_ms: 6 - transform_count: 87 - transform_time_ms: 2 + task_total_time_ms: 5 + transform_count: 90 + transform_time_ms: 1 transform_yield_count: 15 insert_time_ms: 0 insert_new_count: 22 @@ -15,9 +15,9 @@ agg-empty-table-tests: MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 335 - task_total_time_ms: 11 - transform_count: 106 - transform_time_ms: 4 + task_total_time_ms: 4 + transform_count: 109 + transform_time_ms: 1 transform_yield_count: 17 insert_time_ms: 0 insert_new_count: 28 @@ -27,9 +27,9 @@ agg-empty-table-tests: | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 335 - task_total_time_ms: 12 - transform_count: 106 - transform_time_ms: 6 + task_total_time_ms: 10 + transform_count: 109 + transform_time_ms: 1 transform_yield_count: 17 insert_time_ms: 0 insert_new_count: 28 @@ -37,45 +37,46 @@ agg-empty-table-tests: - query: EXPLAIN select count(*) from T2; explain: 'AISCAN(T2_I1 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)' - task_count: 450 - task_total_time_ms: 35 - transform_count: 158 - transform_time_ms: 25 - transform_yield_count: 50 - insert_time_ms: 2 - insert_new_count: 43 - insert_reused_count: 4 + task_count: 723 + task_total_time_ms: 19 + transform_count: 244 + transform_time_ms: 10 + transform_yield_count: 71 + insert_time_ms: 0 + insert_new_count: 122 + insert_reused_count: 2 - query: EXPLAIN select count(*) from T2 where col1 = 0; explain: 'AISCAN(T2_I2 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)' task_count: 538 - task_total_time_ms: 22 - transform_count: 182 - transform_time_ms: 13 + task_total_time_ms: 34 + transform_count: 188 + transform_time_ms: 22 transform_yield_count: 60 - insert_time_ms: 3 + insert_time_ms: 0 insert_new_count: 49 insert_reused_count: 4 - query: EXPLAIN select count(*) from T2 where col1 > 0; - explain: SCAN(<,>) | TFILTER T2 | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) - | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, - promote(0l AS LONG)) AS _0) - task_count: 393 - task_total_time_ms: 44 - transform_count: 135 - transform_time_ms: 34 - transform_yield_count: 46 + explain: 'AISCAN(T2_I2 [[GREATER_THAN promote(@c11 AS LONG)]] BY_GROUP -> [_0: + KEY:[0], _1: VALUE:[0]]) | AGG sum_l(_._1) GROUP BY () | MAP ((_._1 AS _0) + AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) + AS _0)' + task_count: 558 + task_total_time_ms: 40 + transform_count: 190 + transform_time_ms: 27 + transform_yield_count: 60 insert_time_ms: 1 - insert_new_count: 28 - insert_reused_count: 2 + insert_new_count: 52 + insert_reused_count: 4 - query: EXPLAIN select count(*) from T2 group by col1; explain: 'AISCAN(T2_I2 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0)' task_count: 259 - task_total_time_ms: 21 - transform_count: 97 - transform_time_ms: 16 + task_total_time_ms: 14 + transform_count: 102 + transform_time_ms: 11 transform_yield_count: 42 insert_time_ms: 0 insert_new_count: 12 @@ -84,9 +85,9 @@ agg-empty-table-tests: explain: 'AISCAN(T2_I2 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0)' task_count: 259 - task_total_time_ms: 26 - transform_count: 97 - transform_time_ms: 18 + task_total_time_ms: 19 + transform_count: 102 + transform_time_ms: 12 transform_yield_count: 42 insert_time_ms: 0 insert_new_count: 12 @@ -95,9 +96,9 @@ agg-empty-table-tests: explain: 'AISCAN(T2_I2 [[GREATER_THAN promote(@c11 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0)' task_count: 259 - task_total_time_ms: 23 - transform_count: 97 - transform_time_ms: 17 + task_total_time_ms: 14 + transform_count: 102 + transform_time_ms: 9 transform_yield_count: 42 insert_time_ms: 0 insert_new_count: 12 @@ -106,11 +107,11 @@ agg-empty-table-tests: explain: ISCAN(T3_I2 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 509 - task_total_time_ms: 16 - transform_count: 151 - transform_time_ms: 6 + task_total_time_ms: 14 + transform_count: 154 + transform_time_ms: 4 transform_yield_count: 44 - insert_time_ms: 1 + insert_time_ms: 0 insert_new_count: 75 insert_reused_count: 6 - query: EXPLAIN select count(*) from T3 where col1 = 0; @@ -118,11 +119,11 @@ agg-empty-table-tests: AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 730 - task_total_time_ms: 44 - transform_count: 215 - transform_time_ms: 15 + task_total_time_ms: 25 + transform_count: 218 + transform_time_ms: 5 transform_yield_count: 50 - insert_time_ms: 2 + insert_time_ms: 1 insert_new_count: 103 insert_reused_count: 5 - query: EXPLAIN select count(*) from T3 where col1 > 0; @@ -130,31 +131,31 @@ agg-empty-table-tests: AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 757 - task_total_time_ms: 161 - transform_count: 218 - transform_time_ms: 99 + task_total_time_ms: 23 + transform_count: 221 + transform_time_ms: 5 transform_yield_count: 53 - insert_time_ms: 10 + insert_time_ms: 1 insert_new_count: 108 insert_reused_count: 5 - query: EXPLAIN select count(*) from T3 group by col1; explain: ISCAN(T3_I1 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0) task_count: 220 - task_total_time_ms: 125 - transform_count: 72 - transform_time_ms: 84 + task_total_time_ms: 9 + transform_count: 75 + transform_time_ms: 3 transform_yield_count: 26 - insert_time_ms: 2 + insert_time_ms: 0 insert_new_count: 18 insert_reused_count: 2 - query: EXPLAIN select count(*) from T3 where col1 = 0 group by col1; explain: ISCAN(T3_I1 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (count_star(*) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0) task_count: 317 - task_total_time_ms: 13 - transform_count: 97 - transform_time_ms: 4 + task_total_time_ms: 12 + transform_count: 100 + transform_time_ms: 3 transform_yield_count: 30 insert_time_ms: 0 insert_new_count: 32 @@ -163,9 +164,9 @@ agg-empty-table-tests: explain: ISCAN(T3_I1 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (count_star(*) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0) task_count: 317 - task_total_time_ms: 16 - transform_count: 97 - transform_time_ms: 7 + task_total_time_ms: 11 + transform_count: 100 + transform_time_ms: 3 transform_yield_count: 30 insert_time_ms: 0 insert_new_count: 32 @@ -174,11 +175,11 @@ agg-empty-table-tests: explain: SCAN(<,>) | TFILTER T1 | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 263 - task_total_time_ms: 126 - transform_count: 87 - transform_time_ms: 83 + task_total_time_ms: 5 + transform_count: 90 + transform_time_ms: 1 transform_yield_count: 15 - insert_time_ms: 5 + insert_time_ms: 0 insert_new_count: 22 insert_reused_count: 2 - query: EXPLAIN select count(col2) from T1 where col1 = 0; @@ -186,9 +187,9 @@ agg-empty-table-tests: MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 335 - task_total_time_ms: 13 - transform_count: 106 - transform_time_ms: 5 + task_total_time_ms: 8 + transform_count: 109 + transform_time_ms: 2 transform_yield_count: 17 insert_time_ms: 0 insert_new_count: 28 @@ -198,9 +199,9 @@ agg-empty-table-tests: | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 335 - task_total_time_ms: 12 - transform_count: 106 - transform_time_ms: 4 + task_total_time_ms: 9 + transform_count: 109 + transform_time_ms: 2 transform_yield_count: 17 insert_time_ms: 0 insert_new_count: 28 @@ -208,45 +209,46 @@ agg-empty-table-tests: - query: EXPLAIN select count(col2) from T2; explain: 'AISCAN(T2_I3 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)' - task_count: 450 - task_total_time_ms: 19 - transform_count: 158 - transform_time_ms: 10 - transform_yield_count: 50 + task_count: 723 + task_total_time_ms: 39 + transform_count: 244 + transform_time_ms: 24 + transform_yield_count: 71 insert_time_ms: 1 - insert_new_count: 43 - insert_reused_count: 4 + insert_new_count: 122 + insert_reused_count: 2 - query: EXPLAIN select count(col2) from T2 where col1 = 0; explain: 'AISCAN(T2_I4 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)' task_count: 538 - task_total_time_ms: 52 - transform_count: 182 - transform_time_ms: 35 + task_total_time_ms: 18 + transform_count: 188 + transform_time_ms: 12 transform_yield_count: 60 - insert_time_ms: 2 + insert_time_ms: 0 insert_new_count: 49 insert_reused_count: 4 - query: EXPLAIN select count(col2) from T2 where col1 > 0; - explain: SCAN(<,>) | TFILTER T2 | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) - | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, - promote(0l AS LONG)) AS _0) - task_count: 393 - task_total_time_ms: 20 - transform_count: 135 - transform_time_ms: 15 - transform_yield_count: 46 - insert_time_ms: 0 - insert_new_count: 28 - insert_reused_count: 2 + explain: 'AISCAN(T2_I4 [[GREATER_THAN promote(@c11 AS LONG)]] BY_GROUP -> [_0: + KEY:[0], _1: VALUE:[0]]) | AGG sum_l(_._1) GROUP BY () | MAP ((_._1 AS _0) + AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) + AS _0)' + task_count: 558 + task_total_time_ms: 40 + transform_count: 190 + transform_time_ms: 27 + transform_yield_count: 60 + insert_time_ms: 1 + insert_new_count: 52 + insert_reused_count: 4 - query: EXPLAIN select count(col2) from T2 group by col1; explain: 'AISCAN(T2_I4 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0)' task_count: 259 - task_total_time_ms: 118 - transform_count: 97 - transform_time_ms: 91 + task_total_time_ms: 12 + transform_count: 102 + transform_time_ms: 8 transform_yield_count: 42 insert_time_ms: 0 insert_new_count: 12 @@ -256,8 +258,8 @@ agg-empty-table-tests: _1: VALUE:[0]]) | MAP (_._1 AS _0)' task_count: 259 task_total_time_ms: 17 - transform_count: 97 - transform_time_ms: 11 + transform_count: 102 + transform_time_ms: 12 transform_yield_count: 42 insert_time_ms: 0 insert_new_count: 12 @@ -266,9 +268,9 @@ agg-empty-table-tests: explain: 'AISCAN(T2_I4 [[GREATER_THAN promote(@c11 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0)' task_count: 259 - task_total_time_ms: 23 - transform_count: 97 - transform_time_ms: 16 + task_total_time_ms: 15 + transform_count: 102 + transform_time_ms: 10 transform_yield_count: 42 insert_time_ms: 0 insert_new_count: 12 @@ -277,11 +279,11 @@ agg-empty-table-tests: explain: ISCAN(T3_I1 <,>) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 509 - task_total_time_ms: 23 - transform_count: 151 - transform_time_ms: 9 + task_total_time_ms: 17 + transform_count: 154 + transform_time_ms: 4 transform_yield_count: 44 - insert_time_ms: 2 + insert_time_ms: 1 insert_new_count: 75 insert_reused_count: 6 - query: EXPLAIN select count(col2) from T3 where col1 = 0; @@ -289,9 +291,9 @@ agg-empty-table-tests: AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 730 - task_total_time_ms: 20 - transform_count: 215 - transform_time_ms: 7 + task_total_time_ms: 24 + transform_count: 218 + transform_time_ms: 5 transform_yield_count: 50 insert_time_ms: 1 insert_new_count: 103 @@ -301,9 +303,9 @@ agg-empty-table-tests: AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 757 - task_total_time_ms: 22 - transform_count: 218 - transform_time_ms: 7 + task_total_time_ms: 21 + transform_count: 221 + transform_time_ms: 4 transform_yield_count: 53 insert_time_ms: 1 insert_new_count: 108 @@ -312,19 +314,19 @@ agg-empty-table-tests: explain: ISCAN(T3_I1 <,>) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0) task_count: 220 - task_total_time_ms: 21 - transform_count: 72 - transform_time_ms: 11 + task_total_time_ms: 8 + transform_count: 75 + transform_time_ms: 3 transform_yield_count: 26 - insert_time_ms: 1 + insert_time_ms: 0 insert_new_count: 18 insert_reused_count: 2 - query: EXPLAIN select count(col2) from T3 where col1 = 0 group by col1; explain: ISCAN(T3_I1 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0) task_count: 317 - task_total_time_ms: 12 - transform_count: 97 + task_total_time_ms: 13 + transform_count: 100 transform_time_ms: 3 transform_yield_count: 30 insert_time_ms: 0 @@ -335,9 +337,9 @@ agg-empty-table-tests: AGG (count(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0) task_count: 317 - task_total_time_ms: 19 - transform_count: 97 - transform_time_ms: 8 + task_total_time_ms: 10 + transform_count: 100 + transform_time_ms: 4 transform_yield_count: 30 insert_time_ms: 0 insert_new_count: 32 @@ -346,9 +348,9 @@ agg-empty-table-tests: explain: SCAN(<,>) | TFILTER T1 | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) task_count: 263 - task_total_time_ms: 11 - transform_count: 87 - transform_time_ms: 5 + task_total_time_ms: 6 + transform_count: 90 + transform_time_ms: 1 transform_yield_count: 15 insert_time_ms: 0 insert_new_count: 22 @@ -358,11 +360,11 @@ agg-empty-table-tests: MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) task_count: 335 - task_total_time_ms: 16 - transform_count: 106 - transform_time_ms: 4 + task_total_time_ms: 9 + transform_count: 109 + transform_time_ms: 2 transform_yield_count: 17 - insert_time_ms: 2 + insert_time_ms: 0 insert_new_count: 28 insert_reused_count: 2 - query: EXPLAIN select sum(col1) from T1 where col2 = 0; @@ -370,9 +372,9 @@ agg-empty-table-tests: MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) task_count: 335 - task_total_time_ms: 5 - transform_count: 106 - transform_time_ms: 1 + task_total_time_ms: 11 + transform_count: 109 + transform_time_ms: 4 transform_yield_count: 17 insert_time_ms: 0 insert_new_count: 28 @@ -382,9 +384,9 @@ agg-empty-table-tests: | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) task_count: 335 - task_total_time_ms: 7 - transform_count: 106 - transform_time_ms: 2 + task_total_time_ms: 8 + transform_count: 109 + transform_time_ms: 1 transform_yield_count: 17 insert_time_ms: 0 insert_new_count: 28 @@ -394,9 +396,9 @@ agg-empty-table-tests: | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) task_count: 335 - task_total_time_ms: 10 - transform_count: 106 - transform_time_ms: 3 + task_total_time_ms: 4 + transform_count: 109 + transform_time_ms: 1 transform_yield_count: 17 insert_time_ms: 0 insert_new_count: 28 @@ -404,69 +406,69 @@ agg-empty-table-tests: - query: EXPLAIN select sum(col1) from T2; explain: 'AISCAN(T2_I5 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)' - task_count: 450 - task_total_time_ms: 145 - transform_count: 158 - transform_time_ms: 102 - transform_yield_count: 50 - insert_time_ms: 6 - insert_new_count: 43 - insert_reused_count: 4 + task_count: 723 + task_total_time_ms: 35 + transform_count: 244 + transform_time_ms: 22 + transform_yield_count: 71 + insert_time_ms: 1 + insert_new_count: 122 + insert_reused_count: 2 - query: EXPLAIN select sum(col1) from T2 where col1 = 0; explain: SCAN(<,>) | TFILTER T2 | FILTER _.COL1 EQUALS promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) - task_count: 393 - task_total_time_ms: 27 - transform_count: 135 - transform_time_ms: 14 - transform_yield_count: 46 + task_count: 409 + task_total_time_ms: 31 + transform_count: 146 + transform_time_ms: 24 + transform_yield_count: 54 insert_time_ms: 0 - insert_new_count: 28 + insert_new_count: 31 insert_reused_count: 2 - query: EXPLAIN select sum(col1) from T2 where col2 = 0; explain: 'AISCAN(T2_I6 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)' task_count: 538 - task_total_time_ms: 54 - transform_count: 182 - transform_time_ms: 32 + task_total_time_ms: 41 + transform_count: 188 + transform_time_ms: 27 transform_yield_count: 60 - insert_time_ms: 3 + insert_time_ms: 0 insert_new_count: 49 insert_reused_count: 4 - query: EXPLAIN select sum(col1) from T2 where col1 > 0; explain: SCAN(<,>) | TFILTER T2 | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) - task_count: 393 - task_total_time_ms: 18 - transform_count: 135 - transform_time_ms: 14 - transform_yield_count: 46 + task_count: 409 + task_total_time_ms: 32 + transform_count: 146 + transform_time_ms: 26 + transform_yield_count: 54 insert_time_ms: 0 - insert_new_count: 28 + insert_new_count: 31 insert_reused_count: 2 - query: EXPLAIN select sum(col1) from T2 where col2 > 0; - explain: SCAN(<,>) | TFILTER T2 | FILTER _.COL2 GREATER_THAN promote(@c11 AS LONG) - | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 - AS _0) - task_count: 393 - task_total_time_ms: 36 - transform_count: 135 - transform_time_ms: 29 - transform_yield_count: 46 - insert_time_ms: 1 - insert_new_count: 28 - insert_reused_count: 2 + explain: 'AISCAN(T2_I6 [[GREATER_THAN promote(@c11 AS LONG)]] BY_GROUP -> [_0: + KEY:[0], _1: VALUE:[0]]) | AGG sum_l(_._1) GROUP BY () | MAP ((_._1 AS _0) + AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)' + task_count: 558 + task_total_time_ms: 20 + transform_count: 190 + transform_time_ms: 14 + transform_yield_count: 60 + insert_time_ms: 0 + insert_new_count: 52 + insert_reused_count: 4 - query: EXPLAIN select sum(col1) from T2 where col2 = 0 group by col2; explain: 'AISCAN(T2_I6 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0)' task_count: 259 task_total_time_ms: 19 - transform_count: 97 - transform_time_ms: 13 + transform_count: 102 + transform_time_ms: 12 transform_yield_count: 42 insert_time_ms: 0 insert_new_count: 12 @@ -475,9 +477,9 @@ agg-empty-table-tests: explain: 'AISCAN(T2_I6 [[GREATER_THAN promote(@c11 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0)' task_count: 259 - task_total_time_ms: 20 - transform_count: 97 - transform_time_ms: 15 + task_total_time_ms: 18 + transform_count: 102 + transform_time_ms: 12 transform_yield_count: 42 insert_time_ms: 0 insert_new_count: 12 @@ -486,19 +488,19 @@ agg-empty-table-tests: explain: ISCAN(T3_I1 <,>) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) task_count: 509 - task_total_time_ms: 23 - transform_count: 151 - transform_time_ms: 10 + task_total_time_ms: 16 + transform_count: 154 + transform_time_ms: 5 transform_yield_count: 44 - insert_time_ms: 2 + insert_time_ms: 1 insert_new_count: 75 insert_reused_count: 6 - query: EXPLAIN select sum(col1) from T3 where col1 = 0; explain: ISCAN(T3_I1 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) task_count: 730 - task_total_time_ms: 17 - transform_count: 215 + task_total_time_ms: 23 + transform_count: 218 transform_time_ms: 5 transform_yield_count: 50 insert_time_ms: 1 @@ -508,33 +510,33 @@ agg-empty-table-tests: explain: ISCAN(T3_I2 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) task_count: 730 - task_total_time_ms: 36 - transform_count: 215 - transform_time_ms: 8 + task_total_time_ms: 14 + transform_count: 218 + transform_time_ms: 3 transform_yield_count: 50 - insert_time_ms: 2 + insert_time_ms: 0 insert_new_count: 103 insert_reused_count: 5 - query: EXPLAIN select sum(col1) from T3 where col1 > 0; explain: ISCAN(T3_I1 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) task_count: 757 - task_total_time_ms: 24 - transform_count: 218 - transform_time_ms: 8 + task_total_time_ms: 22 + transform_count: 221 + transform_time_ms: 5 transform_yield_count: 53 - insert_time_ms: 3 + insert_time_ms: 1 insert_new_count: 108 insert_reused_count: 5 - query: EXPLAIN select sum(col1) from T3 where col2 > 0; explain: ISCAN(T3_I2 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) task_count: 757 - task_total_time_ms: 160 - transform_count: 218 - transform_time_ms: 96 + task_total_time_ms: 25 + transform_count: 221 + transform_time_ms: 5 transform_yield_count: 53 - insert_time_ms: 9 + insert_time_ms: 1 insert_new_count: 108 insert_reused_count: 5 - query: EXPLAIN select sum(col1) from T3 where col1 = 0 group by col2; @@ -543,8 +545,8 @@ agg-empty-table-tests: AS _0) task_count: 299 task_total_time_ms: 10 - transform_count: 95 - transform_time_ms: 4 + transform_count: 98 + transform_time_ms: 3 transform_yield_count: 29 insert_time_ms: 0 insert_new_count: 28 @@ -553,9 +555,9 @@ agg-empty-table-tests: explain: ISCAN(T3_I2 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) GROUP BY (_._0.COL2 AS _0) | MAP (_._1._0 AS _0) task_count: 317 - task_total_time_ms: 22 - transform_count: 97 - transform_time_ms: 9 + task_total_time_ms: 13 + transform_count: 100 + transform_time_ms: 3 transform_yield_count: 30 insert_time_ms: 0 insert_new_count: 32 @@ -565,9 +567,9 @@ agg-empty-table-tests: MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) GROUP BY (_._0.COL2 AS _0) | MAP (_._1._0 AS _0) task_count: 299 - task_total_time_ms: 13 - transform_count: 95 - transform_time_ms: 6 + task_total_time_ms: 9 + transform_count: 98 + transform_time_ms: 3 transform_yield_count: 29 insert_time_ms: 0 insert_new_count: 28 @@ -577,9 +579,9 @@ agg-empty-table-tests: AGG (sum_l(_._0.COL1) AS _0) GROUP BY (_._0.COL2 AS _0) | MAP (_._1._0 AS _0) task_count: 317 - task_total_time_ms: 10 - transform_count: 97 - transform_time_ms: 5 + task_total_time_ms: 13 + transform_count: 100 + transform_time_ms: 3 transform_yield_count: 30 insert_time_ms: 0 insert_new_count: 32 @@ -589,9 +591,9 @@ agg-empty-table-tests-after-modifications: explain: SCAN(<,>) | TFILTER T1 | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 263 - task_total_time_ms: 6 - transform_count: 87 - transform_time_ms: 2 + task_total_time_ms: 5 + transform_count: 90 + transform_time_ms: 1 transform_yield_count: 15 insert_time_ms: 0 insert_new_count: 22 @@ -601,9 +603,9 @@ agg-empty-table-tests-after-modifications: MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 335 - task_total_time_ms: 11 - transform_count: 106 - transform_time_ms: 4 + task_total_time_ms: 4 + transform_count: 109 + transform_time_ms: 1 transform_yield_count: 17 insert_time_ms: 0 insert_new_count: 28 @@ -613,9 +615,9 @@ agg-empty-table-tests-after-modifications: | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 335 - task_total_time_ms: 12 - transform_count: 106 - transform_time_ms: 6 + task_total_time_ms: 10 + transform_count: 109 + transform_time_ms: 1 transform_yield_count: 17 insert_time_ms: 0 insert_new_count: 28 @@ -623,58 +625,59 @@ agg-empty-table-tests-after-modifications: - query: EXPLAIN select count(*) from T2; explain: 'AISCAN(T2_I1 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)' - task_count: 450 - task_total_time_ms: 35 - transform_count: 158 - transform_time_ms: 25 - transform_yield_count: 50 - insert_time_ms: 2 - insert_new_count: 43 - insert_reused_count: 4 + task_count: 723 + task_total_time_ms: 19 + transform_count: 244 + transform_time_ms: 10 + transform_yield_count: 71 + insert_time_ms: 0 + insert_new_count: 122 + insert_reused_count: 2 - query: EXPLAIN select count(col2) from T2; explain: 'AISCAN(T2_I3 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)' - task_count: 450 - task_total_time_ms: 19 - transform_count: 158 - transform_time_ms: 10 - transform_yield_count: 50 + task_count: 723 + task_total_time_ms: 39 + transform_count: 244 + transform_time_ms: 24 + transform_yield_count: 71 insert_time_ms: 1 - insert_new_count: 43 - insert_reused_count: 4 + insert_new_count: 122 + insert_reused_count: 2 - query: EXPLAIN select count(col2) from T2 where col1 = 0; explain: 'AISCAN(T2_I4 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)' task_count: 538 - task_total_time_ms: 52 - transform_count: 182 - transform_time_ms: 35 + task_total_time_ms: 18 + transform_count: 188 + transform_time_ms: 12 transform_yield_count: 60 - insert_time_ms: 2 + insert_time_ms: 0 insert_new_count: 49 insert_reused_count: 4 - query: EXPLAIN select count(col2) from T2 where col1 > 0; - explain: SCAN(<,>) | TFILTER T2 | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) - | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, - promote(0l AS LONG)) AS _0) - task_count: 393 - task_total_time_ms: 20 - transform_count: 135 - transform_time_ms: 15 - transform_yield_count: 46 - insert_time_ms: 0 - insert_new_count: 28 - insert_reused_count: 2 + explain: 'AISCAN(T2_I4 [[GREATER_THAN promote(@c11 AS LONG)]] BY_GROUP -> [_0: + KEY:[0], _1: VALUE:[0]]) | AGG sum_l(_._1) GROUP BY () | MAP ((_._1 AS _0) + AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) + AS _0)' + task_count: 558 + task_total_time_ms: 40 + transform_count: 190 + transform_time_ms: 27 + transform_yield_count: 60 + insert_time_ms: 1 + insert_new_count: 52 + insert_reused_count: 4 - query: EXPLAIN select count(col2) from T3; explain: ISCAN(T3_I1 <,>) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 509 - task_total_time_ms: 23 - transform_count: 151 - transform_time_ms: 9 + task_total_time_ms: 17 + transform_count: 154 + transform_time_ms: 4 transform_yield_count: 44 - insert_time_ms: 2 + insert_time_ms: 1 insert_new_count: 75 insert_reused_count: 6 - query: EXPLAIN select count(col2) from T3 where col1 = 0; @@ -682,9 +685,9 @@ agg-empty-table-tests-after-modifications: AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 730 - task_total_time_ms: 20 - transform_count: 215 - transform_time_ms: 7 + task_total_time_ms: 24 + transform_count: 218 + transform_time_ms: 5 transform_yield_count: 50 insert_time_ms: 1 insert_new_count: 103 @@ -694,9 +697,9 @@ agg-empty-table-tests-after-modifications: AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 757 - task_total_time_ms: 22 - transform_count: 218 - transform_time_ms: 7 + task_total_time_ms: 21 + transform_count: 221 + transform_time_ms: 4 transform_yield_count: 53 insert_time_ms: 1 insert_new_count: 108 @@ -705,19 +708,19 @@ agg-empty-table-tests-after-modifications: explain: ISCAN(T3_I1 <,>) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0) task_count: 220 - task_total_time_ms: 21 - transform_count: 72 - transform_time_ms: 11 + task_total_time_ms: 8 + transform_count: 75 + transform_time_ms: 3 transform_yield_count: 26 - insert_time_ms: 1 + insert_time_ms: 0 insert_new_count: 18 insert_reused_count: 2 - query: EXPLAIN select count(col2) from T3 where col1 = 0 group by col1; explain: ISCAN(T3_I1 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0) task_count: 317 - task_total_time_ms: 12 - transform_count: 97 + task_total_time_ms: 13 + transform_count: 100 transform_time_ms: 3 transform_yield_count: 30 insert_time_ms: 0 @@ -728,9 +731,9 @@ agg-empty-table-tests-after-modifications: AGG (count(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0) task_count: 317 - task_total_time_ms: 19 - transform_count: 97 - transform_time_ms: 8 + task_total_time_ms: 10 + transform_count: 100 + transform_time_ms: 4 transform_yield_count: 30 insert_time_ms: 0 insert_new_count: 32 @@ -739,9 +742,9 @@ agg-empty-table-tests-after-modifications: explain: SCAN(<,>) | TFILTER T1 | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) task_count: 263 - task_total_time_ms: 11 - transform_count: 87 - transform_time_ms: 5 + task_total_time_ms: 6 + transform_count: 90 + transform_time_ms: 1 transform_yield_count: 15 insert_time_ms: 0 insert_new_count: 22 @@ -751,11 +754,11 @@ agg-empty-table-tests-after-modifications: MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) task_count: 335 - task_total_time_ms: 16 - transform_count: 106 - transform_time_ms: 4 + task_total_time_ms: 9 + transform_count: 109 + transform_time_ms: 2 transform_yield_count: 17 - insert_time_ms: 2 + insert_time_ms: 0 insert_new_count: 28 insert_reused_count: 2 - query: EXPLAIN select sum(col1) from T1 where col2 = 0; @@ -763,9 +766,9 @@ agg-empty-table-tests-after-modifications: MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) task_count: 335 - task_total_time_ms: 5 - transform_count: 106 - transform_time_ms: 1 + task_total_time_ms: 11 + transform_count: 109 + transform_time_ms: 4 transform_yield_count: 17 insert_time_ms: 0 insert_new_count: 28 @@ -775,9 +778,9 @@ agg-empty-table-tests-after-modifications: | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) task_count: 335 - task_total_time_ms: 7 - transform_count: 106 - transform_time_ms: 2 + task_total_time_ms: 8 + transform_count: 109 + transform_time_ms: 1 transform_yield_count: 17 insert_time_ms: 0 insert_new_count: 28 @@ -787,9 +790,9 @@ agg-empty-table-tests-after-modifications: | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) task_count: 335 - task_total_time_ms: 10 - transform_count: 106 - transform_time_ms: 3 + task_total_time_ms: 4 + transform_count: 109 + transform_time_ms: 1 transform_yield_count: 17 insert_time_ms: 0 insert_new_count: 28 @@ -797,68 +800,56 @@ agg-empty-table-tests-after-modifications: - query: EXPLAIN select sum(col1) from T2; explain: 'AISCAN(T2_I5 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)' - task_count: 450 - task_total_time_ms: 145 - transform_count: 158 - transform_time_ms: 102 - transform_yield_count: 50 - insert_time_ms: 6 - insert_new_count: 43 - insert_reused_count: 4 + task_count: 723 + task_total_time_ms: 35 + transform_count: 244 + transform_time_ms: 22 + transform_yield_count: 71 + insert_time_ms: 1 + insert_new_count: 122 + insert_reused_count: 2 - query: EXPLAIN select sum(col1) from T2 where col2 = 0; explain: 'AISCAN(T2_I6 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)' task_count: 538 - task_total_time_ms: 54 - transform_count: 182 - transform_time_ms: 32 + task_total_time_ms: 41 + transform_count: 188 + transform_time_ms: 27 transform_yield_count: 60 - insert_time_ms: 3 + insert_time_ms: 0 insert_new_count: 49 insert_reused_count: 4 - query: EXPLAIN select sum(col1) from T2 where col1 > 0; explain: SCAN(<,>) | TFILTER T2 | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) - task_count: 393 - task_total_time_ms: 18 - transform_count: 135 - transform_time_ms: 14 - transform_yield_count: 46 + task_count: 409 + task_total_time_ms: 32 + transform_count: 146 + transform_time_ms: 26 + transform_yield_count: 54 insert_time_ms: 0 - insert_new_count: 28 + insert_new_count: 31 insert_reused_count: 2 - query: EXPLAIN select sum(col1) from T2 where col2 > 0; - explain: SCAN(<,>) | TFILTER T2 | FILTER _.COL2 GREATER_THAN promote(@c11 AS LONG) - | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 - AS _0) - task_count: 393 - task_total_time_ms: 36 - transform_count: 135 - transform_time_ms: 29 - transform_yield_count: 46 - insert_time_ms: 1 - insert_new_count: 28 - insert_reused_count: 2 -- query: EXPLAIN select sum(col1) from T2 where col2 > 0; - explain: SCAN(<,>) | TFILTER T2 | FILTER _.COL2 GREATER_THAN promote(@c11 AS LONG) - | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 - AS _0) - task_count: 393 - task_total_time_ms: 36 - transform_count: 135 - transform_time_ms: 29 - transform_yield_count: 46 - insert_time_ms: 1 - insert_new_count: 28 - insert_reused_count: 2 + explain: 'AISCAN(T2_I6 [[GREATER_THAN promote(@c11 AS LONG)]] BY_GROUP -> [_0: + KEY:[0], _1: VALUE:[0]]) | AGG sum_l(_._1) GROUP BY () | MAP ((_._1 AS _0) + AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)' + task_count: 558 + task_total_time_ms: 20 + transform_count: 190 + transform_time_ms: 14 + transform_yield_count: 60 + insert_time_ms: 0 + insert_new_count: 52 + insert_reused_count: 4 - query: EXPLAIN select sum(col1) from T3 where col1 = 0; explain: ISCAN(T3_I1 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) task_count: 730 - task_total_time_ms: 17 - transform_count: 215 + task_total_time_ms: 23 + transform_count: 218 transform_time_ms: 5 transform_yield_count: 50 insert_time_ms: 1 @@ -868,32 +859,32 @@ agg-empty-table-tests-after-modifications: explain: ISCAN(T3_I2 [EQUALS promote(@c11 AS LONG)]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) task_count: 730 - task_total_time_ms: 36 - transform_count: 215 - transform_time_ms: 8 + task_total_time_ms: 14 + transform_count: 218 + transform_time_ms: 3 transform_yield_count: 50 - insert_time_ms: 2 + insert_time_ms: 0 insert_new_count: 103 insert_reused_count: 5 - query: EXPLAIN select sum(col1) from T3 where col1 > 0; explain: ISCAN(T3_I1 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) task_count: 757 - task_total_time_ms: 24 - transform_count: 218 - transform_time_ms: 8 + task_total_time_ms: 22 + transform_count: 221 + transform_time_ms: 5 transform_yield_count: 53 - insert_time_ms: 3 + insert_time_ms: 1 insert_new_count: 108 insert_reused_count: 5 - query: EXPLAIN select sum(col1) from T3 where col2 > 0; explain: ISCAN(T3_I2 [[GREATER_THAN promote(@c11 AS LONG)]]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) task_count: 757 - task_total_time_ms: 160 - transform_count: 218 - transform_time_ms: 96 + task_total_time_ms: 25 + transform_count: 221 + transform_time_ms: 5 transform_yield_count: 53 - insert_time_ms: 9 + insert_time_ms: 1 insert_new_count: 108 insert_reused_count: 5 diff --git a/yaml-tests/src/test/resources/aggregate-empty-table.yamsql b/yaml-tests/src/test/resources/aggregate-empty-table.yamsql index ab0c3c5044..ba7f2fa770 100644 --- a/yaml-tests/src/test/resources/aggregate-empty-table.yamsql +++ b/yaml-tests/src/test/resources/aggregate-empty-table.yamsql @@ -74,7 +74,7 @@ test_block: - result: [{0}] - - query: select count(*) from T2 where col1 > 0; - - explain: "SCAN(<,>) | TFILTER T2 | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)" + - explain: "AISCAN(T2_I2 [[GREATER_THAN promote(@c11 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | AGG sum_l(_._1) GROUP BY () | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)" - result: [{0}] - - query: select count(*) from T2 group by col1; @@ -152,7 +152,7 @@ test_block: - result: [{0}] - - query: select count(col2) from T2 where col1 > 0; - - explain: "SCAN(<,>) | TFILTER T2 | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)" + - explain: "AISCAN(T2_I4 [[GREATER_THAN promote(@c11 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | AGG sum_l(_._1) GROUP BY () | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)" - result: [{0}] - - query: select count(col2) from T2 group by col1; @@ -231,7 +231,7 @@ test_block: - result: [{!null _}] - - query: select sum(col1) from T2 where col2 > 0; - - explain: "SCAN(<,>) | TFILTER T2 | FILTER _.COL2 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)" + - explain: "AISCAN(T2_I6 [[GREATER_THAN promote(@c11 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | AGG sum_l(_._1) GROUP BY () | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)" - result: [{!null _}] - - query: select sum(col1) from T2 where col1 = 0 group by col2; @@ -415,7 +415,7 @@ test_block: - result: [{0}] - - query: select count(col2) from T2 where col1 > 0; - - explain: "SCAN(<,>) | TFILTER T2 | FILTER _.COL1 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)" + - explain: "AISCAN(T2_I4 [[GREATER_THAN promote(@c11 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | AGG sum_l(_._1) GROUP BY () | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)" - result: [{0}] # - # # TODO ([POST] count index returns 0 instead of nothing when running on a table that was cleared) @@ -497,8 +497,9 @@ test_block: - result: [{!null _}] - - query: select sum(col1) from T2 where col2 > 0; - - explain: "SCAN(<,>) | TFILTER T2 | FILTER _.COL2 GREATER_THAN promote(@c11 AS LONG) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)" - - result: [{!null _}] + - supported_version: !current_version + - explain: "AISCAN(T2_I6 [[GREATER_THAN promote(@c11 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | AGG sum_l(_._1) GROUP BY () | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)" + - result: [{!l 0}] - - query: select sum(col1) from T2 where col1 = 0 group by col2; - error: "0AF00" diff --git a/yaml-tests/src/test/resources/aggregate-index-tests-count-empty.metrics.binpb b/yaml-tests/src/test/resources/aggregate-index-tests-count-empty.metrics.binpb index 6f88e647e0033d64d787f89359c21d5d04427af1..8c4d48666788759c1b3063b0e65e761b02e3faed 100644 GIT binary patch delta 1491 zcmZpf%y?)9Bje+Vj81Y3gt??R4zmi}UwVRH;tiw1l9}zC8ukXw=bS969GE61b~66l z+#v9emEY0bJ=!nsjpA_$A zWNPG@e2~*$asxM)B*$k)fjt){aZ1D~G*6wtrlDl;wUKMGCRY&CQLf320=G85mttb# zf*BKUIQgSYFVtQmBJJH=!zaeb^j>(fpNW%#q0maG?;cOOC;;-^#_c~qzT17)4dlDY z-}pP3nuInt3jAf2fcVcCYEOJ#eo1^@X-*E&9%bp};qspxU?Mm9rM=SR8Il4LJE2~_ zxOfp8(94IeonQfadB@(#2PA`;&f)Yi)FmdQx&-WXmS^Hzc3@Zd$ScY(76%4;53|6c z&5PM2sudpJKg6gZXRz*po`t>xi%`qtjV3yicgROE{SyU-fd%tsA7wEn4OsYNMk-1a z8*lEnvSTD(^#V0z;#Gr^53jkMLQY~*YL2Z^p^5oqMgD@x>p8eLY0hF~+93i=Q}&Z@ zYYE6d7Y2Iq0;9nCSsPd++!a1=xy`5{V$j~fZz1HsB$Pe5SKfMZg@Yl}9U)K(oBUpi zb#s@aJ>%paWvR&o?7*S{3evMq(v#;qHco!Wl25v42Q2nk4vWAunvwi_X#7vwH3t;` pzptGE#sB&@eBk)c1IEAh!gRx~YBjetQj81aDgt(+QHZco4TrrPBVj82ut}C4^8d?T(cBxrtJFrYl>}0wu zIQgN|t<7r`W;&d7*OVmAdInx#H$^RXlCd*0*NWk2^`u|&2pu6Yw{$~cd`@{Rmu2R7` zoNWR#6RWe|iE-J1oz117sIXcL7%Dx?0Kk1PeFqky7RJdA zI@Xih6ucPQHeXcmXPxXQRx;UFRAur5wPl;vsVg%=T|L=>LyFhfP9Y~TDK*DdsnEoD za-eYuAdK>BwQ3uE}qP& zA!6{fnR~L8P7%`;!Oahy&f{Zn%Ar1?b6^+b2Pu+ BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)' - task_count: 434 - task_total_time_ms: 17 - transform_count: 150 - transform_time_ms: 8 - transform_yield_count: 42 - insert_time_ms: 0 - insert_new_count: 43 - insert_reused_count: 4 + task_count: 707 + task_total_time_ms: 32 + transform_count: 236 + transform_time_ms: 18 + transform_yield_count: 63 + insert_time_ms: 1 + insert_new_count: 122 + insert_reused_count: 2 - query: EXPLAIN select count(*) from t1 group by col2 explain: 'AISCAN(MV2 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0)' task_count: 243 - task_total_time_ms: 9 - transform_count: 89 - transform_time_ms: 6 + task_total_time_ms: 19 + transform_count: 94 + transform_time_ms: 12 transform_yield_count: 34 insert_time_ms: 0 insert_new_count: 12 @@ -24,21 +24,21 @@ agg-index-tests-count-empty: - query: EXPLAIN select count(col1) from t1 explain: 'AISCAN(MV3 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)' - task_count: 434 - task_total_time_ms: 18 - transform_count: 150 - transform_time_ms: 9 - transform_yield_count: 42 - insert_time_ms: 0 - insert_new_count: 43 - insert_reused_count: 4 + task_count: 707 + task_total_time_ms: 34 + transform_count: 236 + transform_time_ms: 20 + transform_yield_count: 63 + insert_time_ms: 1 + insert_new_count: 122 + insert_reused_count: 2 - query: EXPLAIN select count(col1) from t1 group by col2 explain: 'AISCAN(MV4 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0)' task_count: 243 - task_total_time_ms: 12 - transform_count: 89 - transform_time_ms: 8 + task_total_time_ms: 13 + transform_count: 94 + transform_time_ms: 9 transform_yield_count: 34 insert_time_ms: 0 insert_new_count: 12 @@ -47,8 +47,8 @@ agg-index-tests-count-empty: explain: ISCAN(MV5 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 396 - task_total_time_ms: 12 - transform_count: 120 + task_total_time_ms: 13 + transform_count: 123 transform_time_ms: 3 transform_yield_count: 30 insert_time_ms: 0 @@ -58,9 +58,9 @@ agg-index-tests-count-empty: explain: ISCAN(MV5 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) GROUP BY (_._0.COL2 AS _0) | MAP (_._1._0 AS _0) task_count: 208 - task_total_time_ms: 5 - transform_count: 68 - transform_time_ms: 2 + task_total_time_ms: 9 + transform_count: 71 + transform_time_ms: 3 transform_yield_count: 20 insert_time_ms: 0 insert_new_count: 18 @@ -69,8 +69,8 @@ agg-index-tests-count-empty: explain: ISCAN(MV5 <,>) | MAP (_ AS _0) | AGG (count(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 396 - task_total_time_ms: 12 - transform_count: 120 + task_total_time_ms: 13 + transform_count: 123 transform_time_ms: 3 transform_yield_count: 30 insert_time_ms: 0 @@ -80,8 +80,8 @@ agg-index-tests-count-empty: explain: ISCAN(MV5 <,>) | MAP (_ AS _0) | AGG (count(_._0.COL1) AS _0) GROUP BY (_._0.COL2 AS _0) | MAP (_._1._0 AS _0) task_count: 208 - task_total_time_ms: 9 - transform_count: 68 + task_total_time_ms: 8 + transform_count: 71 transform_time_ms: 3 transform_yield_count: 20 insert_time_ms: 0 diff --git a/yaml-tests/src/test/resources/aggregate-index-tests-count.metrics.binpb b/yaml-tests/src/test/resources/aggregate-index-tests-count.metrics.binpb index 4ec0b6e91a93b234054236ace97890494df9b6a1..d368273f9683888c64e0b14dcfe433014f0fbaff 100644 GIT binary patch delta 1532 zcmbO~nepBXM#j4n8Exbi2y;ns9A*``@_UAe#2ZG1`+FL=HS7&O%?`Dwa$uSm-O2P* zaB?Bnt<47*m09^6-QA;o!wjtzlJiURN@6EJ)HR>HKsH9o$KTIg!7*6D+26-dM*)dv zH2I&+*3Ehx-HeRCC-36)lH9<}CCTxbQQ&{uMNWx0g|G7`vuP+9yjsmYS(Yn^@#y9P zuDeWJFazQZC)){UPJST5I@woD9%{Q03AS%8;1gqHc`3|gJ$Wyu#NS95uQ9zM_z2=egcC;XjEO+s)VOF(>V47D>pFTW%{uQVrzB(Jly^Kf~B9S|pJ zB)JnB0v+?ZxPT$>dfgjP2t0YtHF>3E5aT&~Apmua2|2ET1jT1@F7L^KCfbu7hv}avG!){PHajSbF=@bJ1v8RSqTG0L z09(oA0@qVSYuJ3-TA7h()u0r`Yi_5IlbDp6W2;nXVm|qzM8ReQyQPdwM@1%2(29|N zE)4Y81xA6nU7J}X+!Z!ly27X-V$k=M-$KZNNho`AqrCNGH*G_vJD`ZZzd1sul99tq zFWx{8=(WiQR3=SMu;dUzcq-lil(xZ%aXwIb8u3mo6qzyko$4~;HQX2NpPXegg?J7B zY~*>3%@CnsJo%w|*JMw-y3O{+e2k3$Ci|HL$*+b+^v#F!*ntuK{O3JTME9LEwa|B9 z5o({@Ag?pI!9jTPKNByeW-)lQPj*mt;MD*IFf?ckH76fbnYcN@(w2nS8nDE`azTVE z2AtMe9E>F2Lz6_?^97(J(LUn^C`rtFD=^vLp_J(%EFsu4vS<_BSORAy!N4Ktja=s9`we0B#W#?zA@aC%8LaC1p=d}b8bdipt=M5MyIrXCgz zC4+-cxh6Yv1u;(D+$eRIX)>Q%=H&fsDnR{4VEwz~#26WOO}@)-4|hQ0tc73)Y2C^@}4YUrak$;yrRS^F)j&?9%g|HOa3xSR4BZA6R#m>u;QBdWJ`q}rZ!P% zSi~`H{;w>?G&z8+Wb%FYQ=4DeDl<-=&%Tw{*iIoQF)202R;kd$c=HBLQ6`qX!d#JH zaq4&dm)bJ&cTPlX=a8 zpcjrl+rR|$Lwk>fg}wueQ2S(i1)a&O%wn0k5x$xHU)h001L)+*@~+aG7g+6KB*tq@ zCxj>SImOFAhkELD*Kd%gK1}`v^3I779;3 BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)' - task_count: 434 - task_total_time_ms: 17 - transform_count: 150 - transform_time_ms: 8 - transform_yield_count: 42 - insert_time_ms: 0 - insert_new_count: 43 - insert_reused_count: 4 + task_count: 707 + task_total_time_ms: 42 + transform_count: 236 + transform_time_ms: 23 + transform_yield_count: 63 + insert_time_ms: 1 + insert_new_count: 122 + insert_reused_count: 2 - query: EXPLAIN select count(*) from t1 group by col2 explain: 'AISCAN(MV2 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0)' task_count: 243 - task_total_time_ms: 14 - transform_count: 89 - transform_time_ms: 8 + task_total_time_ms: 20 + transform_count: 94 + transform_time_ms: 12 transform_yield_count: 34 insert_time_ms: 0 insert_new_count: 12 @@ -24,21 +24,21 @@ agg-index-tests-count: - query: EXPLAIN select count(col1) from t1 explain: 'AISCAN(MV3 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)' - task_count: 434 - task_total_time_ms: 17 - transform_count: 150 - transform_time_ms: 8 - transform_yield_count: 42 - insert_time_ms: 0 - insert_new_count: 43 - insert_reused_count: 4 + task_count: 707 + task_total_time_ms: 42 + transform_count: 236 + transform_time_ms: 25 + transform_yield_count: 63 + insert_time_ms: 1 + insert_new_count: 122 + insert_reused_count: 2 - query: EXPLAIN select count(col1) from t1 group by col2 explain: 'AISCAN(MV4 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0)' task_count: 243 - task_total_time_ms: 16 - transform_count: 89 - transform_time_ms: 10 + task_total_time_ms: 21 + transform_count: 94 + transform_time_ms: 14 transform_yield_count: 34 insert_time_ms: 0 insert_new_count: 12 @@ -48,9 +48,9 @@ agg-index-tests-count-after-more-inserts: explain: ISCAN(MV5 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 396 - task_total_time_ms: 4 - transform_count: 120 - transform_time_ms: 1 + task_total_time_ms: 10 + transform_count: 123 + transform_time_ms: 2 transform_yield_count: 30 insert_time_ms: 0 insert_new_count: 47 @@ -59,8 +59,8 @@ agg-index-tests-count-after-more-inserts: explain: ISCAN(MV5 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) GROUP BY (_._0.COL2 AS _0) | MAP (_._1._0 AS _0) task_count: 208 - task_total_time_ms: 12 - transform_count: 68 + task_total_time_ms: 9 + transform_count: 71 transform_time_ms: 3 transform_yield_count: 20 insert_time_ms: 0 @@ -71,8 +71,8 @@ agg-index-tests-count-after-more-inserts: NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 396 task_total_time_ms: 15 - transform_count: 120 - transform_time_ms: 4 + transform_count: 123 + transform_time_ms: 3 transform_yield_count: 30 insert_time_ms: 0 insert_new_count: 47 @@ -81,9 +81,9 @@ agg-index-tests-count-after-more-inserts: explain: ISCAN(MV5 <,>) | MAP (_ AS _0) | AGG (count(_._0.COL1) AS _0) GROUP BY (_._0.COL2 AS _0) | MAP (_._1._0 AS _0) task_count: 208 - task_total_time_ms: 12 - transform_count: 68 - transform_time_ms: 4 + task_total_time_ms: 8 + transform_count: 71 + transform_time_ms: 3 transform_yield_count: 20 insert_time_ms: 0 insert_new_count: 18 diff --git a/yaml-tests/src/test/resources/aggregate-index-tests.metrics.binpb b/yaml-tests/src/test/resources/aggregate-index-tests.metrics.binpb index ef1d24a6af..7f92f14250 100644 --- a/yaml-tests/src/test/resources/aggregate-index-tests.metrics.binpb +++ b/yaml-tests/src/test/resources/aggregate-index-tests.metrics.binpb @@ -1,417 +1,414 @@ - + H -agg-index-tests5EXPLAIN select col1, sum(col2) from T1 group by col1; -  (@0-80@YAISCAN(MV1 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL1, _._1 AS _1) +agg-index-tests5EXPLAIN select col1, sum(col2) from T1 group by col1; + ޘ(@0+80@YAISCAN(MV1 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL1, _._1 AS _1) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL1, q6._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, )" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL1, q6._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS _1)" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 3 [ label=<
    Index
    AGG[MV1; sum]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} = -agg-index-tests*EXPLAIN select col1 from T1 group by col1; -ϼy (608$@ZISCAN(VI1 <,>) | MAP (_ AS _0) | AGG () GROUP BY (_._0.COL1 AS _0) | MAP (_._0._0 AS COL1)digraph G { +agg-index-tests*EXPLAIN select col1 from T1 group by col1; +| (60Ժ$8$@ZISCAN(VI1 <,>) | MAP (_ AS _0) | AGG () GROUP BY (_._0.COL1 AS _0) | MAP (_._0._0 AS COL1)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS COL1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1)" ]; - 2 [ label=<
    Streaming Aggregate
    COLLECT ()
    GROUP BY (q102._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, )" ]; - 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 4 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 5 [ label=<
    Index
    VI1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q102> label="q102" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 [ label=<
    Streaming Aggregate
    COLLECT ()
    GROUP BY (q106._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, AS _1)" ]; + 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 4 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 5 [ label=<
    Index
    VI1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 -> 2 [ label=< q106> label="q106" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} B -agg-index-tests/EXPLAIN select sum(col2) from T1 group by col1; - (@0&80@KAISCAN(MV1 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0) +agg-index-tests/EXPLAIN select sum(col2) from T1 group by col1; + (@0)80@KAISCAN(MV1 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0) digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 3 [ label=<
    Index
    AGG[MV1; sum]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} Z -agg-index-testsGEXPLAIN select col1, sum(col2) from T1 group by col1 order by col1 asc; -ހ (@0"80@YAISCAN(MV1 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL1, _._1 AS _1) +agg-index-testsGEXPLAIN select col1, sum(col2) from T1 group by col1 order by col1 asc; +¶ (@0)80@YAISCAN(MV1 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL1, _._1 AS _1) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL1, q6._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, )" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL1, q6._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS _1)" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 3 [ label=<
    Index
    AGG[MV1; sum]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} [ -agg-index-testsHEXPLAIN select col1, sum(col2) from T1 group by col1 order by col1 desc; -  ґ(@0%80@aAISCAN(MV1 <,> BY_GROUP REVERSE -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL1, _._1 AS _1) -digraph G { +agg-index-testsHEXPLAIN select col1, sum(col2) from T1 group by col1 order by col1 desc; + (@0&80@aAISCAN(MV1 <,> BY_GROUP REVERSE -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL1, _._1 AS _1) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL1, q6._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, )" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL1, q6._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS _1)" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 3 [ label=<
    Index
    AGG[MV1; sum]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} L -agg-index-tests9EXPLAIN select col1, sum(col2) + 1 from T1 group by col1; - կ(@0љ&80@]AISCAN(MV1 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL1, _._1 + 1 AS _1) +agg-index-tests9EXPLAIN select col1, sum(col2) + 1 from T1 group by col1; + է(@0*80@]AISCAN(MV1 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL1, _._1 + 1 AS _1) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL1, q6._1 + 1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, )" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL1, q6._1 + 1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS _1)" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 3 [ label=<
    Index
    AGG[MV1; sum]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} H -agg-index-tests5EXPLAIN select col1, max(col2) from T1 group by col1; -׃  ӽ(B0-80@WAISCAN(MV8 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1]]) | MAP (_._0 AS COL1, _._1 AS _1) +agg-index-tests5EXPLAIN select col1, max(col2) from T1 group by col1; + (B0.80@WAISCAN(MV8 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1]]) | MAP (_._0 AS COL1, _._1 AS _1) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL1, q6._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, )" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV8
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL1, q6._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS _1)" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 3 [ label=<
    Index
    AGG[MV8; permuted_max]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} V -agg-index-testsCEXPLAIN select col1, max(col2) from T1 group by col1 order by col1; -  (B0/80@WAISCAN(MV8 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1]]) | MAP (_._0 AS COL1, _._1 AS _1) +agg-index-testsCEXPLAIN select col1, max(col2) from T1 group by col1 order by col1; + ʂ (B0&80@WAISCAN(MV8 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1]]) | MAP (_._0 AS COL1, _._1 AS _1) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL1, q6._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, )" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV8
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL1, q6._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS _1)" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 3 [ label=<
    Index
    AGG[MV8; permuted_max]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} [ -agg-index-testsHEXPLAIN select col1, max(col2) from T1 group by col1 order by col1 desc; -Ɩ (B0ב80@_AISCAN(MV8 <,> BY_GROUP REVERSE -> [_0: KEY:[0], _1: KEY:[1]]) | MAP (_._0 AS COL1, _._1 AS _1) -digraph G { +agg-index-testsHEXPLAIN select col1, max(col2) from T1 group by col1 order by col1 desc; +  (B0(80@_AISCAN(MV8 <,> BY_GROUP REVERSE -> [_0: KEY:[0], _1: KEY:[1]]) | MAP (_._0 AS COL1, _._1 AS _1) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL1, q6._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, )" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV8
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL1, q6._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS _1)" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 3 [ label=<
    Index
    AGG[MV8; permuted_max]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} X -agg-index-testsEEXPLAIN select col1, max(col2) from T1 where col1 = 10 group by col1; - (J098L@rAISCAN(MV8 [EQUALS promote(@c13 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1]]) | MAP (_._0 AS COL1, _._1 AS _1) +agg-index-testsEEXPLAIN select col1, max(col2) from T1 where col1 = 10 group by col1; + (J0;8L@rAISCAN(MV8 [EQUALS promote(@c13 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1]]) | MAP (_._0 AS COL1, _._1 AS _1) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL1, q6._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, )" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c13 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV8
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL1, q6._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS _1)" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c13 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 3 [ label=<
    Index
    AGG[MV8; permuted_max]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} D -agg-index-tests1EXPLAIN select max(col2) from T1 use index (mv8); -ȭb χ(08@cISCAN(MV8 <,>) | MAP (_ AS _0) | AGG (max_l(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +agg-index-tests1EXPLAIN select max(col2) from T1 use index (mv8); +  (#0A83@AISCAN(MV8 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1]]) | AGG max_l(_._1) GROUP BY () | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (max_l(q90._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    MV8
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Value Computation
    MAP ((q4._1 AS _0) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Streaming Aggregate
    COLLECT max_l(q96._1)
    GROUP BY ()
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; + 5 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 6 [ label=<
    Index
    AGG[MV8; permuted_max]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q90> label="q90" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q96> label="q96" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} ? -agg-index-tests,EXPLAIN select col2 from T1 where col1 = 10; -  (F0U8J@nCOVERING(MV8 [EQUALS promote(@c8 AS LONG)] -> [COL1: KEY[0], COL2: KEY[1], ID: KEY[3]]) | MAP (_.COL2 AS COL2) +agg-index-tests,EXPLAIN select col2 from T1 where col1 = 10; +  ۃ(F0׊K8J@nCOVERING(MV8 [EQUALS promote(@c8 AS LONG)] -> [COL1: KEY[0], COL2: KEY[1], ID: KEY[3]]) | MAP (_.COL2 AS COL2) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q124.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL2)" ]; - 2 [ label=<
    Covering Index Scan
    comparisons: [EQUALS promote(@c8 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 [ label=<
    Index
    MV8
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q130.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL2)" ]; + 2 [ label=<
    Covering Index Scan
    comparisons: [EQUALS promote(@c8 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 [ label=<
    Index
    MV8
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 2 -> 1 [ label=< q124> label="q124" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} + 2 -> 1 [ label=< q130> label="q130" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +} R -agg-index-tests?EXPLAIN select col2 from T1 where col1 = 10 order by col2 desc; -ŜK Ȗ(,08 @vCOVERING(MV8 [EQUALS promote(@c8 AS LONG)] REVERSE -> [COL1: KEY[0], COL2: KEY[1], ID: KEY[3]]) | MAP (_.COL2 AS COL2) +agg-index-tests?EXPLAIN select col2 from T1 where col1 = 10 order by col2 desc; +ӪN Ž(,08 @vCOVERING(MV8 [EQUALS promote(@c8 AS LONG)] REVERSE -> [COL1: KEY[0], COL2: KEY[1], ID: KEY[3]]) | MAP (_.COL2 AS COL2) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q81.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL2)" ]; - 2 [ label=<
    Covering Index Scan
    comparisons: [EQUALS promote(@c8 AS LONG)]
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 [ label=<
    Index
    MV8
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q82.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL2)" ]; + 2 [ label=<
    Covering Index Scan
    comparisons: [EQUALS promote(@c8 AS LONG)]
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 [ label=<
    Index
    MV8
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 2 -> 1 [ label=< q81> label="q81" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} + 2 -> 1 [ label=< q82> label="q82" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +} H -agg-index-tests5EXPLAIN select min(col3) from T2 group by col1, col2; -\ (00 8@ISCAN(MV2 <,>) | MAP (_ AS _0) | AGG (min_l(_._0.COL3) AS _0) GROUP BY (_._0.COL1 AS _0, _._0.COL2 AS _1) | MAP (_._1._0 AS _0)digraph G { +agg-index-tests5EXPLAIN select min(col3) from T2 group by col1, col2; +_ (008@ISCAN(MV2 <,>) | MAP (_ AS _0) | AGG (min_l(_._0.COL3) AS _0) GROUP BY (_._0.COL1 AS _0, _._0.COL2 AS _1) | MAP (_._1._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Streaming Aggregate
    COLLECT (min_l(q84._0.COL3) AS _0)
    GROUP BY (q84._0.COL1 AS _0, q84._0.COL2 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, AS _0, )" ]; - 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 4 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 5 [ label=<
    Index
    MV2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q84> label="q84" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 [ label=<
    Streaming Aggregate
    COLLECT (min_l(q86._0.COL3) AS _0)
    GROUP BY (q86._0.COL1 AS _0, q86._0.COL2 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1 AS _0, LONG AS _0 AS _1)" ]; + 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3 AS _0)" ]; + 4 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; + 5 [ label=<
    Index
    MV2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; + 3 -> 2 [ label=< q86> label="q86" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} 4 -agg-index-tests!EXPLAIN select max(col2) from t2; - Ʀ(J0i8k@cISCAN(MV3 <,>) | MAP (_ AS _0) | AGG (max_l(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +agg-index-tests!EXPLAIN select max(col2) from t2; + Þ (W08@ +AISCAN(MV9 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | AGG max_l(_._2) GROUP BY () | MAP ((_._2 AS _0) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (max_l(q115._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    MV3
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Value Computation
    MAP ((q4._2 AS _0) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Streaming Aggregate
    COLLECT max_l(q131._2)
    GROUP BY ()
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; + 5 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1, LONG AS _2)" ]; + 6 [ label=<
    Index
    AGG[MV9; permuted_max]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q115> label="q115" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q131> label="q131" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} X -agg-index-testsEEXPLAIN select col1, sum(col2) from T1 USE INDEX (vi1) group by col1; -@ j(0 8@ISCAN(VI1 <,>) | MAP (_ AS _0) | AGG (sum_l(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._0._0 AS COL1, _._1._0 AS _1)digraph G { +agg-index-testsEEXPLAIN select col1, sum(col2) from T1 USE INDEX (vi1) group by col1; +C ȭ(08@ISCAN(VI1 <,>) | MAP (_ AS _0) | AGG (sum_l(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._0._0 AS COL1, _._1._0 AS _1)digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS COL1, q6._1._0 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, )" ]; - 2 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q90._0.COL2) AS _0)
    GROUP BY (q90._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, )" ]; - 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 4 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 5 [ label=<
    Index
    VI1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q90> label="q90" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS COL1, q6._1._0 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS _1)" ]; + 2 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q92._0.COL2) AS _0)
    GROUP BY (q92._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, LONG AS _0 AS _1)" ]; + 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 4 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 5 [ label=<
    Index
    VI1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 -> 2 [ label=< q92> label="q92" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} H -agg-index-tests5EXPLAIN select max(col2) from t2 group by col1, col3; - (D0ۍ280@VAISCAN(MV9 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._2 AS _0) +agg-index-tests5EXPLAIN select max(col2) from t2 group by col1, col3; +  ߢ(D0&80@VAISCAN(MV9 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._2 AS _0) digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV9
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1, LONG AS _2)" ]; + 3 [ label=<
    Index
    AGG[MV9; permuted_max]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} T -agg-index-testsAEXPLAIN select col1, col3, max(col2) from t2 group by col1, col3; -ɮ (D0380@rAISCAN(MV9 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._0 AS COL1, _._1 AS COL3, _._2 AS _2) -digraph G { +agg-index-testsAEXPLAIN select col1, col3, max(col2) from t2 group by col1, col3; + ͢ +(D0-80@rAISCAN(MV9 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._0 AS COL1, _._1 AS COL3, _._2 AS _2) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL1, q6._1 AS COL3, q6._2 AS _2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, )" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV9
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL1, q6._1 AS COL3, q6._2 AS _2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS COL3, LONG AS _2)" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1, LONG AS _2)" ]; + 3 [ label=<
    Index
    AGG[MV9; permuted_max]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} ] -agg-index-testsJEXPLAIN select col3, max(col2) from t2 where col1 = 2 group by col1, col3; - ԥ(L0<8L@AISCAN(MV9 [EQUALS promote(@c13 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._1 AS COL3, _._2 AS _1) -digraph G { +agg-index-testsJEXPLAIN select col3, max(col2) from t2 where col1 = 2 group by col1, col3; + (L0ΜA8L@AISCAN(MV9 [EQUALS promote(@c13 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._1 AS COL3, _._2 AS _1) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._1 AS COL3, q6._2 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL3, )" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c13 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV9
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q6._1 AS COL3, q6._2 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL3, LONG AS _1)" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c13 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1, LONG AS _2)" ]; + 3 [ label=<
    Index
    AGG[MV9; permuted_max]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} u -agg-index-testsbEXPLAIN select col3, max(col2) from t2 where col1 = 1 group by col1, col3 order by max(col2) desc; - e 뉫(40 8 @AISCAN(MV9 [EQUALS promote(@c13 AS LONG)] BY_GROUP REVERSE -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._1 AS COL3, _._2 AS _1) -digraph G { +agg-index-testsbEXPLAIN select col3, max(col2) from t2 where col1 = 1 group by col1, col3 order by max(col2) desc; +j +(40 8 @AISCAN(MV9 [EQUALS promote(@c13 AS LONG)] BY_GROUP REVERSE -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._1 AS COL3, _._2 AS _1) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._1 AS COL3, q6._2 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL3, )" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c13 AS LONG)]
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV9
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q6._1 AS COL3, q6._2 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL3, LONG AS _1)" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c13 AS LONG)]
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1, LONG AS _2)" ]; + 3 [ label=<
    Index
    AGG[MV9; permuted_max]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +}  -agg-index-testswEXPLAIN select col3, max(col2) from t2 where col1 = 1 group by col1, col3 having max(col2) < 2 order by max(col2) desc; - -f ˰(40ի 8 @AISCAN(MV9 [EQUALS promote(@c13 AS LONG), [LESS_THAN promote(@c25 AS LONG)]] BY_GROUP REVERSE -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._1 AS COL3, _._2 AS _1) digraph G { +agg-index-testswEXPLAIN select col3, max(col2) from t2 where col1 = 1 group by col1, col3 having max(col2) < 2 order by max(col2) desc; +ǹ k ؉ (40ڳ +8 @AISCAN(MV9 [EQUALS promote(@c13 AS LONG), [LESS_THAN promote(@c25 AS LONG)]] BY_GROUP REVERSE -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._1 AS COL3, _._2 AS _1) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._1 AS COL3, q6._2 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL3, )" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c13 AS LONG), [LESS_THAN promote(@c25 AS LONG)]]
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV9
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q6._1 AS COL3, q6._2 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL3, LONG AS _1)" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c13 AS LONG), [LESS_THAN promote(@c25 AS LONG)]]
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1, LONG AS _2)" ]; + 3 [ label=<
    Index
    AGG[MV9; permuted_max]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +}  -agg-index-testsEXPLAIN select col3, max(col2) from t2 where col1 = 1 group by col1, col3 having max(col2) < 2 and max(col2) >= 1 order by max(col2) desc; - f Ȧ(40 8 @AISCAN(MV9 [EQUALS promote(@c13 AS LONG), [GREATER_THAN_OR_EQUALS promote(@c13 AS LONG) && LESS_THAN promote(@c25 AS LONG)]] BY_GROUP REVERSE -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._1 AS COL3, _._2 AS _1) digraph G { +agg-index-testsEXPLAIN select col3, max(col2) from t2 where col1 = 1 group by col1, col3 having max(col2) < 2 and max(col2) >= 1 order by max(col2) desc; +k +(40 8 @AISCAN(MV9 [EQUALS promote(@c13 AS LONG), [GREATER_THAN_OR_EQUALS promote(@c13 AS LONG) && LESS_THAN promote(@c25 AS LONG)]] BY_GROUP REVERSE -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._1 AS COL3, _._2 AS _1) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._1 AS COL3, q6._2 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL3, )" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c13 AS LONG), [GREATER_THAN_OR_EQUALS promote(@c13 AS LONG) && LESS_THAN promote(@c25 AS LONG)]]
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV9
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q6._1 AS COL3, q6._2 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL3, LONG AS _1)" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c13 AS LONG), [GREATER_THAN_OR_EQUALS promote(@c13 AS LONG) && LESS_THAN promote(@c25 AS LONG)]]
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1, LONG AS _2)" ]; + 3 [ label=<
    Index
    AGG[MV9; permuted_max]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +}  -agg-index-testsEXPLAIN select t.* from (select col3, max(col2) as m from t2 where col1 = 1 group by col1, col3) as t where m < 2 order by m desc; -׵ p (40 -8@AISCAN(MV9 [EQUALS promote(@c21 AS LONG)] BY_GROUP REVERSE -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._1 AS COL3, _._2 AS M) | FILTER _.M LESS_THAN promote(@c33 AS LONG)digraph G { +agg-index-testsEXPLAIN select t.* from (select col3, max(col2) as m from t2 where col1 = 1 group by col1, col3) as t where m < 2 order by m desc; +u Ը (40 8@AISCAN(MV9 [EQUALS promote(@c21 AS LONG)] BY_GROUP REVERSE -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._1 AS COL3, _._2 AS M) | FILTER _.M LESS_THAN promote(@c33 AS LONG)digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Predicate Filter
    WHERE q8.M LESS_THAN promote(@c33 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL3, )" ]; - 2 [ label=<
    Value Computation
    MAP (q6._1 AS COL3, q6._2 AS M)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL3, )" ]; - 3 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c21 AS LONG)]
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 4 [ label=<
    Index
    MV9
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Predicate Filter
    WHERE q8.M LESS_THAN promote(@c33 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL3, LONG AS M)" ]; + 2 [ label=<
    Value Computation
    MAP (q6._1 AS COL3, q6._2 AS M)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL3, LONG AS M)" ]; + 3 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c21 AS LONG)]
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1, LONG AS _2)" ]; + 4 [ label=<
    Index
    AGG[MV9; permuted_max]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +}  -agg-index-testszEXPLAIN select col3, m from (select col3, max(col2) as m from t2 where col1 = 1 group by col1, col3) as t order by m desc; - p ܟ(40 -8@AISCAN(MV9 [EQUALS promote(@c21 AS LONG)] BY_GROUP REVERSE -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._1 AS COL3, _._2 AS M) | MAP (_.COL3 AS COL3, _.M AS M)digraph G { +agg-index-testszEXPLAIN select col3, m from (select col3, max(col2) as m from t2 where col1 = 1 group by col1, col3) as t order by m desc; +u ž +(40 +8@AISCAN(MV9 [EQUALS promote(@c21 AS LONG)] BY_GROUP REVERSE -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._1 AS COL3, _._2 AS M) | MAP (_.COL3 AS COL3, _.M AS M)digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q8.COL3 AS COL3, q8.M AS M)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL3, )" ]; - 2 [ label=<
    Value Computation
    MAP (q6._1 AS COL3, q6._2 AS M)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL3, )" ]; - 3 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c21 AS LONG)]
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 4 [ label=<
    Index
    MV9
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q8.COL3 AS COL3, q8.M AS M)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL3, LONG AS M)" ]; + 2 [ label=<
    Value Computation
    MAP (q6._1 AS COL3, q6._2 AS M)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL3, LONG AS M)" ]; + 3 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c21 AS LONG)]
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1, LONG AS _2)" ]; + 4 [ label=<
    Index
    AGG[MV9; permuted_max]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} V -agg-index-testsCEXPLAIN select col3, col2 from t2 where col1 = 1 order by col3 asc; -ѧ` ׈(20 8@COVERING(MV9 [EQUALS promote(@c10 AS LONG)] -> [COL1: KEY[0], COL2: KEY[2], COL3: KEY[1], ID: KEY[4]]) | MAP (_.COL3 AS COL3, _.COL2 AS COL2) +agg-index-testsCEXPLAIN select col3, col2 from t2 where col1 = 1 order by col3 asc; + c (208@COVERING(MV9 [EQUALS promote(@c10 AS LONG)] -> [COL1: KEY[0], COL2: KEY[2], COL3: KEY[1], ID: KEY[4]]) | MAP (_.COL3 AS COL3, _.COL2 AS COL2) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q81.COL3 AS COL3, q81.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL3, )" ]; - 2 [ label=<
    Covering Index Scan
    comparisons: [EQUALS promote(@c10 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 [ label=<
    Index
    MV9
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q83.COL3 AS COL3, q83.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL3, LONG AS COL2)" ]; + 2 [ label=<
    Covering Index Scan
    comparisons: [EQUALS promote(@c10 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; + 3 [ label=<
    Index
    MV9
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 2 -> 1 [ label=< q81> label="q81" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} + 2 -> 1 [ label=< q83> label="q83" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +} W -agg-index-testsDEXPLAIN select col3, col2 from t2 where col1 = 1 order by col3 desc; -` (208@COVERING(MV9 [EQUALS promote(@c10 AS LONG)] REVERSE -> [COL1: KEY[0], COL2: KEY[2], COL3: KEY[1], ID: KEY[4]]) | MAP (_.COL3 AS COL3, _.COL2 AS COL2) -digraph G { +agg-index-testsDEXPLAIN select col3, col2 from t2 where col1 = 1 order by col3 desc; +c (208@COVERING(MV9 [EQUALS promote(@c10 AS LONG)] REVERSE -> [COL1: KEY[0], COL2: KEY[2], COL3: KEY[1], ID: KEY[4]]) | MAP (_.COL3 AS COL3, _.COL2 AS COL2) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q81.COL3 AS COL3, q81.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL3, )" ]; - 2 [ label=<
    Covering Index Scan
    comparisons: [EQUALS promote(@c10 AS LONG)]
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 [ label=<
    Index
    MV9
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q83.COL3 AS COL3, q83.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL3, LONG AS COL2)" ]; + 2 [ label=<
    Covering Index Scan
    comparisons: [EQUALS promote(@c10 AS LONG)]
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; + 3 [ label=<
    Index
    MV9
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 2 -> 1 [ label=< q81> label="q81" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} + 2 -> 1 [ label=< q83> label="q83" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}  -agg-index-testsqEXPLAIN select col3, sum(col2) as s from t2 use index (mv9) where col1 = 1 group by col1, col3 order by col3 asc; -? (08@ISCAN(MV9 [EQUALS promote(@c20 AS LONG)]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0, _._0.COL3 AS _1) | MAP (_._0._1 AS COL3, _._1._0 AS S)digraph G { +agg-index-testsqEXPLAIN select col3, sum(col2) as s from t2 use index (mv9) where col1 = 1 group by col1, col3 order by col3 asc; +ͷB (08@ISCAN(MV9 [EQUALS promote(@c20 AS LONG)]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0, _._0.COL3 AS _1) | MAP (_._0._1 AS COL3, _._1._0 AS S)digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._0._1 AS COL3, q6._1._0 AS S)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL3, )" ]; - 2 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q80._0.COL2) AS _0)
    GROUP BY (q80._0.COL1 AS _0, q80._0.COL3 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, AS _0, )" ]; - 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 4 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c20 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 5 [ label=<
    Index
    MV9
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q80> label="q80" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 1 [ label=<
    Value Computation
    MAP (q6._0._1 AS COL3, q6._1._0 AS S)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL3, LONG AS S)" ]; + 2 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q81._0.COL2) AS _0)
    GROUP BY (q81._0.COL1 AS _0, q81._0.COL3 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1 AS _0, LONG AS _0 AS _1)" ]; + 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3 AS _0)" ]; + 4 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c20 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; + 5 [ label=<
    Index
    MV9
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; + 3 -> 2 [ label=< q81> label="q81" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +}  -agg-index-testsrEXPLAIN select col3, sum(col2) as s from t2 use index (mv9) where col1 = 1 group by col1, col3 order by col3 desc; -? ͏(0 8@ISCAN(MV9 [EQUALS promote(@c20 AS LONG)] REVERSE) | MAP (_ AS _0) | AGG (sum_l(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0, _._0.COL3 AS _1) | MAP (_._0._1 AS COL3, _._1._0 AS S)digraph G { +agg-index-testsrEXPLAIN select col3, sum(col2) as s from t2 use index (mv9) where col1 = 1 group by col1, col3 order by col3 desc; +B (0ْ8@ISCAN(MV9 [EQUALS promote(@c20 AS LONG)] REVERSE) | MAP (_ AS _0) | AGG (sum_l(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0, _._0.COL3 AS _1) | MAP (_._0._1 AS COL3, _._1._0 AS S)digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._0._1 AS COL3, q6._1._0 AS S)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL3, )" ]; - 2 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q80._0.COL2) AS _0)
    GROUP BY (q80._0.COL1 AS _0, q80._0.COL3 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, AS _0, )" ]; - 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 4 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c20 AS LONG)]
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 5 [ label=<
    Index
    MV9
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q80> label="q80" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 1 [ label=<
    Value Computation
    MAP (q6._0._1 AS COL3, q6._1._0 AS S)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL3, LONG AS S)" ]; + 2 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q81._0.COL2) AS _0)
    GROUP BY (q81._0.COL1 AS _0, q81._0.COL3 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1 AS _0, LONG AS _0 AS _1)" ]; + 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3 AS _0)" ]; + 4 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c20 AS LONG)]
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; + 5 [ label=<
    Index
    MV9
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; + 3 -> 2 [ label=< q81> label="q81" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} H -agg-index-tests5EXPLAIN select max(col3) from t2 group by col1, col3; - -x ힾ(80#8$@ISCAN(MV3 <,>) | MAP (_ AS _0) | AGG (max_l(_._0.COL3) AS _0) GROUP BY (_._0.COL1 AS _0, _._0.COL3 AS _1) | MAP (_._1._0 AS _0)digraph G { +agg-index-tests5EXPLAIN select max(col3) from t2 group by col1, col3; +߰ { (80!8$@ISCAN(MV3 <,>) | MAP (_ AS _0) | AGG (max_l(_._0.COL3) AS _0) GROUP BY (_._0.COL1 AS _0, _._0.COL3 AS _1) | MAP (_._1._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Streaming Aggregate
    COLLECT (max_l(q94._0.COL3) AS _0)
    GROUP BY (q94._0.COL1 AS _0, q94._0.COL3 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, AS _0, )" ]; - 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 4 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 5 [ label=<
    Index
    MV3
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q94> label="q94" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 [ label=<
    Streaming Aggregate
    COLLECT (max_l(q98._0.COL3) AS _0)
    GROUP BY (q98._0.COL1 AS _0, q98._0.COL3 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1 AS _0, LONG AS _0 AS _1)" ]; + 3 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3 AS _0)" ]; + 4 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; + 5 [ label=<
    Index
    MV3
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; + 3 -> 2 [ label=< q98> label="q98" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} 8 -agg-index-tests%EXPLAIN select min_ever(col3) from t2 -  IJ(G0Z8F@ -aAISCAN(MV7 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +agg-index-tests%EXPLAIN select min_ever(col3) from t2 +  Ը(G0D8F@ +aAISCAN(MV7 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; @@ -419,179 +416,180 @@ H 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Value Computation
    MAP (q4 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 4 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 5 [ label=<
    Index
    MV7
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 5 [ label=<
    Index
    AGG[MV7; min_ever_tuple]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} M -agg-index-tests:EXPLAIN select col1, max_ever(col2) from T1 group by col1; -܊ (F082@YAISCAN(MV6 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL1, _._1 AS _1) +agg-index-tests:EXPLAIN select col1, max_ever(col2) from T1 group by col1; + (F0$82@YAISCAN(MV6 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL1, _._1 AS _1) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL1, q6._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, )" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV6
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL1, q6._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS _1)" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 3 [ label=<
    Index
    AGG[MV6; max_ever_tuple]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} M -agg-index-tests:EXPLAIN select col1, min_ever(col2) from T1 group by col1; - ޛ(<08&@ZAISCAN(MV12 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL1, _._1 AS _1) +agg-index-tests:EXPLAIN select col1, min_ever(col2) from T1 group by col1; +Ă  (<0 8&@ZAISCAN(MV12 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL1, _._1 AS _1) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL1, q6._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, )" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV12
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL1, q6._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS _1)" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 3 [ label=<
    Index
    AGG[MV12; min_ever_long]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} M -agg-index-tests:EXPLAIN select col2, max_ever(col1) from T4 group by col2; -P 藏(0Ç8 @ZAISCAN(MV15 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL2, _._1 AS _1) +agg-index-tests:EXPLAIN select col2, max_ever(col1) from T4 group by col2; +U ǯ(0 8 @ZAISCAN(MV15 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL2, _._1 AS _1) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL2, q6._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL2, )" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV15
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL2, q6._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL2, STRING AS _1)" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, STRING AS _1)" ]; + 3 [ label=<
    Index
    AGG[MV15; max_ever_tuple]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} M -agg-index-tests:EXPLAIN select col2, min_ever(col1) from T4 group by col2; -٦P (08 @ZAISCAN(MV14 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL2, _._1 AS _1) +agg-index-tests:EXPLAIN select col2, min_ever(col1) from T4 group by col2; +U (0 +8 @ZAISCAN(MV14 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL2, _._1 AS _1) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL2, q6._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL2, )" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV14
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL2, q6._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL2, STRING AS _1)" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, STRING AS _1)" ]; + 3 [ label=<
    Index
    AGG[MV14; min_ever_tuple]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} X -agg-index-testsEEXPLAIN select col1, sum(col2) from T1 where col1 > 15 group by col1; - (H068L@|AISCAN(MV1 [[GREATER_THAN promote(@c13 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL1, _._1 AS _1) +agg-index-testsEEXPLAIN select col1, sum(col2) from T1 where col1 > 15 group by col1; + ٖ(H038L@|AISCAN(MV1 [[GREATER_THAN promote(@c13 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL1, _._1 AS _1) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL1, q6._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, )" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [[GREATER_THAN promote(@c13 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q6._0 AS COL1, q6._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS _1)" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [[GREATER_THAN promote(@c13 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 3 [ label=<
    Index
    AGG[MV1; sum]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} R -agg-index-tests?EXPLAIN select sum(col2) from T1 where col1 = 10 group by col1 - ڬ(H098L@fAISCAN(MV1 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0) +agg-index-tests?EXPLAIN select sum(col2) from T1 where col1 = 10 group by col1 + +(H0ߓ98L@fAISCAN(MV1 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0) digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c11 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 3 [ label=<
    Index
    AGG[MV1; sum]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} c -agg-index-testsPEXPLAIN select sum(col2) from T1 where col1 <= 10 group by col1 having col1 > 0; -ɫ Є(H098N@AISCAN(MV1 [[GREATER_THAN promote(@c19 AS LONG) && LESS_THAN_OR_EQUALS promote(@c12 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0) -digraph G { +agg-index-testsPEXPLAIN select sum(col2) from T1 where col1 <= 10 group by col1 having col1 > 0; + (H0;8N@AISCAN(MV1 [[GREATER_THAN promote(@c19 AS LONG) && LESS_THAN_OR_EQUALS promote(@c12 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0) digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [[GREATER_THAN promote(@c19 AS LONG) && LESS_THAN_OR_EQUALS promote(@c12 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [[GREATER_THAN promote(@c19 AS LONG) && LESS_THAN_OR_EQUALS promote(@c12 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 3 [ label=<
    Index
    AGG[MV1; sum]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} O -agg-index-tests BY_GROUP -> [_0: KEY:[0], _1: KEY:[1]]) | MAP (_._1 AS X1, _._0 AS X2) +agg-index-tests BY_GROUP -> [_0: KEY:[0], _1: KEY:[1]]) | MAP (_._1 AS X1, _._0 AS X2) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._1 AS X1, q6._0 AS X2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS X1, )" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV10
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q6._1 AS X1, q6._0 AS X2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS X1, LONG AS X2)" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 3 [ label=<
    Index
    AGG[MV10; permuted_max]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS A, LONG AS B)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} O -agg-index-tests BY_GROUP -> [_0: KEY:[0], _1: KEY:[1]]) | MAP (_._0 AS X1, _._1 AS X2) +agg-index-tests BY_GROUP -> [_0: KEY:[0], _1: KEY:[1]]) | MAP (_._0 AS X1, _._1 AS X2) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._0 AS X1, q6._1 AS X2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS X1, )" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV10
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q6._0 AS X1, q6._1 AS X2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS X1, LONG AS X2)" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 3 [ label=<
    Index
    AGG[MV10; permuted_max]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS A, LONG AS B)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} U -agg-index-testsBEXPLAIN select a+b as x1, min(b) as x2 from t3 group by a+b, b+10; -q (+08@cAISCAN(MV11 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: KEY:[2]]) | MAP (_._0 AS X1, _._2 AS X2) +agg-index-testsBEXPLAIN select a+b as x1, min(b) as x2 from t3 group by a+b, b+10; +璶v (+08@cAISCAN(MV11 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: KEY:[2]]) | MAP (_._0 AS X1, _._2 AS X2) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._0 AS X1, q6._2 AS X2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS X1, )" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV11
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q6._0 AS X1, q6._2 AS X2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS X1, LONG AS X2)" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1, LONG AS _2)" ]; + 3 [ label=<
    Index
    AGG[MV11; permuted_min]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS A, LONG AS B)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} X -agg-index-testsEEXPLAIN select M as x1, min(b) as x2 from t3 group by a+b as M, b+10; - q ڈ(+08@cAISCAN(MV11 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: KEY:[2]]) | MAP (_._0 AS X1, _._2 AS X2) +agg-index-testsEEXPLAIN select M as x1, min(b) as x2 from t3 group by a+b as M, b+10; +ۀv (+08@cAISCAN(MV11 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: KEY:[2]]) | MAP (_._0 AS X1, _._2 AS X2) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._0 AS X1, q6._2 AS X2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS X1, )" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV11
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q6._0 AS X1, q6._2 AS X2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS X1, LONG AS X2)" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1, LONG AS _2)" ]; + 3 [ label=<
    Index
    AGG[MV11; permuted_min]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS A, LONG AS B)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} ] -agg-index-testsJEXPLAIN select M as x1, min(b) as x2 from t3 group by a+b as M, b+10 as N; -ο q (+08@cAISCAN(MV11 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: KEY:[2]]) | MAP (_._0 AS X1, _._2 AS X2) +agg-index-testsJEXPLAIN select M as x1, min(b) as x2 from t3 group by a+b as M, b+10 as N; +ϣ v (+08@cAISCAN(MV11 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: KEY:[2]]) | MAP (_._0 AS X1, _._2 AS X2) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._0 AS X1, q6._2 AS X2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS X1, )" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV11
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q6._0 AS X1, q6._2 AS X2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS X1, LONG AS X2)" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1, LONG AS _2)" ]; + 3 [ label=<
    Index
    AGG[MV11; permuted_min]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS A, LONG AS B)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} c -agg-index-testsPEXPLAIN select max(b) as x1, a+3 as x2 from t3 where a + 3 < 10000 group by a+3; -它 - ̼(.08!@vAISCAN(MV10 [[LESS_THAN promote(@c21 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1]]) | MAP (_._1 AS X1, _._0 AS X2) +agg-index-testsPEXPLAIN select max(b) as x1, a+3 as x2 from t3 where a + 3 < 10000 group by a+3; +  (.08!@vAISCAN(MV10 [[LESS_THAN promote(@c21 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1]]) | MAP (_._1 AS X1, _._0 AS X2) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._1 AS X1, q6._0 AS X2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS X1, )" ]; - 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [[LESS_THAN promote(@c21 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 3 [ label=<
    Index
    MV10
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q6._1 AS X1, q6._0 AS X2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS X1, LONG AS X2)" ]; + 2 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [[LESS_THAN promote(@c21 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1)" ]; + 3 [ label=<
    Index
    AGG[MV10; permuted_max]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS A, LONG AS B)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; } \ No newline at end of file diff --git a/yaml-tests/src/test/resources/aggregate-index-tests.metrics.yaml b/yaml-tests/src/test/resources/aggregate-index-tests.metrics.yaml index d774d2122a..991707487f 100644 --- a/yaml-tests/src/test/resources/aggregate-index-tests.metrics.yaml +++ b/yaml-tests/src/test/resources/aggregate-index-tests.metrics.yaml @@ -3,9 +3,9 @@ agg-index-tests: explain: 'AISCAN(MV1 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL1, _._1 AS _1)' task_count: 461 - task_total_time_ms: 27 - transform_count: 155 - transform_time_ms: 15 + task_total_time_ms: 29 + transform_count: 160 + transform_time_ms: 17 transform_yield_count: 64 insert_time_ms: 0 insert_new_count: 48 @@ -14,9 +14,9 @@ agg-index-tests: explain: ISCAN(VI1 <,>) | MAP (_ AS _0) | AGG () GROUP BY (_._0.COL1 AS _0) | MAP (_._0._0 AS COL1) task_count: 363 - task_total_time_ms: 11 - transform_count: 121 - transform_time_ms: 6 + task_total_time_ms: 17 + transform_count: 124 + transform_time_ms: 8 transform_yield_count: 54 insert_time_ms: 0 insert_new_count: 36 @@ -25,9 +25,9 @@ agg-index-tests: explain: 'AISCAN(MV1 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0)' task_count: 461 - task_total_time_ms: 18 - transform_count: 154 - transform_time_ms: 10 + task_total_time_ms: 30 + transform_count: 159 + transform_time_ms: 16 transform_yield_count: 64 insert_time_ms: 0 insert_new_count: 48 @@ -36,9 +36,9 @@ agg-index-tests: explain: 'AISCAN(MV1 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL1, _._1 AS _1)' task_count: 461 - task_total_time_ms: 17 - transform_count: 155 - transform_time_ms: 9 + task_total_time_ms: 34 + transform_count: 160 + transform_time_ms: 18 transform_yield_count: 64 insert_time_ms: 0 insert_new_count: 48 @@ -47,9 +47,9 @@ agg-index-tests: explain: 'AISCAN(MV1 <,> BY_GROUP REVERSE -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL1, _._1 AS _1)' task_count: 461 - task_total_time_ms: 27 - transform_count: 155 - transform_time_ms: 17 + task_total_time_ms: 30 + transform_count: 160 + transform_time_ms: 19 transform_yield_count: 64 insert_time_ms: 0 insert_new_count: 48 @@ -58,9 +58,9 @@ agg-index-tests: explain: 'AISCAN(MV1 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL1, _._1 + 1 AS _1)' task_count: 461 - task_total_time_ms: 18 - transform_count: 155 - transform_time_ms: 9 + task_total_time_ms: 30 + transform_count: 160 + transform_time_ms: 17 transform_yield_count: 64 insert_time_ms: 0 insert_new_count: 48 @@ -69,9 +69,9 @@ agg-index-tests: explain: 'AISCAN(MV8 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1]]) | MAP (_._0 AS COL1, _._1 AS _1)' task_count: 481 - task_total_time_ms: 25 - transform_count: 159 - transform_time_ms: 12 + task_total_time_ms: 29 + transform_count: 164 + transform_time_ms: 15 transform_yield_count: 66 insert_time_ms: 0 insert_new_count: 48 @@ -80,9 +80,9 @@ agg-index-tests: explain: 'AISCAN(MV8 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1]]) | MAP (_._0 AS COL1, _._1 AS _1)' task_count: 481 - task_total_time_ms: 26 - transform_count: 159 - transform_time_ms: 13 + task_total_time_ms: 31 + transform_count: 164 + transform_time_ms: 18 transform_yield_count: 66 insert_time_ms: 0 insert_new_count: 48 @@ -91,9 +91,9 @@ agg-index-tests: explain: 'AISCAN(MV8 <,> BY_GROUP REVERSE -> [_0: KEY:[0], _1: KEY:[1]]) | MAP (_._0 AS COL1, _._1 AS _1)' task_count: 481 - task_total_time_ms: 9 - transform_count: 159 - transform_time_ms: 5 + task_total_time_ms: 25 + transform_count: 164 + transform_time_ms: 13 transform_yield_count: 66 insert_time_ms: 0 insert_new_count: 48 @@ -102,31 +102,31 @@ agg-index-tests: explain: 'AISCAN(MV8 [EQUALS promote(@c13 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1]]) | MAP (_._0 AS COL1, _._1 AS _1)' task_count: 675 - task_total_time_ms: 37 - transform_count: 209 - transform_time_ms: 17 + task_total_time_ms: 40 + transform_count: 214 + transform_time_ms: 18 transform_yield_count: 74 insert_time_ms: 0 insert_new_count: 76 insert_reused_count: 2 - query: EXPLAIN select max(col2) from T1 use index (mv8); - explain: ISCAN(MV8 <,>) | MAP (_ AS _0) | AGG (max_l(_._0.COL2) AS _0) | ON EMPTY - NULL | MAP (_._0._0 AS _0) - task_count: 285 - task_total_time_ms: 11 - transform_count: 98 - transform_time_ms: 4 - transform_yield_count: 21 - insert_time_ms: 0 - insert_new_count: 27 - insert_reused_count: 3 + explain: 'AISCAN(MV8 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1]]) | AGG max_l(_._1) + GROUP BY () | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)' + task_count: 450 + task_total_time_ms: 27 + transform_count: 156 + transform_time_ms: 14 + transform_yield_count: 35 + insert_time_ms: 1 + insert_new_count: 51 + insert_reused_count: 5 - query: EXPLAIN select col2 from T1 where col1 = 10; explain: 'COVERING(MV8 [EQUALS promote(@c8 AS LONG)] -> [COL1: KEY[0], COL2: KEY[1], ID: KEY[3]]) | MAP (_.COL2 AS COL2)' task_count: 708 - task_total_time_ms: 29 - transform_count: 200 - transform_time_ms: 9 + task_total_time_ms: 25 + transform_count: 203 + transform_time_ms: 8 transform_yield_count: 70 insert_time_ms: 1 insert_new_count: 74 @@ -135,9 +135,9 @@ agg-index-tests: explain: 'COVERING(MV8 [EQUALS promote(@c8 AS LONG)] REVERSE -> [COL1: KEY[0], COL2: KEY[1], ID: KEY[3]]) | MAP (_.COL2 AS COL2)' task_count: 220 - task_total_time_ms: 9 - transform_count: 75 - transform_time_ms: 6 + task_total_time_ms: 11 + transform_count: 78 + transform_time_ms: 5 transform_yield_count: 44 insert_time_ms: 0 insert_new_count: 13 @@ -146,31 +146,32 @@ agg-index-tests: explain: ISCAN(MV2 <,>) | MAP (_ AS _0) | AGG (min_l(_._0.COL3) AS _0) GROUP BY (_._0.COL1 AS _0, _._0.COL2 AS _1) | MAP (_._1._0 AS _0) task_count: 264 - task_total_time_ms: 11 - transform_count: 92 - transform_time_ms: 6 + task_total_time_ms: 15 + transform_count: 95 + transform_time_ms: 9 transform_yield_count: 48 insert_time_ms: 0 insert_new_count: 18 insert_reused_count: 2 - query: EXPLAIN select max(col2) from t2; - explain: ISCAN(MV3 <,>) | MAP (_ AS _0) | AGG (max_l(_._0.COL2) AS _0) | ON EMPTY - NULL | MAP (_._0._0 AS _0) - task_count: 654 - task_total_time_ms: 29 - transform_count: 198 - transform_time_ms: 14 - transform_yield_count: 74 - insert_time_ms: 1 - insert_new_count: 107 - insert_reused_count: 8 + explain: 'AISCAN(MV9 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) + | AGG max_l(_._2) GROUP BY () | MAP ((_._2 AS _0) AS _0) | ON EMPTY NULL | + MAP (_._0._0 AS _0)' + task_count: 799 + task_total_time_ms: 44 + transform_count: 254 + transform_time_ms: 23 + transform_yield_count: 87 + insert_time_ms: 2 + insert_new_count: 142 + insert_reused_count: 10 - query: EXPLAIN select col1, sum(col2) from T1 USE INDEX (vi1) group by col1; explain: ISCAN(VI1 <,>) | MAP (_ AS _0) | AGG (sum_l(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._0._0 AS COL1, _._1._0 AS _1) task_count: 196 - task_total_time_ms: 4 - transform_count: 64 - transform_time_ms: 1 + task_total_time_ms: 8 + transform_count: 67 + transform_time_ms: 2 transform_yield_count: 14 insert_time_ms: 0 insert_new_count: 18 @@ -179,9 +180,9 @@ agg-index-tests: explain: 'AISCAN(MV9 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._2 AS _0)' task_count: 485 - task_total_time_ms: 29 - transform_count: 157 - transform_time_ms: 15 + task_total_time_ms: 28 + transform_count: 162 + transform_time_ms: 16 transform_yield_count: 68 insert_time_ms: 0 insert_new_count: 48 @@ -190,9 +191,9 @@ agg-index-tests: explain: 'AISCAN(MV9 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._0 AS COL1, _._1 AS COL3, _._2 AS _2)' task_count: 485 - task_total_time_ms: 32 - transform_count: 159 - transform_time_ms: 17 + task_total_time_ms: 36 + transform_count: 164 + transform_time_ms: 22 transform_yield_count: 68 insert_time_ms: 0 insert_new_count: 48 @@ -201,11 +202,11 @@ agg-index-tests: explain: 'AISCAN(MV9 [EQUALS promote(@c13 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._1 AS COL3, _._2 AS _1)' task_count: 679 - task_total_time_ms: 43 - transform_count: 209 - transform_time_ms: 17 + task_total_time_ms: 52 + transform_count: 214 + transform_time_ms: 24 transform_yield_count: 76 - insert_time_ms: 0 + insert_time_ms: 1 insert_new_count: 76 insert_reused_count: 2 - query: EXPLAIN select col3, max(col2) from t2 where col1 = 1 group by col1, col3 @@ -213,9 +214,9 @@ agg-index-tests: explain: 'AISCAN(MV9 [EQUALS promote(@c13 AS LONG)] BY_GROUP REVERSE -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._1 AS COL3, _._2 AS _1)' task_count: 279 - task_total_time_ms: 26 - transform_count: 101 - transform_time_ms: 15 + task_total_time_ms: 31 + transform_count: 106 + transform_time_ms: 22 transform_yield_count: 52 insert_time_ms: 0 insert_new_count: 12 @@ -225,9 +226,9 @@ agg-index-tests: explain: 'AISCAN(MV9 [EQUALS promote(@c13 AS LONG)] BY_GROUP REVERSE -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._1 AS COL3, _._2 AS _1)' task_count: 279 - task_total_time_ms: 26 - transform_count: 101 - transform_time_ms: 15 + task_total_time_ms: 31 + transform_count: 106 + transform_time_ms: 22 transform_yield_count: 52 insert_time_ms: 0 insert_new_count: 12 @@ -238,9 +239,9 @@ agg-index-tests: LONG)]] BY_GROUP REVERSE -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._1 AS COL3, _._2 AS _1)' task_count: 290 - task_total_time_ms: 21 - transform_count: 102 - transform_time_ms: 13 + task_total_time_ms: 26 + transform_count: 107 + transform_time_ms: 19 transform_yield_count: 52 insert_time_ms: 0 insert_new_count: 13 @@ -251,9 +252,9 @@ agg-index-tests: AS LONG) && LESS_THAN promote(@c25 AS LONG)]] BY_GROUP REVERSE -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | MAP (_._1 AS COL3, _._2 AS _1)' task_count: 290 - task_total_time_ms: 23 - transform_count: 102 - transform_time_ms: 15 + task_total_time_ms: 31 + transform_count: 107 + transform_time_ms: 22 transform_yield_count: 52 insert_time_ms: 0 insert_new_count: 13 @@ -264,9 +265,9 @@ agg-index-tests: _1: KEY:[2], _2: KEY:[1]]) | MAP (_._1 AS COL3, _._2 AS M) | FILTER _.M LESS_THAN promote(@c33 AS LONG)' task_count: 301 - task_total_time_ms: 28 - transform_count: 112 - transform_time_ms: 15 + task_total_time_ms: 34 + transform_count: 117 + transform_time_ms: 23 transform_yield_count: 52 insert_time_ms: 0 insert_new_count: 16 @@ -277,9 +278,9 @@ agg-index-tests: _1: KEY:[2], _2: KEY:[1]]) | MAP (_._1 AS COL3, _._2 AS M) | MAP (_.COL3 AS COL3, _.M AS M)' task_count: 301 - task_total_time_ms: 29 - transform_count: 112 - transform_time_ms: 16 + task_total_time_ms: 35 + transform_count: 117 + transform_time_ms: 21 transform_yield_count: 52 insert_time_ms: 0 insert_new_count: 16 @@ -288,9 +289,9 @@ agg-index-tests: explain: 'COVERING(MV9 [EQUALS promote(@c10 AS LONG)] -> [COL1: KEY[0], COL2: KEY[2], COL3: KEY[1], ID: KEY[4]]) | MAP (_.COL3 AS COL3, _.COL2 AS COL2)' task_count: 291 - task_total_time_ms: 11 - transform_count: 96 - transform_time_ms: 6 + task_total_time_ms: 20 + transform_count: 99 + transform_time_ms: 11 transform_yield_count: 50 insert_time_ms: 0 insert_new_count: 23 @@ -300,8 +301,8 @@ agg-index-tests: COL2: KEY[2], COL3: KEY[1], ID: KEY[4]]) | MAP (_.COL3 AS COL3, _.COL2 AS COL2)' task_count: 291 - task_total_time_ms: 15 - transform_count: 96 + task_total_time_ms: 17 + transform_count: 99 transform_time_ms: 8 transform_yield_count: 50 insert_time_ms: 0 @@ -313,9 +314,9 @@ agg-index-tests: AS _0) GROUP BY (_._0.COL1 AS _0, _._0.COL3 AS _1) | MAP (_._0._1 AS COL3, _._1._0 AS S) task_count: 187 - task_total_time_ms: 9 - transform_count: 63 - transform_time_ms: 4 + task_total_time_ms: 10 + transform_count: 66 + transform_time_ms: 5 transform_yield_count: 16 insert_time_ms: 0 insert_new_count: 14 @@ -326,9 +327,9 @@ agg-index-tests: (sum_l(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0, _._0.COL3 AS _1) | MAP (_._0._1 AS COL3, _._1._0 AS S) task_count: 187 - task_total_time_ms: 14 - transform_count: 63 - transform_time_ms: 6 + task_total_time_ms: 10 + transform_count: 66 + transform_time_ms: 5 transform_yield_count: 16 insert_time_ms: 0 insert_new_count: 14 @@ -337,9 +338,9 @@ agg-index-tests: explain: ISCAN(MV3 <,>) | MAP (_ AS _0) | AGG (max_l(_._0.COL3) AS _0) GROUP BY (_._0.COL1 AS _0, _._0.COL3 AS _1) | MAP (_._1._0 AS _0) task_count: 367 - task_total_time_ms: 22 - transform_count: 120 - transform_time_ms: 13 + task_total_time_ms: 20 + transform_count: 123 + transform_time_ms: 11 transform_yield_count: 56 insert_time_ms: 0 insert_new_count: 36 @@ -348,9 +349,20 @@ agg-index-tests: explain: 'AISCAN(MV7 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)' task_count: 645 - task_total_time_ms: 29 - transform_count: 227 - transform_time_ms: 15 + task_total_time_ms: 26 + transform_count: 233 + transform_time_ms: 13 + transform_yield_count: 71 + insert_time_ms: 1 + insert_new_count: 70 + insert_reused_count: 10 +- query: EXPLAIN select min_ever(col3) from t2 + explain: 'AISCAN(MV7 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY + NULL | MAP (_._0._0 AS _0)' + task_count: 645 + task_total_time_ms: 26 + transform_count: 233 + transform_time_ms: 13 transform_yield_count: 71 insert_time_ms: 1 insert_new_count: 70 @@ -359,9 +371,9 @@ agg-index-tests: explain: 'AISCAN(MV6 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL1, _._1 AS _1)' task_count: 521 - task_total_time_ms: 15 - transform_count: 180 - transform_time_ms: 7 + task_total_time_ms: 34 + transform_count: 185 + transform_time_ms: 23 transform_yield_count: 70 insert_time_ms: 0 insert_new_count: 50 @@ -370,9 +382,9 @@ agg-index-tests: explain: 'AISCAN(MV12 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL1, _._1 AS _1)' task_count: 423 - task_total_time_ms: 17 - transform_count: 148 - transform_time_ms: 9 + task_total_time_ms: 25 + transform_count: 153 + transform_time_ms: 15 transform_yield_count: 60 insert_time_ms: 0 insert_new_count: 38 @@ -381,9 +393,9 @@ agg-index-tests: explain: 'AISCAN(MV15 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL2, _._1 AS _1)' task_count: 227 - task_total_time_ms: 3 - transform_count: 80 - transform_time_ms: 2 + task_total_time_ms: 16 + transform_count: 85 + transform_time_ms: 9 transform_yield_count: 26 insert_time_ms: 0 insert_new_count: 12 @@ -392,9 +404,9 @@ agg-index-tests: explain: 'AISCAN(MV14 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL2, _._1 AS _1)' task_count: 227 - task_total_time_ms: 10 - transform_count: 80 - transform_time_ms: 5 + task_total_time_ms: 16 + transform_count: 85 + transform_time_ms: 10 transform_yield_count: 26 insert_time_ms: 0 insert_new_count: 12 @@ -403,9 +415,9 @@ agg-index-tests: explain: 'AISCAN(MV1 [[GREATER_THAN promote(@c13 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._0 AS COL1, _._1 AS _1)' task_count: 655 - task_total_time_ms: 32 - transform_count: 205 - transform_time_ms: 13 + task_total_time_ms: 33 + transform_count: 210 + transform_time_ms: 16 transform_yield_count: 72 insert_time_ms: 0 insert_new_count: 76 @@ -414,9 +426,9 @@ agg-index-tests: explain: 'AISCAN(MV1 [EQUALS promote(@c11 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0)' task_count: 655 - task_total_time_ms: 37 - transform_count: 205 - transform_time_ms: 18 + task_total_time_ms: 43 + transform_count: 210 + transform_time_ms: 21 transform_yield_count: 72 insert_time_ms: 0 insert_new_count: 76 @@ -427,9 +439,9 @@ agg-index-tests: promote(@c12 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS _0)' task_count: 677 - task_total_time_ms: 34 - transform_count: 206 - transform_time_ms: 16 + task_total_time_ms: 35 + transform_count: 211 + transform_time_ms: 17 transform_yield_count: 72 insert_time_ms: 0 insert_new_count: 78 @@ -438,9 +450,9 @@ agg-index-tests: explain: 'AISCAN(MV10 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1]]) | MAP (_._1 AS X1, _._0 AS X2)' task_count: 325 - task_total_time_ms: 9 - transform_count: 113 - transform_time_ms: 5 + task_total_time_ms: 24 + transform_count: 118 + transform_time_ms: 13 transform_yield_count: 43 insert_time_ms: 0 insert_new_count: 25 @@ -449,9 +461,9 @@ agg-index-tests: explain: 'AISCAN(MV10 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1]]) | MAP (_._0 AS X1, _._1 AS X2)' task_count: 325 - task_total_time_ms: 17 - transform_count: 113 - transform_time_ms: 9 + task_total_time_ms: 22 + transform_count: 118 + transform_time_ms: 13 transform_yield_count: 43 insert_time_ms: 0 insert_new_count: 25 @@ -460,9 +472,9 @@ agg-index-tests: explain: 'AISCAN(MV11 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: KEY:[2]]) | MAP (_._0 AS X1, _._2 AS X2)' task_count: 325 - task_total_time_ms: 8 - transform_count: 113 - transform_time_ms: 5 + task_total_time_ms: 34 + transform_count: 118 + transform_time_ms: 24 transform_yield_count: 43 insert_time_ms: 0 insert_new_count: 25 @@ -471,9 +483,9 @@ agg-index-tests: explain: 'AISCAN(MV11 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: KEY:[2]]) | MAP (_._0 AS X1, _._2 AS X2)' task_count: 325 - task_total_time_ms: 28 - transform_count: 113 - transform_time_ms: 14 + task_total_time_ms: 33 + transform_count: 118 + transform_time_ms: 23 transform_yield_count: 43 insert_time_ms: 0 insert_new_count: 25 @@ -483,9 +495,9 @@ agg-index-tests: explain: 'AISCAN(MV11 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: KEY:[2]]) | MAP (_._0 AS X1, _._2 AS X2)' task_count: 325 - task_total_time_ms: 24 - transform_count: 113 - transform_time_ms: 13 + task_total_time_ms: 27 + transform_count: 118 + transform_time_ms: 19 transform_yield_count: 43 insert_time_ms: 0 insert_new_count: 25 @@ -495,9 +507,9 @@ agg-index-tests: explain: 'AISCAN(MV10 [[LESS_THAN promote(@c21 AS LONG)]] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1]]) | MAP (_._1 AS X1, _._0 AS X2)' task_count: 393 - task_total_time_ms: 21 - transform_count: 133 - transform_time_ms: 11 + task_total_time_ms: 24 + transform_count: 138 + transform_time_ms: 14 transform_yield_count: 46 insert_time_ms: 0 insert_new_count: 33 diff --git a/yaml-tests/src/test/resources/aggregate-index-tests.yamsql b/yaml-tests/src/test/resources/aggregate-index-tests.yamsql index c886c92ceb..dc1c06baae 100644 --- a/yaml-tests/src/test/resources/aggregate-index-tests.yamsql +++ b/yaml-tests/src/test/resources/aggregate-index-tests.yamsql @@ -133,7 +133,7 @@ test_block: # controlling for that, it can still use the index - query: select max(col2) from T1 use index (mv8); - supported_version: 4.1.9.0 - - explain: "ISCAN(MV8 <,>) | MAP (_ AS _0) | AGG (max_l(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)" + - explain: "AISCAN(MV8 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1]]) | AGG max_l(_._1) GROUP BY () | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)" - result: [{!l 13}] - - query: select max(col2) from T1 use index (mv8); @@ -180,7 +180,7 @@ test_block: # over base table scan. - query: select max(col2) from t2; - supported_version: 4.1.9.0 - - explain: "ISCAN(MV3 <,>) | MAP (_ AS _0) | AGG (max_l(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)" + - explain: "AISCAN(MV9 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[2], _2: KEY:[1]]) | AGG max_l(_._2) GROUP BY () | MAP ((_._2 AS _0) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)" - result: [{!l 2}] - - query: select max(col2) from t2; diff --git a/yaml-tests/src/test/resources/bitmap-aggregate-index.metrics.binpb b/yaml-tests/src/test/resources/bitmap-aggregate-index.metrics.binpb index 5b3bbb54f5ebd70f54c7861296368774b544628d..9323e2906d6acc268ca502a635e29c8555098824 100644 GIT binary patch delta 890 zcmbQ5bjXYG)npsq7gCKpTv8k_nFN;3>64LYVpM26@>fJd&*1VwgNf(z8GmfHW9(<- z^YQm{S8xng@ON_yb`9BlmMM#o+bJ@{H5eoqZ#elUSFgOIyL+^gXNa$3fTy2}YlNY- zLQ-Z)Zel@vSz=CUYV2f3dGpC9xnqQaLxMaZra3!?xVrlXMQ&avDaOdMlaK4}WP4tz z$!sD=rLI9;HD%ibBao|3oM=)5y6Wp;gUQkC{Y-1QC)+dLn|zAnuo9+mItpmc?d8m2 z6o-k$8|o+^oNk28=|-eF{iqn%dXUp6$`wxzP~)DQAT231K@=FScNhh}AM4SV@K!kd zYp%S8l)=qA`xz%slD^F}TX=K6%oOyHoqU!lb8?PcD5KHj2hy684YV{_Gzv|OCL5@$ zPqvqzCWvsj0X*b0C)+8U!4|4qigt|H#66U>8SOEHO;brB)|yK}!B|1pPQgeaS|KMf zDK*E|MlCO?xWF3d3OlHX5|F)lfwCwQ%O!EH!{8{J&Q=TbxSmv}7{t@fkCuZxJ@eTg z6`-d-tewfYdAb@aBhxG4$@wzBCeP5=Kt#M@1ctVxkzTxk9xT~_L%={s0UAP@ljmwp SP)0;EOqwcTwnCRmVFmyhaS)mS delta 630 zcmX@)H8qLlI}g|T$sgFHCcE+#Pi|*dmJ&L|%_Yh4l1X6y&vpC~wF)<8PUF(hGiY6@ zFqxS#pJ^A@jf90)qHlY0ruD3D+ z?LV_kWOJYtDOSRvj(M?nK*Pk`J`4wwLj R+a|vkojy5AX$o%V0RZ4{)SUnT diff --git a/yaml-tests/src/test/resources/bitmap-aggregate-index.metrics.yaml b/yaml-tests/src/test/resources/bitmap-aggregate-index.metrics.yaml index 22b8532ad3..8cd9a4c0a1 100644 --- a/yaml-tests/src/test/resources/bitmap-aggregate-index.metrics.yaml +++ b/yaml-tests/src/test/resources/bitmap-aggregate-index.metrics.yaml @@ -1,37 +1,13 @@ bitmap-agg-index-tests: -- query: EXPLAIN SELECT bitmap_construct_agg(bitmap_bit_position(id)) as bitmap, - bitmap_bucket_offset(id) as offset FROM T1 GROUP BY bitmap_bucket_offset(id) - explain: 'AISCAN(BITMAPINDEX1 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | - MAP (_._1 AS BITMAP, _._0 AS OFFSET)' - task_count: 361 - task_total_time_ms: 32 - transform_count: 125 - transform_time_ms: 21 - transform_yield_count: 46 - insert_time_ms: 0 - insert_new_count: 24 - insert_reused_count: 0 -- query: EXPLAIN SELECT bitmap_construct_agg(bitmap_bit_position(id)) as bitmap, - category, bitmap_bucket_offset(id) as offset FROM T1 GROUP BY category, bitmap_bucket_offset(id) - explain: 'AISCAN(BITMAPINDEX2 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) - | MAP (_._2 AS BITMAP, _._0 AS CATEGORY, _._1 AS OFFSET)' - task_count: 361 - task_total_time_ms: 42 - transform_count: 125 - transform_time_ms: 30 - transform_yield_count: 46 - insert_time_ms: 0 - insert_new_count: 24 - insert_reused_count: 0 - query: EXPLAIN SELECT bitmap_construct_agg(bitmap_bit_position(id)) as bitmap, bitmap_bucket_offset(id) as offset FROM T1 GROUP BY bitmap_bucket_offset(id), bitmap_bucket_offset(id), bitmap_bucket_offset(id) explain: 'AISCAN(BITMAPINDEX1 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS BITMAP, _._0 AS OFFSET)' task_count: 361 - task_total_time_ms: 40 - transform_count: 125 - transform_time_ms: 27 + task_total_time_ms: 58 + transform_count: 130 + transform_time_ms: 43 transform_yield_count: 46 insert_time_ms: 0 insert_new_count: 24 @@ -42,9 +18,9 @@ bitmap-agg-index-tests: explain: 'AISCAN(BITMAPINDEX2 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | MAP (_._2 AS BITMAP, _._0 AS CATEGORY, _._1 AS OFFSET)' task_count: 361 - task_total_time_ms: 42 - transform_count: 125 - transform_time_ms: 30 + task_total_time_ms: 105 + transform_count: 130 + transform_time_ms: 79 transform_yield_count: 46 insert_time_ms: 0 insert_new_count: 24 @@ -55,11 +31,11 @@ bitmap-agg-index-tests: bitmap_bit_position 10000) AS _0) GROUP BY ((_._0.ID) bitmap_bucket_offset 10000 AS _0) | MAP (_._1._0 AS BITMAP, _._0._0 AS OFFSET) task_count: 220 - task_total_time_ms: 20 - transform_count: 72 - transform_time_ms: 13 + task_total_time_ms: 98 + transform_count: 75 + transform_time_ms: 65 transform_yield_count: 26 - insert_time_ms: 0 + insert_time_ms: 3 insert_new_count: 18 insert_reused_count: 2 - query: EXPLAIN SELECT bitmap_construct_agg(bitmap_bit_position(id)) as bitmap, @@ -69,10 +45,24 @@ bitmap-agg-index-tests: bitmap_bucket_offset 10000 AS _1) | MAP (_._1._0 AS BITMAP, _._0._0 AS CATEGORY, _._0._1 AS OFFSET) task_count: 220 - task_total_time_ms: 12 - transform_count: 72 - transform_time_ms: 6 + task_total_time_ms: 99 + transform_count: 75 + transform_time_ms: 77 transform_yield_count: 26 - insert_time_ms: 0 + insert_time_ms: 2 + insert_new_count: 18 + insert_reused_count: 2 +- query: EXPLAIN SELECT bitmap_construct_agg(bitmap_bit_position(id)) as bitmap, + category, bitmap_bucket_offset(id) as offset FROM T2 GROUP BY category, bitmap_bucket_offset(id) + explain: ISCAN(AGG_INDEX_2 <,>) | MAP (_ AS _0) | AGG (bitmap_construct_agg_l((_._0.ID) + bitmap_bit_position 10000) AS _0) GROUP BY (_._0.CATEGORY AS _0, (_._0.ID) + bitmap_bucket_offset 10000 AS _1) | MAP (_._1._0 AS BITMAP, _._0._0 AS CATEGORY, + _._0._1 AS OFFSET) + task_count: 220 + task_total_time_ms: 99 + transform_count: 75 + transform_time_ms: 77 + transform_yield_count: 26 + insert_time_ms: 2 insert_new_count: 18 insert_reused_count: 2 diff --git a/yaml-tests/src/test/resources/bitmap-aggregate-index.yamsql b/yaml-tests/src/test/resources/bitmap-aggregate-index.yamsql index 0fe638093f..72bb7eecf9 100644 --- a/yaml-tests/src/test/resources/bitmap-aggregate-index.yamsql +++ b/yaml-tests/src/test/resources/bitmap-aggregate-index.yamsql @@ -47,16 +47,16 @@ setup: test_block: name: bitmap-agg-index-tests tests: - - - - query: SELECT bitmap_construct_agg(bitmap_bit_position(id)) as bitmap, bitmap_bucket_offset(id) as offset FROM T1 GROUP BY bitmap_bucket_offset(id) - - explain: "AISCAN(BITMAPINDEX1 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS BITMAP, _._0 AS OFFSET)" - - unorderedResult: [{BITMAP: xStartsWith_1250'060000c', 'OFFSET':0}, {BITMAP: xStartsWith_1250'02', 'OFFSET':10000}] - - - - query: SELECT bitmap_construct_agg(bitmap_bit_position(id)) as bitmap, category, bitmap_bucket_offset(id) as offset FROM T1 GROUP BY category, bitmap_bucket_offset(id) - - explain: "AISCAN(BITMAPINDEX2 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | MAP (_._2 AS BITMAP, _._0 AS CATEGORY, _._1 AS OFFSET)" - - unorderedResult: [{BITMAP: xStartsWith_1250'0200004', 'CATEGORY': 'hello', 'OFFSET':0}, - {BITMAP: xStartsWith_1250'02', 'CATEGORY': 'hello', 'OFFSET':10000}, - {BITMAP: xStartsWith_1250'0400008', 'CATEGORY': 'world', 'OFFSET':0}] + #- + # - query: SELECT bitmap_construct_agg(bitmap_bit_position(id)) as bitmap, bitmap_bucket_offset(id) as offset FROM T1 GROUP BY bitmap_bucket_offset(id) + # - explain: "AISCAN(BITMAPINDEX1 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS BITMAP, _._0 AS OFFSET)" + # - unorderedResult: [{BITMAP: xStartsWith_1250'060000c', 'OFFSET':0}, {BITMAP: xStartsWith_1250'02', 'OFFSET':10000}] + #- + # - query: SELECT bitmap_construct_agg(bitmap_bit_position(id)) as bitmap, category, bitmap_bucket_offset(id) as offset FROM T1 GROUP BY category, bitmap_bucket_offset(id) + # - explain: "AISCAN(BITMAPINDEX2 <,> BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | MAP (_._2 AS BITMAP, _._0 AS CATEGORY, _._1 AS OFFSET)" + # - unorderedResult: [{BITMAP: xStartsWith_1250'0200004', 'CATEGORY': 'hello', 'OFFSET':0}, + # {BITMAP: xStartsWith_1250'02', 'CATEGORY': 'hello', 'OFFSET':10000}, + # {BITMAP: xStartsWith_1250'0400008', 'CATEGORY': 'world', 'OFFSET':0}] - - query: SELECT bitmap_construct_agg(bitmap_bit_position(id)) as bitmap, bitmap_bucket_offset(id) as offset FROM T1 GROUP BY bitmap_bucket_offset(id), bitmap_bucket_offset(id), bitmap_bucket_offset(id) - explain: "AISCAN(BITMAPINDEX1 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS BITMAP, _._0 AS OFFSET)" diff --git a/yaml-tests/src/test/resources/catalog.metrics.binpb b/yaml-tests/src/test/resources/catalog.metrics.binpb index 8868c886e0..f0df119e86 100644 --- a/yaml-tests/src/test/resources/catalog.metrics.binpb +++ b/yaml-tests/src/test/resources/catalog.metrics.binpb @@ -1,40 +1,40 @@ - +  - catalog-testsEXPLAIN select sum(cnt) from (select count(*) as cnt, template_name, template_version from schemas group by template_name, template_version having template_name = 'TEST_TEMPLATE_1') as t; -ٌ -('0I80@AISCAN(TEMPLATES_COUNT_INDEX [EQUALS promote(@c29 AS STRING)] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | MAP (_._2 AS CNT, _._0 AS TEMPLATE_NAME, _._1 AS TEMPLATE_VERSION) | MAP (_ AS _0) | AGG (sum_l(_._0.CNT) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { + catalog-testsEXPLAIN select sum(cnt) from (select count(*) as cnt, template_name, template_version from schemas group by template_name, template_version having template_name = 'TEST_TEMPLATE_1') as t; +ഀ Ѻ +('0080@AISCAN(TEMPLATES_COUNT_INDEX [EQUALS promote(@c29 AS STRING)] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | MAP (_._2 AS CNT, _._0 AS TEMPLATE_NAME, _._1 AS TEMPLATE_VERSION) | MAP (_ AS _0) | AGG (sum_l(_._0.CNT) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q12._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q12 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q62._0.CNT) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q8 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS CNT, AS _0)" ]; - 5 [ label=<
    Value Computation
    MAP (q6._2 AS CNT, q6._0 AS TEMPLATE_NAME, q6._1 AS TEMPLATE_VERSION)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS CNT, )" ]; - 6 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c29 AS STRING)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS _0, )" ]; - 7 [ label=<
    Index
    TEMPLATES_COUNT_INDEX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS DATABASE_ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q66._0.CNT) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q8 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS CNT, STRING AS TEMPLATE_NAME, INT AS TEMPLATE_VERSION AS _0)" ]; + 5 [ label=<
    Value Computation
    MAP (q6._2 AS CNT, q6._0 AS TEMPLATE_NAME, q6._1 AS TEMPLATE_VERSION)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS CNT, STRING AS TEMPLATE_NAME, INT AS TEMPLATE_VERSION)" ]; + 6 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c29 AS STRING)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS _0, INT AS _1, LONG AS _2)" ]; + 7 [ label=<
    Index
    AGG[TEMPLATES_COUNT_INDEX; count]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS DATABASE_ID, STRING AS SCHEMA_NAME, STRING AS TEMPLATE_NAME, INT AS TEMPLATE_VERSION)" ]; 3 -> 2 [ label=< q12> label="q12" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q62> label="q62" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q66> label="q66" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q12> label="q12" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +}  - catalog-testsEXPLAIN select sum(cnt) from (select count(*) as cnt, template_name, template_version from schemas group by template_name, template_version having template_name = 'TEST_TEMPLATE_1' and template_version = 1) as t; -޽ ܹ ('0U80@AISCAN(TEMPLATES_COUNT_INDEX [EQUALS promote(@c29 AS STRING), EQUALS promote(@c33 AS INT)] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | MAP (_._2 AS CNT, _._0 AS TEMPLATE_NAME, _._1 AS TEMPLATE_VERSION) | MAP (_ AS _0) | AGG (sum_l(_._0.CNT) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { + catalog-testsEXPLAIN select sum(cnt) from (select count(*) as cnt, template_name, template_version from schemas group by template_name, template_version having template_name = 'TEST_TEMPLATE_1' and template_version = 1) as t; + ('0380@AISCAN(TEMPLATES_COUNT_INDEX [EQUALS promote(@c29 AS STRING), EQUALS promote(@c33 AS INT)] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: VALUE:[0]]) | MAP (_._2 AS CNT, _._0 AS TEMPLATE_NAME, _._1 AS TEMPLATE_VERSION) | MAP (_ AS _0) | AGG (sum_l(_._0.CNT) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q12._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q12 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q62._0.CNT) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q8 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS CNT, AS _0)" ]; - 5 [ label=<
    Value Computation
    MAP (q6._2 AS CNT, q6._0 AS TEMPLATE_NAME, q6._1 AS TEMPLATE_VERSION)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS CNT, )" ]; - 6 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c29 AS STRING), EQUALS promote(@c33 AS INT)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS _0, )" ]; - 7 [ label=<
    Index
    TEMPLATES_COUNT_INDEX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS DATABASE_ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q66._0.CNT) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q8 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS CNT, STRING AS TEMPLATE_NAME, INT AS TEMPLATE_VERSION AS _0)" ]; + 5 [ label=<
    Value Computation
    MAP (q6._2 AS CNT, q6._0 AS TEMPLATE_NAME, q6._1 AS TEMPLATE_VERSION)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS CNT, STRING AS TEMPLATE_NAME, INT AS TEMPLATE_VERSION)" ]; + 6 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [EQUALS promote(@c29 AS STRING), EQUALS promote(@c33 AS INT)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS _0, INT AS _1, LONG AS _2)" ]; + 7 [ label=<
    Index
    AGG[TEMPLATES_COUNT_INDEX; count]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS DATABASE_ID, STRING AS SCHEMA_NAME, STRING AS TEMPLATE_NAME, INT AS TEMPLATE_VERSION)" ]; 3 -> 2 [ label=< q12> label="q12" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q62> label="q62" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q66> label="q66" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; diff --git a/yaml-tests/src/test/resources/catalog.metrics.yaml b/yaml-tests/src/test/resources/catalog.metrics.yaml index 3b19b743d6..bf7e28362e 100644 --- a/yaml-tests/src/test/resources/catalog.metrics.yaml +++ b/yaml-tests/src/test/resources/catalog.metrics.yaml @@ -7,11 +7,11 @@ catalog-tests: TEMPLATE_NAME, _._1 AS TEMPLATE_VERSION) | MAP (_ AS _0) | AGG (sum_l(_._0.CNT) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)' task_count: 479 - task_total_time_ms: 45 - transform_count: 164 - transform_time_ms: 23 + task_total_time_ms: 37 + transform_count: 169 + transform_time_ms: 22 transform_yield_count: 39 - insert_time_ms: 1 + insert_time_ms: 0 insert_new_count: 48 insert_reused_count: 3 - query: EXPLAIN select sum(cnt) from (select count(*) as cnt, template_name, template_version @@ -23,10 +23,10 @@ catalog-tests: (_ AS _0) | AGG (sum_l(_._0.CNT) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)' task_count: 479 - task_total_time_ms: 52 - transform_count: 164 - transform_time_ms: 24 + task_total_time_ms: 44 + transform_count: 169 + transform_time_ms: 26 transform_yield_count: 39 - insert_time_ms: 1 + insert_time_ms: 0 insert_new_count: 48 insert_reused_count: 3 diff --git a/yaml-tests/src/test/resources/composite-aggregates.yamsql b/yaml-tests/src/test/resources/composite-aggregates.yamsql index 7adce8d4b4..198bbeeb81 100644 --- a/yaml-tests/src/test/resources/composite-aggregates.yamsql +++ b/yaml-tests/src/test/resources/composite-aggregates.yamsql @@ -17,6 +17,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +--- +options: + supported_version: !current_version --- schema_template: create table t1(id bigint, col1 bigint, col2 bigint, col3 bigint, primary key(id)) diff --git a/yaml-tests/src/test/resources/create-drop.metrics.binpb b/yaml-tests/src/test/resources/create-drop.metrics.binpb index 285dcfbaaa..fa813a220d 100644 --- a/yaml-tests/src/test/resources/create-drop.metrics.binpb +++ b/yaml-tests/src/test/resources/create-drop.metrics.binpb @@ -1,69 +1,69 @@ - + S - unnamed-4FEXPLAIN select count(*) from "TEMPLATES" where template_name = 'TEMP1' -ũ7j ʕ%(08@SCAN(<,>) | TFILTER TEMPLATES | FILTER _.TEMPLATE_NAME EQUALS promote(@c11 AS STRING) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { + unnamed-4FEXPLAIN select count(*) from "TEMPLATES" where template_name = 'TEMP1' +Ȱm ΙK(08@SCAN(<,>) | TFILTER TEMPLATES | FILTER _.TEMPLATE_NAME EQUALS promote(@c11 AS STRING) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q23 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS TEMPLATE_NAME, AS _0)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q2.TEMPLATE_NAME EQUALS promote(@c11 AS STRING)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS TEMPLATE_NAME, )" ]; - 6 [ label=<
    Type Filter
    WHERE record IS [TEMPLATES]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS TEMPLATE_NAME, )" ]; + 4 [ label=<
    Value Computation
    MAP (q24 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS TEMPLATE_NAME, INT AS TEMPLATE_VERSION, BYTES AS META_DATA AS _0)" ]; + 5 [ label=<
    Predicate Filter
    WHERE q2.TEMPLATE_NAME EQUALS promote(@c11 AS STRING)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS TEMPLATE_NAME, INT AS TEMPLATE_VERSION, BYTES AS META_DATA)" ]; + 6 [ label=<
    Type Filter
    WHERE record IS [TEMPLATES]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS TEMPLATE_NAME, INT AS TEMPLATE_VERSION, BYTES AS META_DATA)" ]; 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 8 [ label=<
    Primary Storage
    record types: [DATABASES, SCHEMAS, TEMPLATES]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q32> label="q32" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q34> label="q34" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q19> label="q19" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q20> label="q20" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; } T unnamed-10FEXPLAIN select count(*) from "DATABASES" where database_id = '/FRL/DB' -s ۟ (0i8@SCAN(<,>) | TFILTER DATABASES | FILTER _.DATABASE_ID EQUALS promote(@c11 AS STRING) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +y (0 8@SCAN(<,>) | TFILTER DATABASES | FILTER _.DATABASE_ID EQUALS promote(@c11 AS STRING) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q31 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS DATABASE_ID AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q32 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS DATABASE_ID AS _0)" ]; 5 [ label=<
    Predicate Filter
    WHERE q2.DATABASE_ID EQUALS promote(@c11 AS STRING)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS DATABASE_ID)" ]; 6 [ label=<
    Type Filter
    WHERE record IS [DATABASES]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS DATABASE_ID)" ]; 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 8 [ label=<
    Primary Storage
    record types: [DATABASES, SCHEMAS, TEMPLATES]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q40> label="q40" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q31> label="q31" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q42> label="q42" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q32> label="q32" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q27> label="q27" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q28> label="q28" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +}" R -unnamed-20DEXPLAIN select count(*) from "SCHEMAS" where database_id = '/FRL/DB' -› (*08O@COVERING(TEMPLATES_VALUE_INDEX <,> -> [DATABASE_ID: KEY[2], SCHEMA_NAME: KEY[3], TEMPLATE_NAME: KEY[0], TEMPLATE_VERSION: KEY[1]]) | FILTER _.DATABASE_ID EQUALS promote(@c11 AS STRING) | FETCH | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +unnamed-20DEXPLAIN select count(*) from "SCHEMAS" where database_id = '/FRL/DB'" + Ҷ(208R@COVERING(TEMPLATES_VALUE_INDEX <,> -> [DATABASE_ID: KEY[2], SCHEMA_NAME: KEY[3], TEMPLATE_NAME: KEY[0], TEMPLATE_VERSION: KEY[1]]) | FILTER _.DATABASE_ID EQUALS promote(@c11 AS STRING) | FETCH | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q43 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS DATABASE_ID, AS _0)" ]; - 5 [ label=<
    Fetch Records
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(STRING AS DATABASE_ID, )" ]; - 6 [ label=<
    Predicate Filter
    WHERE q48.DATABASE_ID EQUALS promote(@c11 AS STRING)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS DATABASE_ID, )" ]; - 7 [ label=<
    Covering Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS DATABASE_ID, )" ]; - 8 [ label=<
    Index
    TEMPLATES_VALUE_INDEX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS DATABASE_ID, )" ]; + 4 [ label=<
    Value Computation
    MAP (q45 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS DATABASE_ID, STRING AS SCHEMA_NAME, STRING AS TEMPLATE_NAME, INT AS TEMPLATE_VERSION AS _0)" ]; + 5 [ label=<
    Fetch Records
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(STRING AS DATABASE_ID, STRING AS SCHEMA_NAME, STRING AS TEMPLATE_NAME, INT AS TEMPLATE_VERSION)" ]; + 6 [ label=<
    Predicate Filter
    WHERE q50.DATABASE_ID EQUALS promote(@c11 AS STRING)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS DATABASE_ID, STRING AS SCHEMA_NAME, STRING AS TEMPLATE_NAME, INT AS TEMPLATE_VERSION)" ]; + 7 [ label=<
    Covering Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS DATABASE_ID, STRING AS SCHEMA_NAME, STRING AS TEMPLATE_NAME, INT AS TEMPLATE_VERSION)" ]; + 8 [ label=<
    Index
    TEMPLATES_VALUE_INDEX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(STRING AS DATABASE_ID, STRING AS SCHEMA_NAME, STRING AS TEMPLATE_NAME, INT AS TEMPLATE_VERSION)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q72> label="q72" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q43> label="q43" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q50> label="q50" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q48> label="q48" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q76> label="q76" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q45> label="q45" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q52> label="q52" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q50> label="q50" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; } \ No newline at end of file diff --git a/yaml-tests/src/test/resources/create-drop.metrics.yaml b/yaml-tests/src/test/resources/create-drop.metrics.yaml index c88ec478f9..a4d31c2929 100644 --- a/yaml-tests/src/test/resources/create-drop.metrics.yaml +++ b/yaml-tests/src/test/resources/create-drop.metrics.yaml @@ -4,11 +4,11 @@ unnamed-4: AS STRING) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 335 - task_total_time_ms: 116 - transform_count: 106 - transform_time_ms: 77 + task_total_time_ms: 2 + transform_count: 109 + transform_time_ms: 1 transform_yield_count: 17 - insert_time_ms: 5 + insert_time_ms: 0 insert_new_count: 28 insert_reused_count: 2 unnamed-10: @@ -17,11 +17,11 @@ unnamed-10: AS STRING) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 353 - task_total_time_ms: 38 - transform_count: 115 - transform_time_ms: 28 + task_total_time_ms: 4 + transform_count: 121 + transform_time_ms: 2 transform_yield_count: 26 - insert_time_ms: 1 + insert_time_ms: 0 insert_new_count: 28 insert_reused_count: 2 unnamed-20: @@ -31,11 +31,11 @@ unnamed-20: EQUALS promote(@c11 AS STRING) | FETCH | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)' - task_count: 623 - task_total_time_ms: 60 - transform_count: 177 - transform_time_ms: 29 - transform_yield_count: 42 - insert_time_ms: 3 - insert_new_count: 79 + task_count: 639 + task_total_time_ms: 9 + transform_count: 191 + transform_time_ms: 5 + transform_yield_count: 50 + insert_time_ms: 0 + insert_new_count: 82 insert_reused_count: 3 diff --git a/yaml-tests/src/test/resources/cte.metrics.binpb b/yaml-tests/src/test/resources/cte.metrics.binpb index b98e8ea717..0935289631 100644 --- a/yaml-tests/src/test/resources/cte.metrics.binpb +++ b/yaml-tests/src/test/resources/cte.metrics.binpb @@ -1,46 +1,46 @@ - + 7 - cte-tests*EXPLAIN select col1 from t1 where col2 < 3 -䒗{ t(!08.@rCOVERING(I1 [[LESS_THAN promote(@c8 AS LONG)]] -> [COL1: KEY[1], COL2: KEY[0], ID: KEY[3]]) | MAP (_.COL1 AS COL1) + cte-tests*EXPLAIN select col1 from t1 where col2 < 3 +~ f(!08.@rCOVERING(I1 [[LESS_THAN promote(@c8 AS LONG)]] -> [COL1: KEY[1], COL2: KEY[0], ID: KEY[3]]) | MAP (_.COL1 AS COL1) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q48.COL1 AS COL1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1)" ]; - 2 [ label=<
    Covering Index Scan
    comparisons: [[LESS_THAN promote(@c8 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q52.COL1 AS COL1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1)" ]; + 2 [ label=<
    Covering Index Scan
    comparisons: [[LESS_THAN promote(@c8 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 2 -> 1 [ label=< q48> label="q48" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} + 2 -> 1 [ label=< q52> label="q52" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +} [ - cte-testsNEXPLAIN select x from (select col1 as x, col2 as y from t1) as sub where y < 3 -Z T(08 @hSCAN(<,>) | MAP (_.COL1 AS X, _.COL2 AS Y) | FILTER _.Y LESS_THAN promote(@c21 AS LONG) | MAP (_.X AS X)digraph G { + cte-testsNEXPLAIN select x from (select col1 as x, col2 as y from t1) as sub where y < 3 +א] A(0 8 @hSCAN(<,>) | MAP (_.COL1 AS X, _.COL2 AS Y) | FILTER _.Y LESS_THAN promote(@c21 AS LONG) | MAP (_.X AS X)digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q42.X AS X)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS X)" ]; - 2 [ label=<
    Predicate Filter
    WHERE q4.Y LESS_THAN promote(@c21 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS X, )" ]; - 3 [ label=<
    Value Computation
    MAP (q2.COL1 AS X, q2.COL2 AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS X, )" ]; - 4 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 5 [ label=<
    Primary Storage
    record types: [T1]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q46.X AS X)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS X)" ]; + 2 [ label=<
    Predicate Filter
    WHERE q4.Y LESS_THAN promote(@c21 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS X, LONG AS Y)" ]; + 3 [ label=<
    Value Computation
    MAP (q2.COL1 AS X, q2.COL2 AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS X, LONG AS Y)" ]; + 4 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 5 [ label=<
    Primary Storage
    record types: [T1]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 2 -> 1 [ label=< q42> label="q42" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} + 2 -> 1 [ label=< q46> label="q46" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +} ^ - cte-testsQEXPLAIN with c1(x, y) as (select col1, col2 from t1) select x from c1 where y < 3 -Z Z(08 @tSCAN(<,>) | MAP (_.COL1 AS COL1, _.COL2 AS COL2) | FILTER _.COL2 LESS_THAN promote(@c24 AS LONG) | MAP (_.COL1 AS X)digraph G { + cte-testsQEXPLAIN with c1(x, y) as (select col1, col2 from t1) select x from c1 where y < 3 +ز] ڔ>(0 8 @tSCAN(<,>) | MAP (_.COL1 AS COL1, _.COL2 AS COL2) | FILTER _.COL2 LESS_THAN promote(@c24 AS LONG) | MAP (_.COL1 AS X)digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q44.COL1 AS X)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS X)" ]; - 2 [ label=<
    Predicate Filter
    WHERE q6.COL2 LESS_THAN promote(@c24 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, )" ]; - 3 [ label=<
    Value Computation
    MAP (q2.COL1 AS COL1, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, )" ]; - 4 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 5 [ label=<
    Primary Storage
    record types: [T1]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q48.COL1 AS X)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS X)" ]; + 2 [ label=<
    Predicate Filter
    WHERE q6.COL2 LESS_THAN promote(@c24 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS COL2)" ]; + 3 [ label=<
    Value Computation
    MAP (q2.COL1 AS COL1, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS COL2)" ]; + 4 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 5 [ label=<
    Primary Storage
    record types: [T1]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 2 -> 1 [ label=< q44> label="q44" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 -> 1 [ label=< q48> label="q48" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; } \ No newline at end of file diff --git a/yaml-tests/src/test/resources/cte.metrics.yaml b/yaml-tests/src/test/resources/cte.metrics.yaml index 433f090ab7..ccfd6b0bcc 100644 --- a/yaml-tests/src/test/resources/cte.metrics.yaml +++ b/yaml-tests/src/test/resources/cte.metrics.yaml @@ -4,7 +4,7 @@ cte-tests: KEY[0], ID: KEY[3]]) | MAP (_.COL1 AS COL1)' task_count: 440 task_total_time_ms: 4 - transform_count: 123 + transform_count: 126 transform_time_ms: 1 transform_yield_count: 33 insert_time_ms: 0 @@ -16,7 +16,7 @@ cte-tests: AS LONG) | MAP (_.X AS X) task_count: 295 task_total_time_ms: 3 - transform_count: 90 + transform_count: 93 transform_time_ms: 1 transform_yield_count: 25 insert_time_ms: 0 @@ -27,8 +27,8 @@ cte-tests: explain: SCAN(<,>) | MAP (_.COL1 AS COL1, _.COL2 AS COL2) | FILTER _.COL2 LESS_THAN promote(@c24 AS LONG) | MAP (_.COL1 AS X) task_count: 295 - task_total_time_ms: 3 - transform_count: 90 + task_total_time_ms: 2 + transform_count: 93 transform_time_ms: 1 transform_yield_count: 25 insert_time_ms: 0 diff --git a/yaml-tests/src/test/resources/field-index-tests-proto.metrics.binpb b/yaml-tests/src/test/resources/field-index-tests-proto.metrics.binpb index f9cc1bc266..75f1b717eb 100644 --- a/yaml-tests/src/test/resources/field-index-tests-proto.metrics.binpb +++ b/yaml-tests/src/test/resources/field-index-tests-proto.metrics.binpb @@ -1,54 +1,54 @@ - +  -field-index-tests-prototEXPLAIN select count(*) from (select * from (select * from (select * from "MyTable" where ID = 5) as x) as y) as z; -0 $(08@SCAN([EQUALS promote(@c23 AS LONG)]) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +field-index-tests-prototEXPLAIN select count(*) from (select * from (select * from (select * from "MyTable" where ID = 5) as x) as y) as z; + |(08@SCAN([EQUALS promote(@c23 AS LONG)]) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q12._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q12 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q8 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Scan
    comparisons: [EQUALS promote(@c23 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Primary Storage
    record types: [MyTable]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 4 [ label=<
    Value Computation
    MAP (q8 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL31, LONG AS COL32, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Scan
    comparisons: [EQUALS promote(@c23 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL31, LONG AS COL32, LONG AS COL2)" ]; + 6 [ label=<
    Primary Storage
    record types: [MyTable]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL31, LONG AS COL32, LONG AS COL2)" ]; 3 -> 2 [ label=< q12> label="q12" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q30> label="q30" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q32> label="q32" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q12> label="q12" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} C -field-index-tests-proto(EXPLAIN select sum(COL1) from "MyTable"; -ȝ1W &(08@^SCAN(<,>) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +field-index-tests-proto(EXPLAIN select sum(COL1) from "MyTable"; +Z [(0ӏ8@^SCAN(<,>) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q23._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Primary Storage
    record types: [MyTable]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q25._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL31, LONG AS COL32, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL31, LONG AS COL32, LONG AS COL2)" ]; + 6 [ label=<
    Primary Storage
    record types: [MyTable]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL31, LONG AS COL32, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q25> label="q25" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} E -field-index-tests-proto*EXPLAIN select count(COL1) from "MyTable"; -ÿW (0Ŏ8@SCAN(<,>) | MAP (_ AS _0) | AGG (count(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +field-index-tests-proto*EXPLAIN select count(COL1) from "MyTable"; +Z >(0 8@SCAN(<,>) | MAP (_ AS _0) | AGG (count(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q23._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Primary Storage
    record types: [MyTable]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q25._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL31, LONG AS COL32, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL31, LONG AS COL32, LONG AS COL2)" ]; + 6 [ label=<
    Primary Storage
    record types: [MyTable]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL31, LONG AS COL32, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q25> label="q25" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; diff --git a/yaml-tests/src/test/resources/field-index-tests-proto.metrics.yaml b/yaml-tests/src/test/resources/field-index-tests-proto.metrics.yaml index e1bd65c7c6..d22e26c4e8 100644 --- a/yaml-tests/src/test/resources/field-index-tests-proto.metrics.yaml +++ b/yaml-tests/src/test/resources/field-index-tests-proto.metrics.yaml @@ -5,32 +5,32 @@ field-index-tests-proto: AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 395 - task_total_time_ms: 100 - transform_count: 142 - transform_time_ms: 76 + task_total_time_ms: 10 + transform_count: 145 + transform_time_ms: 2 transform_yield_count: 22 - insert_time_ms: 2 + insert_time_ms: 0 insert_new_count: 31 insert_reused_count: 1 - query: EXPLAIN select sum(COL1) from "MyTable"; explain: SCAN(<,>) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) task_count: 249 - task_total_time_ms: 102 - transform_count: 87 - transform_time_ms: 80 + task_total_time_ms: 7 + transform_count: 90 + transform_time_ms: 1 transform_yield_count: 15 - insert_time_ms: 6 + insert_time_ms: 0 insert_new_count: 20 insert_reused_count: 2 - query: EXPLAIN select count(COL1) from "MyTable"; explain: SCAN(<,>) | MAP (_ AS _0) | AGG (count(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 249 - task_total_time_ms: 15 - transform_count: 87 - transform_time_ms: 5 + task_total_time_ms: 3 + transform_count: 90 + transform_time_ms: 1 transform_yield_count: 15 - insert_time_ms: 2 + insert_time_ms: 0 insert_new_count: 20 insert_reused_count: 2 diff --git a/yaml-tests/src/test/resources/groupby-tests.metrics.binpb b/yaml-tests/src/test/resources/groupby-tests.metrics.binpb index 15d0f6a12b..2101897b22 100644 --- a/yaml-tests/src/test/resources/groupby-tests.metrics.binpb +++ b/yaml-tests/src/test/resources/groupby-tests.metrics.binpb @@ -1,152 +1,152 @@ - + b -group-by-testsPEXPLAIN select AVG(x.col2) from (select col1,col2 from t1) as x group by x.col1; -P (08@ISCAN(I1 <,>) | MAP (_.COL1 AS COL1, _.COL2 AS COL2) | MAP (_ AS _0) | AGG (avg_l(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0)digraph G { +group-by-testsPEXPLAIN select AVG(x.col2) from (select col1,col2 from t1) as x group by x.col1; +S (08@ISCAN(I1 <,>) | MAP (_.COL1 AS COL1, _.COL2 AS COL2) | MAP (_ AS _0) | AGG (avg_l(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q8._1._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(DOUBLE AS _0)" ]; - 2 [ label=<
    Streaming Aggregate
    COLLECT (avg_l(q37._0.COL2) AS _0)
    GROUP BY (q37._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, )" ]; - 3 [ label=<
    Value Computation
    MAP (q4 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2.COL1 AS COL1, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, )" ]; - 5 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q37> label="q37" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 [ label=<
    Streaming Aggregate
    COLLECT (avg_l(q39._0.COL2) AS _0)
    GROUP BY (q39._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, DOUBLE AS _0 AS _1)" ]; + 3 [ label=<
    Value Computation
    MAP (q4 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS COL2 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q2.COL1 AS COL1, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS COL2)" ]; + 5 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 -> 2 [ label=< q39> label="q39" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +}  -group-by-testsmEXPLAIN select SUM(x.col2) / COUNT(x.col2), AVG(x.col2) from (select col1,col2 from t1) as x group by x.col1; -팩#P Ҽ(0ݍ8@ISCAN(I1 <,>) | MAP (_.COL1 AS COL1, _.COL2 AS COL2) | MAP (_ AS _0) | AGG (sum_l(_._0.COL2) AS _0, count(_._0.COL2) AS _1, avg_l(_._0.COL2) AS _2) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 / _._1._1 AS _0, _._1._2 AS _1)digraph G { +group-by-testsmEXPLAIN select SUM(x.col2) / COUNT(x.col2), AVG(x.col2) from (select col1,col2 from t1) as x group by x.col1; +S (08@ISCAN(I1 <,>) | MAP (_.COL1 AS COL1, _.COL2 AS COL2) | MAP (_ AS _0) | AGG (sum_l(_._0.COL2) AS _0, count(_._0.COL2) AS _1, avg_l(_._0.COL2) AS _2) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 / _._1._1 AS _0, _._1._2 AS _1)digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q8._1._0 / q8._1._1 AS _0, q8._1._2 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, )" ]; - 2 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q37._0.COL2) AS _0, count(q37._0.COL2) AS _1, avg_l(q37._0.COL2) AS _2)
    GROUP BY (q37._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, )" ]; - 3 [ label=<
    Value Computation
    MAP (q4 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2.COL1 AS COL1, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, )" ]; - 5 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q37> label="q37" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 1 [ label=<
    Value Computation
    MAP (q8._1._0 / q8._1._1 AS _0, q8._1._2 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, DOUBLE AS _1)" ]; + 2 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q39._0.COL2) AS _0, count(q39._0.COL2) AS _1, avg_l(q39._0.COL2) AS _2)
    GROUP BY (q39._0.COL1 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0, LONG AS _0, LONG AS _1, DOUBLE AS _2 AS _1)" ]; + 3 [ label=<
    Value Computation
    MAP (q4 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS COL2 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q2.COL1 AS COL1, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS COL2)" ]; + 5 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 -> 2 [ label=< q39> label="q39" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} R -group-by-tests@EXPLAIN select MAX(x.col2) from (select col1,col2 from t1) as x; - ( 083@ISCAN(I1 <,>) | MAP (_.COL1 AS COL1, _.COL2 AS COL2) | MAP (_ AS _0) | AGG (max_l(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +group-by-tests@EXPLAIN select MAX(x.col2) from (select col1,col2 from t1) as x; + ( 0383@ISCAN(I1 <,>) | MAP (_.COL1 AS COL1, _.COL2 AS COL2) | MAP (_ AS _0) | AGG (max_l(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q8._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q8 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (max_l(q47._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q4 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, AS _0)" ]; - 5 [ label=<
    Value Computation
    MAP (q2.COL1 AS COL1, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, )" ]; - 6 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 7 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (max_l(q51._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q4 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Value Computation
    MAP (q2.COL1 AS COL1, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 7 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q47> label="q47" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q51> label="q51" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} R -group-by-tests@EXPLAIN select MIN(x.col2) from (select col1,col2 from t1) as x; -ת ަ( 083@ISCAN(I1 <,>) | MAP (_.COL1 AS COL1, _.COL2 AS COL2) | MAP (_ AS _0) | AGG (min_l(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +group-by-tests@EXPLAIN select MIN(x.col2) from (select col1,col2 from t1) as x; + y( 083@ISCAN(I1 <,>) | MAP (_.COL1 AS COL1, _.COL2 AS COL2) | MAP (_ AS _0) | AGG (min_l(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q8._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q8 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (min_l(q47._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q4 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, AS _0)" ]; - 5 [ label=<
    Value Computation
    MAP (q2.COL1 AS COL1, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, )" ]; - 6 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 7 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (min_l(q51._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q4 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Value Computation
    MAP (q2.COL1 AS COL1, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 7 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q47> label="q47" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q51> label="q51" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} T -group-by-testsBEXPLAIN select COUNT(x.col2) from (select col1,col2 from t1) as x; -C 1( 083@ISCAN(I1 <,>) | MAP (_.COL1 AS COL1, _.COL2 AS COL2) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +group-by-testsBEXPLAIN select COUNT(x.col2) from (select col1,col2 from t1) as x; + ( 0,83@ISCAN(I1 <,>) | MAP (_.COL1 AS COL1, _.COL2 AS COL2) | MAP (_ AS _0) | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q8._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q8 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q47._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q4 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, AS _0)" ]; - 5 [ label=<
    Value Computation
    MAP (q2.COL1 AS COL1, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, )" ]; - 6 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 7 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q51._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q4 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Value Computation
    MAP (q2.COL1 AS COL1, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 7 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q47> label="q47" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q51> label="q51" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} R -group-by-tests@EXPLAIN select AVG(x.col2) from (select col1,col2 from t1) as x; - Ĵ( 0e83@ISCAN(I1 <,>) | MAP (_.COL1 AS COL1, _.COL2 AS COL2) | MAP (_ AS _0) | AGG (avg_l(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { +group-by-tests@EXPLAIN select AVG(x.col2) from (select col1,col2 from t1) as x; +ͷ ( 0283@ISCAN(I1 <,>) | MAP (_.COL1 AS COL1, _.COL2 AS COL2) | MAP (_ AS _0) | AGG (avg_l(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q8._0._0 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(DOUBLE AS _0)" ]; 2 [ label=<
    Value Computation
    $q8 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(DOUBLE AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (avg_l(q47._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(DOUBLE AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q4 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, AS _0)" ]; - 5 [ label=<
    Value Computation
    MAP (q2.COL1 AS COL1, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, )" ]; - 6 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 7 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (avg_l(q51._0.COL2) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(DOUBLE AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q4 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Value Computation
    MAP (q2.COL1 AS COL1, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 7 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q47> label="q47" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q51> label="q51" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} 2 -group-by-tests EXPLAIN select COUNT(*) from T1; -۔Bx 1(08/@ISCAN(I1 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +group-by-tests EXPLAIN select COUNT(*) from T1; +{ ф(028/@ISCAN(I1 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q43> label="q43" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q47> label="q47" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} 5 -group-by-tests#EXPLAIN select COUNT(col1) from T1; -Bx 1(08/@ISCAN(I1 <,>) | MAP (_ AS _0) | AGG (count(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +group-by-tests#EXPLAIN select COUNT(col1) from T1; +{ (038/@ISCAN(I1 <,>) | MAP (_ AS _0) | AGG (count(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q43._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (count(q47._0.COL1) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q43> label="q43" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q47> label="q47" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; diff --git a/yaml-tests/src/test/resources/groupby-tests.metrics.yaml b/yaml-tests/src/test/resources/groupby-tests.metrics.yaml index d9c9ac9a69..fbe82c40f5 100644 --- a/yaml-tests/src/test/resources/groupby-tests.metrics.yaml +++ b/yaml-tests/src/test/resources/groupby-tests.metrics.yaml @@ -5,9 +5,9 @@ group-by-tests: | AGG (avg_l(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 AS _0) task_count: 240 - task_total_time_ms: 10 - transform_count: 80 - transform_time_ms: 5 + task_total_time_ms: 14 + transform_count: 83 + transform_time_ms: 4 transform_yield_count: 21 insert_time_ms: 0 insert_new_count: 20 @@ -19,33 +19,33 @@ group-by-tests: _2) GROUP BY (_._0.COL1 AS _0) | MAP (_._1._0 / _._1._1 AS _0, _._1._2 AS _1) task_count: 240 - task_total_time_ms: 74 - transform_count: 80 - transform_time_ms: 47 + task_total_time_ms: 9 + transform_count: 83 + transform_time_ms: 3 transform_yield_count: 21 - insert_time_ms: 2 + insert_time_ms: 0 insert_new_count: 20 insert_reused_count: 2 - query: EXPLAIN select MAX(x.col2) from (select col1,col2 from t1) as x; explain: ISCAN(I1 <,>) | MAP (_.COL1 AS COL1, _.COL2 AS COL2) | MAP (_ AS _0) | AGG (max_l(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) task_count: 438 - task_total_time_ms: 33 - transform_count: 134 - transform_time_ms: 13 + task_total_time_ms: 15 + transform_count: 137 + transform_time_ms: 4 transform_yield_count: 32 - insert_time_ms: 3 + insert_time_ms: 0 insert_new_count: 51 insert_reused_count: 4 - query: EXPLAIN select MIN(x.col2) from (select col1,col2 from t1) as x; explain: ISCAN(I1 <,>) | MAP (_.COL1 AS COL1, _.COL2 AS COL2) | MAP (_ AS _0) | AGG (min_l(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) task_count: 438 - task_total_time_ms: 51 - transform_count: 134 - transform_time_ms: 15 + task_total_time_ms: 5 + transform_count: 137 + transform_time_ms: 1 transform_yield_count: 32 - insert_time_ms: 3 + insert_time_ms: 0 insert_new_count: 51 insert_reused_count: 4 - query: EXPLAIN select COUNT(x.col2) from (select col1,col2 from t1) as x; @@ -53,43 +53,76 @@ group-by-tests: | AGG (count(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 438 - task_total_time_ms: 142 - transform_count: 134 - transform_time_ms: 104 + task_total_time_ms: 11 + transform_count: 137 + transform_time_ms: 3 + transform_yield_count: 32 + insert_time_ms: 0 + insert_new_count: 51 + insert_reused_count: 4 +- query: EXPLAIN select AVG(x.col2) from (select col1,col2 from t1) as x; + explain: ISCAN(I1 <,>) | MAP (_.COL1 AS COL1, _.COL2 AS COL2) | MAP (_ AS _0) + | AGG (avg_l(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) + task_count: 438 + task_total_time_ms: 13 + transform_count: 137 + transform_time_ms: 3 transform_yield_count: 32 - insert_time_ms: 7 + insert_time_ms: 0 insert_new_count: 51 insert_reused_count: 4 - query: EXPLAIN select AVG(x.col2) from (select col1,col2 from t1) as x; explain: ISCAN(I1 <,>) | MAP (_.COL1 AS COL1, _.COL2 AS COL2) | MAP (_ AS _0) | AGG (avg_l(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0) task_count: 438 - task_total_time_ms: 17 - transform_count: 134 - transform_time_ms: 7 + task_total_time_ms: 13 + transform_count: 137 + transform_time_ms: 3 transform_yield_count: 32 - insert_time_ms: 1 + insert_time_ms: 0 insert_new_count: 51 insert_reused_count: 4 - query: EXPLAIN select COUNT(*) from T1; explain: ISCAN(I1 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 396 - task_total_time_ms: 138 - transform_count: 120 - transform_time_ms: 104 + task_total_time_ms: 14 + transform_count: 123 + transform_time_ms: 3 transform_yield_count: 30 - insert_time_ms: 8 + insert_time_ms: 0 + insert_new_count: 47 + insert_reused_count: 4 +- query: EXPLAIN select COUNT(*) from T1; + explain: ISCAN(I1 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY + NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) + task_count: 396 + task_total_time_ms: 14 + transform_count: 123 + transform_time_ms: 3 + transform_yield_count: 30 + insert_time_ms: 0 insert_new_count: 47 insert_reused_count: 4 - query: EXPLAIN select COUNT(col1) from T1; explain: ISCAN(I1 <,>) | MAP (_ AS _0) | AGG (count(_._0.COL1) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 396 - task_total_time_ms: 138 - transform_count: 120 - transform_time_ms: 103 + task_total_time_ms: 13 + transform_count: 123 + transform_time_ms: 3 transform_yield_count: 30 - insert_time_ms: 10 + insert_time_ms: 0 + insert_new_count: 47 + insert_reused_count: 4 +- query: EXPLAIN select COUNT(col1) from T1; + explain: ISCAN(I1 <,>) | MAP (_ AS _0) | AGG (count(_._0.COL1) AS _0) | ON EMPTY + NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) + task_count: 396 + task_total_time_ms: 13 + transform_count: 123 + transform_time_ms: 3 + transform_yield_count: 30 + insert_time_ms: 0 insert_new_count: 47 insert_reused_count: 4 diff --git a/yaml-tests/src/test/resources/indexed-functions.metrics.binpb b/yaml-tests/src/test/resources/indexed-functions.metrics.binpb index 90dd5b777b..362ce688da 100644 --- a/yaml-tests/src/test/resources/indexed-functions.metrics.binpb +++ b/yaml-tests/src/test/resources/indexed-functions.metrics.binpb @@ -1,49 +1,47 @@ - + 5 - unnamed-2(EXPLAIN select * from t where b + c > 7; - (K0ߎ8a@ -4ISCAN(BPLUSC [[GREATER_THAN promote(@c10 AS LONG)]])digraph G { + unnamed-2(EXPLAIN select * from t where b + c > 7; + ټ(K0ʺ8a@ +4ISCAN(BPLUSC [[GREATER_THAN promote(@c10 AS LONG)]])digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c10 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 2 [ label=<
    Index
    BPLUSC
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; + 1 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c10 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B, LONG AS C, LONG AS D, STRING AS E)" ]; + 2 [ label=<
    Index
    BPLUSC
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B, LONG AS C, LONG AS D, STRING AS E)" ]; 2 -> 1 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} T - unnamed-2GEXPLAIN select a, b + c AS sum from t where e = 'alpha' order by b + c; - k (+0+8"@TISCAN(BPLUSCBYE [EQUALS promote(@c14 AS STRING)]) | MAP (_.A AS A, _.B + _.C AS SUM) + unnamed-2GEXPLAIN select a, b + c AS sum from t where e = 'alpha' order by b + c; +ڐn غ(+0+8"@TISCAN(BPLUSCBYE [EQUALS promote(@c14 AS STRING)]) | MAP (_.A AS A, _.B + _.C AS SUM) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q2.A AS A, q2.B + q2.C AS SUM)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 2 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c14 AS STRING)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 3 [ label=<
    Index
    BPLUSCBYE
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; + 1 [ label=<
    Value Computation
    MAP (q2.A AS A, q2.B + q2.C AS SUM)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS SUM)" ]; + 2 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c14 AS STRING)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B, LONG AS C, LONG AS D, STRING AS E)" ]; + 3 [ label=<
    Index
    BPLUSCBYE
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B, LONG AS C, LONG AS D, STRING AS E)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} 5 - unnamed-2(EXPLAIN select * from t where d & 1 = 0; - -(K08a@ -,ISCAN(DMASK1 [EQUALS promote(@c10 AS LONG)])digraph G { + unnamed-2(EXPLAIN select * from t where d & 1 = 0; + (K08a@ +,ISCAN(DMASK1 [EQUALS promote(@c10 AS LONG)])digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c10 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 2 [ label=<
    Index
    DMASK1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; + 1 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c10 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B, LONG AS C, LONG AS D, STRING AS E)" ]; + 2 [ label=<
    Index
    DMASK1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B, LONG AS C, LONG AS D, STRING AS E)" ]; 2 -> 1 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} 5 - unnamed-2(EXPLAIN select * from t where d & 2 = 0; -ϳ -(K08a@ -,ISCAN(DMASK2 [EQUALS promote(@c10 AS LONG)])digraph G { + unnamed-2(EXPLAIN select * from t where d & 2 = 0; + (K08a@ +,ISCAN(DMASK2 [EQUALS promote(@c10 AS LONG)])digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c10 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 2 [ label=<
    Index
    DMASK2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; + 1 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c10 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B, LONG AS C, LONG AS D, STRING AS E)" ]; + 2 [ label=<
    Index
    DMASK2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B, LONG AS C, LONG AS D, STRING AS E)" ]; 2 -> 1 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; } \ No newline at end of file diff --git a/yaml-tests/src/test/resources/indexed-functions.metrics.yaml b/yaml-tests/src/test/resources/indexed-functions.metrics.yaml index d758a1c971..be2f15e882 100644 --- a/yaml-tests/src/test/resources/indexed-functions.metrics.yaml +++ b/yaml-tests/src/test/resources/indexed-functions.metrics.yaml @@ -2,9 +2,9 @@ unnamed-2: - query: EXPLAIN select * from t where b + c > 7; explain: ISCAN(BPLUSC [[GREATER_THAN promote(@c10 AS LONG)]]) task_count: 836 - task_total_time_ms: 58 - transform_count: 269 - transform_time_ms: 19 + task_total_time_ms: 59 + transform_count: 272 + transform_time_ms: 17 transform_yield_count: 75 insert_time_ms: 3 insert_new_count: 97 @@ -13,9 +13,9 @@ unnamed-2: explain: ISCAN(BPLUSCBYE [EQUALS promote(@c14 AS STRING)]) | MAP (_.A AS A, _.B + _.C AS SUM) task_count: 339 - task_total_time_ms: 28 - transform_count: 107 - transform_time_ms: 14 + task_total_time_ms: 31 + transform_count: 110 + transform_time_ms: 15 transform_yield_count: 43 insert_time_ms: 0 insert_new_count: 34 @@ -23,19 +23,19 @@ unnamed-2: - query: EXPLAIN select * from t where d & 1 = 0; explain: ISCAN(DMASK1 [EQUALS promote(@c10 AS LONG)]) task_count: 836 - task_total_time_ms: 62 - transform_count: 270 - transform_time_ms: 22 + task_total_time_ms: 59 + transform_count: 273 + transform_time_ms: 16 transform_yield_count: 75 - insert_time_ms: 10 + insert_time_ms: 9 insert_new_count: 97 insert_reused_count: 10 - query: EXPLAIN select * from t where d & 2 = 0; explain: ISCAN(DMASK2 [EQUALS promote(@c10 AS LONG)]) task_count: 836 - task_total_time_ms: 61 - transform_count: 270 - transform_time_ms: 21 + task_total_time_ms: 59 + transform_count: 273 + transform_time_ms: 17 transform_yield_count: 75 insert_time_ms: 3 insert_new_count: 97 diff --git a/yaml-tests/src/test/resources/null-operator-tests.metrics.binpb b/yaml-tests/src/test/resources/null-operator-tests.metrics.binpb index 00391fc441..05302e58b8 100644 --- a/yaml-tests/src/test/resources/null-operator-tests.metrics.binpb +++ b/yaml-tests/src/test/resources/null-operator-tests.metrics.binpb @@ -1,23 +1,23 @@ - + v -null-operator-tests_EXPLAIN select count(*) from (select * from (select * from T1) as x where ID is not null) as y; -6 ($08:@COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.ID NOT_NULL | FETCH | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +null-operator-tests_EXPLAIN select count(*) from (select * from (select * from T1) as x where ID is not null) as y; + ($0+8:@COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.ID NOT_NULL | FETCH | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q10._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q10 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q6 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Fetch Records
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Predicate Filter
    WHERE q42.ID NOT_NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 7 [ label=<
    Covering Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 8 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 4 [ label=<
    Value Computation
    MAP (q6 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Fetch Records
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Predicate Filter
    WHERE q46.ID NOT_NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 7 [ label=<
    Covering Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 8 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q10> label="q10" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q49> label="q49" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q53> label="q53" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q44> label="q44" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q42> label="q42" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q48> label="q48" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q46> label="q46" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q10> label="q10" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; } \ No newline at end of file diff --git a/yaml-tests/src/test/resources/null-operator-tests.metrics.yaml b/yaml-tests/src/test/resources/null-operator-tests.metrics.yaml index 32497670e9..a4d206f9f2 100644 --- a/yaml-tests/src/test/resources/null-operator-tests.metrics.yaml +++ b/yaml-tests/src/test/resources/null-operator-tests.metrics.yaml @@ -5,10 +5,10 @@ null-operator-tests: | FETCH | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)' task_count: 499 - task_total_time_ms: 114 - transform_count: 157 - transform_time_ms: 62 + task_total_time_ms: 9 + transform_count: 160 + transform_time_ms: 2 transform_yield_count: 36 - insert_time_ms: 7 + insert_time_ms: 0 insert_new_count: 58 insert_reused_count: 5 diff --git a/yaml-tests/src/test/resources/orderby.metrics.binpb b/yaml-tests/src/test/resources/orderby.metrics.binpb index 6232b7fcb8..ee4258aa25 100644 --- a/yaml-tests/src/test/resources/orderby.metrics.binpb +++ b/yaml-tests/src/test/resources/orderby.metrics.binpb @@ -1,69 +1,71 @@ - + 4 - orderby-tests#EXPLAIN select c from t1 order by b -L (!0 8@cCOVERING(I1 <,> -> [A: KEY[2], B: KEY[0], C: VALUE[0]]) | MAP (_.C AS C, _.B AS B) | MAP (_.C AS C) digraph G { + orderby-tests#EXPLAIN select c from t1 order by b +֚O ލ(!0 +8@cCOVERING(I1 <,> -> [A: KEY[2], B: KEY[0], C: VALUE[0]]) | MAP (_.C AS C, _.B AS B) | MAP (_.C AS C) digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6.C AS C)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C)" ]; - 2 [ label=<
    Value Computation
    MAP (q39.C AS C, q39.B AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C, )" ]; - 3 [ label=<
    Covering Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 4 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 3 -> 2 [ label=< q39> label="q39" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 [ label=<
    Value Computation
    MAP (q40.C AS C, q40.B AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C, LONG AS B)" ]; + 3 [ label=<
    Covering Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B, LONG AS C)" ]; + 4 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B, LONG AS C)" ]; + 3 -> 2 [ label=< q40> label="q40" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} 4 - orderby-tests#EXPLAIN select b from t1 order by c -l ֣(*098,@cCOVERING(I2 <,> -> [A: KEY[2], B: VALUE[0], C: KEY[0]]) | MAP (_.B AS B, _.C AS C) | MAP (_.B AS B) digraph G { + orderby-tests#EXPLAIN select b from t1 order by c +o (*088,@cCOVERING(I2 <,> -> [A: KEY[2], B: VALUE[0], C: KEY[0]]) | MAP (_.B AS B, _.C AS C) | MAP (_.B AS B) digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6.B AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS B)" ]; - 2 [ label=<
    Value Computation
    MAP (q46.B AS B, q46.C AS C)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS B, )" ]; - 3 [ label=<
    Covering Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 4 [ label=<
    Index
    I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 3 -> 2 [ label=< q46> label="q46" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 [ label=<
    Value Computation
    MAP (q48.B AS B, q48.C AS C)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS B, LONG AS C)" ]; + 3 [ label=<
    Covering Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B, LONG AS C)" ]; + 4 [ label=<
    Index
    I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B, LONG AS C)" ]; + 3 -> 2 [ label=< q48> label="q48" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} 9 - orderby-tests(EXPLAIN select c from t1 order by b desc - L (!08@kCOVERING(I1 <,> REVERSE -> [A: KEY[2], B: KEY[0], C: VALUE[0]]) | MAP (_.C AS C, _.B AS B) | MAP (_.C AS C) digraph G { + orderby-tests(EXPLAIN select c from t1 order by b desc +戒O (!08@kCOVERING(I1 <,> REVERSE -> [A: KEY[2], B: KEY[0], C: VALUE[0]]) | MAP (_.C AS C, _.B AS B) | MAP (_.C AS C)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6.C AS C)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C)" ]; - 2 [ label=<
    Value Computation
    MAP (q39.C AS C, q39.B AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C, )" ]; - 3 [ label=<
    Covering Index Scan
    range: <-∞, ∞>
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 4 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 3 -> 2 [ label=< q39> label="q39" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 [ label=<
    Value Computation
    MAP (q40.C AS C, q40.B AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C, LONG AS B)" ]; + 3 [ label=<
    Covering Index Scan
    range: <-∞, ∞>
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B, LONG AS C)" ]; + 4 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B, LONG AS C)" ]; + 3 -> 2 [ label=< q40> label="q40" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} 9 - orderby-tests(EXPLAIN select b from t1 order by c desc -ؿl (*0,8,@kCOVERING(I2 <,> REVERSE -> [A: KEY[2], B: VALUE[0], C: KEY[0]]) | MAP (_.B AS B, _.C AS C) | MAP (_.B AS B) digraph G { + orderby-tests(EXPLAIN select b from t1 order by c desc +o ߐ(*0Ҳ58,@kCOVERING(I2 <,> REVERSE -> [A: KEY[2], B: VALUE[0], C: KEY[0]]) | MAP (_.B AS B, _.C AS C) | MAP (_.B AS B)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6.B AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS B)" ]; - 2 [ label=<
    Value Computation
    MAP (q46.B AS B, q46.C AS C)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS B, )" ]; - 3 [ label=<
    Covering Index Scan
    range: <-∞, ∞>
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 4 [ label=<
    Index
    I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 3 -> 2 [ label=< q46> label="q46" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 [ label=<
    Value Computation
    MAP (q48.B AS B, q48.C AS C)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS B, LONG AS C)" ]; + 3 [ label=<
    Covering Index Scan
    range: <-∞, ∞>
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B, LONG AS C)" ]; + 4 [ label=<
    Index
    I2
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B, LONG AS C)" ]; + 3 -> 2 [ label=< q48> label="q48" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} @ - orderby-tests/EXPLAIN select c, b from t5 order by c, b desc; -չ8 (08@vCOVERING(I8 <,> -> [A: KEY[3], B: from_ordered_bytes(KEY:[1], DESC_NULLS_LAST), C: KEY[0]]) | MAP (_.C AS C, _.B AS B) digraph G { + orderby-tests/EXPLAIN select c, b from t5 order by c, b desc; +̞; (08@vCOVERING(I8 <,> -> [A: KEY[3], B: from_ordered_bytes(KEY:[1], DESC_NULLS_LAST), C: KEY[0]]) | MAP (_.C AS C, _.B AS B) +digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q25.C AS C, q25.B AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C, )" ]; - 2 [ label=<
    Covering Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 3 [ label=<
    Index
    I8
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; + 1 [ label=<
    Value Computation
    MAP (q26.C AS C, q26.B AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C, LONG AS B)" ]; + 2 [ label=<
    Covering Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B, LONG AS C)" ]; + 3 [ label=<
    Index
    I8
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B, LONG AS C)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 2 -> 1 [ label=< q25> label="q25" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 -> 1 [ label=< q26> label="q26" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; } \ No newline at end of file diff --git a/yaml-tests/src/test/resources/orderby.metrics.yaml b/yaml-tests/src/test/resources/orderby.metrics.yaml index d4c301b80d..0eddec4850 100644 --- a/yaml-tests/src/test/resources/orderby.metrics.yaml +++ b/yaml-tests/src/test/resources/orderby.metrics.yaml @@ -4,7 +4,7 @@ orderby-tests: C, _.B AS B) | MAP (_.C AS C)' task_count: 241 task_total_time_ms: 4 - transform_count: 76 + transform_count: 79 transform_time_ms: 2 transform_yield_count: 33 insert_time_ms: 0 @@ -14,9 +14,9 @@ orderby-tests: explain: 'COVERING(I2 <,> -> [A: KEY[2], B: VALUE[0], C: KEY[0]]) | MAP (_.B AS B, _.C AS C) | MAP (_.B AS B)' task_count: 363 - task_total_time_ms: 17 - transform_count: 108 - transform_time_ms: 6 + task_total_time_ms: 18 + transform_count: 111 + transform_time_ms: 7 transform_yield_count: 42 insert_time_ms: 0 insert_new_count: 44 @@ -25,9 +25,9 @@ orderby-tests: explain: 'COVERING(I1 <,> REVERSE -> [A: KEY[2], B: KEY[0], C: VALUE[0]]) | MAP (_.C AS C, _.B AS B) | MAP (_.C AS C)' task_count: 241 - task_total_time_ms: 19 - transform_count: 76 - transform_time_ms: 12 + task_total_time_ms: 12 + transform_count: 79 + transform_time_ms: 5 transform_yield_count: 33 insert_time_ms: 0 insert_new_count: 22 @@ -36,9 +36,9 @@ orderby-tests: explain: 'COVERING(I2 <,> REVERSE -> [A: KEY[2], B: VALUE[0], C: KEY[0]]) | MAP (_.B AS B, _.C AS C) | MAP (_.B AS B)' task_count: 363 - task_total_time_ms: 15 - transform_count: 108 - transform_time_ms: 5 + task_total_time_ms: 17 + transform_count: 111 + transform_time_ms: 6 transform_yield_count: 42 insert_time_ms: 0 insert_new_count: 44 @@ -47,8 +47,8 @@ orderby-tests: explain: 'COVERING(I8 <,> -> [A: KEY[3], B: from_ordered_bytes(KEY:[1], DESC_NULLS_LAST), C: KEY[0]]) | MAP (_.C AS C, _.B AS B)' task_count: 185 - task_total_time_ms: 9 - transform_count: 56 + task_total_time_ms: 10 + transform_count: 59 transform_time_ms: 5 transform_yield_count: 20 insert_time_ms: 0 diff --git a/yaml-tests/src/test/resources/primary-key-tests.metrics.binpb b/yaml-tests/src/test/resources/primary-key-tests.metrics.binpb index a9ff43c359..278b738a44 100644 --- a/yaml-tests/src/test/resources/primary-key-tests.metrics.binpb +++ b/yaml-tests/src/test/resources/primary-key-tests.metrics.binpb @@ -1,18 +1,18 @@ - + 4 -primary-key-testsEXPLAIN SELECT COUNT(*) FROM T1 -%W (0ܛ8@SCAN(<,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +primary-key-testsEXPLAIN SELECT COUNT(*) FROM T1 +Z F(0 8@SCAN(<,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, AS ID, AS _0)" ]; - 5 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, AS ID, )" ]; - 6 [ label=<
    Primary Storage
    record types: [T1]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, AS ID, )" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B, LONG AS Q, LONG AS Z AS ID, LONG AS G AS _0)" ]; + 5 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B, LONG AS Q, LONG AS Z AS ID, LONG AS G)" ]; + 6 [ label=<
    Primary Storage
    record types: [T1]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B, LONG AS Q, LONG AS Z AS ID, LONG AS G)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q25> label="q25" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; diff --git a/yaml-tests/src/test/resources/primary-key-tests.metrics.yaml b/yaml-tests/src/test/resources/primary-key-tests.metrics.yaml index 8f905ed66a..f77644c539 100644 --- a/yaml-tests/src/test/resources/primary-key-tests.metrics.yaml +++ b/yaml-tests/src/test/resources/primary-key-tests.metrics.yaml @@ -3,10 +3,10 @@ primary-key-tests: explain: SCAN(<,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 249 - task_total_time_ms: 78 - transform_count: 87 - transform_time_ms: 60 + task_total_time_ms: 2 + transform_count: 90 + transform_time_ms: 1 transform_yield_count: 15 - insert_time_ms: 4 + insert_time_ms: 0 insert_new_count: 20 insert_reused_count: 2 diff --git a/yaml-tests/src/test/resources/recursive-cte.metrics.binpb b/yaml-tests/src/test/resources/recursive-cte.metrics.binpb index d562cdd5b0..e0ed288b47 100644 --- a/yaml-tests/src/test/resources/recursive-cte.metrics.binpb +++ b/yaml-tests/src/test/resources/recursive-cte.metrics.binpb @@ -1,72 +1,72 @@ -2 +4  -recursive-cte-testsEXPLAIN with recursive c1 as ( select id, parent from t1 where parent = -1 union all select b.id, b.parent from c1 as a, t1 as b where a.id = b.parent) select id from c11 - ٴ (Z0b8@ RUNION q0, q1 { INITIAL { ISCAN(PARENTIDX [EQUALS promote(@c15 AS LONG)]) | INSERT INTO TEMP q1 } RECURSIVE { ISCAN(CHILDIDX <,>) | FLATMAP q2 -> { TEMP SCAN base() | FILTER _.ID EQUALS q2.PARENT AS q3 RETURN (q2.ID AS ID, q2.PARENT AS PARENT) } | INSERT INTO TEMP q1 }} | MAP (_.ID AS ID).digraph G { +recursive-cte-testsEXPLAIN with recursive c1 as ( select id, parent from t1 where parent = -1 union all select b.id, b.parent from c1 as a, t1 as b where a.id = b.parent) select id from c12 + Ր (Z0T8@ RUNION q0, q1 { INITIAL { ISCAN(PARENTIDX [EQUALS promote(@c15 AS LONG)]) | INSERT INTO TEMP q1 } RECURSIVE { ISCAN(CHILDIDX <,>) | FLATMAP q2 -> { TEMP SCAN base() | FILTER _.ID EQUALS q2.PARENT AS q3 RETURN (q2.ID AS ID, q2.PARENT AS PARENT) } | INSERT INTO TEMP q1 }} | MAP (_.ID AS ID)0digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q20.ID AS ID)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID)" ]; - 2 [ label=<
    Recursive Union
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS ID, )" ]; - 3 [ label=<
    Modification
    TempTableInsert
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 4 [ label=<
    Modification
    TempTableInsert
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 5 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c15 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Temporary Buffer
    C1forInsert
    > color="black" shape="plain" style="filled" fillcolor="goldenrod2" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 7 [ label=<
    Nested Loop Join
    FLATMAP (q10.ID AS ID, q10.PARENT AS PARENT)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 8 [ label=<
    Temporary Buffer
    C1forInsert
    > color="black" shape="plain" style="filled" fillcolor="goldenrod2" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 9 [ label=<
    Index
    PARENTIDX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 10 [ label=<
    Predicate Filter
    WHERE q8.ID EQUALS q10.PARENT
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 11 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 12 [ label=<
    Temp Table Scan
    C1forScan
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 13 [ label=<
    Index
    CHILDIDX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q176> label="q176" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 2 [ label=< q178> label="q178" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="none" arrowtail="normal" dir="both" ]; + 2 [ label=<
    Recursive Union
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 3 [ label=<
    Modification
    TempTableInsert
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 4 [ label=<
    Modification
    TempTableInsert
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 5 [ label=<
    Temporary Buffer
    C1forInsert
    > color="black" shape="plain" style="filled" fillcolor="goldenrod2" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 6 [ label=<
    Nested Loop Join
    FLATMAP (q10.ID AS ID, q10.PARENT AS PARENT)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 7 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c15 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 8 [ label=<
    Temporary Buffer
    C1forInsert
    > color="black" shape="plain" style="filled" fillcolor="goldenrod2" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 9 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 10 [ label=<
    Predicate Filter
    WHERE q8.ID EQUALS q10.PARENT
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 11 [ label=<
    Index
    PARENTIDX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 12 [ label=<
    Index
    CHILDIDX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 13 [ label=<
    Temp Table Scan
    C1forScan
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 3 -> 2 [ label=< q193> label="q193" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 2 [ label=< q191> label="q191" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="none" arrowtail="normal" dir="both" ]; + 6 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="none" arrowtail="normal" dir="both" ]; - 9 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 10 -> 7 [ label=< q8> label="q8" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 11 -> 7 [ label=< q10> label="q10" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 12 -> 10 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 13 -> 11 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 9 -> 6 [ label=< q10> label="q10" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 10 -> 6 [ label=< q8> label="q8" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 11 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 12 -> 9 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 13 -> 10 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q20> label="q20" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; { rank=same; rankDir=LR; - 11 -> 10 [ color="red" style="invis" ]; + 9 -> 10 [ color="red" style="invis" ]; } { rank=same; rankDir=LR; - 7 -> 8 [ color="red" style="invis" ]; + 6 -> 5 [ color="red" style="invis" ]; } { rank=same; rankDir=LR; - 5 -> 6 [ color="red" style="invis" ]; + 7 -> 8 [ color="red" style="invis" ]; } -}2 +}4  -recursive-cte-testsEXPLAIN with recursive c1 as ( select id, parent from t1 where id = 250 union all select b.id, b.parent from c1 as a, t1 as b where a.parent = b.id) select id from c11 -  (Z0K8@ RUNION q0, q1 { INITIAL { ISCAN(CHILDIDX [EQUALS promote(@c15 AS LONG)]) | INSERT INTO TEMP q1 } RECURSIVE { ISCAN(CHILDIDX <,>) | FLATMAP q2 -> { TEMP SCAN base() | FILTER _.PARENT EQUALS q2.ID AS q3 RETURN (q2.ID AS ID, q2.PARENT AS PARENT) } | INSERT INTO TEMP q1 }} | MAP (_.ID AS ID).digraph G { +recursive-cte-testsEXPLAIN with recursive c1 as ( select id, parent from t1 where id = 250 union all select b.id, b.parent from c1 as a, t1 as b where a.parent = b.id) select id from c12 +  ׄ(Z0L8@ RUNION q0, q1 { INITIAL { ISCAN(CHILDIDX [EQUALS promote(@c15 AS LONG)]) | INSERT INTO TEMP q1 } RECURSIVE { ISCAN(CHILDIDX <,>) | FLATMAP q2 -> { TEMP SCAN base() | FILTER _.PARENT EQUALS q2.ID AS q3 RETURN (q2.ID AS ID, q2.PARENT AS PARENT) } | INSERT INTO TEMP q1 }} | MAP (_.ID AS ID)0digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q20.ID AS ID)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID)" ]; - 2 [ label=<
    Recursive Union
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS ID, )" ]; - 3 [ label=<
    Modification
    TempTableInsert
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 4 [ label=<
    Modification
    TempTableInsert
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 5 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c15 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Temporary Buffer
    C1forInsert
    > color="black" shape="plain" style="filled" fillcolor="goldenrod2" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 7 [ label=<
    Nested Loop Join
    FLATMAP (q10.ID AS ID, q10.PARENT AS PARENT)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 8 [ label=<
    Temporary Buffer
    C1forInsert
    > color="black" shape="plain" style="filled" fillcolor="goldenrod2" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 9 [ label=<
    Index
    CHILDIDX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 10 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 11 [ label=<
    Predicate Filter
    WHERE q8.PARENT EQUALS q10.ID
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 12 [ label=<
    Index
    CHILDIDX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 13 [ label=<
    Temp Table Scan
    C1forScan
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q176> label="q176" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 2 [ label=< q178> label="q178" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 [ label=<
    Recursive Union
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 3 [ label=<
    Modification
    TempTableInsert
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 4 [ label=<
    Modification
    TempTableInsert
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 5 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c15 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 6 [ label=<
    Temporary Buffer
    C1forInsert
    > color="black" shape="plain" style="filled" fillcolor="goldenrod2" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 7 [ label=<
    Nested Loop Join
    FLATMAP (q10.ID AS ID, q10.PARENT AS PARENT)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 8 [ label=<
    Temporary Buffer
    C1forInsert
    > color="black" shape="plain" style="filled" fillcolor="goldenrod2" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 9 [ label=<
    Index
    CHILDIDX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 10 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 11 [ label=<
    Predicate Filter
    WHERE q8.PARENT EQUALS q10.ID
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 12 [ label=<
    Index
    CHILDIDX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 13 [ label=<
    Temp Table Scan
    C1forScan
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 3 -> 2 [ label=< q191> label="q191" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 2 [ label=< q193> label="q193" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="none" arrowtail="normal" dir="both" ]; 7 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; @@ -80,51 +80,51 @@ { rank=same; rankDir=LR; - 10 -> 11 [ color="red" style="invis" ]; + 5 -> 6 [ color="red" style="invis" ]; } { rank=same; rankDir=LR; - 5 -> 6 [ color="red" style="invis" ]; + 10 -> 11 [ color="red" style="invis" ]; } { rank=same; rankDir=LR; 7 -> 8 [ color="red" style="invis" ]; } -}` +}b  -recursive-cte-testsEXPLAIN with recursive allDescendants as ( with recursive ancestorsOf250 as ( select id, parent from t1 where id = 250 union all select b.id, b.parent from ancestorsOf250 as a, t1 as b where a.parent = b.id) select id, parent from ancestorsOf250 union all select b.id, b.parent from allDescendants as a, t1 as b where a.id = b.parent) select id, parent from allDescendants\ -Ԋ ꁄ(0w8@RUNION q0, q1 { INITIAL { RUNION q2, q3 { INITIAL { ISCAN(CHILDIDX [EQUALS promote(@c20 AS LONG)]) | INSERT INTO TEMP q3 } RECURSIVE { ISCAN(CHILDIDX <,>) | FLATMAP q4 -> { TEMP SCAN base() | FILTER _.PARENT EQUALS q4.ID AS q5 RETURN (q4.ID AS ID, q4.PARENT AS PARENT) } | INSERT INTO TEMP q3 }} | MAP (_.ID AS ID, _.PARENT AS PARENT) | INSERT INTO TEMP q1 } RECURSIVE { ISCAN(CHILDIDX <,>) | FLATMAP q6 -> { TEMP SCAN base() | FILTER _.ID EQUALS q6.PARENT AS q7 RETURN (q6.ID AS ID, q6.PARENT AS PARENT) } | INSERT INTO TEMP q1 }} | MAP (_.ID AS ID, _.PARENT AS PARENT)Xdigraph G { +recursive-cte-testsEXPLAIN with recursive allDescendants as ( with recursive ancestorsOf250 as ( select id, parent from t1 where id = 250 union all select b.id, b.parent from ancestorsOf250 as a, t1 as b where a.parent = b.id) select id, parent from ancestorsOf250 union all select b.id, b.parent from allDescendants as a, t1 as b where a.id = b.parent) select id, parent from allDescendants_ + (0s8@RUNION q0, q1 { INITIAL { RUNION q2, q3 { INITIAL { ISCAN(CHILDIDX [EQUALS promote(@c20 AS LONG)]) | INSERT INTO TEMP q3 } RECURSIVE { ISCAN(CHILDIDX <,>) | FLATMAP q4 -> { TEMP SCAN base() | FILTER _.PARENT EQUALS q4.ID AS q5 RETURN (q4.ID AS ID, q4.PARENT AS PARENT) } | INSERT INTO TEMP q3 }} | MAP (_.ID AS ID, _.PARENT AS PARENT) | INSERT INTO TEMP q1 } RECURSIVE { ISCAN(CHILDIDX <,>) | FLATMAP q6 -> { TEMP SCAN base() | FILTER _.ID EQUALS q6.PARENT AS q7 RETURN (q6.ID AS ID, q6.PARENT AS PARENT) } | INSERT INTO TEMP q1 }} | MAP (_.ID AS ID, _.PARENT AS PARENT)Zdigraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q38.ID AS ID, q38.PARENT AS PARENT)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 2 [ label=<
    Recursive Union
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS ID, )" ]; - 3 [ label=<
    Modification
    TempTableInsert
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 4 [ label=<
    Modification
    TempTableInsert
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 5 [ label=<
    Value Computation
    MAP (q20.ID AS ID, q20.PARENT AS PARENT)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Temporary Buffer
    ALLDESCENDANTSforInsert
    > color="black" shape="plain" style="filled" fillcolor="goldenrod2" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 7 [ label=<
    Nested Loop Join
    FLATMAP (q28.ID AS ID, q28.PARENT AS PARENT)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 8 [ label=<
    Temporary Buffer
    ALLDESCENDANTSforInsert
    > color="black" shape="plain" style="filled" fillcolor="goldenrod2" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 9 [ label=<
    Recursive Union
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS ID, )" ]; - 10 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 11 [ label=<
    Predicate Filter
    WHERE q26.ID EQUALS q28.PARENT
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 12 [ label=<
    Modification
    TempTableInsert
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 13 [ label=<
    Modification
    TempTableInsert
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 14 [ label=<
    Index
    CHILDIDX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 15 [ label=<
    Temp Table Scan
    ALLDESCENDANTSforScan
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 16 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c20 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 17 [ label=<
    Temporary Buffer
    ANCESTORSOF250forInsert
    > color="black" shape="plain" style="filled" fillcolor="goldenrod2" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 18 [ label=<
    Temporary Buffer
    ANCESTORSOF250forInsert
    > color="black" shape="plain" style="filled" fillcolor="goldenrod2" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 19 [ label=<
    Nested Loop Join
    FLATMAP (q10.ID AS ID, q10.PARENT AS PARENT)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 20 [ label=<
    Index
    CHILDIDX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 21 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 22 [ label=<
    Predicate Filter
    WHERE q8.PARENT EQUALS q10.ID
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 23 [ label=<
    Index
    CHILDIDX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 24 [ label=<
    Temp Table Scan
    ANCESTORSOF250forScan
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q269> label="q269" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 2 [ label=< q271> label="q271" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 1 [ label=<
    Value Computation
    MAP (q38.ID AS ID, q38.PARENT AS PARENT)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 2 [ label=<
    Recursive Union
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 3 [ label=<
    Modification
    TempTableInsert
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 4 [ label=<
    Modification
    TempTableInsert
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 5 [ label=<
    Value Computation
    MAP (q20.ID AS ID, q20.PARENT AS PARENT)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 6 [ label=<
    Temporary Buffer
    ALLDESCENDANTSforInsert
    > color="black" shape="plain" style="filled" fillcolor="goldenrod2" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 7 [ label=<
    Nested Loop Join
    FLATMAP (q28.ID AS ID, q28.PARENT AS PARENT)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 8 [ label=<
    Temporary Buffer
    ALLDESCENDANTSforInsert
    > color="black" shape="plain" style="filled" fillcolor="goldenrod2" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 9 [ label=<
    Recursive Union
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 10 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 11 [ label=<
    Predicate Filter
    WHERE q26.ID EQUALS q28.PARENT
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 12 [ label=<
    Modification
    TempTableInsert
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 13 [ label=<
    Modification
    TempTableInsert
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 14 [ label=<
    Index
    CHILDIDX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 15 [ label=<
    Temp Table Scan
    ALLDESCENDANTSforScan
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 16 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c20 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 17 [ label=<
    Temporary Buffer
    ANCESTORSOF250forInsert
    > color="black" shape="plain" style="filled" fillcolor="goldenrod2" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 18 [ label=<
    Nested Loop Join
    FLATMAP (q10.ID AS ID, q10.PARENT AS PARENT)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 19 [ label=<
    Temporary Buffer
    ANCESTORSOF250forInsert
    > color="black" shape="plain" style="filled" fillcolor="goldenrod2" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 20 [ label=<
    Index
    CHILDIDX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 21 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 22 [ label=<
    Predicate Filter
    WHERE q8.PARENT EQUALS q10.ID
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 23 [ label=<
    Index
    CHILDIDX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 24 [ label=<
    Temp Table Scan
    ANCESTORSOF250forScan
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS PARENT)" ]; + 3 -> 2 [ label=< q290> label="q290" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 2 [ label=< q292> label="q292" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="none" arrowtail="normal" dir="both" ]; 7 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; @@ -132,34 +132,34 @@ 9 -> 5 [ label=< q20> label="q20" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 10 -> 7 [ label=< q28> label="q28" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 11 -> 7 [ label=< q26> label="q26" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 12 -> 9 [ label=< q263> label="q263" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 13 -> 9 [ label=< q265> label="q265" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 12 -> 9 [ label=< q284> label="q284" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 13 -> 9 [ label=< q286> label="q286" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 14 -> 10 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 15 -> 11 [ label=< q26> label="q26" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 16 -> 12 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 17 -> 12 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="none" arrowtail="normal" dir="both" ]; - 18 -> 13 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="none" arrowtail="normal" dir="both" ]; - 19 -> 13 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 18 -> 13 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 19 -> 13 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="none" arrowtail="normal" dir="both" ]; 20 -> 16 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 21 -> 19 [ label=< q10> label="q10" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 22 -> 19 [ label=< q8> label="q8" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 21 -> 18 [ label=< q10> label="q10" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 22 -> 18 [ label=< q8> label="q8" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 23 -> 21 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 24 -> 22 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q38> label="q38" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; { rank=same; rankDir=LR; - 7 -> 8 [ color="red" style="invis" ]; + 21 -> 22 [ color="red" style="invis" ]; } { rank=same; rankDir=LR; - 19 -> 18 [ color="red" style="invis" ]; + 5 -> 6 [ color="red" style="invis" ]; } { rank=same; rankDir=LR; - 5 -> 6 [ color="red" style="invis" ]; + 16 -> 17 [ color="red" style="invis" ]; } { rank=same; @@ -169,11 +169,11 @@ { rank=same; rankDir=LR; - 16 -> 17 [ color="red" style="invis" ]; + 18 -> 19 [ color="red" style="invis" ]; } { rank=same; rankDir=LR; - 21 -> 22 [ color="red" style="invis" ]; + 7 -> 8 [ color="red" style="invis" ]; } } \ No newline at end of file diff --git a/yaml-tests/src/test/resources/recursive-cte.metrics.yaml b/yaml-tests/src/test/resources/recursive-cte.metrics.yaml index 4180745c45..a65354de30 100644 --- a/yaml-tests/src/test/resources/recursive-cte.metrics.yaml +++ b/yaml-tests/src/test/resources/recursive-cte.metrics.yaml @@ -7,9 +7,9 @@ recursive-cte-tests: TEMP SCAN base() | FILTER _.ID EQUALS q2.PARENT AS q3 RETURN (q2.ID AS ID, q2.PARENT AS PARENT) } | INSERT INTO TEMP q1 }} | MAP (_.ID AS ID) task_count: 1586 - task_total_time_ms: 16 - transform_count: 403 - transform_time_ms: 7 + task_total_time_ms: 15 + transform_count: 409 + transform_time_ms: 6 transform_yield_count: 90 insert_time_ms: 1 insert_new_count: 368 @@ -22,8 +22,8 @@ recursive-cte-tests: TEMP SCAN base() | FILTER _.PARENT EQUALS q2.ID AS q3 RETURN (q2.ID AS ID, q2.PARENT AS PARENT) } | INSERT INTO TEMP q1 }} | MAP (_.ID AS ID) task_count: 1586 - task_total_time_ms: 11 - transform_count: 403 + task_total_time_ms: 12 + transform_count: 409 transform_time_ms: 4 transform_yield_count: 90 insert_time_ms: 1 @@ -44,7 +44,7 @@ recursive-cte-tests: TEMP q1 }} | MAP (_.ID AS ID, _.PARENT AS PARENT) task_count: 2407 task_total_time_ms: 18 - transform_count: 615 + transform_count: 623 transform_time_ms: 6 transform_yield_count: 128 insert_time_ms: 1 @@ -58,9 +58,9 @@ recursive-cte-tests: TEMP SCAN base() | FILTER _.ID EQUALS q2.PARENT AS q3 RETURN (q2.ID AS ID, q2.PARENT AS PARENT) } | INSERT INTO TEMP q1 }} | MAP (_.ID AS ID) task_count: 1586 - task_total_time_ms: 16 - transform_count: 403 - transform_time_ms: 7 + task_total_time_ms: 15 + transform_count: 409 + transform_time_ms: 6 transform_yield_count: 90 insert_time_ms: 1 insert_new_count: 368 @@ -80,7 +80,7 @@ recursive-cte-tests: TEMP q1 }} | MAP (_.ID AS ID, _.PARENT AS PARENT) task_count: 2407 task_total_time_ms: 18 - transform_count: 615 + transform_count: 623 transform_time_ms: 6 transform_yield_count: 128 insert_time_ms: 1 diff --git a/yaml-tests/src/test/resources/select-a-star.metrics.binpb b/yaml-tests/src/test/resources/select-a-star.metrics.binpb index 3ef2056746..83090698e2 100644 --- a/yaml-tests/src/test/resources/select-a-star.metrics.binpb +++ b/yaml-tests/src/test/resources/select-a-star.metrics.binpb @@ -1,28 +1,28 @@ -+ +- e -select-star-testsPEXPLAIN select B1 from B where exists (select A.*, B1 from A group by A1,A2,A3);* -5 ͞"($08&@SCAN(<,>) | TFILTER B | FLATMAP q0 -> { ISCAN(A_IDX <,>) | MAP (_ AS _0) | AGG () GROUP BY (_._0.A1 AS _0, _._0.A2 AS _1, _._0.A3 AS _2) | MAP (_._0._0 AS A1, _._0._1 AS A2, _._0._2 AS A3, q0.B1 AS B1) | DEFAULT NULL | FILTER _ NOT_NULL AS q0 RETURN (q0.B1 AS B1) }(digraph G { +select-star-testsPEXPLAIN select B1 from B where exists (select A.*, B1 from A group by A1,A2,A3);, +  ($0+8&@SCAN(<,>) | TFILTER B | FLATMAP q0 -> { ISCAN(A_IDX <,>) | MAP (_ AS _0) | AGG () GROUP BY (_._0.A1 AS _0, _._0.A2 AS _1, _._0.A3 AS _2) | MAP (_._0._0 AS A1, _._0._1 AS A2, _._0._2 AS A3, q0.B1 AS B1) | DEFAULT NULL | FILTER _ NOT_NULL AS q0 RETURN (q0.B1 AS B1) }*digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Nested Loop Join
    FLATMAP (q2.B1 AS B1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS B1)" ]; - 2 [ label=<
    Type Filter
    WHERE record IS [B]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS B1, )" ]; + 2 [ label=<
    Type Filter
    WHERE record IS [B]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS B1, LONG AS B2, LONG AS S1, LONG AS S2 AS B3)" ]; 3 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 4 [ label=<
    Primary Storage
    record types: [A, B]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q14 NOT_NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; - 6 [ label=<
    Value Computation
    FIRST $q14 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; - 7 [ label=<
    Value Computation
    MAP (q10._0._0 AS A1, q10._0._1 AS A2, q10._0._2 AS A3, q2.B1 AS B1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; - 8 [ label=<
    Streaming Aggregate
    COLLECT ()
    GROUP BY (q48._0.A1 AS _0, q48._0.A2 AS _1, q48._0.A3 AS _2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, AS _0, )" ]; - 9 [ label=<
    Value Computation
    MAP (q6 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, AS _0)" ]; - 10 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; - 11 [ label=<
    Index
    A_IDX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; - 3 -> 2 [ label=< q52> label="q52" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 [ label=<
    Predicate Filter
    WHERE q14 NOT_NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3, LONG AS B1)" ]; + 6 [ label=<
    Value Computation
    FIRST $q14 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3, LONG AS B1)" ]; + 7 [ label=<
    Value Computation
    MAP (q10._0._0 AS A1, q10._0._1 AS A2, q10._0._2 AS A3, q2.B1 AS B1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3, LONG AS B1)" ]; + 8 [ label=<
    Streaming Aggregate
    COLLECT ()
    GROUP BY (q50._0.A1 AS _0, q50._0.A2 AS _1, q50._0.A3 AS _2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1, LONG AS _2 AS _0, AS _1)" ]; + 9 [ label=<
    Value Computation
    MAP (q6 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3 AS _0)" ]; + 10 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; + 11 [ label=<
    Index
    A_IDX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; + 3 -> 2 [ label=< q55> label="q55" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q14> label="q14" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ label=< q14> label="q14" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ label=< q10> label="q10" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 9 -> 8 [ label=< q48> label="q48" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 9 -> 8 [ label=< q50> label="q50" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 10 -> 9 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 11 -> 10 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 1 [ label=< q14> label="q14" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; @@ -31,31 +31,31 @@ e rankDir=LR; 2 -> 5 [ color="red" style="invis" ]; } -}+ +}. g -select-star-testsREXPLAIN select B.* from B where exists (select A.*, B.* from A group by A1,A2,A3);* -  ($0F8&@SCAN(<,>) | TFILTER B | FLATMAP q0 -> { ISCAN(A_IDX <,>) | MAP (_ AS _0) | AGG () GROUP BY (_._0.A1 AS _0, _._0.A2 AS _1, _._0.A3 AS _2) | MAP (_._0._0 AS A1, _._0._1 AS A2, _._0._2 AS A3, q0.B1 AS B1, q0.B2 AS B2, q0.B3 AS B3) | DEFAULT NULL | FILTER _ NOT_NULL AS q0 RETURN q0 }(digraph G { +select-star-testsREXPLAIN select B.* from B where exists (select A.*, B.* from A group by A1,A2,A3);- +  ($0&8&@SCAN(<,>) | TFILTER B | FLATMAP q0 -> { ISCAN(A_IDX <,>) | MAP (_ AS _0) | AGG () GROUP BY (_._0.A1 AS _0, _._0.A2 AS _1, _._0.A3 AS _2) | MAP (_._0._0 AS A1, _._0._1 AS A2, _._0._2 AS A3, q0.B1 AS B1, q0.B2 AS B2, q0.B3 AS B3) | DEFAULT NULL | FILTER _ NOT_NULL AS q0 RETURN q0 }+digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Nested Loop Join
    FLATMAP q2
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS B1, )" ]; - 2 [ label=<
    Type Filter
    WHERE record IS [B]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS B1, )" ]; + 1 [ label=<
    Nested Loop Join
    FLATMAP q2
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS B1, LONG AS B2, LONG AS S1, LONG AS S2 AS B3)" ]; + 2 [ label=<
    Type Filter
    WHERE record IS [B]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS B1, LONG AS B2, LONG AS S1, LONG AS S2 AS B3)" ]; 3 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 4 [ label=<
    Primary Storage
    record types: [A, B]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q14 NOT_NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; - 6 [ label=<
    Value Computation
    FIRST $q14 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; - 7 [ label=<
    Value Computation
    MAP (q10._0._0 AS A1, q10._0._1 AS A2, q10._0._2 AS A3, q2.B1 AS B1, q2.B2 AS B2, q2.B3 AS B3)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; - 8 [ label=<
    Streaming Aggregate
    COLLECT ()
    GROUP BY (q48._0.A1 AS _0, q48._0.A2 AS _1, q48._0.A3 AS _2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, AS _0, )" ]; - 9 [ label=<
    Value Computation
    MAP (q6 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, AS _0)" ]; - 10 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; - 11 [ label=<
    Index
    A_IDX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; - 3 -> 2 [ label=< q52> label="q52" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 [ label=<
    Predicate Filter
    WHERE q14 NOT_NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3, LONG AS B1, LONG AS B2, LONG AS S1, LONG AS S2 AS B3)" ]; + 6 [ label=<
    Value Computation
    FIRST $q14 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3, LONG AS B1, LONG AS B2, LONG AS S1, LONG AS S2 AS B3)" ]; + 7 [ label=<
    Value Computation
    MAP (q10._0._0 AS A1, q10._0._1 AS A2, q10._0._2 AS A3, q2.B1 AS B1, q2.B2 AS B2, q2.B3 AS B3)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3, LONG AS B1, LONG AS B2, LONG AS S1, LONG AS S2 AS B3)" ]; + 8 [ label=<
    Streaming Aggregate
    COLLECT ()
    GROUP BY (q50._0.A1 AS _0, q50._0.A2 AS _1, q50._0.A3 AS _2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1, LONG AS _2 AS _0, AS _1)" ]; + 9 [ label=<
    Value Computation
    MAP (q6 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3 AS _0)" ]; + 10 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; + 11 [ label=<
    Index
    A_IDX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; + 3 -> 2 [ label=< q55> label="q55" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q14> label="q14" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ label=< q14> label="q14" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ label=< q10> label="q10" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 9 -> 8 [ label=< q48> label="q48" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 9 -> 8 [ label=< q50> label="q50" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 10 -> 9 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 11 -> 10 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 1 [ label=< q14> label="q14" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; diff --git a/yaml-tests/src/test/resources/select-a-star.metrics.yaml b/yaml-tests/src/test/resources/select-a-star.metrics.yaml index 5ea814676c..3396311fe0 100644 --- a/yaml-tests/src/test/resources/select-a-star.metrics.yaml +++ b/yaml-tests/src/test/resources/select-a-star.metrics.yaml @@ -5,11 +5,11 @@ select-star-tests: (_._0._0 AS A1, _._0._1 AS A2, _._0._2 AS A3, q0.B1 AS B1) | DEFAULT NULL | FILTER _ NOT_NULL AS q0 RETURN (q0.B1 AS B1) } task_count: 445 - task_total_time_ms: 112 - transform_count: 145 - transform_time_ms: 71 + task_total_time_ms: 26 + transform_count: 151 + transform_time_ms: 10 transform_yield_count: 36 - insert_time_ms: 6 + insert_time_ms: 0 insert_new_count: 38 insert_reused_count: 4 - query: EXPLAIN select B1 from B where exists (select A.*, B1 from A group by A1,A2,A3); @@ -18,11 +18,11 @@ select-star-tests: (_._0._0 AS A1, _._0._1 AS A2, _._0._2 AS A3, q0.B1 AS B1) | DEFAULT NULL | FILTER _ NOT_NULL AS q0 RETURN (q0.B1 AS B1) } task_count: 445 - task_total_time_ms: 112 - transform_count: 145 - transform_time_ms: 71 + task_total_time_ms: 26 + transform_count: 151 + transform_time_ms: 10 transform_yield_count: 36 - insert_time_ms: 6 + insert_time_ms: 0 insert_new_count: 38 insert_reused_count: 4 - query: EXPLAIN select B.* from B where exists (select A.*, B.* from A group by @@ -32,10 +32,10 @@ select-star-tests: (_._0._0 AS A1, _._0._1 AS A2, _._0._2 AS A3, q0.B1 AS B1, q0.B2 AS B2, q0.B3 AS B3) | DEFAULT NULL | FILTER _ NOT_NULL AS q0 RETURN q0 } task_count: 445 - task_total_time_ms: 27 - transform_count: 145 - transform_time_ms: 11 + task_total_time_ms: 20 + transform_count: 151 + transform_time_ms: 7 transform_yield_count: 36 - insert_time_ms: 1 + insert_time_ms: 0 insert_new_count: 38 insert_reused_count: 4 diff --git a/yaml-tests/src/test/resources/standard-tests-metadata.metrics.binpb b/yaml-tests/src/test/resources/standard-tests-metadata.metrics.binpb index a5ceff0fad..d6ce115245 100644 --- a/yaml-tests/src/test/resources/standard-tests-metadata.metrics.binpb +++ b/yaml-tests/src/test/resources/standard-tests-metadata.metrics.binpb @@ -1,18 +1,18 @@ - +  -standard-tests-metadatamEXPLAIN select count(*) from (select * from (select * from (select * from T1 where ID = 5) as x) as y) as z; -խ/ (08@SCAN([EQUALS promote(@c23 AS LONG)]) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +standard-tests-metadatamEXPLAIN select count(*) from (select * from (select * from (select * from T1 where ID = 5) as x) as y) as z; + H(0 8@SCAN([EQUALS promote(@c23 AS LONG)]) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q12._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q12 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q8 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Scan
    comparisons: [EQUALS promote(@c23 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Primary Storage
    record types: [T1]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 4 [ label=<
    Value Computation
    MAP (q8 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Scan
    comparisons: [EQUALS promote(@c23 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Primary Storage
    record types: [T1]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q12> label="q12" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q30> label="q30" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q32> label="q32" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q12> label="q12" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; diff --git a/yaml-tests/src/test/resources/standard-tests-metadata.metrics.yaml b/yaml-tests/src/test/resources/standard-tests-metadata.metrics.yaml index 231aff59f2..f614fb9d69 100644 --- a/yaml-tests/src/test/resources/standard-tests-metadata.metrics.yaml +++ b/yaml-tests/src/test/resources/standard-tests-metadata.metrics.yaml @@ -5,10 +5,10 @@ standard-tests-metadata: AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 395 - task_total_time_ms: 99 - transform_count: 142 - transform_time_ms: 65 + task_total_time_ms: 6 + transform_count: 145 + transform_time_ms: 1 transform_yield_count: 22 - insert_time_ms: 6 + insert_time_ms: 0 insert_new_count: 31 insert_reused_count: 1 diff --git a/yaml-tests/src/test/resources/standard-tests-proto.metrics.binpb b/yaml-tests/src/test/resources/standard-tests-proto.metrics.binpb index cb21c4fc4e9c12a1b8468f4a18392cd16a51d4e6..076f478249e5a15dad4213bbd991c6970065870c 100644 GIT binary patch delta 609 zcmeA%Uu?-Vk!SKrR_}?vq7v)5xggsypctW5#p)@ zh?CYc3apsX#4O>au;D>4&`EpGaZaq!=QT0{IRoSXO{qJZ>)E;)@t8^-w@u#2GIO#Z zcP-OyiOCbVYo+#xb4hV@GYd4#y~rvtkx}8sx;{n?F@x^q3X?T>7BMx5O>SUYIypel zbn`OaG8R0}+bkpG&8UnNm}o((siY8V&847VHd&B2fj|IGUM#Ym$H-10Cow5C$5yG( zc=CCX;>|ZjmohT$n_MqmA#s!)7|&Cg1nw?g#3+%j(0a>GL)hR+2kT@(31g;TY+yI9 WVN#yVCwUN`lg~@q;05@_+Rp|O&I*4zH>d&) z`MK{s$PjDBzRf4ux)~ALHw$o!F*3aqpRB=CEB#)KOPZsbS>XK4<34)ozvCV{Qn-daecDE$7sMN>oA;L*I< gjFZ1e7&9GX1DQYhoaB?qc^sLO1z0XmR+4E10K710+W-In diff --git a/yaml-tests/src/test/resources/standard-tests-proto.metrics.yaml b/yaml-tests/src/test/resources/standard-tests-proto.metrics.yaml index a05e55caad..7161b4a10f 100644 --- a/yaml-tests/src/test/resources/standard-tests-proto.metrics.yaml +++ b/yaml-tests/src/test/resources/standard-tests-proto.metrics.yaml @@ -3,22 +3,22 @@ unnamed-2: 5) as y; explain: SCAN(<,>) | FILTER _.ID EQUALS promote(@c19 AS LONG) task_count: 178 - task_total_time_ms: 108 - transform_count: 66 - transform_time_ms: 77 + task_total_time_ms: 5 + transform_count: 69 + transform_time_ms: 1 transform_yield_count: 12 - insert_time_ms: 4 + insert_time_ms: 0 insert_new_count: 9 insert_reused_count: 1 - query: EXPLAIN select * from (select * from (select * from T1) as x) as y where ID = 5; explain: SCAN(<,>) | FILTER _.ID EQUALS promote(@c22 AS LONG) task_count: 175 - task_total_time_ms: 102 - transform_count: 67 - transform_time_ms: 78 + task_total_time_ms: 6 + transform_count: 70 + transform_time_ms: 1 transform_yield_count: 12 - insert_time_ms: 3 + insert_time_ms: 0 insert_new_count: 9 insert_reused_count: 1 - query: EXPLAIN select count(*) from (select * from (select * from (select * from @@ -27,21 +27,21 @@ unnamed-2: AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) task_count: 395 - task_total_time_ms: 106 - transform_count: 142 - transform_time_ms: 65 + task_total_time_ms: 11 + transform_count: 145 + transform_time_ms: 2 transform_yield_count: 22 - insert_time_ms: 3 + insert_time_ms: 0 insert_new_count: 31 insert_reused_count: 1 - query: EXPLAIN select * from (select * from (select * from (select * from T1 where ID > 10) as x) as y) as z; explain: SCAN([[GREATER_THAN promote(@c20 AS LONG)]]) task_count: 277 - task_total_time_ms: 119 - transform_count: 100 - transform_time_ms: 86 + task_total_time_ms: 2 + transform_count: 103 + transform_time_ms: 1 transform_yield_count: 19 - insert_time_ms: 2 + insert_time_ms: 0 insert_new_count: 16 insert_reused_count: 0 diff --git a/yaml-tests/src/test/resources/standard-tests.metrics.binpb b/yaml-tests/src/test/resources/standard-tests.metrics.binpb index fbaf83bdc7..44b2d33bd6 100644 --- a/yaml-tests/src/test/resources/standard-tests.metrics.binpb +++ b/yaml-tests/src/test/resources/standard-tests.metrics.binpb @@ -1,92 +1,89 @@ - +  -standard-testsnEXPLAIN select id, case when col1 = 10 then 100 when col2 in (6,7,8,9) then 200 else 300 end as NEWCOL from T1 -G ľ(08@ISCAN(I1 <,>) | MAP (_.ID AS ID, pick(ConditionSelector(_.COL1 equals @c8, _.COL2 IN promote(@c14 AS ARRAY(LONG)), TRUE), @c10, @c24, @c26) AS NEWCOL) -digraph G { +standard-testsnEXPLAIN select id, case when col1 = 10 then 100 when col2 in (6,7,8,9) then 200 else 300 end as NEWCOL from T1 +J Ӗ(0܅'8@ISCAN(I1 <,>) | MAP (_.ID AS ID, pick(ConditionSelector(_.COL1 equals @c8, _.COL2 IN promote(@c14 AS ARRAY(LONG)), TRUE), @c10, @c24, @c26) AS NEWCOL) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q2.ID AS ID, pick(ConditionSelector(q2.COL1 equals @c8, q2.COL2 IN promote(@c14 AS ARRAY(LONG)), TRUE), @c10, @c24, @c26) AS NEWCOL)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 2 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q2.ID AS ID, pick(ConditionSelector(q2.COL1 equals @c8, q2.COL2 IN promote(@c14 AS ARRAY(LONG)), TRUE), @c10, @c24, @c26) AS NEWCOL)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, INT AS NEWCOL)" ]; + 2 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} w -standard-testseEXPLAIN select id, case when col1 = 10 then 100 when col2 in (6,7,8,9) then 200 end as NEWCOL from T1 -G (08@ISCAN(I1 <,>) | MAP (_.ID AS ID, pick(ConditionSelector(_.COL1 equals @c8, _.COL2 IN promote(@c14 AS ARRAY(LONG))), @c10, @c24) AS NEWCOL) -digraph G { +standard-testseEXPLAIN select id, case when col1 = 10 then 100 when col2 in (6,7,8,9) then 200 end as NEWCOL from T1 +J (0 8@ISCAN(I1 <,>) | MAP (_.ID AS ID, pick(ConditionSelector(_.COL1 equals @c8, _.COL2 IN promote(@c14 AS ARRAY(LONG))), @c10, @c24) AS NEWCOL) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q2.ID AS ID, pick(ConditionSelector(q2.COL1 equals @c8, q2.COL2 IN promote(@c14 AS ARRAY(LONG))), @c10, @c24) AS NEWCOL)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 2 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q2.ID AS ID, pick(ConditionSelector(q2.COL1 equals @c8, q2.COL2 IN promote(@c14 AS ARRAY(LONG))), @c10, @c24) AS NEWCOL)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, INT AS NEWCOL)" ]; + 2 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} b -standard-testsPEXPLAIN select * from (select * from (select * from T1) as x where ID = 5) as y; -Ζ:m +(0Ŀ8@aCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.ID EQUALS promote(@c19 AS LONG) | FETCH digraph G { +standard-testsPEXPLAIN select * from (select * from (select * from T1) as x where ID = 5) as y; +ʿp Ϟ(0,8@aCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.ID EQUALS promote(@c19 AS LONG) | FETCHdigraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Fetch Records
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS ID, )" ]; - 2 [ label=<
    Predicate Filter
    WHERE q38.ID EQUALS promote(@c19 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 [ label=<
    Covering Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 4 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q38> label="q38" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 1 [ label=<
    Fetch Records
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 2 [ label=<
    Predicate Filter
    WHERE q42.ID EQUALS promote(@c19 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 [ label=<
    Covering Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 4 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 -> 2 [ label=< q42> label="q42" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 2 -> 1 [ label=< q40> label="q40" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} + 2 -> 1 [ label=< q44> label="q44" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +} b -standard-testsPEXPLAIN select * from (select * from (select * from T1) as x) as y where ID = 5; -ȱ -p (058@aCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.ID EQUALS promote(@c22 AS LONG) | FETCH digraph G { +standard-testsPEXPLAIN select * from (select * from (select * from T1) as x) as y where ID = 5; +s (048@aCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.ID EQUALS promote(@c22 AS LONG) | FETCHdigraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Fetch Records
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS ID, )" ]; - 2 [ label=<
    Predicate Filter
    WHERE q38.ID EQUALS promote(@c22 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 [ label=<
    Covering Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 4 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q38> label="q38" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 1 [ label=<
    Fetch Records
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 2 [ label=<
    Predicate Filter
    WHERE q42.ID EQUALS promote(@c22 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 [ label=<
    Covering Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 4 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 -> 2 [ label=< q42> label="q42" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 2 -> 1 [ label=< q40> label="q40" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} + 2 -> 1 [ label=< q44> label="q44" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}  -standard-testsmEXPLAIN select count(*) from (select * from (select * from (select * from T1 where ID = 5) as x) as y) as z; -B .(-08L@COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.ID EQUALS promote(@c23 AS LONG) | FETCH | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { +standard-testsmEXPLAIN select count(*) from (select * from (select * from (select * from T1 where ID = 5) as x) as y) as z; + 㺭(-0t8L@COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.ID EQUALS promote(@c23 AS LONG) | FETCH | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (coalesce_long(q12._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
    Value Computation
    $q12 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q8 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Fetch Records
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Predicate Filter
    WHERE q38.ID EQUALS promote(@c23 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 7 [ label=<
    Covering Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 8 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 4 [ label=<
    Value Computation
    MAP (q8 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Fetch Records
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Predicate Filter
    WHERE q40.ID EQUALS promote(@c23 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 7 [ label=<
    Covering Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 8 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q12> label="q12" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q59> label="q59" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q63> label="q63" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q40> label="q40" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q38> label="q38" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q42> label="q42" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q40> label="q40" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q12> label="q12" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} y -standard-testsgEXPLAIN select * from (select * from (select * from (select * from T1 where ID > 10) as x) as y) as z; -@ /('081@gCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.ID GREATER_THAN promote(@c20 AS LONG) | FETCH digraph G { +standard-testsgEXPLAIN select * from (select * from (select * from (select * from T1 where ID > 10) as x) as y) as z; + Μ('0F81@gCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.ID GREATER_THAN promote(@c20 AS LONG) | FETCHdigraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Fetch Records
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS ID, )" ]; - 2 [ label=<
    Predicate Filter
    WHERE q34.ID GREATER_THAN promote(@c20 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 [ label=<
    Covering Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 4 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 -> 2 [ label=< q34> label="q34" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 1 [ label=<
    Fetch Records
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 2 [ label=<
    Predicate Filter
    WHERE q36.ID GREATER_THAN promote(@c20 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 [ label=<
    Covering Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 4 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 -> 2 [ label=< q36> label="q36" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 2 -> 1 [ label=< q36> label="q36" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 -> 1 [ label=< q38> label="q38" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; } \ No newline at end of file diff --git a/yaml-tests/src/test/resources/standard-tests.metrics.yaml b/yaml-tests/src/test/resources/standard-tests.metrics.yaml index 46d3609a3c..9a7be2dc1f 100644 --- a/yaml-tests/src/test/resources/standard-tests.metrics.yaml +++ b/yaml-tests/src/test/resources/standard-tests.metrics.yaml @@ -4,11 +4,11 @@ standard-tests: explain: ISCAN(I1 <,>) | MAP (_.ID AS ID, pick(ConditionSelector(_.COL1 equals @c8, _.COL2 IN promote(@c14 AS ARRAY(LONG)), TRUE), @c10, @c24, @c26) AS NEWCOL) task_count: 213 - task_total_time_ms: 66 - transform_count: 71 - transform_time_ms: 38 + task_total_time_ms: 15 + transform_count: 74 + transform_time_ms: 5 transform_yield_count: 22 - insert_time_ms: 4 + insert_time_ms: 0 insert_new_count: 21 insert_reused_count: 3 - query: EXPLAIN select id, case when col1 = 10 then 100 when col2 in (6,7,8,9) @@ -16,11 +16,11 @@ standard-tests: explain: ISCAN(I1 <,>) | MAP (_.ID AS ID, pick(ConditionSelector(_.COL1 equals @c8, _.COL2 IN promote(@c14 AS ARRAY(LONG))), @c10, @c24) AS NEWCOL) task_count: 213 - task_total_time_ms: 66 - transform_count: 71 - transform_time_ms: 39 + task_total_time_ms: 12 + transform_count: 74 + transform_time_ms: 5 transform_yield_count: 22 - insert_time_ms: 3 + insert_time_ms: 0 insert_new_count: 21 insert_reused_count: 3 - query: EXPLAIN select * from (select * from (select * from T1) as x where ID = @@ -28,11 +28,11 @@ standard-tests: explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.ID EQUALS promote(@c19 AS LONG) | FETCH' task_count: 350 - task_total_time_ms: 122 - transform_count: 109 - transform_time_ms: 90 + task_total_time_ms: 13 + transform_count: 112 + transform_time_ms: 4 transform_yield_count: 30 - insert_time_ms: 4 + insert_time_ms: 0 insert_new_count: 31 insert_reused_count: 4 - query: EXPLAIN select * from (select * from (select * from T1) as x) as y where @@ -40,9 +40,9 @@ standard-tests: explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.ID EQUALS promote(@c22 AS LONG) | FETCH' task_count: 344 - task_total_time_ms: 21 - transform_count: 112 - transform_time_ms: 6 + task_total_time_ms: 15 + transform_count: 115 + transform_time_ms: 4 transform_yield_count: 30 insert_time_ms: 0 insert_new_count: 31 @@ -53,11 +53,11 @@ standard-tests: promote(@c23 AS LONG) | FETCH | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)' task_count: 704 - task_total_time_ms: 139 - transform_count: 212 - transform_time_ms: 97 + task_total_time_ms: 18 + transform_count: 215 + transform_time_ms: 7 transform_yield_count: 45 - insert_time_ms: 7 + insert_time_ms: 1 insert_new_count: 76 insert_reused_count: 5 - query: EXPLAIN select * from (select * from (select * from (select * from T1 where @@ -65,10 +65,10 @@ standard-tests: explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.ID GREATER_THAN promote(@c20 AS LONG) | FETCH' task_count: 555 - task_total_time_ms: 135 - transform_count: 164 - transform_time_ms: 100 + task_total_time_ms: 18 + transform_count: 167 + transform_time_ms: 5 transform_yield_count: 39 - insert_time_ms: 5 + insert_time_ms: 1 insert_new_count: 49 insert_reused_count: 4 diff --git a/yaml-tests/src/test/resources/subquery-tests.metrics.binpb b/yaml-tests/src/test/resources/subquery-tests.metrics.binpb index 3526d993d9..2ccbca5418 100644 --- a/yaml-tests/src/test/resources/subquery-tests.metrics.binpb +++ b/yaml-tests/src/test/resources/subquery-tests.metrics.binpb @@ -1,29 +1,30 @@ -) +* [ -subquery-testsIEXPLAIN select ida from a where exists (select ida from a where ida = 1);) -  (0g88@SCAN(<,>) | TFILTER A | FILTER _.IDA EQUALS promote(@c15 AS INT) | MAP (_.IDA AS IDA) | DEFAULT NULL | FLATMAP q0 -> { SCAN(<,>) | TFILTER A | FILTER q0 NOT_NULL AS q1 RETURN (q1.IDA AS IDA) }'digraph G { +subquery-testsIEXPLAIN select ida from a where exists (select ida from a where ida = 1);) + + џ(0ɨQ88@SCAN(<,>) | TFILTER A | FILTER _.IDA EQUALS promote(@c15 AS INT) | MAP (_.IDA AS IDA) | DEFAULT NULL | FLATMAP q0 -> { SCAN(<,>) | TFILTER A | FILTER q0 NOT_NULL AS q1 RETURN (q1.IDA AS IDA) }'digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Nested Loop Join
    FLATMAP (q2.IDA AS IDA)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDA)" ]; 2 [ label=<
    Value Computation
    FIRST $q8 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDA)" ]; - 3 [ label=<
    Value Computation
    MAP (q25.IDA AS IDA)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDA)" ]; - 4 [ label=<
    Predicate Filter
    WHERE q4.IDA EQUALS promote(@c15 AS INT)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDA, )" ]; - 5 [ label=<
    Type Filter
    WHERE record IS [A]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDA, )" ]; + 3 [ label=<
    Value Computation
    MAP (q26.IDA AS IDA)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDA)" ]; + 4 [ label=<
    Predicate Filter
    WHERE q4.IDA EQUALS promote(@c15 AS INT)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDA, INT AS X)" ]; + 5 [ label=<
    Type Filter
    WHERE record IS [A]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDA, INT AS X)" ]; 6 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 7 [ label=<
    Primary Storage
    record types: [X, A, B, R]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 8 [ label=<
    Predicate Filter
    WHERE q8 NOT_NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDA, )" ]; - 9 [ label=<
    Type Filter
    WHERE record IS [A]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDA, )" ]; + 8 [ label=<
    Predicate Filter
    WHERE q8 NOT_NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDA, INT AS X)" ]; + 9 [ label=<
    Type Filter
    WHERE record IS [A]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDA, INT AS X)" ]; 10 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 11 [ label=<
    Primary Storage
    record types: [X, A, B, R]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q25> label="q25" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q26> label="q26" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q21> label="q21" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q22> label="q22" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q8> label="q8" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 9 -> 8 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 10 -> 9 [ label=< q21> label="q21" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 10 -> 9 [ label=< q22> label="q22" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 11 -> 10 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 1 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; { @@ -31,32 +32,32 @@ rankDir=LR; 2 -> 8 [ color="red" style="invis" ]; } -}) +}* Y -subquery-testsGEXPLAIN select idx from x where exists (select x from a where ida = 1);) -@ ر'('0ÿ8>@SCAN(<,>) | TFILTER A | FILTER _.IDA EQUALS promote(@c15 AS INT) | MAP (_.X AS X) | DEFAULT NULL | FLATMAP q0 -> { SCAN(<,>) | TFILTER X | FILTER q0 NOT_NULL AS q1 RETURN (q1.IDX AS IDX) }'digraph G { +subquery-testsGEXPLAIN select idx from x where exists (select x from a where ida = 1);) +  ʨ('0[8>@SCAN(<,>) | TFILTER A | FILTER _.IDA EQUALS promote(@c15 AS INT) | MAP (_.X AS X) | DEFAULT NULL | FLATMAP q0 -> { SCAN(<,>) | TFILTER X | FILTER q0 NOT_NULL AS q1 RETURN (q1.IDX AS IDX) }'digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Nested Loop Join
    FLATMAP (q2.IDX AS IDX)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDX)" ]; 2 [ label=<
    Value Computation
    FIRST $q10 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS X)" ]; - 3 [ label=<
    Value Computation
    MAP (q33.X AS X)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS X)" ]; - 4 [ label=<
    Predicate Filter
    WHERE q6.IDA EQUALS promote(@c15 AS INT)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDA, )" ]; - 5 [ label=<
    Type Filter
    WHERE record IS [A]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDA, )" ]; + 3 [ label=<
    Value Computation
    MAP (q34.X AS X)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS X)" ]; + 4 [ label=<
    Predicate Filter
    WHERE q6.IDA EQUALS promote(@c15 AS INT)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDA, INT AS X)" ]; + 5 [ label=<
    Type Filter
    WHERE record IS [A]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDA, INT AS X)" ]; 6 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 7 [ label=<
    Primary Storage
    record types: [X, A, B, R]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 8 [ label=<
    Predicate Filter
    WHERE q10 NOT_NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDX, )" ]; - 9 [ label=<
    Type Filter
    WHERE record IS [X]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDX, )" ]; + 8 [ label=<
    Predicate Filter
    WHERE q10 NOT_NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDX, INT AS Y)" ]; + 9 [ label=<
    Type Filter
    WHERE record IS [X]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDX, INT AS Y)" ]; 10 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 11 [ label=<
    Primary Storage
    record types: [X, A, B, R]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q10> label="q10" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q33> label="q33" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q34> label="q34" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q29> label="q29" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q30> label="q30" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q10> label="q10" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 9 -> 8 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 10 -> 9 [ label=< q43> label="q43" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 10 -> 9 [ label=< q46> label="q46" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 11 -> 10 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 1 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; { @@ -64,31 +65,31 @@ Y rankDir=LR; 2 -> 8 [ color="red" style="invis" ]; } -}* +}+ m -subquery-tests[EXPLAIN select x from a where exists (select a.x, max(idb) from b where q > a.x group by q)) -ԁ1 ((0莩84@SCAN(<,>) | TFILTER A | FLATMAP q0 -> { ISCAN(IB [[GREATER_THAN q0.X]]) | MAP (_ AS _0) | AGG (max_i(_._0.IDB) AS _0) GROUP BY (_._0.Q AS _0) | MAP (q0.X AS X, _._1._0 AS _1) | DEFAULT NULL | FILTER _ NOT_NULL AS q0 RETURN (q0.X AS X) }'digraph G { +subquery-tests[EXPLAIN select x from a where exists (select a.x, max(idb) from b where q > a.x group by q)* + ((0N84@SCAN(<,>) | TFILTER A | FLATMAP q0 -> { ISCAN(IB [[GREATER_THAN q0.X]]) | MAP (_ AS _0) | AGG (max_i(_._0.IDB) AS _0) GROUP BY (_._0.Q AS _0) | MAP (q0.X AS X, _._1._0 AS _1) | DEFAULT NULL | FILTER _ NOT_NULL AS q0 RETURN (q0.X AS X) }(digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Nested Loop Join
    FLATMAP (q2.X AS X)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS X)" ]; - 2 [ label=<
    Type Filter
    WHERE record IS [A]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDA, )" ]; + 2 [ label=<
    Type Filter
    WHERE record IS [A]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDA, INT AS X)" ]; 3 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 4 [ label=<
    Primary Storage
    record types: [X, A, B, R]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q14 NOT_NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS X, )" ]; - 6 [ label=<
    Value Computation
    FIRST $q14 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS X, )" ]; - 7 [ label=<
    Value Computation
    MAP (q2.X AS X, q10._1._0 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS X, )" ]; - 8 [ label=<
    Streaming Aggregate
    COLLECT (max_i(q56._0.IDB) AS _0)
    GROUP BY (q56._0.Q AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS _0 AS _0, )" ]; - 9 [ label=<
    Value Computation
    MAP (q6 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDB, AS _0)" ]; - 10 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN q2.X]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDB, )" ]; - 11 [ label=<
    Index
    IB
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDB, )" ]; - 3 -> 2 [ label=< q60> label="q60" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 [ label=<
    Predicate Filter
    WHERE q14 NOT_NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS X, INT AS _1)" ]; + 6 [ label=<
    Value Computation
    FIRST $q14 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS X, INT AS _1)" ]; + 7 [ label=<
    Value Computation
    MAP (q2.X AS X, q10._1._0 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS X, INT AS _1)" ]; + 8 [ label=<
    Streaming Aggregate
    COLLECT (max_i(q58._0.IDB) AS _0)
    GROUP BY (q58._0.Q AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS _0 AS _0, INT AS _0 AS _1)" ]; + 9 [ label=<
    Value Computation
    MAP (q6 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDB, INT AS Q, INT AS R AS _0)" ]; + 10 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN q2.X]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDB, INT AS Q, INT AS R)" ]; + 11 [ label=<
    Index
    IB
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDB, INT AS Q, INT AS R)" ]; + 3 -> 2 [ label=< q63> label="q63" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q14> label="q14" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ label=< q14> label="q14" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ label=< q10> label="q10" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 9 -> 8 [ label=< q56> label="q56" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 9 -> 8 [ label=< q58> label="q58" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 10 -> 9 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 11 -> 10 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 1 [ label=< q14> label="q14" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; @@ -97,31 +98,31 @@ m rankDir=LR; 2 -> 5 [ color="red" style="invis" ]; } -}* +}+ i -subquery-testsWEXPLAIN select x from a where exists (select x, max(idb) from b where q > x group by q)) -2 ((084@SCAN(<,>) | TFILTER A | FLATMAP q0 -> { ISCAN(IB [[GREATER_THAN q0.X]]) | MAP (_ AS _0) | AGG (max_i(_._0.IDB) AS _0) GROUP BY (_._0.Q AS _0) | MAP (q0.X AS X, _._1._0 AS _1) | DEFAULT NULL | FILTER _ NOT_NULL AS q0 RETURN (q0.X AS X) }'digraph G { +subquery-testsWEXPLAIN select x from a where exists (select x, max(idb) from b where q > x group by q)* + ((0F84@SCAN(<,>) | TFILTER A | FLATMAP q0 -> { ISCAN(IB [[GREATER_THAN q0.X]]) | MAP (_ AS _0) | AGG (max_i(_._0.IDB) AS _0) GROUP BY (_._0.Q AS _0) | MAP (q0.X AS X, _._1._0 AS _1) | DEFAULT NULL | FILTER _ NOT_NULL AS q0 RETURN (q0.X AS X) }(digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Nested Loop Join
    FLATMAP (q2.X AS X)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS X)" ]; - 2 [ label=<
    Type Filter
    WHERE record IS [A]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDA, )" ]; + 2 [ label=<
    Type Filter
    WHERE record IS [A]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDA, INT AS X)" ]; 3 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 4 [ label=<
    Primary Storage
    record types: [X, A, B, R]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q14 NOT_NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS X, )" ]; - 6 [ label=<
    Value Computation
    FIRST $q14 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS X, )" ]; - 7 [ label=<
    Value Computation
    MAP (q2.X AS X, q10._1._0 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS X, )" ]; - 8 [ label=<
    Streaming Aggregate
    COLLECT (max_i(q56._0.IDB) AS _0)
    GROUP BY (q56._0.Q AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS _0 AS _0, )" ]; - 9 [ label=<
    Value Computation
    MAP (q6 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDB, AS _0)" ]; - 10 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN q2.X]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDB, )" ]; - 11 [ label=<
    Index
    IB
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDB, )" ]; - 3 -> 2 [ label=< q60> label="q60" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 [ label=<
    Predicate Filter
    WHERE q14 NOT_NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS X, INT AS _1)" ]; + 6 [ label=<
    Value Computation
    FIRST $q14 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS X, INT AS _1)" ]; + 7 [ label=<
    Value Computation
    MAP (q2.X AS X, q10._1._0 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS X, INT AS _1)" ]; + 8 [ label=<
    Streaming Aggregate
    COLLECT (max_i(q58._0.IDB) AS _0)
    GROUP BY (q58._0.Q AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS _0 AS _0, INT AS _0 AS _1)" ]; + 9 [ label=<
    Value Computation
    MAP (q6 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDB, INT AS Q, INT AS R AS _0)" ]; + 10 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN q2.X]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDB, INT AS Q, INT AS R)" ]; + 11 [ label=<
    Index
    IB
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDB, INT AS Q, INT AS R)" ]; + 3 -> 2 [ label=< q63> label="q63" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q14> label="q14" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ label=< q14> label="q14" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ label=< q10> label="q10" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 9 -> 8 [ label=< q56> label="q56" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 9 -> 8 [ label=< q58> label="q58" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 10 -> 9 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 11 -> 10 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 1 [ label=< q14> label="q14" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; @@ -130,31 +131,31 @@ i rankDir=LR; 2 -> 5 [ color="red" style="invis" ]; } -}+ +}, n -subquery-tests\EXPLAIN select x from a where exists (select max(x), max(idb) from b where q > x group by q)* -0 ((0ؖ84@SCAN(<,>) | TFILTER A | FLATMAP q0 -> { ISCAN(IB [[GREATER_THAN q0.X]]) | MAP (_ AS _0) | AGG (max_i(q0.X) AS _0, max_i(_._0.IDB) AS _1) GROUP BY (_._0.Q AS _0) | MAP (_._1._0 AS _0, _._1._1 AS _1) | DEFAULT NULL | FILTER _ NOT_NULL AS q0 RETURN (q0.X AS X) }(digraph G { +subquery-tests\EXPLAIN select x from a where exists (select max(x), max(idb) from b where q > x group by q)+ + ߍ((0E84@SCAN(<,>) | TFILTER A | FLATMAP q0 -> { ISCAN(IB [[GREATER_THAN q0.X]]) | MAP (_ AS _0) | AGG (max_i(q0.X) AS _0, max_i(_._0.IDB) AS _1) GROUP BY (_._0.Q AS _0) | MAP (_._1._0 AS _0, _._1._1 AS _1) | DEFAULT NULL | FILTER _ NOT_NULL AS q0 RETURN (q0.X AS X) }(digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Nested Loop Join
    FLATMAP (q2.X AS X)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS X)" ]; - 2 [ label=<
    Type Filter
    WHERE record IS [A]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDA, )" ]; + 2 [ label=<
    Type Filter
    WHERE record IS [A]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDA, INT AS X)" ]; 3 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 4 [ label=<
    Primary Storage
    record types: [X, A, B, R]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q14 NOT_NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS _0, )" ]; - 6 [ label=<
    Value Computation
    FIRST $q14 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS _0, )" ]; - 7 [ label=<
    Value Computation
    MAP (q10._1._0 AS _0, q10._1._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS _0, )" ]; - 8 [ label=<
    Streaming Aggregate
    COLLECT (max_i(q2.X) AS _0, max_i(q56._0.IDB) AS _1)
    GROUP BY (q56._0.Q AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS _0 AS _0, )" ]; - 9 [ label=<
    Value Computation
    MAP (q6 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDB, AS _0)" ]; - 10 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN q2.X]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDB, )" ]; - 11 [ label=<
    Index
    IB
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDB, )" ]; - 3 -> 2 [ label=< q60> label="q60" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 [ label=<
    Predicate Filter
    WHERE q14 NOT_NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS _0, INT AS _1)" ]; + 6 [ label=<
    Value Computation
    FIRST $q14 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS _0, INT AS _1)" ]; + 7 [ label=<
    Value Computation
    MAP (q10._1._0 AS _0, q10._1._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS _0, INT AS _1)" ]; + 8 [ label=<
    Streaming Aggregate
    COLLECT (max_i(q2.X) AS _0, max_i(q58._0.IDB) AS _1)
    GROUP BY (q58._0.Q AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS _0 AS _0, INT AS _0, INT AS _1 AS _1)" ]; + 9 [ label=<
    Value Computation
    MAP (q6 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDB, INT AS Q, INT AS R AS _0)" ]; + 10 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN q2.X]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDB, INT AS Q, INT AS R)" ]; + 11 [ label=<
    Index
    IB
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDB, INT AS Q, INT AS R)" ]; + 3 -> 2 [ label=< q63> label="q63" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q14> label="q14" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ label=< q14> label="q14" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ label=< q10> label="q10" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 9 -> 8 [ label=< q56> label="q56" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 9 -> 8 [ label=< q58> label="q58" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 10 -> 9 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 11 -> 10 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 1 [ label=< q14> label="q14" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; @@ -163,31 +164,31 @@ n rankDir=LR; 2 -> 5 [ color="red" style="invis" ]; } -}+ +}, p -subquery-tests^EXPLAIN select x from a where exists (select max(a.x), max(idb) from b where q > x group by q)* - ((084@SCAN(<,>) | TFILTER A | FLATMAP q0 -> { ISCAN(IB [[GREATER_THAN q0.X]]) | MAP (_ AS _0) | AGG (max_i(q0.X) AS _0, max_i(_._0.IDB) AS _1) GROUP BY (_._0.Q AS _0) | MAP (_._1._0 AS _0, _._1._1 AS _1) | DEFAULT NULL | FILTER _ NOT_NULL AS q0 RETURN (q0.X AS X) }(digraph G { +subquery-tests^EXPLAIN select x from a where exists (select max(a.x), max(idb) from b where q > x group by q)+ + ((0M84@SCAN(<,>) | TFILTER A | FLATMAP q0 -> { ISCAN(IB [[GREATER_THAN q0.X]]) | MAP (_ AS _0) | AGG (max_i(q0.X) AS _0, max_i(_._0.IDB) AS _1) GROUP BY (_._0.Q AS _0) | MAP (_._1._0 AS _0, _._1._1 AS _1) | DEFAULT NULL | FILTER _ NOT_NULL AS q0 RETURN (q0.X AS X) }(digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Nested Loop Join
    FLATMAP (q2.X AS X)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS X)" ]; - 2 [ label=<
    Type Filter
    WHERE record IS [A]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDA, )" ]; + 2 [ label=<
    Type Filter
    WHERE record IS [A]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDA, INT AS X)" ]; 3 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 4 [ label=<
    Primary Storage
    record types: [X, A, B, R]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 5 [ label=<
    Predicate Filter
    WHERE q14 NOT_NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS _0, )" ]; - 6 [ label=<
    Value Computation
    FIRST $q14 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS _0, )" ]; - 7 [ label=<
    Value Computation
    MAP (q10._1._0 AS _0, q10._1._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS _0, )" ]; - 8 [ label=<
    Streaming Aggregate
    COLLECT (max_i(q2.X) AS _0, max_i(q56._0.IDB) AS _1)
    GROUP BY (q56._0.Q AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS _0 AS _0, )" ]; - 9 [ label=<
    Value Computation
    MAP (q6 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDB, AS _0)" ]; - 10 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN q2.X]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDB, )" ]; - 11 [ label=<
    Index
    IB
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDB, )" ]; - 3 -> 2 [ label=< q60> label="q60" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 [ label=<
    Predicate Filter
    WHERE q14 NOT_NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS _0, INT AS _1)" ]; + 6 [ label=<
    Value Computation
    FIRST $q14 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS _0, INT AS _1)" ]; + 7 [ label=<
    Value Computation
    MAP (q10._1._0 AS _0, q10._1._1 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS _0, INT AS _1)" ]; + 8 [ label=<
    Streaming Aggregate
    COLLECT (max_i(q2.X) AS _0, max_i(q58._0.IDB) AS _1)
    GROUP BY (q58._0.Q AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS _0 AS _0, INT AS _0, INT AS _1 AS _1)" ]; + 9 [ label=<
    Value Computation
    MAP (q6 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDB, INT AS Q, INT AS R AS _0)" ]; + 10 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN q2.X]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDB, INT AS Q, INT AS R)" ]; + 11 [ label=<
    Index
    IB
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS IDB, INT AS Q, INT AS R)" ]; + 3 -> 2 [ label=< q63> label="q63" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q14> label="q14" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ label=< q14> label="q14" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ label=< q10> label="q10" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 9 -> 8 [ label=< q56> label="q56" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 9 -> 8 [ label=< q58> label="q58" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 10 -> 9 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 11 -> 10 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 1 [ label=< q14> label="q14" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; diff --git a/yaml-tests/src/test/resources/subquery-tests.metrics.yaml b/yaml-tests/src/test/resources/subquery-tests.metrics.yaml index cc92bf20f4..9bb8e63f98 100644 --- a/yaml-tests/src/test/resources/subquery-tests.metrics.yaml +++ b/yaml-tests/src/test/resources/subquery-tests.metrics.yaml @@ -4,9 +4,9 @@ subquery-tests: (_.IDA AS IDA) | DEFAULT NULL | FLATMAP q0 -> { SCAN(<,>) | TFILTER A | FILTER q0 NOT_NULL AS q1 RETURN (q1.IDA AS IDA) } task_count: 576 - task_total_time_ms: 23 - transform_count: 168 - transform_time_ms: 5 + task_total_time_ms: 22 + transform_count: 173 + transform_time_ms: 4 transform_yield_count: 31 insert_time_ms: 1 insert_new_count: 56 @@ -16,11 +16,11 @@ subquery-tests: (_.X AS X) | DEFAULT NULL | FLATMAP q0 -> { SCAN(<,>) | TFILTER X | FILTER q0 NOT_NULL AS q1 RETURN (q1.IDX AS IDX) } task_count: 671 - task_total_time_ms: 135 - transform_count: 195 - transform_time_ms: 82 + task_total_time_ms: 26 + transform_count: 203 + transform_time_ms: 6 transform_yield_count: 39 - insert_time_ms: 7 + insert_time_ms: 1 insert_new_count: 62 insert_reused_count: 3 - query: EXPLAIN select x from a where exists (select a.x, max(idb) from b where @@ -30,11 +30,11 @@ subquery-tests: (q0.X AS X, _._1._0 AS _1) | DEFAULT NULL | FILTER _ NOT_NULL AS q0 RETURN (q0.X AS X) } task_count: 542 - task_total_time_ms: 104 - transform_count: 170 - transform_time_ms: 55 + task_total_time_ms: 34 + transform_count: 176 + transform_time_ms: 10 transform_yield_count: 40 - insert_time_ms: 2 + insert_time_ms: 1 insert_new_count: 52 insert_reused_count: 3 - query: EXPLAIN select x from a where exists (select x, max(idb) from b where q @@ -44,11 +44,11 @@ subquery-tests: (q0.X AS X, _._1._0 AS _1) | DEFAULT NULL | FILTER _ NOT_NULL AS q0 RETURN (q0.X AS X) } task_count: 542 - task_total_time_ms: 106 - transform_count: 170 - transform_time_ms: 56 + task_total_time_ms: 33 + transform_count: 176 + transform_time_ms: 10 transform_yield_count: 40 - insert_time_ms: 3 + insert_time_ms: 1 insert_new_count: 52 insert_reused_count: 3 - query: EXPLAIN select x from a where exists (select max(x), max(idb) from b where @@ -58,11 +58,11 @@ subquery-tests: (_._0.Q AS _0) | MAP (_._1._0 AS _0, _._1._1 AS _1) | DEFAULT NULL | FILTER _ NOT_NULL AS q0 RETURN (q0.X AS X) } task_count: 542 - task_total_time_ms: 102 - transform_count: 170 - transform_time_ms: 52 + task_total_time_ms: 30 + transform_count: 176 + transform_time_ms: 8 transform_yield_count: 40 - insert_time_ms: 3 + insert_time_ms: 1 insert_new_count: 52 insert_reused_count: 3 - query: EXPLAIN select x from a where exists (select max(a.x), max(idb) from b @@ -72,10 +72,10 @@ subquery-tests: (_._0.Q AS _0) | MAP (_._1._0 AS _0, _._1._1 AS _1) | DEFAULT NULL | FILTER _ NOT_NULL AS q0 RETURN (q0.X AS X) } task_count: 542 - task_total_time_ms: 33 - transform_count: 170 - transform_time_ms: 13 + task_total_time_ms: 31 + transform_count: 176 + transform_time_ms: 8 transform_yield_count: 40 - insert_time_ms: 2 + insert_time_ms: 1 insert_new_count: 52 insert_reused_count: 3 diff --git a/yaml-tests/src/test/resources/table-functions.metrics.binpb b/yaml-tests/src/test/resources/table-functions.metrics.binpb index 9396e2076059b2b5aaaed8248e5c5366df18f983..c1497bf6fe07abe28c84975076bf802b02ac581d 100644 GIT binary patch delta 1239 zcmX?5@VJEW+eF5Cv2UzgVjOk?Qy0ldh%4M`XVYLdxVDUO;`C)qyI3YO8ZMojAY(B3 zznI{}^}Um8NILUA2mKPV-T>#Dho+>?WZmxzHKl_Id@yP1Td!jsQz z8Y~7auNf!vikv6fIh+5B=}-_lXZRK(=UqxRh+rc1XS^;Vl%7qBqs4=O^U!Mf3gasYv)a1 zlmj!FZHU|C3%a6{`87l~Uso+*W;`<4M>9t3IS()xas-Y)i2w$}t6Q8JYzEt|u}?mr zIh$!4H!v9PO}5rv%<1C~$=FWtB;lvRGx@qM-{gCmqLY8=PT6dwdx44Z$z*PWH1WUu zT;d$fi~>ilmq-{ZOrEBv!D(>q8`I=2gHpzin+zu~iXlo0V6g!+J8JU;BO^v}gq*X# Wk0EkkCQQ~gxy*+uzxkhu6Egr*?{VS) delta 606 zcmaD{a-e|m@I=OX@x!cK;v9AYx0}~7N{B1WZIaMnHu!RkYvQzJOl>Ta7jj*lJXc6? z;=10+w!%G}no0_>)?BrhxF%OIw~C+U1Zs5=_^{~%mxQRovo9e)t%uHwO%`Q2%k-Rm z^FppR#>p3TX95innykmt2QqT5#DElmlPgv+Nhm5j`rx6#VsPsn=j2dPbOS)au{l>l8rhH! ze3PT3Hc0H_<&xk?5qLcHJu}ddcU!hI0!=wO)o-$b^lK)dmlkp@oxDlr3OG#GYH&=h z;}!rpYx5tuql}xsDwHzv?|+^KjD)9mIDzh;_=kCOrIH8} { TF range(0l, promote(@c23 AS LONG), STEP 1l) AS q1 RETURN (q0.ID AS A, q1.ID AS B) } task_count: 108 - task_total_time_ms: 25 + task_total_time_ms: 1 transform_count: 33 - transform_time_ms: 5 + transform_time_ms: 0 transform_yield_count: 6 - insert_time_ms: 1 + insert_time_ms: 0 insert_new_count: 10 insert_reused_count: 0 - query: EXPLAIN select a.id as x, a.col1 as y, b.id as z from t1 as a, range(a.id) @@ -127,9 +127,9 @@ table-functions: explain: SCAN(<,>) | FLATMAP q0 -> { TF range(0l, q0.ID, STEP 1l) AS q1 RETURN (q0.ID AS X, q0.COL1 AS Y, q1.ID AS Z) } task_count: 131 - task_total_time_ms: 55 - transform_count: 49 - transform_time_ms: 46 + task_total_time_ms: 1 + transform_count: 51 + transform_time_ms: 0 transform_yield_count: 9 insert_time_ms: 0 insert_new_count: 8 diff --git a/yaml-tests/src/test/resources/union-empty-tables.metrics.binpb b/yaml-tests/src/test/resources/union-empty-tables.metrics.binpb index 5a849fca07..3e31d5af24 100644 --- a/yaml-tests/src/test/resources/union-empty-tables.metrics.binpb +++ b/yaml-tests/src/test/resources/union-empty-tables.metrics.binpb @@ -1,361 +1,362 @@ - + A - unnamed-14EXPLAIN select sum(col1) as a, count(*) as b from t1 -BW ,(08@SCAN(<,>) | TFILTER T1 | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0, count_star(*) AS _1) | ON EMPTY NULL | MAP (_._0._0 AS A, coalesce_long(_._0._1, promote(0l AS LONG)) AS B)digraph G { + unnamed-14EXPLAIN select sum(col1) as a, count(*) as b from t1 +Z X(08@SCAN(<,>) | TFILTER T1 | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0, count_star(*) AS _1) | ON EMPTY NULL | MAP (_._0._0 AS A, coalesce_long(_._0._1, promote(0l AS LONG)) AS B)digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS A, coalesce_long(q6._0._1, promote(0l AS LONG)) AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q27._0.COL1) AS _0, count_star(*) AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 5 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q6._0._0 AS A, coalesce_long(q6._0._1, promote(0l AS LONG)) AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B)" ]; + 2 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1 AS _0)" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q29._0.COL1) AS _0, count_star(*) AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 5 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 6 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 7 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q27> label="q27" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q29> label="q29" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q19> label="q19" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q20> label="q20" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}J +}L  - unnamed-1EXPLAIN select sum(a) as a, sum(b) as b from (select sum(col1) as a, count(*) as b from t1 union all select sum(col1) as a, count(*) as b from t2) as xI -  (&0m8=@SCAN(<,>) | TFILTER T1 | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0, count_star(*) AS _1) | ON EMPTY NULL | MAP (_._0._0 AS A, coalesce_long(_._0._1, promote(0l AS LONG)) AS B) ⊎ SCAN(<,>) | TFILTER T2 | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0, count_star(*) AS _1) | ON EMPTY NULL | MAP (_._0._0 AS A, coalesce_long(_._0._1, promote(0l AS LONG)) AS B) | MAP (_ AS _0) | AGG (sum_l(_._0.A) AS _0, sum_l(_._0.B) AS _1) | ON EMPTY NULL | MAP (_._0._0 AS A, _._0._1 AS B)Edigraph G { + unnamed-1EXPLAIN select sum(a) as a, sum(b) as b from (select sum(col1) as a, count(*) as b from t1 union all select sum(col1) as a, count(*) as b from t2) as xK +ɍ + (&0L8=@SCAN(<,>) | TFILTER T1 | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0, count_star(*) AS _1) | ON EMPTY NULL | MAP (_._0._0 AS A, coalesce_long(_._0._1, promote(0l AS LONG)) AS B) ⊎ SCAN(<,>) | TFILTER T2 | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0, count_star(*) AS _1) | ON EMPTY NULL | MAP (_._0._0 AS A, coalesce_long(_._0._1, promote(0l AS LONG)) AS B) | MAP (_ AS _0) | AGG (sum_l(_._0.A) AS _0, sum_l(_._0.B) AS _1) | ON EMPTY NULL | MAP (_._0._0 AS A, _._0._1 AS B)Gdigraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q24._0._0 AS A, q24._0._1 AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 2 [ label=<
    Value Computation
    $q24 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q85._0.A) AS _0, sum_l(q85._0.B) AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q20 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, AS _0)" ]; - 5 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS A, )" ]; - 6 [ label=<
    Value Computation
    MAP (q6._0._0 AS A, coalesce_long(q6._0._1, promote(0l AS LONG)) AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 7 [ label=<
    Value Computation
    MAP (q16._0._0 AS A, coalesce_long(q16._0._1, promote(0l AS LONG)) AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 8 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, AS _0)" ]; - 9 [ label=<
    Value Computation
    $q16 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, AS _0)" ]; - 10 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q70._0.COL1) AS _0, count_star(*) AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, AS _0)" ]; - 11 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q51._0.COL1) AS _0, count_star(*) AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, AS _0)" ]; - 12 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 13 [ label=<
    Value Computation
    MAP (q12 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 14 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 15 [ label=<
    Type Filter
    WHERE record IS [T2]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q24._0._0 AS A, q24._0._1 AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B)" ]; + 2 [ label=<
    Value Computation
    $q24 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1 AS _0)" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q89._0.A) AS _0, sum_l(q89._0.B) AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q20 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B AS _0)" ]; + 5 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS A, LONG AS B)" ]; + 6 [ label=<
    Value Computation
    MAP (q6._0._0 AS A, coalesce_long(q6._0._1, promote(0l AS LONG)) AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B)" ]; + 7 [ label=<
    Value Computation
    MAP (q16._0._0 AS A, coalesce_long(q16._0._1, promote(0l AS LONG)) AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B)" ]; + 8 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1 AS _0)" ]; + 9 [ label=<
    Value Computation
    $q16 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1 AS _0)" ]; + 10 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q74._0.COL1) AS _0, count_star(*) AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1 AS _0)" ]; + 11 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q53._0.COL1) AS _0, count_star(*) AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1 AS _0)" ]; + 12 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 13 [ label=<
    Value Computation
    MAP (q12 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3 AS _0)" ]; + 14 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 15 [ label=<
    Type Filter
    WHERE record IS [T2]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; 16 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 17 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 18 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 19 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q85> label="q85" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q89> label="q89" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q20> label="q20" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q80> label="q80" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 5 [ label=< q82> label="q82" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q84> label="q84" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 5 [ label=< q86> label="q86" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 6 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 9 -> 7 [ label=< q16> label="q16" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 10 -> 8 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 11 -> 9 [ label=< q16> label="q16" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 12 -> 10 [ label=< q70> label="q70" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 13 -> 11 [ label=< q51> label="q51" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 12 -> 10 [ label=< q74> label="q74" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 13 -> 11 [ label=< q53> label="q53" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 14 -> 12 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 15 -> 13 [ label=< q12> label="q12" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 16 -> 14 [ label=< q62> label="q62" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 17 -> 15 [ label=< q43> label="q43" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 16 -> 14 [ label=< q65> label="q65" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 17 -> 15 [ label=< q44> label="q44" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 18 -> 16 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 19 -> 17 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}! +}! R - unnamed-1EEXPLAIN select col1, col2 from t1 union all select col1, col2 from t1 -B ߔ(0,8@SCAN(<,>) | TFILTER T1 | MAP (_.COL1 AS COL1, _.COL2 AS COL2) ⊎ SCAN(<,>) | TFILTER T1 | MAP (_.COL1 AS COL1, _.COL2 AS COL2)digraph G { + unnamed-1EEXPLAIN select col1, col2 from t1 union all select col1, col2 from t1! +ݒG ШK(08@SCAN(<,>) | TFILTER T1 | MAP (_.COL1 AS COL1, _.COL2 AS COL2) ⊎ SCAN(<,>) | TFILTER T1 | MAP (_.COL1 AS COL1, _.COL2 AS COL2) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS COL1, )" ]; - 2 [ label=<
    Value Computation
    MAP (q2.COL1 AS COL1, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, )" ]; - 3 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS COL1, LONG AS COL2)" ]; + 2 [ label=<
    Value Computation
    MAP (q2.COL1 AS COL1, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS COL2)" ]; + 3 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 4 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 5 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 6 [ label=<
    Value Computation
    MAP (q8.COL1 AS COL1, q8.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, )" ]; - 7 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 6 [ label=<
    Value Computation
    MAP (q8.COL1 AS COL1, q8.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL1, LONG AS COL2)" ]; + 7 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 8 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 9 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 2 -> 1 [ label=< q40> label="q40" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 -> 1 [ label=< q44> label="q44" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 8 -> 7 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 8 -> 7 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 9 -> 8 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 1 [ label=< q42> label="q42" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} + 6 -> 1 [ label=< q46> label="q46" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +} A - unnamed-14EXPLAIN select * from t1 union all select * from t1; -ȱ@@ +(08@1SCAN(<,>) | TFILTER T1 ⊎ SCAN(<,>) | TFILTER T1digraph G { + unnamed-14EXPLAIN select * from t1 union all select * from t1; +D g(0ģ8@1SCAN(<,>) | TFILTER T1 ⊎ SCAN(<,>) | TFILTER T1digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS ID, )" ]; - 2 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 2 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 4 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 5 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 5 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 6 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 7 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 3 -> 2 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 3 -> 2 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 2 -> 1 [ label=< q34> label="q34" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 -> 1 [ label=< q37> label="q37" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 1 [ label=< q36> label="q36" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} + 5 -> 1 [ label=< q39> label="q39" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +} N - unnamed-1AEXPLAIN select * from t1 union all select id, col1, col2 from t1; -BQ +(0°8@dSCAN(<,>) | TFILTER T1 ⊎ SCAN(<,>) | TFILTER T1 | MAP (_.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2)digraph G { + unnamed-1AEXPLAIN select * from t1 union all select id, col1, col2 from t1; +ϿU f(08@dSCAN(<,>) | TFILTER T1 ⊎ SCAN(<,>) | TFILTER T1 | MAP (_.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2)digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS ID, )" ]; - 2 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 2 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 4 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 5 [ label=<
    Value Computation
    MAP (q8.ID AS ID, q8.COL1 AS COL1, q8.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 5 [ label=<
    Value Computation
    MAP (q8.ID AS ID, q8.COL1 AS COL1, q8.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 8 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 3 -> 2 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 3 -> 2 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 2 -> 1 [ label=< q35> label="q35" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 -> 1 [ label=< q38> label="q38" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 1 [ label=< q37> label="q37" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} + 5 -> 1 [ label=< q40> label="q40" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +} N - unnamed-1AEXPLAIN select id, col1, col2 from t1 union all select * from t1; -BS ,(08@dSCAN(<,>) | TFILTER T1 | MAP (_.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2) ⊎ SCAN(<,>) | TFILTER T1digraph G { + unnamed-1AEXPLAIN select id, col1, col2 from t1 union all select * from t1; +X ۹(0ű8@dSCAN(<,>) | TFILTER T1 | MAP (_.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2) ⊎ SCAN(<,>) | TFILTER T1digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS ID, )" ]; - 2 [ label=<
    Value Computation
    MAP (q2.ID AS ID, q2.COL1 AS COL1, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 2 [ label=<
    Value Computation
    MAP (q2.ID AS ID, q2.COL1 AS COL1, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 4 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 5 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 6 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 7 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 8 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 2 -> 1 [ label=< q39> label="q39" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q23> label="q23" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 -> 1 [ label=< q43> label="q43" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 1 [ label=< q41> label="q41" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}% + 6 -> 1 [ label=< q45> label="q45" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}& ] - unnamed-1PEXPLAIN select id as W, col1 as X, col2 as Y from t1 union all select * from t1;$ -CZ +(08@SCAN(<,>) | TFILTER T1 | MAP (_.ID AS W, _.COL1 AS X, _.COL2 AS Y) | MAP (_.W AS W, _.X AS X, _.Y AS Y) ⊎ SCAN(<,>) | TFILTER T1 | MAP (_.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2)#digraph G { + unnamed-1PEXPLAIN select id as W, col1 as X, col2 as Y from t1 union all select * from t1;% +Ԍ_ ۽(0 8@SCAN(<,>) | TFILTER T1 | MAP (_.ID AS W, _.COL1 AS X, _.COL2 AS Y) | MAP (_.W AS W, _.X AS X, _.Y AS Y) ⊎ SCAN(<,>) | TFILTER T1 | MAP (_.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2)$digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS W, )" ]; - 2 [ label=<
    Value Computation
    MAP (q6.W AS W, q6.X AS X, q6.Y AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS W, )" ]; - 3 [ label=<
    Value Computation
    MAP (q2.ID AS W, q2.COL1 AS X, q2.COL2 AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS W, )" ]; - 4 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS W, LONG AS X, LONG AS Y)" ]; + 2 [ label=<
    Value Computation
    MAP (q6.W AS W, q6.X AS X, q6.Y AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS W, LONG AS X, LONG AS Y)" ]; + 3 [ label=<
    Value Computation
    MAP (q2.ID AS W, q2.COL1 AS X, q2.COL2 AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS W, LONG AS X, LONG AS Y)" ]; + 4 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 5 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 6 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 7 [ label=<
    Value Computation
    MAP (q12.ID AS ID, q12.COL1 AS COL1, q12.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 8 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 7 [ label=<
    Value Computation
    MAP (q12.ID AS ID, q12.COL1 AS COL1, q12.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 8 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 9 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 10 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q27> label="q27" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q28> label="q28" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 2 -> 1 [ label=< q45> label="q45" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 -> 1 [ label=< q49> label="q49" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ label=< q12> label="q12" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 9 -> 8 [ label=< q27> label="q27" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 9 -> 8 [ label=< q28> label="q28" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 10 -> 9 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 1 [ label=< q47> label="q47" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}% + 7 -> 1 [ label=< q51> label="q51" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}& _ - unnamed-1REXPLAIN (select id as W, col1 as X, col2 as Y from t1) union all select * from t1;$ -䄻Z (0$8@SCAN(<,>) | TFILTER T1 | MAP (_.ID AS W, _.COL1 AS X, _.COL2 AS Y) | MAP (_.W AS W, _.X AS X, _.Y AS Y) ⊎ SCAN(<,>) | TFILTER T1 | MAP (_.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2)#digraph G { + unnamed-1REXPLAIN (select id as W, col1 as X, col2 as Y from t1) union all select * from t1;% +_ (08@SCAN(<,>) | TFILTER T1 | MAP (_.ID AS W, _.COL1 AS X, _.COL2 AS Y) | MAP (_.W AS W, _.X AS X, _.Y AS Y) ⊎ SCAN(<,>) | TFILTER T1 | MAP (_.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2)$digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS W, )" ]; - 2 [ label=<
    Value Computation
    MAP (q6.W AS W, q6.X AS X, q6.Y AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS W, )" ]; - 3 [ label=<
    Value Computation
    MAP (q2.ID AS W, q2.COL1 AS X, q2.COL2 AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS W, )" ]; - 4 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS W, LONG AS X, LONG AS Y)" ]; + 2 [ label=<
    Value Computation
    MAP (q6.W AS W, q6.X AS X, q6.Y AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS W, LONG AS X, LONG AS Y)" ]; + 3 [ label=<
    Value Computation
    MAP (q2.ID AS W, q2.COL1 AS X, q2.COL2 AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS W, LONG AS X, LONG AS Y)" ]; + 4 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 5 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 6 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 7 [ label=<
    Value Computation
    MAP (q12.ID AS ID, q12.COL1 AS COL1, q12.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 8 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 7 [ label=<
    Value Computation
    MAP (q12.ID AS ID, q12.COL1 AS COL1, q12.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 8 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 9 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 10 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q27> label="q27" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q28> label="q28" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 2 -> 1 [ label=< q45> label="q45" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 -> 1 [ label=< q49> label="q49" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ label=< q12> label="q12" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 9 -> 8 [ label=< q27> label="q27" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 9 -> 8 [ label=< q28> label="q28" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 10 -> 9 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 1 [ label=< q47> label="q47" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}% + 7 -> 1 [ label=< q51> label="q51" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}& _ - unnamed-1REXPLAIN select id as W, col1 as X, col2 as Y from t1 union all (select * from t1);$ -Z (058@SCAN(<,>) | TFILTER T1 | MAP (_.ID AS W, _.COL1 AS X, _.COL2 AS Y) | MAP (_.W AS W, _.X AS X, _.Y AS Y) ⊎ SCAN(<,>) | TFILTER T1 | MAP (_.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2)#digraph G { + unnamed-1REXPLAIN select id as W, col1 as X, col2 as Y from t1 union all (select * from t1);% +_ ͳ_(08@SCAN(<,>) | TFILTER T1 | MAP (_.ID AS W, _.COL1 AS X, _.COL2 AS Y) | MAP (_.W AS W, _.X AS X, _.Y AS Y) ⊎ SCAN(<,>) | TFILTER T1 | MAP (_.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2)$digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS W, )" ]; - 2 [ label=<
    Value Computation
    MAP (q6.W AS W, q6.X AS X, q6.Y AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS W, )" ]; - 3 [ label=<
    Value Computation
    MAP (q2.ID AS W, q2.COL1 AS X, q2.COL2 AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS W, )" ]; - 4 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS W, LONG AS X, LONG AS Y)" ]; + 2 [ label=<
    Value Computation
    MAP (q6.W AS W, q6.X AS X, q6.Y AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS W, LONG AS X, LONG AS Y)" ]; + 3 [ label=<
    Value Computation
    MAP (q2.ID AS W, q2.COL1 AS X, q2.COL2 AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS W, LONG AS X, LONG AS Y)" ]; + 4 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 5 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 6 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 7 [ label=<
    Value Computation
    MAP (q12.ID AS ID, q12.COL1 AS COL1, q12.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 8 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 7 [ label=<
    Value Computation
    MAP (q12.ID AS ID, q12.COL1 AS COL1, q12.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 8 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 9 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 10 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q27> label="q27" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q28> label="q28" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 2 -> 1 [ label=< q45> label="q45" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 -> 1 [ label=< q49> label="q49" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ label=< q12> label="q12" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 9 -> 8 [ label=< q27> label="q27" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 9 -> 8 [ label=< q28> label="q28" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 10 -> 9 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 1 [ label=< q47> label="q47" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}% + 7 -> 1 [ label=< q51> label="q51" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}& a - unnamed-1TEXPLAIN (select id as W, col1 as X, col2 as Y from t1 union all (select * from t1));$ -̘Z Ѧ(0ڥ&8@SCAN(<,>) | TFILTER T1 | MAP (_.ID AS W, _.COL1 AS X, _.COL2 AS Y) | MAP (_.W AS W, _.X AS X, _.Y AS Y) ⊎ SCAN(<,>) | TFILTER T1 | MAP (_.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2)#digraph G { + unnamed-1TEXPLAIN (select id as W, col1 as X, col2 as Y from t1 union all (select * from t1));% +ǘ_ j(08@SCAN(<,>) | TFILTER T1 | MAP (_.ID AS W, _.COL1 AS X, _.COL2 AS Y) | MAP (_.W AS W, _.X AS X, _.Y AS Y) ⊎ SCAN(<,>) | TFILTER T1 | MAP (_.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2)$digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS W, )" ]; - 2 [ label=<
    Value Computation
    MAP (q6.W AS W, q6.X AS X, q6.Y AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS W, )" ]; - 3 [ label=<
    Value Computation
    MAP (q2.ID AS W, q2.COL1 AS X, q2.COL2 AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS W, )" ]; - 4 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS W, LONG AS X, LONG AS Y)" ]; + 2 [ label=<
    Value Computation
    MAP (q6.W AS W, q6.X AS X, q6.Y AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS W, LONG AS X, LONG AS Y)" ]; + 3 [ label=<
    Value Computation
    MAP (q2.ID AS W, q2.COL1 AS X, q2.COL2 AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS W, LONG AS X, LONG AS Y)" ]; + 4 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 5 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 6 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 7 [ label=<
    Value Computation
    MAP (q12.ID AS ID, q12.COL1 AS COL1, q12.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 8 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 7 [ label=<
    Value Computation
    MAP (q12.ID AS ID, q12.COL1 AS COL1, q12.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 8 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 9 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 10 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q27> label="q27" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q28> label="q28" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 2 -> 1 [ label=< q45> label="q45" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 -> 1 [ label=< q49> label="q49" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ label=< q12> label="q12" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 9 -> 8 [ label=< q27> label="q27" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 9 -> 8 [ label=< q28> label="q28" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 10 -> 9 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 1 [ label=< q47> label="q47" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}% + 7 -> 1 [ label=< q51> label="q51" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}& a - unnamed-1TEXPLAIN ((select id as W, col1 as X, col2 as Y from t1) union all select * from t1);$ -Z (0ҿ,8@SCAN(<,>) | TFILTER T1 | MAP (_.ID AS W, _.COL1 AS X, _.COL2 AS Y) | MAP (_.W AS W, _.X AS X, _.Y AS Y) ⊎ SCAN(<,>) | TFILTER T1 | MAP (_.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2)#digraph G { + unnamed-1TEXPLAIN ((select id as W, col1 as X, col2 as Y from t1) union all select * from t1);% +_ (0 8@SCAN(<,>) | TFILTER T1 | MAP (_.ID AS W, _.COL1 AS X, _.COL2 AS Y) | MAP (_.W AS W, _.X AS X, _.Y AS Y) ⊎ SCAN(<,>) | TFILTER T1 | MAP (_.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2)$digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS W, )" ]; - 2 [ label=<
    Value Computation
    MAP (q6.W AS W, q6.X AS X, q6.Y AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS W, )" ]; - 3 [ label=<
    Value Computation
    MAP (q2.ID AS W, q2.COL1 AS X, q2.COL2 AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS W, )" ]; - 4 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS W, LONG AS X, LONG AS Y)" ]; + 2 [ label=<
    Value Computation
    MAP (q6.W AS W, q6.X AS X, q6.Y AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS W, LONG AS X, LONG AS Y)" ]; + 3 [ label=<
    Value Computation
    MAP (q2.ID AS W, q2.COL1 AS X, q2.COL2 AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS W, LONG AS X, LONG AS Y)" ]; + 4 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 5 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 6 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 7 [ label=<
    Value Computation
    MAP (q12.ID AS ID, q12.COL1 AS COL1, q12.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 8 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 7 [ label=<
    Value Computation
    MAP (q12.ID AS ID, q12.COL1 AS COL1, q12.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 8 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 9 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 10 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q27> label="q27" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q28> label="q28" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 2 -> 1 [ label=< q45> label="q45" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 -> 1 [ label=< q49> label="q49" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ label=< q12> label="q12" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 9 -> 8 [ label=< q27> label="q27" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 9 -> 8 [ label=< q28> label="q28" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 10 -> 9 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 1 [ label=< q47> label="q47" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}) + 7 -> 1 [ label=< q51> label="q51" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}) F - unnamed-19EXPLAIN select a, b from t3 union all select a, b from t4( - v (0;8@SCAN(<,>) | TFILTER T3 | MAP (_.A AS A, _.B AS B) | MAP (_.A AS A, promote(_.B AS DOUBLE) AS B) ⊎ SCAN(<,>) | TFILTER T4 | MAP (_.A AS A, _.B AS B) | MAP (promote(_.A AS DOUBLE) AS A, _.B AS B)&digraph G { + unnamed-19EXPLAIN select a, b from t3 union all select a, b from t4) +| (08@SCAN(<,>) | TFILTER T3 | MAP (_.A AS A, _.B AS B) | MAP (_.A AS A, promote(_.B AS DOUBLE) AS B) ⊎ SCAN(<,>) | TFILTER T4 | MAP (_.A AS A, _.B AS B) | MAP (promote(_.A AS DOUBLE) AS A, _.B AS B)'digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(DOUBLE AS A, )" ]; - 2 [ label=<
    Value Computation
    MAP (q6.A AS A, promote(q6.B AS DOUBLE) AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(DOUBLE AS A, )" ]; - 3 [ label=<
    Value Computation
    MAP (q2.A AS A, q2.B AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(DOUBLE AS A, )" ]; - 4 [ label=<
    Type Filter
    WHERE record IS [T3]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(DOUBLE AS A, DOUBLE AS B)" ]; + 2 [ label=<
    Value Computation
    MAP (q6.A AS A, promote(q6.B AS DOUBLE) AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(DOUBLE AS A, DOUBLE AS B)" ]; + 3 [ label=<
    Value Computation
    MAP (q2.A AS A, q2.B AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(DOUBLE AS A, LONG AS B)" ]; + 4 [ label=<
    Type Filter
    WHERE record IS [T3]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, DOUBLE AS A, LONG AS B)" ]; 5 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 6 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 7 [ label=<
    Value Computation
    MAP (promote(q14.A AS DOUBLE) AS A, q14.B AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(DOUBLE AS A, )" ]; - 8 [ label=<
    Value Computation
    MAP (q10.A AS A, q10.B AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 9 [ label=<
    Type Filter
    WHERE record IS [T4]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 7 [ label=<
    Value Computation
    MAP (promote(q14.A AS DOUBLE) AS A, q14.B AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(DOUBLE AS A, DOUBLE AS B)" ]; + 8 [ label=<
    Value Computation
    MAP (q10.A AS A, q10.B AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, DOUBLE AS B)" ]; + 9 [ label=<
    Type Filter
    WHERE record IS [T4]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS A, DOUBLE AS B)" ]; 10 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 11 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q55> label="q55" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q58> label="q58" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 2 -> 1 [ label=< q64> label="q64" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 -> 1 [ label=< q68> label="q68" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ label=< q14> label="q14" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 9 -> 8 [ label=< q10> label="q10" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 10 -> 9 [ label=< q45> label="q45" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 10 -> 9 [ label=< q46> label="q46" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 11 -> 10 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 1 [ label=< q66> label="q66" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}= + 7 -> 1 [ label=< q70> label="q70" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}>  - unnamed-1}EXPLAIN select sum(Y) as S from (select count(*) as Y from t3 where a < 10 group by a union all select count(*) from t4) as X< -ꠒ (.0f87@AISCAN(MV10 [[LESS_THAN promote(@c22 AS DOUBLE)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS Y) | MAP (_.Y AS Y) ⊎ SCAN(<,>) | TFILTER T4 | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) | MAP (_ AS _0) | AGG (sum_l(_._0.Y) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS S)9digraph G { + unnamed-1}EXPLAIN select sum(Y) as S from (select count(*) as Y from t3 where a < 10 group by a union all select count(*) from t4) as X= +  (.0,87@AISCAN(MV10 [[LESS_THAN promote(@c22 AS DOUBLE)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS Y) | MAP (_.Y AS Y) ⊎ SCAN(<,>) | TFILTER T4 | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) | MAP (_ AS _0) | AGG (sum_l(_._0.Y) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS S):digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q26._0._0 AS S)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS S)" ]; 2 [ label=<
    Value Computation
    $q26 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q86._0.Y) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q90._0.Y) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 4 [ label=<
    Value Computation
    MAP (q22 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS Y AS _0)" ]; 5 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS Y)" ]; 6 [ label=<
    Value Computation
    MAP (q8.Y AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS Y)" ]; 7 [ label=<
    Value Computation
    MAP (coalesce_long(q16._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 8 [ label=<
    Value Computation
    MAP (q6._1 AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS Y)" ]; 9 [ label=<
    Value Computation
    $q16 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 10 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [[LESS_THAN promote(@c22 AS DOUBLE)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(DOUBLE AS _0, )" ]; + 10 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [[LESS_THAN promote(@c22 AS DOUBLE)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(DOUBLE AS _0, LONG AS _1)" ]; 11 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 12 [ label=<
    Index
    MV10
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 13 [ label=<
    Value Computation
    MAP (q12 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 14 [ label=<
    Type Filter
    WHERE record IS [T4]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 12 [ label=<
    Index
    AGG[MV10; count]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, DOUBLE AS A, LONG AS B)" ]; + 13 [ label=<
    Value Computation
    MAP (q12 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS A, DOUBLE AS B AS _0)" ]; + 14 [ label=<
    Type Filter
    WHERE record IS [T4]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS A, DOUBLE AS B)" ]; 15 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 16 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q26> label="q26" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q86> label="q86" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q90> label="q90" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q22> label="q22" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q81> label="q81" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 5 [ label=< q83> label="q83" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q85> label="q85" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 5 [ label=< q87> label="q87" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 6 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 9 -> 7 [ label=< q16> label="q16" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 10 -> 8 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 11 -> 9 [ label=< q16> label="q16" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 12 -> 10 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 13 -> 11 [ label=< q63> label="q63" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 13 -> 11 [ label=< q65> label="q65" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 14 -> 13 [ label=< q12> label="q12" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 15 -> 14 [ label=< q55> label="q55" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 15 -> 14 [ label=< q56> label="q56" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 16 -> 15 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q26> label="q26" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}L +}J r - unnamed-1eEXPLAIN select sum(Y) as S from (select count(*) as Y from t3 union all select count(*) from t1) as XK -K ̕1(,08?@SCAN(<,>) | TFILTER T3 | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS Y) | MAP (_.Y AS Y) ⊎ SCAN(<,>) | TFILTER T1 | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) | MAP (_ AS _0) | AGG (sum_l(_._0.Y) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS S)Gdigraph G { + unnamed-1eEXPLAIN select sum(Y) as S from (select count(*) as Y from t3 union all select count(*) from t1) as XI +ȝ ʳ(:0}8Z@AISCAN(MV10 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | AGG sum_l(_._1) GROUP BY () | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS Y) | MAP (_.Y AS Y) ⊎ SCAN(<,>) | TFILTER T1 | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) | MAP (_ AS _0) | AGG (sum_l(_._0.Y) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS S)Edigraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q26._0._0 AS S)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS S)" ]; 2 [ label=<
    Value Computation
    $q26 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q98._0.Y) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q120._0.Y) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 4 [ label=<
    Value Computation
    MAP (q22 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS Y AS _0)" ]; 5 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS Y)" ]; 6 [ label=<
    Value Computation
    MAP (q8.Y AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS Y)" ]; @@ -364,43 +365,41 @@ r 9 [ label=<
    Value Computation
    $q16 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 10 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 11 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 12 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 13 [ label=<
    Value Computation
    MAP (q12 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 14 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 15 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 16 [ label=<
    Type Filter
    WHERE record IS [T3]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 12 [ label=<
    Value Computation
    MAP ((q4._1 AS _0) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 13 [ label=<
    Value Computation
    MAP (q12 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 14 [ label=<
    Streaming Aggregate
    COLLECT sum_l(q90._1)
    GROUP BY ()
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; + 15 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 16 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(DOUBLE AS _0, LONG AS _1)" ]; 17 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 18 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; + 18 [ label=<
    Index
    AGG[MV10; count]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, DOUBLE AS A, LONG AS B)" ]; 19 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 20 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q26> label="q26" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q98> label="q98" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q120> label="q120" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q22> label="q22" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q93> label="q93" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 5 [ label=< q95> label="q95" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q115> label="q115" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 5 [ label=< q117> label="q117" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 6 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 9 -> 7 [ label=< q16> label="q16" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 10 -> 8 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 11 -> 9 [ label=< q16> label="q16" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 12 -> 10 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 13 -> 11 [ label=< q63> label="q63" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 14 -> 12 [ label=< q82> label="q82" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 13 -> 11 [ label=< q65> label="q65" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 14 -> 12 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 15 -> 13 [ label=< q12> label="q12" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 16 -> 14 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 17 -> 15 [ label=< q55> label="q55" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 18 -> 16 [ label=< q74> label="q74" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 16 -> 14 [ label=< q90> label="q90" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 17 -> 15 [ label=< q56> label="q56" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 18 -> 16 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 19 -> 17 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 20 -> 18 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q26> label="q26" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}G +}H  - unnamed-1xEXPLAIN select col2 from t1 where exists (select a from t3 where col2 <= id union all select b from t4 where col2 <= id)F -V ;(3088@SCAN(<,>) | TFILTER T1 | FLATMAP q0 -> { SCAN(<,>) | TFILTER T3 | FILTER _.ID GREATER_THAN_OR_EQUALS q0.COL2 | MAP (_.A AS A) | MAP (_.A AS A) ⊎ SCAN(<,>) | TFILTER T4 | FILTER _.ID GREATER_THAN_OR_EQUALS q0.COL2 | MAP (_.B AS B) | MAP (_.B AS B) | DEFAULT NULL | FILTER _ NOT_NULL AS q1 RETURN (q0.COL2 AS COL2) }Ddigraph G { + unnamed-1xEXPLAIN select col2 from t1 where exists (select a from t3 where col2 <= id union all select b from t4 where col2 <= id)G + (30988@SCAN(<,>) | TFILTER T1 | FLATMAP q0 -> { SCAN(<,>) | TFILTER T3 | FILTER _.ID GREATER_THAN_OR_EQUALS q0.COL2 | MAP (_.A AS A) | MAP (_.A AS A) ⊎ SCAN(<,>) | TFILTER T4 | FILTER _.ID GREATER_THAN_OR_EQUALS q0.COL2 | MAP (_.B AS B) | MAP (_.B AS B) | DEFAULT NULL | FILTER _ NOT_NULL AS q1 RETURN (q0.COL2 AS COL2) }Edigraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Nested Loop Join
    FLATMAP (q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS COL2)" ]; - 2 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 2 [ label=<
    Type Filter
    WHERE record IS [T1]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 4 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 5 [ label=<
    Predicate Filter
    WHERE q22 NOT_NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(DOUBLE AS A)" ]; @@ -408,31 +407,31 @@ r 7 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(DOUBLE AS A)" ]; 8 [ label=<
    Value Computation
    MAP (q8.A AS A)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(DOUBLE AS A)" ]; 9 [ label=<
    Value Computation
    MAP (q14.B AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(DOUBLE AS B)" ]; - 10 [ label=<
    Value Computation
    MAP (q76.A AS A)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(DOUBLE AS A)" ]; - 11 [ label=<
    Value Computation
    MAP (q61.B AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(DOUBLE AS B)" ]; - 12 [ label=<
    Predicate Filter
    WHERE q6.ID GREATER_THAN_OR_EQUALS q2.COL2
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 13 [ label=<
    Predicate Filter
    WHERE q12.ID GREATER_THAN_OR_EQUALS q2.COL2
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 14 [ label=<
    Type Filter
    WHERE record IS [T3]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 15 [ label=<
    Type Filter
    WHERE record IS [T4]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 10 [ label=<
    Value Computation
    MAP (q79.A AS A)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(DOUBLE AS A)" ]; + 11 [ label=<
    Value Computation
    MAP (q62.B AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(DOUBLE AS B)" ]; + 12 [ label=<
    Predicate Filter
    WHERE q6.ID GREATER_THAN_OR_EQUALS q2.COL2
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, DOUBLE AS A, LONG AS B)" ]; + 13 [ label=<
    Predicate Filter
    WHERE q12.ID GREATER_THAN_OR_EQUALS q2.COL2
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS A, DOUBLE AS B)" ]; + 14 [ label=<
    Type Filter
    WHERE record IS [T3]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, DOUBLE AS A, LONG AS B)" ]; + 15 [ label=<
    Type Filter
    WHERE record IS [T4]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS A, DOUBLE AS B)" ]; 16 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 17 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 18 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 19 [ label=<
    Primary Storage
    record types: [T4, T5, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 3 -> 2 [ label=< q91> label="q91" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 3 -> 2 [ label=< q96> label="q96" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 5 [ label=< q22> label="q22" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ label=< q22> label="q22" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 8 -> 7 [ label=< q86> label="q86" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 9 -> 7 [ label=< q88> label="q88" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 8 -> 7 [ label=< q90> label="q90" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 9 -> 7 [ label=< q92> label="q92" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 10 -> 8 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 11 -> 9 [ label=< q14> label="q14" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 12 -> 10 [ label=< q76> label="q76" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 13 -> 11 [ label=< q61> label="q61" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 12 -> 10 [ label=< q79> label="q79" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 13 -> 11 [ label=< q62> label="q62" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 14 -> 12 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 15 -> 13 [ label=< q12> label="q12" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 16 -> 14 [ label=< q72> label="q72" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 17 -> 15 [ label=< q57> label="q57" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 16 -> 14 [ label=< q75> label="q75" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 17 -> 15 [ label=< q58> label="q58" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 18 -> 16 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 19 -> 17 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 1 [ label=< q22> label="q22" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; diff --git a/yaml-tests/src/test/resources/union-empty-tables.metrics.yaml b/yaml-tests/src/test/resources/union-empty-tables.metrics.yaml index 6cfa500c28..3cc24d72ab 100644 --- a/yaml-tests/src/test/resources/union-empty-tables.metrics.yaml +++ b/yaml-tests/src/test/resources/union-empty-tables.metrics.yaml @@ -4,11 +4,11 @@ unnamed-1: count_star(*) AS _1) | ON EMPTY NULL | MAP (_._0._0 AS A, coalesce_long(_._0._1, promote(0l AS LONG)) AS B) task_count: 263 - task_total_time_ms: 139 - transform_count: 87 - transform_time_ms: 92 + task_total_time_ms: 5 + transform_count: 90 + transform_time_ms: 1 transform_yield_count: 15 - insert_time_ms: 7 + insert_time_ms: 0 insert_new_count: 22 insert_reused_count: 2 - query: EXPLAIN select sum(a) as a, sum(b) as b from (select sum(col1) as a, count(*) @@ -21,9 +21,9 @@ unnamed-1: AGG (sum_l(_._0.A) AS _0, sum_l(_._0.B) AS _1) | ON EMPTY NULL | MAP (_._0._0 AS A, _._0._1 AS B) task_count: 696 - task_total_time_ms: 24 - transform_count: 235 - transform_time_ms: 7 + task_total_time_ms: 21 + transform_count: 241 + transform_time_ms: 4 transform_yield_count: 38 insert_time_ms: 1 insert_new_count: 61 @@ -32,9 +32,9 @@ unnamed-1: explain: SCAN(<,>) | TFILTER T1 | MAP (_.COL1 AS COL1, _.COL2 AS COL2) ⊎ SCAN(<,>) | TFILTER T1 | MAP (_.COL1 AS COL1, _.COL2 AS COL2) task_count: 235 - task_total_time_ms: 10 - transform_count: 66 - transform_time_ms: 3 + task_total_time_ms: 4 + transform_count: 71 + transform_time_ms: 1 transform_yield_count: 15 insert_time_ms: 0 insert_new_count: 19 @@ -42,33 +42,33 @@ unnamed-1: - query: EXPLAIN select * from t1 union all select * from t1; explain: SCAN(<,>) | TFILTER T1 ⊎ SCAN(<,>) | TFILTER T1 task_count: 210 - task_total_time_ms: 134 - transform_count: 64 - transform_time_ms: 92 + task_total_time_ms: 6 + transform_count: 68 + transform_time_ms: 1 transform_yield_count: 15 - insert_time_ms: 6 + insert_time_ms: 0 insert_new_count: 15 insert_reused_count: 2 - query: EXPLAIN select * from t1 union all select id, col1, col2 from t1; explain: SCAN(<,>) | TFILTER T1 ⊎ SCAN(<,>) | TFILTER T1 | MAP (_.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2) task_count: 270 - task_total_time_ms: 140 - transform_count: 81 - transform_time_ms: 90 + task_total_time_ms: 7 + transform_count: 85 + transform_time_ms: 1 transform_yield_count: 18 - insert_time_ms: 2 + insert_time_ms: 0 insert_new_count: 22 insert_reused_count: 1 - query: EXPLAIN select id, col1, col2 from t1 union all select * from t1; explain: SCAN(<,>) | TFILTER T1 | MAP (_.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2) ⊎ SCAN(<,>) | TFILTER T1 task_count: 295 - task_total_time_ms: 140 - transform_count: 83 - transform_time_ms: 92 + task_total_time_ms: 10 + transform_count: 88 + transform_time_ms: 2 transform_yield_count: 18 - insert_time_ms: 6 + insert_time_ms: 0 insert_new_count: 24 insert_reused_count: 2 - query: EXPLAIN select id as W, col1 as X, col2 as Y from t1 union all select * @@ -77,11 +77,11 @@ unnamed-1: MAP (_.W AS W, _.X AS X, _.Y AS Y) ⊎ SCAN(<,>) | TFILTER T1 | MAP (_.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2) task_count: 299 - task_total_time_ms: 141 - transform_count: 90 - transform_time_ms: 92 + task_total_time_ms: 10 + transform_count: 95 + transform_time_ms: 2 transform_yield_count: 17 - insert_time_ms: 6 + insert_time_ms: 0 insert_new_count: 22 insert_reused_count: 3 - query: EXPLAIN (select id as W, col1 as X, col2 as Y from t1) union all select @@ -90,9 +90,9 @@ unnamed-1: MAP (_.W AS W, _.X AS X, _.Y AS Y) ⊎ SCAN(<,>) | TFILTER T1 | MAP (_.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2) task_count: 299 - task_total_time_ms: 9 - transform_count: 90 - transform_time_ms: 3 + task_total_time_ms: 10 + transform_count: 95 + transform_time_ms: 2 transform_yield_count: 17 insert_time_ms: 0 insert_new_count: 22 @@ -103,9 +103,9 @@ unnamed-1: MAP (_.W AS W, _.X AS X, _.Y AS Y) ⊎ SCAN(<,>) | TFILTER T1 | MAP (_.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2) task_count: 299 - task_total_time_ms: 9 - transform_count: 90 - transform_time_ms: 4 + task_total_time_ms: 6 + transform_count: 95 + transform_time_ms: 1 transform_yield_count: 17 insert_time_ms: 0 insert_new_count: 22 @@ -116,9 +116,9 @@ unnamed-1: MAP (_.W AS W, _.X AS X, _.Y AS Y) ⊎ SCAN(<,>) | TFILTER T1 | MAP (_.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2) task_count: 299 - task_total_time_ms: 8 - transform_count: 90 - transform_time_ms: 3 + task_total_time_ms: 6 + transform_count: 95 + transform_time_ms: 1 transform_yield_count: 17 insert_time_ms: 0 insert_new_count: 22 @@ -130,8 +130,8 @@ unnamed-1: ID, _.COL1 AS COL1, _.COL2 AS COL2) task_count: 299 task_total_time_ms: 10 - transform_count: 90 - transform_time_ms: 3 + transform_count: 95 + transform_time_ms: 2 transform_yield_count: 17 insert_time_ms: 0 insert_new_count: 22 @@ -141,9 +141,9 @@ unnamed-1: AS DOUBLE) AS B) ⊎ SCAN(<,>) | TFILTER T4 | MAP (_.A AS A, _.B AS B) | MAP (promote(_.A AS DOUBLE) AS A, _.B AS B) task_count: 362 - task_total_time_ms: 24 - transform_count: 118 - transform_time_ms: 11 + task_total_time_ms: 6 + transform_count: 124 + transform_time_ms: 2 transform_yield_count: 30 insert_time_ms: 0 insert_new_count: 25 @@ -156,29 +156,29 @@ unnamed-1: promote(0l AS LONG)) AS _0) | MAP (_ AS _0) | AGG (sum_l(_._0.Y) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS S)' task_count: 676 - task_total_time_ms: 50 - transform_count: 237 - transform_time_ms: 31 + task_total_time_ms: 25 + transform_count: 245 + transform_time_ms: 16 transform_yield_count: 46 - insert_time_ms: 1 + insert_time_ms: 0 insert_new_count: 55 insert_reused_count: 3 - query: EXPLAIN select sum(Y) as S from (select count(*) as Y from t3 union all select count(*) from t1) as X - explain: SCAN(<,>) | TFILTER T3 | MAP (_ AS _0) | AGG (count_star(*) AS _0) | - ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS Y) | MAP - (_.Y AS Y) ⊎ SCAN(<,>) | TFILTER T1 | MAP (_ AS _0) | AGG (count_star(*) AS - _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS - _0) | MAP (_ AS _0) | AGG (sum_l(_._0.Y) AS _0) | ON EMPTY NULL | MAP (_._0._0 - AS S) - task_count: 738 - task_total_time_ms: 157 - transform_count: 252 - transform_time_ms: 104 - transform_yield_count: 44 - insert_time_ms: 10 - insert_new_count: 63 - insert_reused_count: 5 + explain: 'AISCAN(MV10 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | AGG sum_l(_._1) + GROUP BY () | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, + promote(0l AS LONG)) AS Y) | MAP (_.Y AS Y) ⊎ SCAN(<,>) | TFILTER T1 | MAP + (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, + promote(0l AS LONG)) AS _0) | MAP (_ AS _0) | AGG (sum_l(_._0.Y) AS _0) | + ON EMPTY NULL | MAP (_._0._0 AS S)' + task_count: 903 + task_total_time_ms: 31 + transform_count: 313 + transform_time_ms: 13 + transform_yield_count: 58 + insert_time_ms: 2 + insert_new_count: 90 + insert_reused_count: 6 - query: EXPLAIN select col2 from t1 where exists (select a from t3 where col2 <= id union all select b from t4 where col2 <= id) explain: SCAN(<,>) | TFILTER T1 | FLATMAP q0 -> { SCAN(<,>) | TFILTER T3 | FILTER @@ -187,10 +187,10 @@ unnamed-1: | MAP (_.B AS B) | DEFAULT NULL | FILTER _ NOT_NULL AS q1 RETURN (q0.COL2 AS COL2) } task_count: 727 - task_total_time_ms: 180 - transform_count: 231 - transform_time_ms: 124 + task_total_time_ms: 18 + transform_count: 240 + transform_time_ms: 6 transform_yield_count: 51 - insert_time_ms: 7 + insert_time_ms: 0 insert_new_count: 56 insert_reused_count: 4 diff --git a/yaml-tests/src/test/resources/union-empty-tables.yamsql b/yaml-tests/src/test/resources/union-empty-tables.yamsql index 16e95bb0f2..a129176347 100644 --- a/yaml-tests/src/test/resources/union-empty-tables.yamsql +++ b/yaml-tests/src/test/resources/union-empty-tables.yamsql @@ -89,7 +89,7 @@ test_block: - query: select sum(Y) as S from (select count(*) as Y from t3 union all select count(*) from t1) as X # Query does not work with force continuations before 4.1.9.0 for a few reasons, including: https://github.com/FoundationDB/fdb-record-layer/issues/3096 - supported_version: 4.1.9.0 - - explain: "SCAN(<,>) | TFILTER T3 | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS Y) | MAP (_.Y AS Y) ⊎ SCAN(<,>) | TFILTER T1 | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) | MAP (_ AS _0) | AGG (sum_l(_._0.Y) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS S)" + - explain: "AISCAN(MV10 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | AGG sum_l(_._1) GROUP BY () | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS Y) | MAP (_.Y AS Y) ⊎ SCAN(<,>) | TFILTER T1 | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) | MAP (_ AS _0) | AGG (sum_l(_._0.Y) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS S)" - unorderedResult: [{0}] - - query: select col2 from t1 where exists (select a from t3 where col2 <= id union all select b from t4 where col2 <= id) diff --git a/yaml-tests/src/test/resources/union.metrics.binpb b/yaml-tests/src/test/resources/union.metrics.binpb index 9bc437f341..0f22cd8da2 100644 --- a/yaml-tests/src/test/resources/union.metrics.binpb +++ b/yaml-tests/src/test/resources/union.metrics.binpb @@ -1,138 +1,136 @@ -G +I  - union-testsEXPLAIN select sum(a) as a, sum(b) as b from (select sum(col1) as a, count(*) as b from t1 union all select sum(col1) as a, count(*) as b from t2) as xE - ޣ(608Y@ISCAN(VI1 <,>) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0, count_star(*) AS _1) | ON EMPTY NULL | MAP (_._0._0 AS A, coalesce_long(_._0._1, promote(0l AS LONG)) AS B) ⊎ SCAN(<,>) | TFILTER T2 | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0, count_star(*) AS _1) | ON EMPTY NULL | MAP (_._0._0 AS A, coalesce_long(_._0._1, promote(0l AS LONG)) AS B) | MAP (_ AS _0) | AGG (sum_l(_._0.A) AS _0, sum_l(_._0.B) AS _1) | ON EMPTY NULL | MAP (_._0._0 AS A, _._0._1 AS B)Adigraph G { + union-testsEXPLAIN select sum(a) as a, sum(b) as b from (select sum(col1) as a, count(*) as b from t1 union all select sum(col1) as a, count(*) as b from t2) as xG + + (60J8Y@ISCAN(VI1 <,>) | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0, count_star(*) AS _1) | ON EMPTY NULL | MAP (_._0._0 AS A, coalesce_long(_._0._1, promote(0l AS LONG)) AS B) ⊎ SCAN(<,>) | TFILTER T2 | MAP (_ AS _0) | AGG (sum_l(_._0.COL1) AS _0, count_star(*) AS _1) | ON EMPTY NULL | MAP (_._0._0 AS A, coalesce_long(_._0._1, promote(0l AS LONG)) AS B) | MAP (_ AS _0) | AGG (sum_l(_._0.A) AS _0, sum_l(_._0.B) AS _1) | ON EMPTY NULL | MAP (_._0._0 AS A, _._0._1 AS B)Cdigraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q24._0._0 AS A, q24._0._1 AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 2 [ label=<
    Value Computation
    $q24 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q105._0.A) AS _0, sum_l(q105._0.B) AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, AS _0)" ]; - 4 [ label=<
    Value Computation
    MAP (q20 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, AS _0)" ]; - 5 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS A, )" ]; - 6 [ label=<
    Value Computation
    MAP (q6._0._0 AS A, coalesce_long(q6._0._1, promote(0l AS LONG)) AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 7 [ label=<
    Value Computation
    MAP (q16._0._0 AS A, coalesce_long(q16._0._1, promote(0l AS LONG)) AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 8 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, AS _0)" ]; - 9 [ label=<
    Value Computation
    $q16 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, AS _0)" ]; - 10 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q86._0.COL1) AS _0, count_star(*) AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, AS _0)" ]; - 11 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q57._0.COL1) AS _0, count_star(*) AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, AS _0)" ]; - 12 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 13 [ label=<
    Value Computation
    MAP (q12 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 14 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 15 [ label=<
    Type Filter
    WHERE record IS [T2]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 16 [ label=<
    Index
    VI1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q24._0._0 AS A, q24._0._1 AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B)" ]; + 2 [ label=<
    Value Computation
    $q24 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1 AS _0)" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q111._0.A) AS _0, sum_l(q111._0.B) AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1 AS _0)" ]; + 4 [ label=<
    Value Computation
    MAP (q20 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B AS _0)" ]; + 5 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS A, LONG AS B)" ]; + 6 [ label=<
    Value Computation
    MAP (q6._0._0 AS A, coalesce_long(q6._0._1, promote(0l AS LONG)) AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B)" ]; + 7 [ label=<
    Value Computation
    MAP (q16._0._0 AS A, coalesce_long(q16._0._1, promote(0l AS LONG)) AS B)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, LONG AS B)" ]; + 8 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1 AS _0)" ]; + 9 [ label=<
    Value Computation
    $q16 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1 AS _0)" ]; + 10 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q92._0.COL1) AS _0, count_star(*) AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1 AS _0)" ]; + 11 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q59._0.COL1) AS _0, count_star(*) AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0, LONG AS _1 AS _0)" ]; + 12 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 13 [ label=<
    Value Computation
    MAP (q12 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3 AS _0)" ]; + 14 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 15 [ label=<
    Type Filter
    WHERE record IS [T2]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2, LONG AS COL3)" ]; + 16 [ label=<
    Index
    VI1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 17 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 18 [ label=<
    Primary Storage
    record types: [T4, T5, T6, T7, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q105> label="q105" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q111> label="q111" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q20> label="q20" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q100> label="q100" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 5 [ label=< q102> label="q102" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q106> label="q106" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 5 [ label=< q108> label="q108" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 6 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 9 -> 7 [ label=< q16> label="q16" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 10 -> 8 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 11 -> 9 [ label=< q16> label="q16" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 12 -> 10 [ label=< q86> label="q86" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 13 -> 11 [ label=< q57> label="q57" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 12 -> 10 [ label=< q92> label="q92" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 13 -> 11 [ label=< q59> label="q59" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 14 -> 12 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 15 -> 13 [ label=< q12> label="q12" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 16 -> 14 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 17 -> 15 [ label=< q49> label="q49" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 17 -> 15 [ label=< q50> label="q50" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 18 -> 17 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q24> label="q24" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}= +}>  - union-tests}EXPLAIN select sum(Y) as S from (select count(*) as Y from t3 where a < 10 group by a union all select count(*) from t4) as X< -, (.0ܜ87@AISCAN(MV10 [[LESS_THAN promote(@c22 AS DOUBLE)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS Y) | MAP (_.Y AS Y) ⊎ SCAN(<,>) | TFILTER T4 | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) | MAP (_ AS _0) | AGG (sum_l(_._0.Y) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS S)9digraph G { + union-tests}EXPLAIN select sum(Y) as S from (select count(*) as Y from t3 where a < 10 group by a union all select count(*) from t4) as X= +  Ϟ(.0'87@AISCAN(MV10 [[LESS_THAN promote(@c22 AS DOUBLE)]] BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | MAP (_._1 AS Y) | MAP (_.Y AS Y) ⊎ SCAN(<,>) | TFILTER T4 | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) | MAP (_ AS _0) | AGG (sum_l(_._0.Y) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS S):digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q26._0._0 AS S)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS S)" ]; 2 [ label=<
    Value Computation
    $q26 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q86._0.Y) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q90._0.Y) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 4 [ label=<
    Value Computation
    MAP (q22 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS Y AS _0)" ]; 5 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS Y)" ]; 6 [ label=<
    Value Computation
    MAP (q8.Y AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS Y)" ]; 7 [ label=<
    Value Computation
    MAP (coalesce_long(q16._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 8 [ label=<
    Value Computation
    MAP (q6._1 AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS Y)" ]; 9 [ label=<
    Value Computation
    $q16 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 10 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [[LESS_THAN promote(@c22 AS DOUBLE)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(DOUBLE AS _0, )" ]; + 10 [ label=<
    Index Scan
    scan type: BY_GROUP
    comparisons: [[LESS_THAN promote(@c22 AS DOUBLE)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(DOUBLE AS _0, LONG AS _1)" ]; 11 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 12 [ label=<
    Index
    MV10
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 13 [ label=<
    Value Computation
    MAP (q12 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 14 [ label=<
    Type Filter
    WHERE record IS [T4]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 12 [ label=<
    Index
    AGG[MV10; count]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, DOUBLE AS A, LONG AS B)" ]; + 13 [ label=<
    Value Computation
    MAP (q12 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS A, DOUBLE AS B AS _0)" ]; + 14 [ label=<
    Type Filter
    WHERE record IS [T4]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS A, DOUBLE AS B)" ]; 15 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 16 [ label=<
    Primary Storage
    record types: [T4, T5, T6, T7, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; 3 -> 2 [ label=< q26> label="q26" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q86> label="q86" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q90> label="q90" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q22> label="q22" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q81> label="q81" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 5 [ label=< q83> label="q83" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q85> label="q85" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 5 [ label=< q87> label="q87" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 6 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 9 -> 7 [ label=< q16> label="q16" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 10 -> 8 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 11 -> 9 [ label=< q16> label="q16" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 12 -> 10 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 13 -> 11 [ label=< q63> label="q63" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 13 -> 11 [ label=< q65> label="q65" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 14 -> 13 [ label=< q12> label="q12" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 15 -> 14 [ label=< q55> label="q55" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 15 -> 14 [ label=< q56> label="q56" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 16 -> 15 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q26> label="q26" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}H +}F t - union-testseEXPLAIN select sum(Y) as S from (select count(*) as Y from t3 union all select count(*) from t1) as XG -3 ߈(<0ȭ8[@SCAN(<,>) | TFILTER T3 | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS Y) | MAP (_.Y AS Y) ⊎ ISCAN(VI1 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) | MAP (_ AS _0) | AGG (sum_l(_._0.Y) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS S)Ddigraph G { + union-testseEXPLAIN select sum(Y) as S from (select count(*) as Y from t3 union all select count(*) from t1) as XE + (J0w8v@AISCAN(MV10 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | AGG sum_l(_._1) GROUP BY () | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS Y) | MAP (_.Y AS Y) ⊎ ISCAN(VI1 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) | MAP (_ AS _0) | AGG (sum_l(_._0.Y) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS S)Bdigraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q26._0._0 AS S)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS S)" ]; 2 [ label=<
    Value Computation
    $q26 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q118._0.Y) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q142._0.Y) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 4 [ label=<
    Value Computation
    MAP (q22 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS Y AS _0)" ]; 5 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS Y)" ]; - 6 [ label=<
    Value Computation
    MAP (q8.Y AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS Y)" ]; - 7 [ label=<
    Value Computation
    MAP (coalesce_long(q16._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 8 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS Y)" ]; - 9 [ label=<
    Value Computation
    $q16 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 10 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 11 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 12 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 13 [ label=<
    Value Computation
    MAP (q12 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 14 [ label=<
    Value Computation
    MAP (q2 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, AS _0)" ]; - 15 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 16 [ label=<
    Type Filter
    WHERE record IS [T3]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 17 [ label=<
    Index
    VI1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 18 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; - 19 [ label=<
    Primary Storage
    record types: [T4, T5, T6, T7, T1, T2, T3]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(RECORD)" ]; + 6 [ label=<
    Value Computation
    MAP (coalesce_long(q16._0._0, promote(0l AS LONG)) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; + 7 [ label=<
    Value Computation
    MAP (q8.Y AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS Y)" ]; + 8 [ label=<
    Value Computation
    $q16 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 9 [ label=<
    Value Computation
    MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS Y)" ]; + 10 [ label=<
    Streaming Aggregate
    COLLECT (count_star(*) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 11 [ label=<
    Value Computation
    $q6 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 12 [ label=<
    Value Computation
    MAP (q12 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2 AS _0)" ]; + 13 [ label=<
    Value Computation
    MAP ((q4._1 AS _0) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 14 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 15 [ label=<
    Streaming Aggregate
    COLLECT sum_l(q112._1)
    GROUP BY ()
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; + 16 [ label=<
    Index
    VI1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 17 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(DOUBLE AS _0, LONG AS _1)" ]; + 18 [ label=<
    Index
    AGG[MV10; count]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, DOUBLE AS A, LONG AS B)" ]; 3 -> 2 [ label=< q26> label="q26" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q118> label="q118" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q142> label="q142" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q22> label="q22" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q113> label="q113" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 5 [ label=< q115> label="q115" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 8 -> 6 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 9 -> 7 [ label=< q16> label="q16" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 10 -> 8 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 11 -> 9 [ label=< q16> label="q16" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 12 -> 10 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 13 -> 11 [ label=< q79> label="q79" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 14 -> 12 [ label=< q102> label="q102" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 15 -> 13 [ label=< q12> label="q12" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 16 -> 14 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 17 -> 15 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 18 -> 16 [ label=< q94> label="q94" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 19 -> 18 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q139> label="q139" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 5 [ label=< q137> label="q137" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 8 -> 6 [ label=< q16> label="q16" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 9 -> 7 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 10 -> 8 [ label=< q16> label="q16" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 11 -> 9 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 12 -> 10 [ label=< q83> label="q83" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 13 -> 11 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 14 -> 12 [ label=< q12> label="q12" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 15 -> 13 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 16 -> 14 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 17 -> 15 [ label=< q112> label="q112" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 18 -> 17 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q26> label="q26" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}= +}> t - union-testseEXPLAIN select sum(Y) as S from (select count(*) as Y from t6 union all select count(*) from t7) as X< -Ɬ Պ -(G08o@AISCAN(MV11 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS Y) | MAP (_.Y AS Y) ⊎ AISCAN(MV12 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) | MAP (_ AS _0) | AGG (sum_l(_._0.Y) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS S)9digraph G { + union-testseEXPLAIN select sum(Y) as S from (select count(*) as Y from t6 union all select count(*) from t7) as X= + Բ(G0j8o@AISCAN(MV11 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS Y) | MAP (_.Y AS Y) ⊎ AISCAN(MV12 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) | MAP (_ AS _0) | AGG (sum_l(_._0.Y) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS S):digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q26._0._0 AS S)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS S)" ]; 2 [ label=<
    Value Computation
    $q26 OR NULL
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q122._0.Y) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 3 [ label=<
    Streaming Aggregate
    COLLECT (sum_l(q132._0.Y) AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 4 [ label=<
    Value Computation
    MAP (q22 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS Y AS _0)" ]; 5 [ label=<
    Union All
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS Y)" ]; 6 [ label=<
    Value Computation
    MAP (q8.Y AS Y)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS Y)" ]; @@ -144,13 +142,13 @@ t 12 [ label=<
    Value Computation
    MAP (q4 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 13 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 14 [ label=<
    Index Scan
    scan type: BY_GROUP
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 15 [ label=<
    Index
    MV12
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 16 [ label=<
    Index
    MV11
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 15 [ label=<
    Index
    AGG[MV12; count]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 16 [ label=<
    Index
    AGG[MV11; count]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q26> label="q26" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q122> label="q122" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q132> label="q132" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ label=< q22> label="q22" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q117> label="q117" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 5 [ label=< q119> label="q119" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q127> label="q127" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 5 [ label=< q129> label="q129" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 6 [ label=< q8> label="q8" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 9 -> 7 [ label=< q16> label="q16" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 10 -> 8 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; diff --git a/yaml-tests/src/test/resources/union.metrics.yaml b/yaml-tests/src/test/resources/union.metrics.yaml index 7ebb25fde3..69d7a704dc 100644 --- a/yaml-tests/src/test/resources/union.metrics.yaml +++ b/yaml-tests/src/test/resources/union.metrics.yaml @@ -8,11 +8,11 @@ union-tests: promote(0l AS LONG)) AS B) | MAP (_ AS _0) | AGG (sum_l(_._0.A) AS _0, sum_l(_._0.B) AS _1) | ON EMPTY NULL | MAP (_._0._0 AS A, _._0._1 AS B) task_count: 831 - task_total_time_ms: 46 - transform_count: 269 - transform_time_ms: 13 + task_total_time_ms: 22 + transform_count: 275 + transform_time_ms: 5 transform_yield_count: 54 - insert_time_ms: 3 + insert_time_ms: 1 insert_new_count: 89 insert_reused_count: 6 - query: EXPLAIN select sum(Y) as S from (select count(*) as Y from t3 where a < @@ -23,29 +23,29 @@ union-tests: promote(0l AS LONG)) AS _0) | MAP (_ AS _0) | AGG (sum_l(_._0.Y) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS S)' task_count: 676 - task_total_time_ms: 92 - transform_count: 237 - transform_time_ms: 58 + task_total_time_ms: 19 + transform_count: 245 + transform_time_ms: 8 transform_yield_count: 46 - insert_time_ms: 4 + insert_time_ms: 0 insert_new_count: 55 insert_reused_count: 3 - query: EXPLAIN select sum(Y) as S from (select count(*) as Y from t3 union all select count(*) from t1) as X - explain: SCAN(<,>) | TFILTER T3 | MAP (_ AS _0) | AGG (count_star(*) AS _0) | - ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS Y) | MAP - (_.Y AS Y) ⊎ ISCAN(VI1 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | - ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) | - MAP (_ AS _0) | AGG (sum_l(_._0.Y) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS - S) - task_count: 873 - task_total_time_ms: 107 - transform_count: 286 - transform_time_ms: 61 - transform_yield_count: 60 - insert_time_ms: 5 - insert_new_count: 91 - insert_reused_count: 6 + explain: 'AISCAN(MV10 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | AGG sum_l(_._1) + GROUP BY () | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, + promote(0l AS LONG)) AS Y) | MAP (_.Y AS Y) ⊎ ISCAN(VI1 <,>) | MAP (_ AS _0) + | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, + promote(0l AS LONG)) AS _0) | MAP (_ AS _0) | AGG (sum_l(_._0.Y) AS _0) | + ON EMPTY NULL | MAP (_._0._0 AS S)' + task_count: 1038 + task_total_time_ms: 43 + transform_count: 347 + transform_time_ms: 17 + transform_yield_count: 74 + insert_time_ms: 1 + insert_new_count: 118 + insert_reused_count: 7 - query: EXPLAIN select sum(Y) as S from (select count(*) as Y from t6 union all select count(*) from t7) as X explain: 'AISCAN(MV11 <,> BY_GROUP -> [_0: VALUE:[0]]) | MAP (_ AS _0) | ON EMPTY @@ -54,10 +54,10 @@ union-tests: NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) | MAP (_ AS _0) | AGG (sum_l(_._0.Y) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS S)' task_count: 1026 - task_total_time_ms: 51 - transform_count: 351 - transform_time_ms: 22 + task_total_time_ms: 42 + transform_count: 363 + transform_time_ms: 15 transform_yield_count: 71 - insert_time_ms: 3 + insert_time_ms: 1 insert_new_count: 111 insert_reused_count: 7 diff --git a/yaml-tests/src/test/resources/union.yamsql b/yaml-tests/src/test/resources/union.yamsql index 0ab46d08e5..0ed9a1db93 100644 --- a/yaml-tests/src/test/resources/union.yamsql +++ b/yaml-tests/src/test/resources/union.yamsql @@ -168,7 +168,7 @@ test_block: # Does not work in force continuations mode on prior versions due to: https://github.com/FoundationDB/fdb-record-layer/issues/3096 # Hard to write asserts for on older versions, but no unexpected mixed mode issues when running with older versions - supported_version: 4.1.9.0 - - explain: "SCAN(<,>) | TFILTER T3 | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS Y) | MAP (_.Y AS Y) ⊎ ISCAN(VI1 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) | MAP (_ AS _0) | AGG (sum_l(_._0.Y) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS S)" + - explain: "AISCAN(MV10 <,> BY_GROUP -> [_0: KEY:[0], _1: VALUE:[0]]) | AGG sum_l(_._1) GROUP BY () | MAP ((_._1 AS _0) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS Y) | MAP (_.Y AS Y) ⊎ ISCAN(VI1 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) | MAP (_ AS _0) | AGG (sum_l(_._0.Y) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS S)" - result: [{S: 5}] - - query: select col2 from t1 where exists (select a from t3 where col2 <= id union all select b from t4 where col2 <= id) diff --git a/yaml-tests/src/test/resources/update-delete-returning.metrics.binpb b/yaml-tests/src/test/resources/update-delete-returning.metrics.binpb index 7b3bf8883a..9560b8e98f 100644 --- a/yaml-tests/src/test/resources/update-delete-returning.metrics.binpb +++ b/yaml-tests/src/test/resources/update-delete-returning.metrics.binpb @@ -1,21 +1,21 @@ - + e - unnamed-1XEXPLAIN update A set A2 = 42, A3 = 44 where A1 <= 2 returning "new".A3 OPTIONS(DRY RUN); -ƹ~N 8(08@tSCAN(<,>) | DISTINCT BY PK | FILTER _.A1 LESS_THAN_OR_EQUALS promote(@c15 AS LONG) | UPDATE A | MAP (_.new.A3 AS A3)digraph G { + unnamed-1XEXPLAIN update A set A2 = 42, A3 = 44 where A1 <= 2 returning "new".A3 OPTIONS(DRY RUN); +{Q 5(08@tSCAN(<,>) | DISTINCT BY PK | FILTER _.A1 LESS_THAN_OR_EQUALS promote(@c15 AS LONG) | UPDATE A | MAP (_.new.A3 AS A3)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6.new.A3 AS A3)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A3)" ]; - 2 [ label=<
    Modification
    UPDATE
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, AS old, )" ]; - 3 [ label=<
    Primary Storage
    A
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, AS old, )" ]; - 4 [ label=<
    Predicate Filter
    WHERE q30.A1 LESS_THAN_OR_EQUALS promote(@c15 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; - 5 [ label=<
    Unordered Primary Key Distinct
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS A1, )" ]; - 6 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; - 7 [ label=<
    Primary Storage
    record types: [A]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; + 2 [ label=<
    Modification
    UPDATE
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3 AS old, LONG AS A1, LONG AS A2, LONG AS A3 AS new)" ]; + 3 [ label=<
    Primary Storage
    A
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3 AS old, LONG AS A1, LONG AS A2, LONG AS A3 AS new)" ]; + 4 [ label=<
    Predicate Filter
    WHERE q32.A1 LESS_THAN_OR_EQUALS promote(@c15 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; + 5 [ label=<
    Unordered Primary Key Distinct
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; + 6 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; + 7 [ label=<
    Primary Storage
    record types: [A]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="none" arrowtail="normal" dir="both" ]; 4 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q30> label="q30" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q28> label="q28" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q32> label="q32" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q30> label="q30" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; { @@ -23,24 +23,24 @@ e rankDir=LR; 4 -> 3 [ color="red" style="invis" ]; } -} +} T - unnamed-1GEXPLAIN update A set A2 = 42, A3 = 44 where A1 <= 2 returning "new".A3; -ƹ~N 8(08@tSCAN(<,>) | DISTINCT BY PK | FILTER _.A1 LESS_THAN_OR_EQUALS promote(@c15 AS LONG) | UPDATE A | MAP (_.new.A3 AS A3)digraph G { + unnamed-1GEXPLAIN update A set A2 = 42, A3 = 44 where A1 <= 2 returning "new".A3; +{Q 5(08@tSCAN(<,>) | DISTINCT BY PK | FILTER _.A1 LESS_THAN_OR_EQUALS promote(@c15 AS LONG) | UPDATE A | MAP (_.new.A3 AS A3)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6.new.A3 AS A3)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A3)" ]; - 2 [ label=<
    Modification
    UPDATE
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, AS old, )" ]; - 3 [ label=<
    Primary Storage
    A
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, AS old, )" ]; - 4 [ label=<
    Predicate Filter
    WHERE q30.A1 LESS_THAN_OR_EQUALS promote(@c15 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; - 5 [ label=<
    Unordered Primary Key Distinct
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS A1, )" ]; - 6 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; - 7 [ label=<
    Primary Storage
    record types: [A]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; + 2 [ label=<
    Modification
    UPDATE
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3 AS old, LONG AS A1, LONG AS A2, LONG AS A3 AS new)" ]; + 3 [ label=<
    Primary Storage
    A
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3 AS old, LONG AS A1, LONG AS A2, LONG AS A3 AS new)" ]; + 4 [ label=<
    Predicate Filter
    WHERE q32.A1 LESS_THAN_OR_EQUALS promote(@c15 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; + 5 [ label=<
    Unordered Primary Key Distinct
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; + 6 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; + 7 [ label=<
    Primary Storage
    record types: [A]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="none" arrowtail="normal" dir="both" ]; 4 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q30> label="q30" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q28> label="q28" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q32> label="q32" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q30> label="q30" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; { @@ -48,24 +48,24 @@ T rankDir=LR; 4 -> 3 [ color="red" style="invis" ]; } -} +} p - unnamed-1cEXPLAIN update A set A2 = 42, A3 = 44 where A1 <= 2 returning "new".A3 + "new".A3 OPTIONS(DRY RUN); -ߪN ˠ(0׮ 8@SCAN(<,>) | DISTINCT BY PK | FILTER _.A1 LESS_THAN_OR_EQUALS promote(@c15 AS LONG) | UPDATE A | MAP (_.new.A3 + _.new.A3 AS _0)digraph G { + unnamed-1cEXPLAIN update A set A2 = 42, A3 = 44 where A1 <= 2 returning "new".A3 + "new".A3 OPTIONS(DRY RUN); +mQ -(08@SCAN(<,>) | DISTINCT BY PK | FILTER _.A1 LESS_THAN_OR_EQUALS promote(@c15 AS LONG) | UPDATE A | MAP (_.new.A3 + _.new.A3 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6.new.A3 + q6.new.A3 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Modification
    UPDATE
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, AS old, )" ]; - 3 [ label=<
    Predicate Filter
    WHERE q30.A1 LESS_THAN_OR_EQUALS promote(@c15 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; - 4 [ label=<
    Primary Storage
    A
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, AS old, )" ]; - 5 [ label=<
    Unordered Primary Key Distinct
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS A1, )" ]; - 6 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; - 7 [ label=<
    Primary Storage
    record types: [A]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; + 2 [ label=<
    Modification
    UPDATE
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3 AS old, LONG AS A1, LONG AS A2, LONG AS A3 AS new)" ]; + 3 [ label=<
    Predicate Filter
    WHERE q32.A1 LESS_THAN_OR_EQUALS promote(@c15 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; + 4 [ label=<
    Primary Storage
    A
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3 AS old, LONG AS A1, LONG AS A2, LONG AS A3 AS new)" ]; + 5 [ label=<
    Unordered Primary Key Distinct
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; + 6 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; + 7 [ label=<
    Primary Storage
    record types: [A]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="none" arrowtail="normal" dir="both" ]; - 5 -> 3 [ label=< q30> label="q30" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q28> label="q28" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 3 [ label=< q32> label="q32" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q30> label="q30" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; { @@ -73,24 +73,24 @@ p rankDir=LR; 3 -> 4 [ color="red" style="invis" ]; } -} +} _ - unnamed-1REXPLAIN update A set A2 = 42, A3 = 44 where A1 <= 2 returning "new".A3 + "new".A3; -ߪN ˠ(0׮ 8@SCAN(<,>) | DISTINCT BY PK | FILTER _.A1 LESS_THAN_OR_EQUALS promote(@c15 AS LONG) | UPDATE A | MAP (_.new.A3 + _.new.A3 AS _0)digraph G { + unnamed-1REXPLAIN update A set A2 = 42, A3 = 44 where A1 <= 2 returning "new".A3 + "new".A3; +mQ -(08@SCAN(<,>) | DISTINCT BY PK | FILTER _.A1 LESS_THAN_OR_EQUALS promote(@c15 AS LONG) | UPDATE A | MAP (_.new.A3 + _.new.A3 AS _0)digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
    Value Computation
    MAP (q6.new.A3 + q6.new.A3 AS _0)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
    Modification
    UPDATE
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, AS old, )" ]; - 3 [ label=<
    Predicate Filter
    WHERE q30.A1 LESS_THAN_OR_EQUALS promote(@c15 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; - 4 [ label=<
    Primary Storage
    A
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, AS old, )" ]; - 5 [ label=<
    Unordered Primary Key Distinct
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS A1, )" ]; - 6 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; - 7 [ label=<
    Primary Storage
    record types: [A]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; + 2 [ label=<
    Modification
    UPDATE
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3 AS old, LONG AS A1, LONG AS A2, LONG AS A3 AS new)" ]; + 3 [ label=<
    Predicate Filter
    WHERE q32.A1 LESS_THAN_OR_EQUALS promote(@c15 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; + 4 [ label=<
    Primary Storage
    A
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3 AS old, LONG AS A1, LONG AS A2, LONG AS A3 AS new)" ]; + 5 [ label=<
    Unordered Primary Key Distinct
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; + 6 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; + 7 [ label=<
    Primary Storage
    record types: [A]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="none" arrowtail="normal" dir="both" ]; - 5 -> 3 [ label=< q30> label="q30" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q28> label="q28" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 3 [ label=< q32> label="q32" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q30> label="q30" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; { @@ -98,21 +98,21 @@ _ rankDir=LR; 3 -> 4 [ color="red" style="invis" ]; } -} +} H - unnamed-1;EXPLAIN update A set A2 = 52 where A1 > 2 OPTIONS(DRY RUN); -B ?(08@VSCAN(<,>) | DISTINCT BY PK | FILTER _.A1 GREATER_THAN promote(@c10 AS LONG) | UPDATE Adigraph G { + unnamed-1;EXPLAIN update A set A2 = 52 where A1 > 2 OPTIONS(DRY RUN); +eE .(0ī8@VSCAN(<,>) | DISTINCT BY PK | FILTER _.A1 GREATER_THAN promote(@c10 AS LONG) | UPDATE Adigraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Modification
    UPDATE
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, AS old, )" ]; - 2 [ label=<
    Predicate Filter
    WHERE q28.A1 GREATER_THAN promote(@c10 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; - 3 [ label=<
    Unordered Primary Key Distinct
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS A1, )" ]; - 4 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; - 5 [ label=<
    Primary Storage
    record types: [A]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; - 6 [ label=<
    Primary Storage
    A
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, AS old, )" ]; - 3 -> 2 [ label=< q28> label="q28" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q26> label="q26" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 1 [ label=<
    Modification
    UPDATE
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3 AS old, LONG AS A1, LONG AS A2, LONG AS A3 AS new)" ]; + 2 [ label=<
    Predicate Filter
    WHERE q30.A1 GREATER_THAN promote(@c10 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; + 3 [ label=<
    Unordered Primary Key Distinct
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; + 4 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; + 5 [ label=<
    Primary Storage
    record types: [A]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; + 6 [ label=<
    Primary Storage
    A
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3 AS old, LONG AS A1, LONG AS A2, LONG AS A3 AS new)" ]; + 3 -> 2 [ label=< q30> label="q30" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q28> label="q28" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 1 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="none" arrowtail="normal" dir="both" ]; @@ -121,21 +121,21 @@ H rankDir=LR; 2 -> 6 [ color="red" style="invis" ]; } -} +} 7 - unnamed-1*EXPLAIN update A set A2 = 52 where A1 > 2; -B ?(08@VSCAN(<,>) | DISTINCT BY PK | FILTER _.A1 GREATER_THAN promote(@c10 AS LONG) | UPDATE Adigraph G { + unnamed-1*EXPLAIN update A set A2 = 52 where A1 > 2; +eE .(0ī8@VSCAN(<,>) | DISTINCT BY PK | FILTER _.A1 GREATER_THAN promote(@c10 AS LONG) | UPDATE Adigraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Modification
    UPDATE
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, AS old, )" ]; - 2 [ label=<
    Predicate Filter
    WHERE q28.A1 GREATER_THAN promote(@c10 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; - 3 [ label=<
    Unordered Primary Key Distinct
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS A1, )" ]; - 4 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; - 5 [ label=<
    Primary Storage
    record types: [A]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, )" ]; - 6 [ label=<
    Primary Storage
    A
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, AS old, )" ]; - 3 -> 2 [ label=< q28> label="q28" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q26> label="q26" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 1 [ label=<
    Modification
    UPDATE
    > color="black" shape="plain" style="filled" fillcolor="lightcoral" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3 AS old, LONG AS A1, LONG AS A2, LONG AS A3 AS new)" ]; + 2 [ label=<
    Predicate Filter
    WHERE q30.A1 GREATER_THAN promote(@c10 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; + 3 [ label=<
    Unordered Primary Key Distinct
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; + 4 [ label=<
    Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; + 5 [ label=<
    Primary Storage
    record types: [A]
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3)" ]; + 6 [ label=<
    Primary Storage
    A
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A1, LONG AS A2, LONG AS A3 AS old, LONG AS A1, LONG AS A2, LONG AS A3 AS new)" ]; + 3 -> 2 [ label=< q30> label="q30" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q28> label="q28" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 1 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="none" arrowtail="normal" dir="both" ]; diff --git a/yaml-tests/src/test/resources/update-delete-returning.metrics.yaml b/yaml-tests/src/test/resources/update-delete-returning.metrics.yaml index 3768f59f65..ddba025428 100644 --- a/yaml-tests/src/test/resources/update-delete-returning.metrics.yaml +++ b/yaml-tests/src/test/resources/update-delete-returning.metrics.yaml @@ -5,7 +5,7 @@ unnamed-1: AS LONG) | UPDATE A | MAP (_.new.A3 AS A3) task_count: 252 task_total_time_ms: 2 - transform_count: 78 + transform_count: 81 transform_time_ms: 0 transform_yield_count: 15 insert_time_ms: 0 @@ -16,7 +16,7 @@ unnamed-1: AS LONG) | UPDATE A | MAP (_.new.A3 AS A3) task_count: 252 task_total_time_ms: 2 - transform_count: 78 + transform_count: 81 transform_time_ms: 0 transform_yield_count: 15 insert_time_ms: 0 @@ -27,9 +27,9 @@ unnamed-1: explain: SCAN(<,>) | DISTINCT BY PK | FILTER _.A1 LESS_THAN_OR_EQUALS promote(@c15 AS LONG) | UPDATE A | MAP (_.new.A3 + _.new.A3 AS _0) task_count: 252 - task_total_time_ms: 5 - transform_count: 78 - transform_time_ms: 4 + task_total_time_ms: 1 + transform_count: 81 + transform_time_ms: 0 transform_yield_count: 15 insert_time_ms: 0 insert_new_count: 18 @@ -39,9 +39,9 @@ unnamed-1: explain: SCAN(<,>) | DISTINCT BY PK | FILTER _.A1 LESS_THAN_OR_EQUALS promote(@c15 AS LONG) | UPDATE A | MAP (_.new.A3 + _.new.A3 AS _0) task_count: 252 - task_total_time_ms: 5 - transform_count: 78 - transform_time_ms: 4 + task_total_time_ms: 1 + transform_count: 81 + transform_time_ms: 0 transform_yield_count: 15 insert_time_ms: 0 insert_new_count: 18 @@ -50,9 +50,9 @@ unnamed-1: explain: SCAN(<,>) | DISTINCT BY PK | FILTER _.A1 GREATER_THAN promote(@c10 AS LONG) | UPDATE A task_count: 219 - task_total_time_ms: 2 - transform_count: 66 - transform_time_ms: 1 + task_total_time_ms: 1 + transform_count: 69 + transform_time_ms: 0 transform_yield_count: 14 insert_time_ms: 0 insert_new_count: 16 @@ -61,9 +61,9 @@ unnamed-1: explain: SCAN(<,>) | DISTINCT BY PK | FILTER _.A1 GREATER_THAN promote(@c10 AS LONG) | UPDATE A task_count: 219 - task_total_time_ms: 2 - transform_count: 66 - transform_time_ms: 1 + task_total_time_ms: 1 + transform_count: 69 + transform_time_ms: 0 transform_yield_count: 14 insert_time_ms: 0 insert_new_count: 16 diff --git a/yaml-tests/src/test/resources/uuid.metrics.binpb b/yaml-tests/src/test/resources/uuid.metrics.binpb index a38de0fb50..3ca19085a2 100644 --- a/yaml-tests/src/test/resources/uuid.metrics.binpb +++ b/yaml-tests/src/test/resources/uuid.metrics.binpb @@ -1,58 +1,60 @@ - + B -uuid-in-index-definition&EXPLAIN select b, c from tc order by b - -Z У("098"@SCOVERING(TC1 <,> -> [A: KEY[2], B: KEY[0], C: VALUE[0]]) | MAP (_.B AS B, _.C AS C) digraph G { +uuid-in-index-definition&EXPLAIN select b, c from tc order by b +] ܆("0$8"@SCOVERING(TC1 <,> -> [A: KEY[2], B: KEY[0], C: VALUE[0]]) | MAP (_.B AS B, _.C AS C) +digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q38.B AS B, q38.C AS C)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(UUID AS B, )" ]; - 2 [ label=<
    Covering Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 3 [ label=<
    Index
    TC1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; + 1 [ label=<
    Value Computation
    MAP (q40.B AS B, q40.C AS C)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(UUID AS B, LONG AS C)" ]; + 2 [ label=<
    Covering Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, UUID AS B, LONG AS C)" ]; + 3 [ label=<
    Index
    TC1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, UUID AS B, LONG AS C)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 2 -> 1 [ label=< q38> label="q38" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} + 2 -> 1 [ label=< q40> label="q40" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +} ? -uuid-in-index-definition#EXPLAIN select * from tc order by b -\ ("08@ISCAN(TC1 <,>)digraph G { +uuid-in-index-definition#EXPLAIN select * from tc order by b +帥_ ("08@ISCAN(TC1 <,>)digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 2 [ label=<
    Index
    TC1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; + 1 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, UUID AS B, LONG AS C)" ]; + 2 [ label=<
    Index
    TC1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, UUID AS B, LONG AS C)" ]; 2 -> 1 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} p -uuid-in-index-definitionTEXPLAIN select * from tc where b > 'a8708750-d70f-4800-8c3b-13700d5b369f' order by b - (.0h80@0ISCAN(TC1 [[GREATER_THAN promote(@c8 AS UUID)]])digraph G { +uuid-in-index-definitionTEXPLAIN select * from tc where b > 'a8708750-d70f-4800-8c3b-13700d5b369f' order by b + + (.0ʧ080@0ISCAN(TC1 [[GREATER_THAN promote(@c8 AS UUID)]])digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c8 AS UUID)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 2 [ label=<
    Index
    TC1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; + 1 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c8 AS UUID)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, UUID AS B, LONG AS C)" ]; + 2 [ label=<
    Index
    TC1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, UUID AS B, LONG AS C)" ]; 2 -> 1 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} u -uuid-in-index-definitionYEXPLAIN select * from tc where b < 'a8708750-d70f-4800-8c3b-13700d5b369f' order by b desc -̾# (.0䪷80@5ISCAN(TC1 [[LESS_THAN promote(@c8 AS UUID)]] REVERSE)digraph G { +uuid-in-index-definitionYEXPLAIN select * from tc where b < 'a8708750-d70f-4800-8c3b-13700d5b369f' order by b desc + + ݰ(.0180@5ISCAN(TC1 [[LESS_THAN promote(@c8 AS UUID)]] REVERSE)digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Index Scan
    comparisons: [[LESS_THAN promote(@c8 AS UUID)]]
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 2 [ label=<
    Index
    TC1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; + 1 [ label=<
    Index Scan
    comparisons: [[LESS_THAN promote(@c8 AS UUID)]]
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, UUID AS B, LONG AS C)" ]; + 2 [ label=<
    Index
    TC1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, UUID AS B, LONG AS C)" ]; 2 -> 1 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +}  -uuid-in-index-definitioncEXPLAIN select * from tc where b < 'a8708750-d70f-4800-8c3b-13700d5b369f' and c > 4 order by b desc -雲& (208B@COVERING(TC1 [[LESS_THAN promote(@c8 AS UUID)]] REVERSE -> [A: KEY[2], B: KEY[0], C: VALUE[0]]) | FILTER _.C GREATER_THAN promote(@c12 AS LONG) | FETCH digraph G { +uuid-in-index-definitioncEXPLAIN select * from tc where b < 'a8708750-d70f-4800-8c3b-13700d5b369f' and c > 4 order by b desc + ך(20/8B@COVERING(TC1 [[LESS_THAN promote(@c8 AS UUID)]] REVERSE -> [A: KEY[2], B: KEY[0], C: VALUE[0]]) | FILTER _.C GREATER_THAN promote(@c12 AS LONG) | FETCHdigraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Fetch Records
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS A, )" ]; - 2 [ label=<
    Predicate Filter
    WHERE q55.C GREATER_THAN promote(@c12 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 3 [ label=<
    Covering Index Scan
    comparisons: [[LESS_THAN promote(@c8 AS UUID)]]
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 4 [ label=<
    Index
    TC1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, )" ]; - 3 -> 2 [ label=< q55> label="q55" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 1 [ label=<
    Fetch Records
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS A, UUID AS B, LONG AS C)" ]; + 2 [ label=<
    Predicate Filter
    WHERE q59.C GREATER_THAN promote(@c12 AS LONG)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, UUID AS B, LONG AS C)" ]; + 3 [ label=<
    Covering Index Scan
    comparisons: [[LESS_THAN promote(@c8 AS UUID)]]
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, UUID AS B, LONG AS C)" ]; + 4 [ label=<
    Index
    TC1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS A, UUID AS B, LONG AS C)" ]; + 3 -> 2 [ label=< q59> label="q59" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 2 -> 1 [ label=< q57> label="q57" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 -> 1 [ label=< q61> label="q61" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; } \ No newline at end of file diff --git a/yaml-tests/src/test/resources/uuid.metrics.yaml b/yaml-tests/src/test/resources/uuid.metrics.yaml index 1dae54de72..512b0c5941 100644 --- a/yaml-tests/src/test/resources/uuid.metrics.yaml +++ b/yaml-tests/src/test/resources/uuid.metrics.yaml @@ -3,9 +3,9 @@ uuid-in-index-definition: explain: 'COVERING(TC1 <,> -> [A: KEY[2], B: KEY[0], C: VALUE[0]]) | MAP (_.B AS B, _.C AS C)' task_count: 309 - task_total_time_ms: 15 - transform_count: 90 - transform_time_ms: 6 + task_total_time_ms: 18 + transform_count: 93 + transform_time_ms: 8 transform_yield_count: 34 insert_time_ms: 0 insert_new_count: 34 @@ -13,33 +13,33 @@ uuid-in-index-definition: - query: EXPLAIN select * from tc order by b explain: ISCAN(TC1 <,>) task_count: 281 - task_total_time_ms: 56 - transform_count: 92 - transform_time_ms: 38 + task_total_time_ms: 15 + transform_count: 95 + transform_time_ms: 7 transform_yield_count: 34 - insert_time_ms: 2 + insert_time_ms: 0 insert_new_count: 24 insert_reused_count: 8 - query: EXPLAIN select * from tc where b > 'a8708750-d70f-4800-8c3b-13700d5b369f' order by b explain: ISCAN(TC1 [[GREATER_THAN promote(@c8 AS UUID)]]) task_count: 493 - task_total_time_ms: 30 - transform_count: 142 - transform_time_ms: 9 + task_total_time_ms: 22 + transform_count: 145 + transform_time_ms: 8 transform_yield_count: 46 - insert_time_ms: 1 + insert_time_ms: 0 insert_new_count: 48 insert_reused_count: 6 - query: EXPLAIN select * from tc where b < 'a8708750-d70f-4800-8c3b-13700d5b369f' order by b desc explain: ISCAN(TC1 [[LESS_THAN promote(@c8 AS UUID)]] REVERSE) task_count: 493 - task_total_time_ms: 74 - transform_count: 142 - transform_time_ms: 44 + task_total_time_ms: 22 + transform_count: 145 + transform_time_ms: 7 transform_yield_count: 46 - insert_time_ms: 3 + insert_time_ms: 0 insert_new_count: 48 insert_reused_count: 6 - query: EXPLAIN select * from tc where b < 'a8708750-d70f-4800-8c3b-13700d5b369f' @@ -48,10 +48,10 @@ uuid-in-index-definition: B: KEY[0], C: VALUE[0]]) | FILTER _.C GREATER_THAN promote(@c12 AS LONG) | FETCH' task_count: 605 - task_total_time_ms: 80 - transform_count: 152 - transform_time_ms: 47 + task_total_time_ms: 15 + transform_count: 155 + transform_time_ms: 3 transform_yield_count: 50 - insert_time_ms: 3 + insert_time_ms: 0 insert_new_count: 66 insert_reused_count: 2 diff --git a/yaml-tests/src/test/resources/versions-tests.metrics.binpb b/yaml-tests/src/test/resources/versions-tests.metrics.binpb index 3b8a3e65a6..f7dd32472f 100644 --- a/yaml-tests/src/test/resources/versions-tests.metrics.binpb +++ b/yaml-tests/src/test/resources/versions-tests.metrics.binpb @@ -1,169 +1,163 @@ - + X - unnamed-2KEXPLAIN select "__ROW_VERSION" as version, t1.col2 from t1 where col1 = 10; - (=0^8Y@XISCAN(I1 [EQUALS promote(@c14 AS LONG)]) | MAP (version([_]) AS VERSION, _.COL2 AS COL2) + unnamed-2KEXPLAIN select "__ROW_VERSION" as version, t1.col2 from t1 where col1 = 10; +  (=0U8Y@XISCAN(I1 [EQUALS promote(@c14 AS LONG)]) | MAP (version([_]) AS VERSION, _.COL2 AS COL2) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (version([q2]) AS VERSION, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS VERSION, )" ]; - 2 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c14 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (version([q2]) AS VERSION, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS VERSION, LONG AS COL2)" ]; + 2 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c14 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} 9 - unnamed-2,EXPLAIN select t1.* from t1 where col1 = 10; -̑  (C0h8Q@ (ISCAN(I1 [EQUALS promote(@c10 AS LONG)])digraph G { + unnamed-2,EXPLAIN select t1.* from t1 where col1 = 10; +ȹ (C0o8Q@ (ISCAN(I1 [EQUALS promote(@c10 AS LONG)])digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c10 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 2 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c10 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 2 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 2 -> 1 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +}  - unnamed-2xEXPLAIN select s.version, s.col2 from (select "__ROW_VERSION" as version, t1.col2 as col2 from t1 where col1 = 10) AS s; -擖 (;0^8i@ISCAN(I1 [EQUALS promote(@c26 AS LONG)]) | MAP (version([_]) AS VERSION, _.COL2 AS COL2) | MAP (_.VERSION AS VERSION, _.COL2 AS COL2)digraph G { + unnamed-2xEXPLAIN select s.version, s.col2 from (select "__ROW_VERSION" as version, t1.col2 as col2 from t1 where col1 = 10) AS s; +ޛ (;018i@ISCAN(I1 [EQUALS promote(@c26 AS LONG)]) | MAP (version([_]) AS VERSION, _.COL2 AS COL2) | MAP (_.VERSION AS VERSION, _.COL2 AS COL2)digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q4.VERSION AS VERSION, q4.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS VERSION, )" ]; - 2 [ label=<
    Value Computation
    MAP (version([q2]) AS VERSION, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS VERSION, )" ]; - 3 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c26 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 4 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q4.VERSION AS VERSION, q4.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS VERSION, LONG AS COL2)" ]; + 2 [ label=<
    Value Computation
    MAP (version([q2]) AS VERSION, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS VERSION, LONG AS COL2)" ]; + 3 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c26 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 4 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} z - unnamed-2mEXPLAIN select s."__ROW_VERSION", s.col2 from (select "__ROW_VERSION", t1.col2 from t1 where col1 = 10) AS s; -ـ  ۮ(;0I8i@ISCAN(I1 [EQUALS promote(@c22 AS LONG)]) | MAP (version([_]) AS __ROW_VERSION, _.COL2 AS COL2) | MAP (_.__ROW_VERSION AS __ROW_VERSION, _.COL2 AS COL2)digraph G { + unnamed-2mEXPLAIN select s."__ROW_VERSION", s.col2 from (select "__ROW_VERSION", t1.col2 from t1 where col1 = 10) AS s; +ν ؇(;008i@ISCAN(I1 [EQUALS promote(@c22 AS LONG)]) | MAP (version([_]) AS __ROW_VERSION, _.COL2 AS COL2) | MAP (_.__ROW_VERSION AS __ROW_VERSION, _.COL2 AS COL2)digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (q4.__ROW_VERSION AS __ROW_VERSION, q4.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS __ROW_VERSION, )" ]; - 2 [ label=<
    Value Computation
    MAP (version([q2]) AS __ROW_VERSION, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS __ROW_VERSION, )" ]; - 3 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c22 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 4 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (q4.__ROW_VERSION AS __ROW_VERSION, q4.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS __ROW_VERSION, LONG AS COL2)" ]; + 2 [ label=<
    Value Computation
    MAP (version([q2]) AS __ROW_VERSION, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS __ROW_VERSION, LONG AS COL2)" ]; + 3 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c22 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 4 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q4> label="q4" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} U - unnamed-2HEXPLAIN select "__ROW_VERSION" as version, t1.* from t1 where col1 = 20; -ΰ (=0h8Y@tISCAN(I1 [EQUALS promote(@c14 AS LONG)]) | MAP (version([_]) AS VERSION, _.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2) -digraph G { + unnamed-2HEXPLAIN select "__ROW_VERSION" as version, t1.* from t1 where col1 = 20; + ؖ(=0k8Y@tISCAN(I1 [EQUALS promote(@c14 AS LONG)]) | MAP (version([_]) AS VERSION, _.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (version([q2]) AS VERSION, q2.ID AS ID, q2.COL1 AS COL1, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS VERSION, )" ]; - 2 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c14 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (version([q2]) AS VERSION, q2.ID AS ID, q2.COL1 AS COL1, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS VERSION, LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 2 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c14 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} W - unnamed-2JEXPLAIN select "__ROW_VERSION" as version, (t1.*) from t1 where col1 = 20; -  (=0W8Y@QISCAN(I1 [EQUALS promote(@c16 AS LONG)]) | MAP (version([_]) AS VERSION, _ AS _1) + unnamed-2JEXPLAIN select "__ROW_VERSION" as version, (t1.*) from t1 where col1 = 20; + (=0g8Y@QISCAN(I1 [EQUALS promote(@c16 AS LONG)]) | MAP (version([_]) AS VERSION, _ AS _1) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (version([q2]) AS VERSION, q2 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS VERSION, )" ]; - 2 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c16 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (version([q2]) AS VERSION, q2 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS VERSION, LONG AS ID, LONG AS COL1, LONG AS COL2 AS _1)" ]; + 2 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c16 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} J - unnamed-2=EXPLAIN select "__ROW_VERSION", t1.* from t1 where col1 = 20; -ā (=0s8Y@zISCAN(I1 [EQUALS promote(@c12 AS LONG)]) | MAP (version([_]) AS __ROW_VERSION, _.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2) -digraph G { + unnamed-2=EXPLAIN select "__ROW_VERSION", t1.* from t1 where col1 = 20; + (=0Ìm8Y@zISCAN(I1 [EQUALS promote(@c12 AS LONG)]) | MAP (version([_]) AS __ROW_VERSION, _.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (version([q2]) AS __ROW_VERSION, q2.ID AS ID, q2.COL1 AS COL1, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS __ROW_VERSION, )" ]; - 2 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c12 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (version([q2]) AS __ROW_VERSION, q2.ID AS ID, q2.COL1 AS COL1, q2.COL2 AS COL2)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS __ROW_VERSION, LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 2 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c12 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} L - unnamed-2?EXPLAIN select "__ROW_VERSION", (t1.*) from t1 where col1 = 20; -  (=0R8Y@WISCAN(I1 [EQUALS promote(@c14 AS LONG)]) | MAP (version([_]) AS __ROW_VERSION, _ AS _1) -digraph G { + unnamed-2?EXPLAIN select "__ROW_VERSION", (t1.*) from t1 where col1 = 20; +﹔ (=058Y@WISCAN(I1 [EQUALS promote(@c14 AS LONG)]) | MAP (version([_]) AS __ROW_VERSION, _ AS _1) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (version([q2]) AS __ROW_VERSION, q2 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS __ROW_VERSION, )" ]; - 2 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c14 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (version([q2]) AS __ROW_VERSION, q2 AS _1)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS __ROW_VERSION, LONG AS ID, LONG AS COL1, LONG AS COL2 AS _1)" ]; + 2 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c14 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 [ label=<
    Index
    I1
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} X - unnamed-2KEXPLAIN select "__ROW_VERSION", t1.id from t1 order by "__ROW_VERSION" ASC; -< (08@JISCAN(VERSION_INDEX <,>) | MAP (version([_]) AS __ROW_VERSION, _.ID AS ID) + unnamed-2KEXPLAIN select "__ROW_VERSION", t1.id from t1 order by "__ROW_VERSION" ASC; +? (0 8@JISCAN(VERSION_INDEX <,>) | MAP (version([_]) AS __ROW_VERSION, _.ID AS ID) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (version([q2]) AS __ROW_VERSION, q2.ID AS ID)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS __ROW_VERSION, )" ]; - 2 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 [ label=<
    Index
    VERSION_INDEX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (version([q2]) AS __ROW_VERSION, q2.ID AS ID)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS __ROW_VERSION, LONG AS ID)" ]; + 2 [ label=<
    Index Scan
    range: <-∞, ∞>
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 [ label=<
    Index
    VERSION_INDEX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} \ - unnamed-2OEXPLAIN select t1."__ROW_VERSION", t1.id from t1 order by "__ROW_VERSION" DESC; -< (0Ӹ8@RISCAN(VERSION_INDEX <,> REVERSE) | MAP (version([_]) AS __ROW_VERSION, _.ID AS ID) -digraph G { + unnamed-2OEXPLAIN select t1."__ROW_VERSION", t1.id from t1 order by "__ROW_VERSION" DESC; +ʅ? (08@RISCAN(VERSION_INDEX <,> REVERSE) | MAP (version([_]) AS __ROW_VERSION, _.ID AS ID) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (version([q2]) AS __ROW_VERSION, q2.ID AS ID)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS __ROW_VERSION, )" ]; - 2 [ label=<
    Index Scan
    range: <-∞, ∞>
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 [ label=<
    Index
    VERSION_INDEX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (version([q2]) AS __ROW_VERSION, q2.ID AS ID)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS __ROW_VERSION, LONG AS ID)" ]; + 2 [ label=<
    Index Scan
    range: <-∞, ∞>
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 [ label=<
    Index
    VERSION_INDEX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} k - unnamed-2^EXPLAIN select t1."__ROW_VERSION", t1.id from t1 where col1 = 20 order by "__ROW_VERSION" ASC; -g (%08"@mISCAN(GROUPED_VERSION_INDEX [EQUALS promote(@c14 AS LONG)]) | MAP (version([_]) AS __ROW_VERSION, _.ID AS ID) + unnamed-2^EXPLAIN select t1."__ROW_VERSION", t1.id from t1 where col1 = 20 order by "__ROW_VERSION" ASC; + j (%08"@mISCAN(GROUPED_VERSION_INDEX [EQUALS promote(@c14 AS LONG)]) | MAP (version([_]) AS __ROW_VERSION, _.ID AS ID) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (version([q2]) AS __ROW_VERSION, q2.ID AS ID)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS __ROW_VERSION, )" ]; - 2 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c14 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 [ label=<
    Index
    GROUPED_VERSION_INDEX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (version([q2]) AS __ROW_VERSION, q2.ID AS ID)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS __ROW_VERSION, LONG AS ID)" ]; + 2 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c14 AS LONG)]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 [ label=<
    Index
    GROUPED_VERSION_INDEX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} i - unnamed-2\EXPLAIN select "__ROW_VERSION", t1.id from t1 where col1 = 20 order by "__ROW_VERSION" DESC; -g (%08"@uISCAN(GROUPED_VERSION_INDEX [EQUALS promote(@c12 AS LONG)] REVERSE) | MAP (version([_]) AS __ROW_VERSION, _.ID AS ID) -digraph G { + unnamed-2\EXPLAIN select "__ROW_VERSION", t1.id from t1 where col1 = 20 order by "__ROW_VERSION" DESC; + j (%08"@uISCAN(GROUPED_VERSION_INDEX [EQUALS promote(@c12 AS LONG)] REVERSE) | MAP (version([_]) AS __ROW_VERSION, _.ID AS ID) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (version([q2]) AS __ROW_VERSION, q2.ID AS ID)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS __ROW_VERSION, )" ]; - 2 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c12 AS LONG)]
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 [ label=<
    Index
    GROUPED_VERSION_INDEX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (version([q2]) AS __ROW_VERSION, q2.ID AS ID)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS __ROW_VERSION, LONG AS ID)" ]; + 2 [ label=<
    Index Scan
    comparisons: [EQUALS promote(@c12 AS LONG)]
    direction: reversed
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 [ label=<
    Index
    GROUPED_VERSION_INDEX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -} +} x - unnamed-2kEXPLAIN select "__ROW_VERSION", col1, t1.id from t1 where col1 > 10 order by col1 asc, "__ROW_VERSION" asc; -W ϻ(#08@ISCAN(GROUPED_VERSION_INDEX [[GREATER_THAN promote(@c14 AS LONG)]]) | MAP (version([_]) AS __ROW_VERSION, _.COL1 AS COL1, _.ID AS ID) -digraph G { + unnamed-2kEXPLAIN select "__ROW_VERSION", col1, t1.id from t1 where col1 > 10 order by col1 asc, "__ROW_VERSION" asc; + Z (#08@ISCAN(GROUPED_VERSION_INDEX [[GREATER_THAN promote(@c14 AS LONG)]]) | MAP (version([_]) AS __ROW_VERSION, _.COL1 AS COL1, _.ID AS ID) digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
    Value Computation
    MAP (version([q2]) AS __ROW_VERSION, q2.COL1 AS COL1, q2.ID AS ID)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS __ROW_VERSION, )" ]; - 2 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c14 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; - 3 [ label=<
    Index
    GROUPED_VERSION_INDEX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, )" ]; + 1 [ label=<
    Value Computation
    MAP (version([q2]) AS __ROW_VERSION, q2.COL1 AS COL1, q2.ID AS ID)
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(VERSION AS __ROW_VERSION, LONG AS COL1, LONG AS ID)" ]; + 2 [ label=<
    Index Scan
    comparisons: [[GREATER_THAN promote(@c14 AS LONG)]]
    > color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; + 3 [ label=<
    Index
    GROUPED_VERSION_INDEX
    > color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, LONG AS COL1, LONG AS COL2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; } \ No newline at end of file diff --git a/yaml-tests/src/test/resources/versions-tests.metrics.yaml b/yaml-tests/src/test/resources/versions-tests.metrics.yaml index e7a743f774..45c7dee04b 100644 --- a/yaml-tests/src/test/resources/versions-tests.metrics.yaml +++ b/yaml-tests/src/test/resources/versions-tests.metrics.yaml @@ -4,9 +4,9 @@ unnamed-2: explain: ISCAN(I1 [EQUALS promote(@c14 AS LONG)]) | MAP (version([_]) AS VERSION, _.COL2 AS COL2) task_count: 759 - task_total_time_ms: 30 - transform_count: 224 - transform_time_ms: 9 + task_total_time_ms: 24 + transform_count: 227 + transform_time_ms: 7 transform_yield_count: 61 insert_time_ms: 1 insert_new_count: 89 @@ -14,9 +14,9 @@ unnamed-2: - query: EXPLAIN select t1.* from t1 where col1 = 10; explain: ISCAN(I1 [EQUALS promote(@c10 AS LONG)]) task_count: 763 - task_total_time_ms: 27 - transform_count: 228 - transform_time_ms: 7 + task_total_time_ms: 30 + transform_count: 231 + transform_time_ms: 8 transform_yield_count: 67 insert_time_ms: 1 insert_new_count: 81 @@ -26,11 +26,11 @@ unnamed-2: explain: ISCAN(I1 [EQUALS promote(@c26 AS LONG)]) | MAP (version([_]) AS VERSION, _.COL2 AS COL2) | MAP (_.VERSION AS VERSION, _.COL2 AS COL2) task_count: 761 - task_total_time_ms: 29 - transform_count: 232 - transform_time_ms: 8 + task_total_time_ms: 12 + transform_count: 235 + transform_time_ms: 4 transform_yield_count: 59 - insert_time_ms: 1 + insert_time_ms: 0 insert_new_count: 105 insert_reused_count: 5 - query: EXPLAIN select s."__ROW_VERSION", s.col2 from (select "__ROW_VERSION", @@ -38,19 +38,19 @@ unnamed-2: explain: ISCAN(I1 [EQUALS promote(@c22 AS LONG)]) | MAP (version([_]) AS __ROW_VERSION, _.COL2 AS COL2) | MAP (_.__ROW_VERSION AS __ROW_VERSION, _.COL2 AS COL2) task_count: 761 - task_total_time_ms: 23 - transform_count: 232 - transform_time_ms: 10 + task_total_time_ms: 15 + transform_count: 235 + transform_time_ms: 4 transform_yield_count: 59 - insert_time_ms: 1 + insert_time_ms: 0 insert_new_count: 105 insert_reused_count: 5 - query: EXPLAIN select "__ROW_VERSION" as version, t1.* from t1 where col1 = 20; explain: ISCAN(I1 [EQUALS promote(@c14 AS LONG)]) | MAP (version([_]) AS VERSION, _.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2) task_count: 759 - task_total_time_ms: 32 - transform_count: 224 + task_total_time_ms: 41 + transform_count: 227 transform_time_ms: 10 transform_yield_count: 61 insert_time_ms: 1 @@ -61,9 +61,9 @@ unnamed-2: explain: ISCAN(I1 [EQUALS promote(@c16 AS LONG)]) | MAP (version([_]) AS VERSION, _ AS _1) task_count: 759 - task_total_time_ms: 24 - transform_count: 224 - transform_time_ms: 8 + task_total_time_ms: 32 + transform_count: 227 + transform_time_ms: 9 transform_yield_count: 61 insert_time_ms: 1 insert_new_count: 89 @@ -72,9 +72,9 @@ unnamed-2: explain: ISCAN(I1 [EQUALS promote(@c12 AS LONG)]) | MAP (version([_]) AS __ROW_VERSION, _.ID AS ID, _.COL1 AS COL1, _.COL2 AS COL2) task_count: 759 - task_total_time_ms: 37 - transform_count: 224 - transform_time_ms: 12 + task_total_time_ms: 36 + transform_count: 227 + transform_time_ms: 10 transform_yield_count: 61 insert_time_ms: 1 insert_new_count: 89 @@ -83,11 +83,11 @@ unnamed-2: explain: ISCAN(I1 [EQUALS promote(@c14 AS LONG)]) | MAP (version([_]) AS __ROW_VERSION, _ AS _1) task_count: 759 - task_total_time_ms: 24 - transform_count: 224 - transform_time_ms: 7 + task_total_time_ms: 15 + transform_count: 227 + transform_time_ms: 4 transform_yield_count: 61 - insert_time_ms: 1 + insert_time_ms: 0 insert_new_count: 89 insert_reused_count: 5 - query: EXPLAIN select "__ROW_VERSION", t1.id from t1 order by "__ROW_VERSION" @@ -95,9 +95,9 @@ unnamed-2: explain: ISCAN(VERSION_INDEX <,>) | MAP (version([_]) AS __ROW_VERSION, _.ID AS ID) task_count: 181 - task_total_time_ms: 5 - transform_count: 60 - transform_time_ms: 3 + task_total_time_ms: 12 + transform_count: 63 + transform_time_ms: 6 transform_yield_count: 30 insert_time_ms: 0 insert_new_count: 14 @@ -107,9 +107,9 @@ unnamed-2: explain: ISCAN(VERSION_INDEX <,> REVERSE) | MAP (version([_]) AS __ROW_VERSION, _.ID AS ID) task_count: 181 - task_total_time_ms: 10 - transform_count: 60 - transform_time_ms: 6 + task_total_time_ms: 6 + transform_count: 63 + transform_time_ms: 3 transform_yield_count: 30 insert_time_ms: 0 insert_new_count: 14 @@ -119,8 +119,8 @@ unnamed-2: explain: ISCAN(GROUPED_VERSION_INDEX [EQUALS promote(@c14 AS LONG)]) | MAP (version([_]) AS __ROW_VERSION, _.ID AS ID) task_count: 327 - task_total_time_ms: 14 - transform_count: 103 + task_total_time_ms: 19 + transform_count: 106 transform_time_ms: 7 transform_yield_count: 37 insert_time_ms: 0 @@ -131,8 +131,8 @@ unnamed-2: explain: ISCAN(GROUPED_VERSION_INDEX [EQUALS promote(@c12 AS LONG)] REVERSE) | MAP (version([_]) AS __ROW_VERSION, _.ID AS ID) task_count: 327 - task_total_time_ms: 15 - transform_count: 103 + task_total_time_ms: 20 + transform_count: 106 transform_time_ms: 7 transform_yield_count: 37 insert_time_ms: 0 @@ -143,9 +143,9 @@ unnamed-2: explain: ISCAN(GROUPED_VERSION_INDEX [[GREATER_THAN promote(@c14 AS LONG)]]) | MAP (version([_]) AS __ROW_VERSION, _.COL1 AS COL1, _.ID AS ID) task_count: 288 - task_total_time_ms: 14 - transform_count: 87 - transform_time_ms: 7 + task_total_time_ms: 19 + transform_count: 90 + transform_time_ms: 8 transform_yield_count: 35 insert_time_ms: 0 insert_new_count: 26