public Result implement(EnumerableRelImplementor implementor, Prefer pref) {
final JavaTypeFactory typeFactory = implementor.getTypeFactory();
final BlockBuilder builder = new BlockBuilder();
final EnumerableRel child = (EnumerableRel) getChild();
final Result result = implementor.visitChild(this, 0, child, pref);
Expression childExp =
builder.append(
"child",
result.block);
final RelDataType inputRowType = getChild().getRowType();
final PhysType physType =
PhysTypeImpl.of(
typeFactory, getRowType(), pref.preferCustom());
// final Enumerable<Employee> child = <<child impl>>;
// Function1<Employee, Integer> keySelector =
// new Function1<Employee, Integer>() {
// public Integer apply(Employee a0) {
// return a0.deptno;
// }
// };
// Function1<Employee, Object[]> accumulatorInitializer =
// new Function1<Employee, Object[]>() {
// public Object[] apply(Employee a0) {
// return new Object[] {0, 0};
// }
// };
// Function2<Object[], Employee, Object[]> accumulatorAdder =
// new Function2<Object[], Employee, Object[]>() {
// public Object[] apply(Object[] a1, Employee a0) {
// a1[0] = ((Integer) a1[0]) + 1;
// a1[1] = ((Integer) a1[1]) + a0.salary;
// return a1;
// }
// };
// Function2<Integer, Object[], Object[]> resultSelector =
// new Function2<Integer, Object[], Object[]>() {
// public Object[] apply(Integer a0, Object[] a1) {
// return new Object[] { a0, a1[0], a1[1] };
// }
// };
// return childEnumerable
// .groupBy(
// keySelector, accumulatorInitializer, accumulatorAdder,
// resultSelector);
//
// or, if key has 0 columns,
//
// return childEnumerable
// .aggregate(
// accumulatorInitializer.apply(),
// accumulatorAdder,
// resultSelector);
//
// with a slightly different resultSelector; or if there are no aggregate
// functions
//
// final Enumerable<Employee> child = <<child impl>>;
// Function1<Employee, Integer> keySelector =
// new Function1<Employee, Integer>() {
// public Integer apply(Employee a0) {
// return a0.deptno;
// }
// };
// EqualityComparer<Employee> equalityComparer =
// new EqualityComparer<Employee>() {
// boolean equal(Employee a0, Employee a1) {
// return a0.deptno;
// }
// };
// return child
// .distinct(equalityComparer);
final PhysType inputPhysType = result.physType;
ParameterExpression parameter =
Expressions.parameter(inputPhysType.getJavaRowType(), "a0");
final List<Expression> keyExpressions = Expressions.list();
PhysType keyPhysType =
inputPhysType.project(
BitSets.toList(groupSet), JavaRowFormat.LIST);
final int keyArity = groupSet.cardinality();
for (int groupKey : BitSets.toIter(groupSet)) {
keyExpressions.add(
inputPhysType.fieldReference(parameter, groupKey));
}
final Expression keySelector =
builder.append(
"keySelector",
inputPhysType.generateSelector(
parameter,
BitSets.toList(groupSet),
keyPhysType.getFormat()));
final List<AggImpState> aggs =
new ArrayList<AggImpState>(aggCalls.size());
for (int i = 0; i < aggCalls.size(); i++) {
AggregateCall call = aggCalls.get(i);
aggs.add(new AggImpState(i, call, false));
}
// Function0<Object[]> accumulatorInitializer =
// new Function0<Object[]>() {
// public Object[] apply() {
// return new Object[] {0, 0};
// }
// };
final List<Expression> initExpressions =
new ArrayList<Expression>();
final BlockBuilder initBlock = new BlockBuilder();
final List<Type> aggStateTypes = new ArrayList<Type>();
for (final AggImpState agg : aggs) {
agg.context =
new AggContext() {
public Aggregation aggregation() {
return agg.call.getAggregation();
}
public RelDataType returnRelType() {
return agg.call.type;
}
public Type returnType() {
return EnumUtil.javaClass(typeFactory, returnRelType());
}
public List<? extends RelDataType> parameterRelTypes() {
return EnumUtil.fieldRowTypes(inputRowType, null,
agg.call.getArgList());
}
public List<? extends Type> parameterTypes() {
return EnumUtil.fieldTypes(typeFactory,
parameterRelTypes());
}
};
List<Type> state =
agg.implementor.getStateType(agg.context);
if (state.isEmpty()) {
continue;
}
aggStateTypes.addAll(state);
final List<Expression> decls =
new ArrayList<Expression>(state.size());
for (int i = 0; i < state.size(); i++) {
String aggName = "a" + agg.aggIdx;
if (OptiqPrepareImpl.DEBUG) {
aggName = Util.toJavaId(agg.call.getAggregation().getName(), 0)
.substring("ID$0$".length()) + aggName;
}
Type type = state.get(i);
ParameterExpression pe =
Expressions.parameter(type,
initBlock.newName(aggName + "s" + i));
initBlock.add(Expressions.declare(0, pe, null));
decls.add(pe);
}
agg.state = decls;
initExpressions.addAll(decls);
agg.implementor.implementReset(agg.context,
new AggResultContextImpl(initBlock, decls));
}
final PhysType accPhysType =
PhysTypeImpl.of(
typeFactory,
typeFactory.createSyntheticType(aggStateTypes));
initBlock.add(accPhysType.record(initExpressions));
final Expression accumulatorInitializer =
builder.append(
"accumulatorInitializer",
Expressions.lambda(
Function0.class,
initBlock.toBlock()));
// Function2<Object[], Employee, Object[]> accumulatorAdder =
// new Function2<Object[], Employee, Object[]>() {
// public Object[] apply(Object[] acc, Employee in) {
// acc[0] = ((Integer) acc[0]) + 1;
// acc[1] = ((Integer) acc[1]) + in.salary;
// return acc;
// }
// };
final BlockBuilder builder2 = new BlockBuilder();
final ParameterExpression inParameter =
Expressions.parameter(inputPhysType.getJavaRowType(), "in");
final ParameterExpression acc_ =
Expressions.parameter(accPhysType.getJavaRowType(), "acc");
for (int i = 0, stateOffset = 0; i < aggs.size(); i++) {
final AggImpState agg = aggs.get(i);
int stateSize = agg.state.size();
List<Expression> accumulator =
new ArrayList<Expression>(stateSize);
for (int j = 0; j < stateSize; j++) {
accumulator.add(accPhysType.fieldReference(
acc_, j + stateOffset));
}
agg.state = accumulator;
stateOffset += stateSize;
AggAddContext addContext =
new AggAddContextImpl(builder2, accumulator) {
public List<RexNode> rexArguments() {
List<RelDataTypeField> inputTypes =
inputPhysType.getRowType().getFieldList();
List<RexNode> args = new ArrayList<RexNode>();
for (Integer index : agg.call.getArgList()) {
args.add(new RexInputRef(index,
inputTypes.get(index).getType()));
}
return args;
}
public RexToLixTranslator rowTranslator() {
return RexToLixTranslator.forAggregation(typeFactory,
currentBlock(), new RexToLixTranslator.InputGetterImpl(
Collections.singletonList(Pair.of(
(Expression) inParameter, inputPhysType))))
.setNullable(currentNullables());
}
};
agg.implementor.implementAdd(agg.context, addContext);
}
builder2.add(acc_);
final Expression accumulatorAdder =
builder.append(
"accumulatorAdder",
Expressions.lambda(
Function2.class,
builder2.toBlock(),
acc_,
inParameter));
// Function2<Integer, Object[], Object[]> resultSelector =
// new Function2<Integer, Object[], Object[]>() {
// public Object[] apply(Integer key, Object[] acc) {
// return new Object[] { key, acc[0], acc[1] };
// }
// };
final BlockBuilder resultBlock = new BlockBuilder();
final List<Expression> results = Expressions.list();
final ParameterExpression key_;
if (keyArity == 0) {
key_ = null;
} else {
final Type keyType = keyPhysType.getJavaRowType();
key_ = Expressions.parameter(keyType, "key");
for (int j = 0; j < keyArity; j++) {
results.add(
keyPhysType.fieldReference(key_, j));
}
}
for (final AggImpState agg : aggs) {
results.add(agg.implementor.implementResult(
agg.context,
new AggResultContextImpl(resultBlock, agg.state)));
}
resultBlock.add(physType.record(results));
if (keyArity == 0) {
final Expression resultSelector =
builder.append(
"resultSelector",
Expressions.lambda(
Function1.class,
resultBlock.toBlock(),
acc_));
builder.add(
Expressions.return_(
null,
Expressions.call(
BuiltinMethod.SINGLETON_ENUMERABLE.method,
Expressions.call(
childExp,
BuiltinMethod.AGGREGATE.method,
Expressions.call(accumulatorInitializer, "apply"),
accumulatorAdder,
resultSelector))));
} else if (aggCalls.isEmpty()) {
builder.add(
Expressions.return_(
null,
Expressions.call(
childExp,
BuiltinMethod.DISTINCT.method,
Expressions.<Expression>list()
.appendIfNotNull(physType.comparer()))));
} else {
final Expression resultSelector =
builder.append(
"resultSelector",
Expressions.lambda(
Function2.class,
resultBlock.toBlock(),