Search in sources :

Example 11 with Pair

use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.util.Pair in project calcite by apache.

the class RelMdCollation method values.

/**
 * Helper method to determine a
 * {@link org.apache.calcite.rel.core.Values}'s collation.
 *
 * <p>We actually under-report the collations. A Values with 0 or 1 rows - an
 * edge case, but legitimate and very common - is ordered by every permutation
 * of every subset of the columns.
 *
 * <p>So, our algorithm aims to:<ul>
 *   <li>produce at most N collations (where N is the number of columns);
 *   <li>make each collation as long as possible;
 *   <li>do not repeat combinations already emitted -
 *       if we've emitted {@code (a, b)} do not later emit {@code (b, a)};
 *   <li>probe the actual values and make sure that each collation is
 *      consistent with the data
 * </ul>
 *
 * <p>So, for an empty Values with 4 columns, we would emit
 * {@code (a, b, c, d), (b, c, d), (c, d), (d)}.
 */
public static List<RelCollation> values(RelMetadataQuery mq, RelDataType rowType, ImmutableList<ImmutableList<RexLiteral>> tuples) {
    // for future use
    Util.discard(mq);
    final List<RelCollation> list = Lists.newArrayList();
    final int n = rowType.getFieldCount();
    final List<Pair<RelFieldCollation, Ordering<List<RexLiteral>>>> pairs = Lists.newArrayList();
    outer: for (int i = 0; i < n; i++) {
        pairs.clear();
        for (int j = i; j < n; j++) {
            final RelFieldCollation fieldCollation = new RelFieldCollation(j);
            Ordering<List<RexLiteral>> comparator = comparator(fieldCollation);
            Ordering<List<RexLiteral>> ordering;
            if (pairs.isEmpty()) {
                ordering = comparator;
            } else {
                ordering = Util.last(pairs).right.compound(comparator);
            }
            pairs.add(Pair.of(fieldCollation, ordering));
            if (!ordering.isOrdered(tuples)) {
                if (j == i) {
                    continue outer;
                }
                pairs.remove(pairs.size() - 1);
            }
        }
        if (!pairs.isEmpty()) {
            list.add(RelCollations.of(Pair.left(pairs)));
        }
    }
    return list;
}
Also used : RexLiteral(org.apache.calcite.rex.RexLiteral) RelCollation(org.apache.calcite.rel.RelCollation) RelFieldCollation(org.apache.calcite.rel.RelFieldCollation) Ordering(com.google.common.collect.Ordering) ArrayList(java.util.ArrayList) ImmutableList(com.google.common.collect.ImmutableList) ImmutableIntList(org.apache.calcite.util.ImmutableIntList) List(java.util.List) Pair(org.apache.calcite.util.Pair)

Example 12 with Pair

use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.util.Pair in project calcite by apache.

the class Schemas method path.

/**
 * Creates a path with a given list of names starting from a given root
 * schema.
 */
public static Path path(CalciteSchema rootSchema, Iterable<String> names) {
    final ImmutableList.Builder<Pair<String, Schema>> builder = ImmutableList.builder();
    Schema schema = rootSchema.plus();
    final Iterator<String> iterator = names.iterator();
    if (!iterator.hasNext()) {
        return PathImpl.EMPTY;
    }
    if (!rootSchema.name.isEmpty()) {
        assert rootSchema.name.equals(iterator.next());
    }
    for (; ; ) {
        final String name = iterator.next();
        builder.add(Pair.of(name, schema));
        if (!iterator.hasNext()) {
            return path(builder.build());
        }
        schema = schema.getSubSchema(name);
    }
}
Also used : ImmutableList(com.google.common.collect.ImmutableList) CalciteSchema(org.apache.calcite.jdbc.CalciteSchema) Pair(org.apache.calcite.util.Pair)

Example 13 with Pair

use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.util.Pair in project calcite by apache.

the class JdbcTest method querify.

/**
 * Returns a list of (query, expected) pairs. The expected result is
 * sometimes null.
 */
