@Override
  public TrimResult trimFields(Aggregate aggregate, ImmutableBitSet fieldsUsed, Set<RelDataTypeField> extraFields) {
    // Fields:
    //
    // | sys fields | group fields | indicator fields | agg functions |
    //
    // Two kinds of trimming:
    //
    // 1. If agg rel has system fields but none of these are used, create an
    // agg rel with no system fields.
    //
    // 2. If aggregate functions are not used, remove them.
    //
    // But group and indicator fields stay, even if they are not used.

    // Compute which input fields are used.


    // agg functions
    // agg functions are added first (before group sets) because rewriteGBConstantsKeys
    // needs it
    final ImmutableBitSet.Builder aggCallFieldsUsedBuilder =  ImmutableBitSet.builder();
    for (AggregateCall aggCall : aggregate.getAggCallList()) {
      for (int i : aggCall.getArgList()) {
        aggCallFieldsUsedBuilder.set(i);
      }
      if (aggCall.filterArg >= 0) {
        aggCallFieldsUsedBuilder.set(aggCall.filterArg);
      }
      aggCallFieldsUsedBuilder.addAll(RelCollations.ordinals(aggCall.collation));
    }

    // transform if group by contain constant keys
    ImmutableBitSet aggCallFieldsUsed = aggCallFieldsUsedBuilder.build();
    aggregate = rewriteGBConstantKeys(aggregate, fieldsUsed, aggCallFieldsUsed);

    // add group fields
    final ImmutableBitSet.Builder inputFieldsUsed =  aggregate.getGroupSet().rebuild();
    inputFieldsUsed.addAll(aggCallFieldsUsed);


    final RelDataType rowType = aggregate.getRowType();

    // Create input with trimmed columns.
    final RelNode input = aggregate.getInput();
    final Set<RelDataTypeField> inputExtraFields = Collections.emptySet();
    final TrimResult trimResult =
        trimChild(aggregate, input, inputFieldsUsed.build(), inputExtraFields);
    final RelNode newInput = trimResult.left;
    final Mapping inputMapping = trimResult.right;

    ImmutableBitSet originalGroupSet = aggregate.getGroupSet();
    ImmutableBitSet updatedGroupSet = generateNewGroupset(aggregate, fieldsUsed);
    ImmutableBitSet gbKeysDeleted = originalGroupSet.except(updatedGroupSet);
    ImmutableBitSet updatedGroupFields = ImmutableBitSet.range(originalGroupSet.cardinality());
    final int updatedGroupCount = updatedGroupSet.cardinality();

    // we need to clear the bits corresponding to deleted gb keys
    int setIdx = 0;
    while(setIdx != -1) {
      setIdx = gbKeysDeleted.nextSetBit(setIdx);
      if(setIdx != -1) {
        updatedGroupFields = updatedGroupFields.clear(setIdx);
        setIdx++;
      }
    }
    fieldsUsed =
        fieldsUsed.union(updatedGroupFields);

    // If the input is unchanged, and we need to project all columns,
    // there's nothing to do.
    if (input == newInput
        && fieldsUsed.equals(ImmutableBitSet.range(rowType.getFieldCount()))) {
      return result(aggregate,
          Mappings.createIdentity(rowType.getFieldCount()));
    }

    // update the group by keys based on inputMapping
    ImmutableBitSet newGroupSet =
        Mappings.apply(inputMapping, updatedGroupSet);

    // Which agg calls are used by our consumer?
    int originalGroupCount = aggregate.getGroupSet().cardinality();
    int j = originalGroupCount;
    int usedAggCallCount = 0;
    for (int i = 0; i < aggregate.getAggCallList().size(); i++) {
      if (fieldsUsed.get(j++)) {
        ++usedAggCallCount;
      }
    }

    // Offset due to the number of system fields having changed.
    Mapping mapping =
        Mappings.create(
            MappingType.INVERSE_SURJECTION,
            rowType.getFieldCount(),
            updatedGroupCount + usedAggCallCount);


    // if group keys were reduced, it means we didn't have grouping therefore
    // we don't need to transform group sets
    ImmutableList<ImmutableBitSet> newGroupSets = null;
    if(!updatedGroupSet.equals(aggregate.getGroupSet())) {
      newGroupSets = ImmutableList.of(newGroupSet);
    } else {
      newGroupSets = ImmutableList.copyOf(
          Iterables.transform(aggregate.getGroupSets(),
              input1 -> Mappings.apply(inputMapping, input1)));
    }

    // Populate mapping of where to find the fields. System, group key and
    // indicator fields first.
    int gbKeyIdx = 0;
    for (j = 0; j < originalGroupCount; j++) {
      if(fieldsUsed.get(j)) {
        mapping.set(j, gbKeyIdx);
        gbKeyIdx++;
      }
    }

    // Now create new agg calls, and populate mapping for them.
    final RelBuilder relBuilder = REL_BUILDER.get();
    relBuilder.push(newInput);
    final List<RelBuilder.AggCall> newAggCallList = new ArrayList<>();
    j = originalGroupCount; // because lookup in fieldsUsed is done using original group count
    for (AggregateCall aggCall : aggregate.getAggCallList()) {
      if (fieldsUsed.get(j)) {
        final ImmutableList<RexNode> args =
            relBuilder.fields(
                Mappings.apply2(inputMapping, aggCall.getArgList()));
        final RexNode filterArg = aggCall.filterArg < 0 ? null
            : relBuilder.field(Mappings.apply(inputMapping, aggCall.filterArg));
        RelBuilder.AggCall newAggCall =
                relBuilder.aggregateCall(aggCall.getAggregation(), args)
                        .distinct(aggCall.isDistinct())
                        .filter(filterArg)
                        .approximate(aggCall.isApproximate())
                        .sort(relBuilder.fields(aggCall.collation))
                        .as(aggCall.name);
        mapping.set(j, updatedGroupCount +  newAggCallList.size());
        newAggCallList.add(newAggCall);
      }
      ++j;
    }

    final RelBuilder.GroupKey groupKey =
        relBuilder.groupKey(newGroupSet, newGroupSets);
    relBuilder.aggregate(groupKey, newAggCallList);

    return result(relBuilder.build(), mapping);
  }
This method replaces group by 'constant key' with group by true (boolean)
if and only if
 group by doesn't have grouping sets
 all keys in group by are constant
 none of the relnode above aggregate refers to these keys

 If all of above is true then group by is rewritten and a new project is introduced
 underneath aggregate

 This is mainly done so that hive is able to push down queries with
 group by 'constant key with type not supported by druid' into druid.
ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/HiveRelFieldTrimmer.java