docs: private void doRewrite(RelBuilder relBuilder, Aggregate aggregate, int n,
  			List<Integer> argList, int filterArg, List<RexInputRef> refs) {
  		final RexBuilder rexBuilder = aggregate.getCluster().getRexBuilder();
  		final List<RelDataTypeField> leftFields;
  		if (n == 0) {
  			leftFields = null;
  		} else {
  			leftFields = relBuilder.peek().getRowType().getFieldList();
  		}
  
  		// Aggregate(
  		//     child,
  		//     {COUNT(DISTINCT 1), SUM(DISTINCT 1), SUM(2)})
  		//
  		// becomes
  		//
  		// Aggregate(
  		//     Join(
  		//         child,
  		//         Aggregate(child, < all columns > {}),
  		//         INNER,
  		//         <f2 = f5>))
  		//
  		// E.g.
  		//   SELECT deptno, SUM(DISTINCT sal), COUNT(DISTINCT gender), MAX(age)
  		//   FROM Emps
  		//   GROUP BY deptno
  		//
  		// becomes
  		//
  		//   SELECT e.deptno, adsal.sum_sal, adgender.count_gender, e.max_age
  		//   FROM (
  		//     SELECT deptno, MAX(age) as max_age
  		//     FROM Emps GROUP BY deptno) AS e
  		//   JOIN (
  		//     SELECT deptno, COUNT(gender) AS count_gender FROM (
  		//       SELECT DISTINCT deptno, gender FROM Emps) AS dgender
  		//     GROUP BY deptno) AS adgender
  		//     ON e.deptno = adgender.deptno
  		//   JOIN (
  		//     SELECT deptno, SUM(sal) AS sum_sal FROM (
  		//       SELECT DISTINCT deptno, sal FROM Emps) AS dsal
  		//     GROUP BY deptno) AS adsal
  		//   ON e.deptno = adsal.deptno
  		//   GROUP BY e.deptno
  		//
  		// Note that if a query contains no non-distinct aggregates, then the
  		// very first join/group by is omitted.  In the example above, if
  		// MAX(age) is removed, then the sub-select of "e" is not needed, and
  		// instead the two other group by's are joined to one another.
  
  		// Project the columns of the GROUP BY plus the arguments
  		// to the agg function.
  		final Map<Integer, Integer> sourceOf = new HashMap<>();
  		createSelectDistinct(relBuilder, aggregate, argList, filterArg, sourceOf);
  
  		// Now compute the aggregate functions on top of the distinct dataset.
  		// Each distinct agg becomes a non-distinct call to the corresponding
  		// field from the right; for example,
  		//   "COUNT(DISTINCT e.sal)"
  		// becomes
  		//   "COUNT(distinct_e.sal)".
  		final List<AggregateCall> aggCallList = new ArrayList<>();
  		final List<AggregateCall> aggCalls = aggregate.getAggCallList();
  
  		final int groupAndIndicatorCount =
  				aggregate.getGroupCount() + aggregate.getIndicatorCount();
  		int i = groupAndIndicatorCount - 1;
  		for (AggregateCall aggCall : aggCalls) {
  			++i;
  
  			// Ignore agg calls which are not distinct or have the wrong set
  			// arguments. If we're rewriting aggs whose args are {sal}, we will
  			// rewrite COUNT(DISTINCT sal) and SUM(DISTINCT sal) but ignore
  			// COUNT(DISTINCT gender) or SUM(sal).
  			if (!aggCall.isDistinct()) {
  				continue;
  			}
  			if (!aggCall.getArgList().equals(argList)) {
  				continue;
  			}
  
  			// Re-map arguments.
  			final int argCount = aggCall.getArgList().size();
  			final List<Integer> newArgs = new ArrayList<>(argCount);
  			for (int j = 0; j < argCount; j++) {
  				final Integer arg = aggCall.getArgList().get(j);
  				newArgs.add(sourceOf.get(arg));
  			}
  			final int newFilterArg =
  					aggCall.filterArg >= 0 ? sourceOf.get(aggCall.filterArg) : -1;
  			final AggregateCall newAggCall =
  					AggregateCall.create(aggCall.getAggregation(), false,
  							aggCall.isApproximate(), newArgs,
  							newFilterArg, aggCall.getType(), aggCall.getName());
  			assert refs.get(i) == null;
  			if (n == 0) {
  				refs.set(i,
  						new RexInputRef(groupAndIndicatorCount + aggCallList.size(),
  								newAggCall.getType()));
  			} else {
  				refs.set(i,
  						new RexInputRef(leftFields.size() + groupAndIndicatorCount
  								+ aggCallList.size(), newAggCall.getType()));
  			}
  			aggCallList.add(newAggCall);
  		}
  
  		final Map<Integer, Integer> map = new HashMap<>();
  		for (Integer key : aggregate.getGroupSet()) {
  			map.put(key, map.size());
  		}
  		final ImmutableBitSet newGroupSet = aggregate.getGroupSet().permute(map);
  		assert newGroupSet
  				.equals(ImmutableBitSet.range(aggregate.getGroupSet().cardinality()));
  		com.google.common.collect.ImmutableList<ImmutableBitSet> newGroupingSets = null;
  		if (aggregate.indicator) {
  			newGroupingSets =
  					ImmutableBitSet.ORDERING.immutableSortedCopy(
  							ImmutableBitSet.permute(aggregate.getGroupSets(), map));
  		}
  
  		relBuilder.push(
  				aggregate.copy(aggregate.getTraitSet(), relBuilder.build(),
  						aggregate.indicator, newGroupSet, newGroupingSets, aggCallList));
  
  		// If there's no left child yet, no need to create the join
  		if (n == 0) {
  			return;
  		}
  
  		// Create the join condition. It is of the form
  		//  'left.f0 = right.f0 and left.f1 = right.f1 and ...'
  		// where {f0, f1, ...} are the GROUP BY fields.
  		final List<RelDataTypeField> distinctFields =
  				relBuilder.peek().getRowType().getFieldList();
  		final List<RexNode> conditions = com.google.common.collect.Lists.newArrayList();
  		for (i = 0; i < groupAndIndicatorCount; ++i) {
  			// null values form its own group
  			// use "is not distinct from" so that the join condition
  			// allows null values to match.
  			conditions.add(
  					rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_DISTINCT_FROM,
  							RexInputRef.of(i, leftFields),
  							new RexInputRef(leftFields.size() + i,
  									distinctFields.get(i).getType())));
  		}
  
  		// Join in the new 'select distinct' relation.
  		relBuilder.join(JoinRelType.INNER, conditions);
  	}