private static List<Pair<String, String>> querify(String[] queries1) {
    final List<Pair<String, String>> list = new ArrayList<>();
    for (int i = 0; i < queries1.length; i++) {
        String query = queries1[i];
        String expected = null;
        if (i + 1 < queries1.length && queries1[i + 1] != null && !queries1[i + 1].startsWith("select")) {
            expected = queries1[++i];
        }
        list.add(Pair.of(query, expected));
    }
    return list;
}
Also used : ArrayList(java.util.ArrayList) CoreMatchers.containsString(org.hamcrest.CoreMatchers.containsString) Pair(org.apache.calcite.util.Pair)

Example 14 with Pair

use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.util.Pair in project calcite by apache.

the class AbstractMaterializedViewRule method perform.

/**
 * Rewriting logic is based on "Optimizing Queries Using Materialized Views:
 * A Practical, Scalable Solution" by Goldstein and Larson.
 *
 * <p>On the query side, rules matches a Project-node chain or node, where node
 * is either an Aggregate or a Join. Subplan rooted at the node operator must
 * be composed of one or more of the following operators: TableScan, Project,
 * Filter, and Join.
 *
 * <p>For each join MV, we need to check the following:
 * <ol>
 * <li> The plan rooted at the Join operator in the view produces all rows
 * needed by the plan rooted at the Join operator in the query.</li>
 * <li> All columns required by compensating predicates, i.e., predicates that
 * need to be enforced over the view, are available at the view output.</li>
 * <li> All output expressions can be computed from the output of the view.</li>
 * <li> All output rows occur with the correct duplication factor. We might
 * rely on existing Unique-Key - Foreign-Key relationships to extract that
 * information.</li>
 * </ol>
 *
 * <p>In turn, for each aggregate MV, we need to check the following:
 * <ol>
 * <li> The plan rooted at the Aggregate operator in the view produces all rows
 * needed by the plan rooted at the Aggregate operator in the query.</li>
 * <li> All columns required by compensating predicates, i.e., predicates that
 * need to be enforced over the view, are available at the view output.</li>
 * <li> The grouping columns in the query are a subset of the grouping columns
 * in the view.</li>
 * <li> All columns required to perform further grouping are available in the
 * view output.</li>
 * <li> All columns required to compute output expressions are available in the
 * view output.</li>
 * </ol>
 *
 * <p>The rule contains multiple extensions compared to the original paper. One of
 * them is the possibility of creating rewritings using Union operators, e.g., if
 * the result of a query is partially contained in the materialized view.
 */
