public Result implement(EnumerableRelImplementor implementor, Prefer pref) {
final JavaTypeFactory typeFactory = implementor.getTypeFactory();
final EnumerableRel child = (EnumerableRel) getChild();
final BlockBuilder builder = new BlockBuilder();
final Result result = implementor.visitChild(this, 0, child, pref);
Expression source_ = builder.append("source", result.block);
final List<Expression> translatedConstants =
new ArrayList<Expression>(constants.size());
for (RexLiteral constant : constants) {
translatedConstants.add(RexToLixTranslator.translateLiteral(
constant, constant.getType(),
typeFactory,
RexImpTable.NullAs.NULL));
}
PhysType inputPhysType = result.physType;
ParameterExpression prevStart =
Expressions.parameter(int.class, builder.newName("prevStart"));
ParameterExpression prevEnd =
Expressions.parameter(int.class, builder.newName("prevEnd"));
builder.add(Expressions.declare(0, prevStart, null));
builder.add(Expressions.declare(0, prevEnd, null));
for (int windowIdx = 0; windowIdx < windows.size(); windowIdx++) {
Window window = windows.get(windowIdx);
// Comparator:
// final Comparator<JdbcTest.Employee> comparator =
// new Comparator<JdbcTest.Employee>() {
// public int compare(JdbcTest.Employee o1,
// JdbcTest.Employee o2) {
// return Integer.compare(o1.empid, o2.empid);
// }
// };
final Expression comparator_ =
builder.append(
"comparator",
inputPhysType.generateComparator(
window.collation()));
Pair<Expression, Expression> partitionIterator =
getPartitionIterator(builder, source_, inputPhysType, window,
comparator_);
final Expression collectionExpr = partitionIterator.left;
final Expression iterator_ = partitionIterator.right;
List<AggImpState> aggs = new ArrayList<AggImpState>();
List<AggregateCall> aggregateCalls = window.getAggregateCalls(this);
for (int aggIdx = 0; aggIdx < aggregateCalls.size(); aggIdx++) {
AggregateCall call = aggregateCalls.get(aggIdx);
aggs.add(new AggImpState(aggIdx, call, true));
}
// The output from this stage is the input plus the aggregate functions.
final RelDataTypeFactory.FieldInfoBuilder typeBuilder =
typeFactory.builder();
typeBuilder.addAll(inputPhysType.getRowType().getFieldList());
for (AggImpState agg : aggs) {
typeBuilder.add(agg.call.name, agg.call.type);
}
RelDataType outputRowType = typeBuilder.build();
final PhysType outputPhysType =
PhysTypeImpl.of(
typeFactory, outputRowType, pref.prefer(result.format));
final Expression list_ =
builder.append(
"list",
Expressions.new_(
ArrayList.class,
Expressions.call(
collectionExpr, BuiltinMethod.COLLECTION_SIZE.method)),
false);
Pair<Expression, Expression> collationKey =
getRowCollationKey(builder, inputPhysType, window, windowIdx);
Expression keySelector = collationKey.left;
Expression keyComparator = collationKey.right;
final BlockBuilder builder3 = new BlockBuilder();
final Expression rows_ =
builder3.append(
"rows",
Expressions.convert_(
Expressions.call(
iterator_, BuiltinMethod.ITERATOR_NEXT.method),
Object[].class),
false);
builder3.add(Expressions.statement(
Expressions.assign(prevStart, Expressions.constant(-1))));
builder3.add(Expressions.statement(
Expressions.assign(prevEnd,
Expressions.constant(Integer.MAX_VALUE))));
final BlockBuilder builder4 = new BlockBuilder();
final ParameterExpression i_ =
Expressions.parameter(int.class, builder4.newName("i"));
final Expression row_ =
builder4.append(
"row",
RexToLixTranslator.convert(
Expressions.arrayIndex(rows_, i_),
inputPhysType.getJavaRowType()));
final RexToLixTranslator.InputGetter inputGetter =
new WindowRelInputGetter(row_, inputPhysType,
result.physType.getRowType().getFieldCount(),
translatedConstants);
final RexToLixTranslator translator =
RexToLixTranslator.forAggregation(typeFactory, builder4,
inputGetter);
final List<Expression> outputRow = new ArrayList<Expression>();
int fieldCountWithAggResults =
inputPhysType.getRowType().getFieldCount();
for (int i = 0; i < fieldCountWithAggResults; i++) {
outputRow.add(
inputPhysType.fieldReference(
row_, i,
outputPhysType.getJavaFieldType(i)));
}
declareAndResetState(typeFactory, builder, result, windowIdx, aggs,
outputPhysType, outputRow);
// There are assumptions that minX==0. If ever change this, look for
// frameRowCount, bounds checking, etc
final Expression minX = Expressions.constant(0);
final Expression partitionRowCount =
builder3.append("partRows", Expressions.field(rows_, "length"));
final Expression maxX = builder3.append("maxX",
Expressions.subtract(
partitionRowCount, Expressions.constant(1)));
final Expression startUnchecked = builder4.append("start",
translateBound(translator, i_, row_, minX, maxX, rows_,
window, true,
inputPhysType, comparator_, keySelector, keyComparator));
final Expression endUnchecked = builder4.append("end",
translateBound(translator, i_, row_, minX, maxX, rows_,
window, false,
inputPhysType, comparator_, keySelector, keyComparator));
final Expression startX;
final Expression endX;
final Expression hasRows;
if (window.isAlwaysNonEmpty()) {
startX = startUnchecked;
endX = endUnchecked;
hasRows = Expressions.constant(true);
} else {
Expression startTmp =
window.lowerBound.isUnbounded() || startUnchecked == i_
? startUnchecked
: builder4.append("startTmp",
Expressions.call(null, BuiltinMethod.MATH_MAX.method,
startUnchecked, minX));
Expression endTmp =
window.upperBound.isUnbounded() || endUnchecked == i_
? endUnchecked
: builder4.append("endTmp",
Expressions.call(null, BuiltinMethod.MATH_MIN.method,
endUnchecked, maxX));
ParameterExpression startPe = Expressions.parameter(0, int.class,
builder4.newName("startChecked"));
ParameterExpression endPe = Expressions.parameter(0, int.class,
builder4.newName("endChecked"));
builder4.add(Expressions.declare(Modifier.FINAL, startPe, null));
builder4.add(Expressions.declare(Modifier.FINAL, endPe, null));
hasRows = builder4.append("hasRows",
Expressions.lessThanOrEqual(startTmp, endTmp));
builder4.add(Expressions.ifThenElse(
hasRows,
Expressions.block(
Expressions.statement(
Expressions.assign(startPe, startTmp)),
Expressions.statement(
Expressions.assign(endPe, endTmp))
),
Expressions.block(
Expressions.statement(
Expressions.assign(startPe, Expressions.constant(-1))),
Expressions.statement(
Expressions.assign(endPe, Expressions.constant(-1))))));
startX = startPe;
endX = endPe;
}
final BlockBuilder builder5 = new BlockBuilder(true, builder4);
BinaryExpression rowCountWhenNonEmpty = Expressions.add(
startX == minX ? endX : Expressions.subtract(endX, startX),
Expressions.constant(1));
final Expression frameRowCount;
if (hasRows.equals(Expressions.constant(true))) {
frameRowCount =
builder4.append("totalRows", rowCountWhenNonEmpty);
} else {
frameRowCount =
builder4.append("totalRows", Expressions.condition(hasRows,
rowCountWhenNonEmpty, Expressions.constant(0)));
}
ParameterExpression actualStart = Expressions.parameter(
0, int.class, builder5.newName("actualStart"));
final BlockBuilder builder6 = new BlockBuilder(true, builder5);
builder6.add(Expressions.statement(
Expressions.assign(actualStart, startX)));
for (final AggImpState agg : aggs) {
agg.implementor.implementReset(agg.context,
new WinAggResetContextImpl(builder6, agg.state, i_, startX, endX,
hasRows, partitionRowCount, frameRowCount));
}
Expression lowerBoundCanChange =
window.lowerBound.isUnbounded() && window.lowerBound.isPreceding()
? Expressions.constant(false)
: Expressions.notEqual(startX, prevStart);
Expression needRecomputeWindow = Expressions.orElse(
lowerBoundCanChange,
Expressions.lessThan(endX, prevEnd));
BlockStatement resetWindowState = builder6.toBlock();
if (resetWindowState.statements.size() == 1) {