protected void perform(RelOptRuleCall call, Project topProject, RelNode node) {
    final RexBuilder rexBuilder = node.getCluster().getRexBuilder();
    final RelMetadataQuery mq = RelMetadataQuery.instance();
    final RelOptPlanner planner = call.getPlanner();
    final RexExecutor executor = Util.first(planner.getExecutor(), RexUtil.EXECUTOR);
    final RelOptPredicateList predicates = RelOptPredicateList.EMPTY;
    final RexSimplify simplify = new RexSimplify(rexBuilder, predicates, true, executor);
    final List<RelOptMaterialization> materializations = (planner instanceof VolcanoPlanner) ? ((VolcanoPlanner) planner).getMaterializations() : ImmutableList.<RelOptMaterialization>of();
    if (!materializations.isEmpty()) {
        // try to generate a rewriting are met
        if (!isValidPlan(topProject, node, mq)) {
            return;
        }
        // Obtain applicable (filtered) materializations
        // TODO: Filtering of relevant materializations needs to be
        // improved so we gather only materializations that might
        // actually generate a valid rewriting.
        final List<RelOptMaterialization> applicableMaterializations = RelOptMaterializations.getApplicableMaterializations(node, materializations);
        if (!applicableMaterializations.isEmpty()) {
            // 2. Initialize all query related auxiliary data structures
            // that will be used throughout query rewriting process
            // Generate query table references
            final Set<RelTableRef> queryTableRefs = mq.getTableReferences(node);
            if (queryTableRefs == null) {
                // Bail out
                return;
            }
            // Extract query predicates
            final RelOptPredicateList queryPredicateList = mq.getAllPredicates(node);
            if (queryPredicateList == null) {
                // Bail out
                return;
            }
            final RexNode pred = simplify.simplify(RexUtil.composeConjunction(rexBuilder, queryPredicateList.pulledUpPredicates, false));
            final Triple<RexNode, RexNode, RexNode> queryPreds = splitPredicates(rexBuilder, pred);
            // Extract query equivalence classes. An equivalence class is a set
            // of columns in the query output that are known to be equal.
            final EquivalenceClasses qEC = new EquivalenceClasses();
            for (RexNode conj : RelOptUtil.conjunctions(queryPreds.getLeft())) {
                assert conj.isA(SqlKind.EQUALS);
                RexCall equiCond = (RexCall) conj;
                qEC.addEquivalenceClass((RexTableInputRef) equiCond.getOperands().get(0), (RexTableInputRef) equiCond.getOperands().get(1));
            }
            // rewrite the given query
            for (RelOptMaterialization materialization : applicableMaterializations) {
                RelNode view = materialization.tableRel;
                Project topViewProject;
                RelNode viewNode;
                if (materialization.queryRel instanceof Project) {
                    topViewProject = (Project) materialization.queryRel;
                    viewNode = topViewProject.getInput();
                } else {
                    topViewProject = null;
                    viewNode = materialization.queryRel;
                }
                // 3.1. View checks before proceeding
                if (!isValidPlan(topViewProject, viewNode, mq)) {
                    // Skip it
                    continue;
                }
                // 3.2. Initialize all query related auxiliary data structures
                // that will be used throughout query rewriting process
                // Extract view predicates
                final RelOptPredicateList viewPredicateList = mq.getAllPredicates(viewNode);
                if (viewPredicateList == null) {
                    // Skip it
                    continue;
                }
                final RexNode viewPred = simplify.simplify(RexUtil.composeConjunction(rexBuilder, viewPredicateList.pulledUpPredicates, false));
                final Triple<RexNode, RexNode, RexNode> viewPreds = splitPredicates(rexBuilder, viewPred);
                // Extract view table references
                final Set<RelTableRef> viewTableRefs = mq.getTableReferences(viewNode);
                if (viewTableRefs == null) {
                    // Bail out
                    return;
                }
                // Extract view tables
                MatchModality matchModality;
                Multimap<RexTableInputRef, RexTableInputRef> compensationEquiColumns = ArrayListMultimap.create();
                if (!queryTableRefs.equals(viewTableRefs)) {
                    // subset of query tables (add additional tables through joins if possible)
                    if (viewTableRefs.containsAll(queryTableRefs)) {
                        matchModality = MatchModality.QUERY_PARTIAL;
                        final EquivalenceClasses vEC = new EquivalenceClasses();
                        for (RexNode conj : RelOptUtil.conjunctions(viewPreds.getLeft())) {
                            assert conj.isA(SqlKind.EQUALS);
                            RexCall equiCond = (RexCall) conj;
                            vEC.addEquivalenceClass((RexTableInputRef) equiCond.getOperands().get(0), (RexTableInputRef) equiCond.getOperands().get(1));
                        }
                        if (!compensatePartial(viewTableRefs, vEC, queryTableRefs, compensationEquiColumns)) {
                            // Cannot rewrite, skip it
                            continue;
                        }
                    } else if (queryTableRefs.containsAll(viewTableRefs)) {
                        matchModality = MatchModality.VIEW_PARTIAL;
                        ViewPartialRewriting partialRewritingResult = compensateViewPartial(call.builder(), rexBuilder, mq, view, topProject, node, queryTableRefs, qEC, topViewProject, viewNode, viewTableRefs);
                        if (partialRewritingResult == null) {
                            // Cannot rewrite, skip it
                            continue;
                        }
                        // Rewrite succeeded
                        view = partialRewritingResult.newView;
                        topViewProject = partialRewritingResult.newTopViewProject;
                        viewNode = partialRewritingResult.newViewNode;
                    } else {
                        // Skip it
                        continue;
                    }
                } else {
                    matchModality = MatchModality.COMPLETE;
                }
                // 4. We map every table in the query to a table with the same qualified
                // name (all query tables are contained in the view, thus this is equivalent
                // to mapping every table in the query to a view table).
                final Multimap<RelTableRef, RelTableRef> multiMapTables = ArrayListMultimap.create();
                for (RelTableRef queryTableRef1 : queryTableRefs) {
                    for (RelTableRef queryTableRef2 : queryTableRefs) {
                        if (queryTableRef1.getQualifiedName().equals(queryTableRef2.getQualifiedName())) {
                            multiMapTables.put(queryTableRef1, queryTableRef2);
                        }
                    }
                }
                // If a table is used multiple times, we will create multiple mappings,
                // and we will try to rewrite the query using each of the mappings.
                // Then, we will try to map every source table (query) to a target
                // table (view), and if we are successful, we will try to create
                // compensation predicates to filter the view results further
                // (if needed).
                final List<BiMap<RelTableRef, RelTableRef>> flatListMappings = generateTableMappings(multiMapTables);
                for (BiMap<RelTableRef, RelTableRef> queryToViewTableMapping : flatListMappings) {
                    // TableMapping : mapping query tables -> view tables
                    // 4.0. If compensation equivalence classes exist, we need to add
                    // the mapping to the query mapping
                    final EquivalenceClasses currQEC = EquivalenceClasses.copy(qEC);
                    if (matchModality == MatchModality.QUERY_PARTIAL) {
                        for (Entry<RexTableInputRef, RexTableInputRef> e : compensationEquiColumns.entries()) {
                            // Copy origin
                            RelTableRef queryTableRef = queryToViewTableMapping.inverse().get(e.getKey().getTableRef());
                            RexTableInputRef queryColumnRef = RexTableInputRef.of(queryTableRef, e.getKey().getIndex(), e.getKey().getType());
                            // Add to query equivalence classes and table mapping
                            currQEC.addEquivalenceClass(queryColumnRef, e.getValue());
                            queryToViewTableMapping.put(e.getValue().getTableRef(), // identity
                            e.getValue().getTableRef());
                        }
                    }
                    // 4.1. Compute compensation predicates, i.e., predicates that need to be
                    // enforced over the view to retain query semantics. The resulting predicates
                    // are expressed using {@link RexTableInputRef} over the query.
                    // First, to establish relationship, we swap column references of the view
                    // predicates to point to query tables and compute equivalence classes.
                    final RexNode viewColumnsEquiPred = RexUtil.swapTableReferences(rexBuilder, viewPreds.getLeft(), queryToViewTableMapping.inverse());
                    final EquivalenceClasses queryBasedVEC = new EquivalenceClasses();
                    for (RexNode conj : RelOptUtil.conjunctions(viewColumnsEquiPred)) {
                        assert conj.isA(SqlKind.EQUALS);
                        RexCall equiCond = (RexCall) conj;
                        queryBasedVEC.addEquivalenceClass((RexTableInputRef) equiCond.getOperands().get(0), (RexTableInputRef) equiCond.getOperands().get(1));
                    }
                    Triple<RexNode, RexNode, RexNode> compensationPreds = computeCompensationPredicates(rexBuilder, simplify, currQEC, queryPreds, queryBasedVEC, viewPreds, queryToViewTableMapping);
                    if (compensationPreds == null && generateUnionRewriting) {
                        // Attempt partial rewriting using union operator. This rewriting
                        // will read some data from the view and the rest of the data from
                        // the query computation. The resulting predicates are expressed
                        // using {@link RexTableInputRef} over the view.
                        compensationPreds = computeCompensationPredicates(rexBuilder, simplify, queryBasedVEC, viewPreds, currQEC, queryPreds, queryToViewTableMapping.inverse());
                        if (compensationPreds == null) {
                            // This was our last chance to use the view, skip it
                            continue;
                        }
                        RexNode compensationColumnsEquiPred = compensationPreds.getLeft();
                        RexNode otherCompensationPred = RexUtil.composeConjunction(rexBuilder, ImmutableList.of(compensationPreds.getMiddle(), compensationPreds.getRight()), false);
                        assert !compensationColumnsEquiPred.isAlwaysTrue() || !otherCompensationPred.isAlwaysTrue();
                        // b. Generate union branch (query).
                        final RelNode unionInputQuery = rewriteQuery(call.builder(), rexBuilder, simplify, mq, compensationColumnsEquiPred, otherCompensationPred, topProject, node, queryToViewTableMapping, queryBasedVEC, currQEC);
                        if (unionInputQuery == null) {
                            // Skip it
                            continue;
                        }
                        // c. Generate union branch (view).
                        // We trigger the unifying method. This method will either create a Project
                        // or an Aggregate operator on top of the view. It will also compute the
                        // output expressions for the query.
                        final RelNode unionInputView = rewriteView(call.builder(), rexBuilder, simplify, mq, matchModality, true, view, topProject, node, topViewProject, viewNode, queryToViewTableMapping, currQEC);
                        if (unionInputView == null) {
                            // Skip it
                            continue;
                        }
                        // d. Generate final rewriting (union).
                        final RelNode result = createUnion(call.builder(), rexBuilder, topProject, unionInputQuery, unionInputView);
                        if (result == null) {
                            // Skip it
                            continue;
                        }
                        call.transformTo(result);
                    } else if (compensationPreds != null) {
                        RexNode compensationColumnsEquiPred = compensationPreds.getLeft();
                        RexNode otherCompensationPred = RexUtil.composeConjunction(rexBuilder, ImmutableList.of(compensationPreds.getMiddle(), compensationPreds.getRight()), false);
                        // a. Compute final compensation predicate.
                        if (!compensationColumnsEquiPred.isAlwaysTrue() || !otherCompensationPred.isAlwaysTrue()) {
                            // All columns required by compensating predicates must be contained
                            // in the view output (condition 2).
                            List<RexNode> viewExprs = topViewProject == null ? extractReferences(rexBuilder, view) : topViewProject.getChildExps();
                            // since we want to enforce the rest
                            if (!compensationColumnsEquiPred.isAlwaysTrue()) {
                                compensationColumnsEquiPred = rewriteExpression(rexBuilder, mq, view, viewNode, viewExprs, queryToViewTableMapping.inverse(), queryBasedVEC, false, compensationColumnsEquiPred);
                                if (compensationColumnsEquiPred == null) {
                                    // Skip it
                                    continue;
                                }
                            }
                            // For the rest, we use the query equivalence classes
                            if (!otherCompensationPred.isAlwaysTrue()) {
                                otherCompensationPred = rewriteExpression(rexBuilder, mq, view, viewNode, viewExprs, queryToViewTableMapping.inverse(), currQEC, true, otherCompensationPred);
                                if (otherCompensationPred == null) {
                                    // Skip it
                                    continue;
                                }
                            }
                        }
                        final RexNode viewCompensationPred = RexUtil.composeConjunction(rexBuilder, ImmutableList.of(compensationColumnsEquiPred, otherCompensationPred), false);
                        // b. Generate final rewriting if possible.
                        // First, we add the compensation predicate (if any) on top of the view.
                        // Then, we trigger the unifying method. This method will either create a
                        // Project or an Aggregate operator on top of the view. It will also compute
                        // the output expressions for the query.
                        RelBuilder builder = call.builder();
                        RelNode viewWithFilter;
                        if (!viewCompensationPred.isAlwaysTrue()) {
                            RexNode newPred = simplify.simplify(viewCompensationPred);
                            viewWithFilter = builder.push(view).filter(newPred).build();
                            // We add (and push) the filter to the view plan before triggering the rewriting.
                            // This is useful in case some of the columns can be folded to same value after
                            // filter is added.
                            Pair<RelNode, RelNode> pushedNodes = pushFilterToOriginalViewPlan(builder, topViewProject, viewNode, newPred);
                            topViewProject = (Project) pushedNodes.left;
                            viewNode = pushedNodes.right;
                        } else {
                            viewWithFilter = builder.push(view).build();
                        }
                        final RelNode result = rewriteView(builder, rexBuilder, simplify, mq, matchModality, false, viewWithFilter, topProject, node, topViewProject, viewNode, queryToViewTableMapping, currQEC);
                        if (result == null) {
                            // Skip it
                            continue;
                        }
                        call.transformTo(result);
                    }
                // end else
                }
            }
        }
    }
}
Also used : RelMetadataQuery(org.apache.calcite.rel.metadata.RelMetadataQuery) RelOptPlanner(org.apache.calcite.plan.RelOptPlanner) RexCall(org.apache.calcite.rex.RexCall) RexExecutor(org.apache.calcite.rex.RexExecutor) RelOptPredicateList(org.apache.calcite.plan.RelOptPredicateList) RexBuilder(org.apache.calcite.rex.RexBuilder) RelOptPredicateList(org.apache.calcite.plan.RelOptPredicateList) List(java.util.List) ArrayList(java.util.ArrayList) ImmutableList(com.google.common.collect.ImmutableList) Pair(org.apache.calcite.util.Pair) RelBuilder(org.apache.calcite.tools.RelBuilder) BiMap(com.google.common.collect.BiMap) HashBiMap(com.google.common.collect.HashBiMap) RelTableRef(org.apache.calcite.rex.RexTableInputRef.RelTableRef) RexTableInputRef(org.apache.calcite.rex.RexTableInputRef) Project(org.apache.calcite.rel.core.Project) RelNode(org.apache.calcite.rel.RelNode) RexSimplify(org.apache.calcite.rex.RexSimplify) RelOptMaterialization(org.apache.calcite.plan.RelOptMaterialization) VolcanoPlanner(org.apache.calcite.plan.volcano.VolcanoPlanner) RexNode(org.apache.calcite.rex.RexNode)

Example 15 with Pair

use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.util.Pair in project calcite by apache.

the class AggregateExpandDistinctAggregatesRule method onMatch.

// ~ Methods ----------------------------------------------------------------
public void onMatch(RelOptRuleCall call) {
    final Aggregate aggregate = call.rel(0);
    if (!aggregate.containsDistinctCall()) {
        return;
    }
    // Find all of the agg expressions. We use a LinkedHashSet to ensure determinism.
    // find all aggregate calls without distinct
    int nonDistinctAggCallCount = 0;
    int filterCount = 0;
    int unsupportedNonDistinctAggCallCount = 0;
    final Set<Pair<List<Integer>, Integer>> argLists = new LinkedHashSet<>();
    for (AggregateCall aggCall : aggregate.getAggCallList()) {
        if (aggCall.filterArg >= 0) {
            ++filterCount;
        }
        if (!aggCall.isDistinct()) {
            ++nonDistinctAggCallCount;
            final SqlKind aggCallKind = aggCall.getAggregation().getKind();
            // We only support COUNT/SUM/MIN/MAX for the "single" count distinct optimization
            switch(aggCallKind) {
                case COUNT:
                case SUM:
                case SUM0:
                case MIN:
                case MAX:
                    break;
                default:
                    ++unsupportedNonDistinctAggCallCount;
            }
        } else {
            argLists.add(Pair.of(aggCall.getArgList(), aggCall.filterArg));
        }
    }
    final int distinctAggCallCount = aggregate.getAggCallList().size() - nonDistinctAggCallCount;
    Preconditions.checkState(argLists.size() > 0, "containsDistinctCall lied");
    // arguments then we can use a more efficient form.
    if (nonDistinctAggCallCount == 0 && argLists.size() == 1 && aggregate.getGroupType() == Group.SIMPLE) {
        final Pair<List<Integer>, Integer> pair = Iterables.getOnlyElement(argLists);
        final RelBuilder relBuilder = call.builder();
        convertMonopole(relBuilder, aggregate, pair.left, pair.right);
        call.transformTo(relBuilder.build());
        return;
    }
    if (useGroupingSets) {
        rewriteUsingGroupingSets(call, aggregate);
        return;
    }
    // we can generate multi-phase aggregates
    if (// one distinct aggregate
    distinctAggCallCount == 1 && // no filter
    filterCount == 0 && // sum/min/max/count in non-distinct aggregate
    unsupportedNonDistinctAggCallCount == 0 && nonDistinctAggCallCount > 0) {
        // one or more non-distinct aggregates
        final RelBuilder relBuilder = call.builder();
        convertSingletonDistinct(relBuilder, aggregate, argLists);
        call.transformTo(relBuilder.build());
        return;
    }
    // Create a list of the expressions which will yield the final result.
    // Initially, the expressions point to the input field.
    final List<RelDataTypeField> aggFields = aggregate.getRowType().getFieldList();
    final List<RexInputRef> refs = new ArrayList<>();
    final List<String> fieldNames = aggregate.getRowType().getFieldNames();
    final ImmutableBitSet groupSet = aggregate.getGroupSet();
    final int groupAndIndicatorCount = aggregate.getGroupCount() + aggregate.getIndicatorCount();
    for (int i : Util.range(groupAndIndicatorCount)) {
        refs.add(RexInputRef.of(i, aggFields));
    }
    // Aggregate the original relation, including any non-distinct aggregates.
    final List<AggregateCall> newAggCallList = new ArrayList<>();
    int i = -1;
    for (AggregateCall aggCall : aggregate.getAggCallList()) {
        ++i;
        if (aggCall.isDistinct()) {
            refs.add(null);
            continue;
        }
        refs.add(new RexInputRef(groupAndIndicatorCount + newAggCallList.size(), aggFields.get(groupAndIndicatorCount + i).getType()));
        newAggCallList.add(aggCall);
    }
    // In the case where there are no non-distinct aggregates (regardless of
    // whether there are group bys), there's no need to generate the
    // extra aggregate and join.
    final RelBuilder relBuilder = call.builder();
    relBuilder.push(aggregate.getInput());
    int n = 0;
    if (!newAggCallList.isEmpty()) {
        final RelBuilder.GroupKey groupKey = relBuilder.groupKey(groupSet, aggregate.getGroupSets());
        relBuilder.aggregate(groupKey, newAggCallList);
        ++n;
    }
    // set of operands.
    for (Pair<List<Integer>, Integer> argList : argLists) {
        doRewrite(relBuilder, aggregate, n++, argList.left, argList.right, refs);
    }
    relBuilder.project(refs, fieldNames);
    call.transformTo(relBuilder.build());
}
Also used : LinkedHashSet(java.util.LinkedHashSet) RelBuilder(org.apache.calcite.tools.RelBuilder) ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) ArrayList(java.util.ArrayList) SqlKind(org.apache.calcite.sql.SqlKind) AggregateCall(org.apache.calcite.rel.core.AggregateCall) RelDataTypeField(org.apache.calcite.rel.type.RelDataTypeField) RexInputRef(org.apache.calcite.rex.RexInputRef) ArrayList(java.util.ArrayList) ImmutableList(com.google.common.collect.ImmutableList) ImmutableIntList(org.apache.calcite.util.ImmutableIntList) List(java.util.List) Aggregate(org.apache.calcite.rel.core.Aggregate) LogicalAggregate(org.apache.calcite.rel.logical.LogicalAggregate) Pair(org.apache.calcite.util.Pair)

Aggregations

Pair (org.apache.calcite.util.Pair)112 RexNode (org.apache.calcite.rex.RexNode)72 ArrayList (java.util.ArrayList)70 RelNode (org.apache.calcite.rel.RelNode)59 RelDataTypeField (org.apache.calcite.rel.type.RelDataTypeField)55 RexInputRef (org.apache.calcite.rex.RexInputRef)29 ImmutableBitSet (org.apache.calcite.util.ImmutableBitSet)29 HashMap (java.util.HashMap)26 RexBuilder (org.apache.calcite.rex.RexBuilder)23 Map (java.util.Map)21 AggregateCall (org.apache.calcite.rel.core.AggregateCall)20 List (java.util.List)19 RelDataType (org.apache.calcite.rel.type.RelDataType)19 ImmutableList (com.google.common.collect.ImmutableList)18 JoinRelType (org.apache.calcite.rel.core.JoinRelType)16 TreeMap (java.util.TreeMap)14 RelDataTypeFactory (org.apache.calcite.rel.type.RelDataTypeFactory)13 RelBuilder (org.apache.calcite.tools.RelBuilder)13 ImmutableMap (com.google.common.collect.ImmutableMap)12 ImmutableSortedMap (com.google.common.collect.ImmutableSortedMap)12