You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2014/06/28 00:27:54 UTC

[7/7] git commit: [OPTIQ-310] Implement LEAD, LAG and NTILE windowed aggregates.

[OPTIQ-310] Implement LEAD, LAG and NTILE windowed aggregates.

Refactor aggregate implementation to interfaces.
Add rowInFrame, and rowInPartition, and needCacheWhenFrameIntact APIs for
windowed aggregates.


Project: http://git-wip-us.apache.org/repos/asf/incubator-optiq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-optiq/commit/99f39682
Tree: http://git-wip-us.apache.org/repos/asf/incubator-optiq/tree/99f39682
Diff: http://git-wip-us.apache.org/repos/asf/incubator-optiq/diff/99f39682

Branch: refs/heads/master
Commit: 99f3968285d5e7c7c50d6d1fc01e3f3aa5486e62
Parents: e34e6e1
Author: Vladimir Sitnikov <si...@gmail.com>
Authored: Tue Jun 24 11:07:29 2014 +0400
Committer: Julian Hyde <ju...@gmail.com>
Committed: Tue Jun 24 20:17:26 2014 -0600

----------------------------------------------------------------------
 REFERENCE.md                                    |   4 +
 .../optiq/rules/java/AggAddContext.java         |  30 +-
 .../optiq/rules/java/AggResetContext.java       |  22 +-
 .../optiq/rules/java/AggResultContext.java      |  18 +-
 .../hydromatic/optiq/rules/java/JavaRules.java  | 266 +++++++--------
 .../optiq/rules/java/NestedBlockBuilder.java    |  57 +---
 .../rules/java/NestedBlockBuilderImpl.java      | 117 +++++++
 .../optiq/rules/java/RexImpTable.java           | 144 +++++++-
 .../optiq/rules/java/RexToLixTranslator.java    |  10 +-
 .../optiq/rules/java/StrictAggImplementor.java  |   4 +-
 .../rules/java/StrictWinAggImplementor.java     |   4 +
 .../optiq/rules/java/WinAggAddContext.java      |  38 +--
 .../optiq/rules/java/WinAggContext.java         |  27 ++
 .../optiq/rules/java/WinAggFrameContext.java    |  73 +++++
 .../rules/java/WinAggFrameResultContext.java    |  69 ++++
 .../optiq/rules/java/WinAggImplementor.java     | 106 +-----
 .../optiq/rules/java/WinAggResetContext.java    |  60 +---
 .../optiq/rules/java/WinAggResultContext.java   |  41 ++-
 .../rules/java/impl/AggAddContextImpl.java      |  39 +++
 .../rules/java/impl/AggResetContextImpl.java    |  51 +++
 .../rules/java/impl/AggResultContextImpl.java   |  44 +++
 .../rules/java/impl/WinAggAddContextImpl.java   |  53 +++
 .../rules/java/impl/WinAggResetContextImpl.java |  89 +++++
 .../java/impl/WinAggResultContextImpl.java      | 108 ++++++
 .../optiq/rules/java/impl/package-info.java     |  24 ++
 .../sql/fun/SqlLeadLagAggFunction.java          |  94 ++++++
 .../eigenbase/sql/fun/SqlNtileAggFunction.java  |  58 ++++
 .../eigenbase/sql/fun/SqlStdOperatorTable.java  |  18 +
 .../sql/type/CompositeOperandTypeChecker.java   |   6 +
 .../sql/type/SqlSingleOperandTypeChecker.java   |   2 +-
 .../net/hydromatic/optiq/test/JdbcTest.java     | 328 ++++++++++++++-----
 31 files changed, 1438 insertions(+), 566 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/REFERENCE.md
----------------------------------------------------------------------
diff --git a/REFERENCE.md b/REFERENCE.md
index 5fe4fdb..92f54eb 100644
--- a/REFERENCE.md
+++ b/REFERENCE.md
@@ -434,8 +434,12 @@ Not implemented:
 | ROW_NUMBER() OVER window
 | FIRST_VALUE(value) OVER window
 | LAST_VALUE(value) OVER window
+| LEAD(value, offset, default) OVER window
+| LAG(value, offset, default) OVER window
+| NTILE(value) OVER window
 
 Not implemented:
+* COUNT(DISTINCT value) OVER window
 * FIRST_VALUE(value) IGNORE NULLS OVER window
 * LAST_VALUE(value) IGNORE NULLS OVER window
 * PERCENT_RANK(value) OVER window

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/net/hydromatic/optiq/rules/java/AggAddContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/AggAddContext.java b/core/src/main/java/net/hydromatic/optiq/rules/java/AggAddContext.java
index 88a88c3..cd1aca3 100644
--- a/core/src/main/java/net/hydromatic/optiq/rules/java/AggAddContext.java
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/AggAddContext.java
@@ -17,7 +17,6 @@
 */
 package net.hydromatic.optiq.rules.java;
 
-import net.hydromatic.linq4j.expressions.BlockBuilder;
 import net.hydromatic.linq4j.expressions.Expression;
 
 import org.eigenbase.rex.RexNode;
@@ -25,22 +24,18 @@ import org.eigenbase.rex.RexNode;
 import java.util.List;
 
 /**
- * Information for a call to {@link AggImplementor#implementAdd(AggContext, AggAddContext)}.
+ * Information for a call to {@link net.hydromatic.optiq.rules.java.AggImplementor#implementAdd(AggContext, AggAddContext)}.
  * Typically, the aggregation implementation will use {@link #arguments()}
  * or {@link #rexArguments()} to update aggregate value.
  */
-public abstract class AggAddContext extends AggResultContext {
-  public AggAddContext(BlockBuilder block, List<Expression> accumulator) {
-    super(block, accumulator);
-  }
-
+public interface AggAddContext extends AggResultContext {
   /**
-   * Returns {@link RexNode} representation of arguments.
+   * Returns {@link org.eigenbase.rex.RexNode} representation of arguments.
    * This can be useful for manual translation of required arguments with
-   * different {@link net.hydromatic.optiq.rules.java.NullPolicy}.
-   * @return {@link RexNode} representation of arguments
+   * different {@link NullPolicy}.
+   * @return {@link org.eigenbase.rex.RexNode} representation of arguments
    */
-  public abstract List<RexNode> rexArguments();
+  List<RexNode> rexArguments();
 
   /**
    * Returns Linq4j form of arguments.
@@ -49,14 +44,13 @@ public abstract class AggAddContext extends AggResultContext {
    * This is handy if you need just operate on argument.
    * @return Linq4j form of arguments.
    */
-  public final List<Expression> arguments() {
-    return rowTranslator().translateList(rexArguments());
-  }
+  List<Expression> arguments();
 
   /**
-   * Returns {@link RexToLixTranslator} suitable to transform the arguments.
-   * @return {@link RexToLixTranslator} suitable to transform the arguments.
+   * Returns {@link net.hydromatic.optiq.rules.java.RexToLixTranslator} suitable to transform the arguments.
+   * @return {@link net.hydromatic.optiq.rules.java.RexToLixTranslator} suitable to transform the arguments.
    */
-  public abstract RexToLixTranslator rowTranslator();
-
+  RexToLixTranslator rowTranslator();
 }
+
+// End AggAddContext.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/net/hydromatic/optiq/rules/java/AggResetContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/AggResetContext.java b/core/src/main/java/net/hydromatic/optiq/rules/java/AggResetContext.java
index 22276a1..b6faada 100644
--- a/core/src/main/java/net/hydromatic/optiq/rules/java/AggResetContext.java
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/AggResetContext.java
@@ -17,7 +17,6 @@
 */
 package net.hydromatic.optiq.rules.java;
 
-import net.hydromatic.linq4j.expressions.BlockBuilder;
 import net.hydromatic.linq4j.expressions.Expression;
 
 import java.util.List;
@@ -27,30 +26,15 @@ import java.util.List;
  * {@link AggResetContext} provides access to the accumulator variables
  * that should be reset.
  */
-public class AggResetContext extends NestedBlockBuilder {
-  private final List<Expression> accumulator;
-
-  /**
-   * Creates aggregate reset context
-   * @param block code block that will contain the added initialization
-   * @param accumulator accumulator variables that store the intermediate
-   *                    aggregate state
-   */
-  public AggResetContext(BlockBuilder block, List<Expression> accumulator) {
-    super(block);
-    this.accumulator = accumulator;
-  }
-
+public interface AggResetContext extends NestedBlockBuilder {
   /**
    * Returns accumulator variables that should be reset.
    * There MUST be an assignment even if you just assign the default value.
    * @return accumulator variables that should be reset or empty list when no
    *   accumulator variables are used by the aggregate implementation.
-   * @see net.hydromatic.optiq.rules.java.AggImplementor#getStateType(AggContext)
+   * @see AggImplementor#getStateType(net.hydromatic.optiq.rules.java.AggContext)
    */
-  public List<Expression> accumulator() {
-    return accumulator;
-  }
+  List<Expression> accumulator();
 }
 
 // End AggResetContext.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/net/hydromatic/optiq/rules/java/AggResultContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/AggResultContext.java b/core/src/main/java/net/hydromatic/optiq/rules/java/AggResultContext.java
index 3c096df..71ab4af 100644
--- a/core/src/main/java/net/hydromatic/optiq/rules/java/AggResultContext.java
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/AggResultContext.java
@@ -17,27 +17,13 @@
 */
 package net.hydromatic.optiq.rules.java;
 
-import net.hydromatic.linq4j.expressions.BlockBuilder;
-import net.hydromatic.linq4j.expressions.Expression;
-
-import java.util.List;
-
 /**
  * Information for a call to {@link AggImplementor#implementResult(AggContext, AggResultContext)}
  * Typically, the aggregation implementation will convert {@link #accumulator()}
  * to the resulting value of the aggregation.
- * The implementation MUST NOT destroy the cotents of {@link #accumulator()}.
+ * The implementation MUST NOT destroy the contents of {@link #accumulator()}.
  */
-public class AggResultContext extends AggResetContext {
-  /**
-   * Creates aggregate result context
-   * @param block code block that will contain the result calculation statements
-   * @param accumulator accumulator variables that store the intermediate
-   *                    aggregate state
-   */
-  public AggResultContext(BlockBuilder block, List<Expression> accumulator) {
-    super(block, accumulator);
-  }
+public interface AggResultContext extends NestedBlockBuilder, AggResetContext {
 }
 
 // End AggResultContext.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/net/hydromatic/optiq/rules/java/JavaRules.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/JavaRules.java b/core/src/main/java/net/hydromatic/optiq/rules/java/JavaRules.java
index cf8ce44..266a7b4 100644
--- a/core/src/main/java/net/hydromatic/optiq/rules/java/JavaRules.java
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/JavaRules.java
@@ -26,6 +26,7 @@ import net.hydromatic.optiq.*;
 import net.hydromatic.optiq.impl.java.JavaTypeFactory;
 import net.hydromatic.optiq.prepare.OptiqPrepareImpl;
 import net.hydromatic.optiq.prepare.Prepare;
+import net.hydromatic.optiq.rules.java.impl.*;
 import net.hydromatic.optiq.runtime.SortedMultiMap;
 import net.hydromatic.optiq.util.BitSets;
 
@@ -1049,7 +1050,7 @@ public class JavaRules {
         agg.state = decls;
         initExpressions.addAll(decls);
         agg.implementor.implementReset(agg.context,
-            new AggResultContext(initBlock, decls));
+            new AggResultContextImpl(initBlock, decls));
       }
 
       final PhysType accPhysType =
@@ -1094,7 +1095,7 @@ public class JavaRules {
         stateOffset += stateSize;
 
         AggAddContext addContext =
-            new AggAddContext(builder2, accumulator) {
+            new AggAddContextImpl(builder2, accumulator) {
               public List<RexNode> rexArguments() {
                 List<RelDataTypeField> inputTypes =
                     inputPhysType.getRowType().getFieldList();
@@ -1149,7 +1150,7 @@ public class JavaRules {
       for (final AggImpState agg : aggs) {
         results.add(agg.implementor.implementResult(
             agg.context,
-            new AggResultContext(resultBlock, agg.state)));
+            new AggResultContextImpl(resultBlock, agg.state)));
       }
       resultBlock.add(physType.record(results));
       if (keyArity == 0) {
@@ -2256,10 +2257,14 @@ public class JavaRules {
         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(
-                Expressions.field(rows_, "length"), Expressions.constant(1)));
+                partitionRowCount, Expressions.constant(1)));
 
         final Expression startUnchecked = builder4.append("start",
             translateBound(translator, i_, row_, minX, maxX, rows_,
@@ -2323,14 +2328,14 @@ public class JavaRules {
             startX == minX ? endX : Expressions.subtract(endX, startX),
             Expressions.constant(1));
 
-        final Expression partitionRowCount;
+        final Expression frameRowCount;
 
         if (hasRows.equals(Expressions.constant(true))) {
-          partitionRowCount =
-              builder3.append("totalRows", rowCountWhenNonEmpty);
+          frameRowCount =
+              builder4.append("totalRows", rowCountWhenNonEmpty);
         } else {
-          partitionRowCount =
-              builder5.append("totalRows", Expressions.condition(hasRows,
+          frameRowCount =
+              builder4.append("totalRows", Expressions.condition(hasRows,
                   rowCountWhenNonEmpty, Expressions.constant(0)));
         }
 
@@ -2343,8 +2348,8 @@ public class JavaRules {
 
         for (final AggImpState agg : aggs) {
           agg.implementor.implementReset(agg.context,
-              new WinAggResetContext(builder6, agg.state, i_, startX, endX,
-                  hasRows, partitionRowCount));
+              new WinAggResetContextImpl(builder6, agg.state, i_, startX, endX,
+                  hasRows, partitionRowCount, frameRowCount));
         }
 
         Expression lowerBoundCanChange =
@@ -2381,10 +2386,12 @@ public class JavaRules {
             Expressions.declare(0, "j", actualStart);
 
         final PhysType inputPhysTypeFinal = inputPhysType;
-        final Function<BlockBuilder, WinAggImplementor.WinAggFrameResultContext>
+        final Function<BlockBuilder, WinAggFrameResultContext>
             resultContextBuilder =
             getBlockBuilderWinAggFrameResultContextFunction(typeFactory, result,
                 translatedConstants, comparator_, rows_, i_, startX, endX,
+                minX, maxX,
+                hasRows, frameRowCount, partitionRowCount,
                 jDecl, inputPhysTypeFinal);
 
         final Function<AggImpState, List<RexNode>> rexArguments =
@@ -2406,8 +2413,7 @@ public class JavaRules {
               }
             };
 
-        implementAdd(aggs, i_, startX, endX, hasRows, partitionRowCount,
-            builder7, jDecl, resultContextBuilder, rexArguments);
+        implementAdd(aggs, builder7, resultContextBuilder, rexArguments, jDecl);
 
         BlockStatement forBlock = builder7.toBlock();
         if (!forBlock.statements.isEmpty()) {
@@ -2423,13 +2429,15 @@ public class JavaRules {
           builder5.add(forAggLoop);
         }
 
-        implementResult(aggs, i_, startX, endX, hasRows, builder5,
-            partitionRowCount,
-            resultContextBuilder, rexArguments);
+        if (implementResult(aggs, builder5, resultContextBuilder, rexArguments,
+                true)) {
+          builder4.add(Expressions.ifThen(Expressions.orElse(
+              lowerBoundCanChange,
+              Expressions.notEqual(endX, prevEnd)), builder5.toBlock()));
+        }
 
-        builder4.add(Expressions.ifThen(Expressions.orElse(
-            lowerBoundCanChange,
-            Expressions.notEqual(endX, prevEnd)), builder5.toBlock()));
+        implementResult(aggs, builder4, resultContextBuilder, rexArguments,
+            false);
 
         builder4.add(
             Expressions.statement(
@@ -2476,25 +2484,28 @@ public class JavaRules {
       return implementor.result(inputPhysType, builder.toBlock());
     }
 
-    private Function<BlockBuilder, WinAggImplementor.WinAggFrameResultContext>
+    private Function<BlockBuilder, WinAggFrameResultContext>
     getBlockBuilderWinAggFrameResultContextFunction(
         final JavaTypeFactory typeFactory, final Result result,
         final List<Expression> translatedConstants,
         final Expression comparator_,
         final Expression rows_, final ParameterExpression i_,
-        final Expression startX,
-        final Expression endX, final DeclarationStatement jDecl,
-        final PhysType inputPhysTypeFinal) {
+        final Expression startX, final Expression endX,
+        final Expression minX, final Expression maxX,
+        final Expression hasRows, final Expression frameRowCount,
+        final Expression partitionRowCount,
+        final DeclarationStatement jDecl,
+        final PhysType inputPhysType) {
       return new Function<BlockBuilder,
-          WinAggImplementor.WinAggFrameResultContext>() {
-        public WinAggImplementor.WinAggFrameResultContext apply(
+          WinAggFrameResultContext>() {
+        public WinAggFrameResultContext apply(
             final BlockBuilder block) {
-          return new WinAggImplementor.WinAggFrameResultContext() {
+          return new WinAggFrameResultContext() {
             public RexToLixTranslator rowTranslator(Expression rowIndex) {
               Expression row =
                   getRow(rowIndex);
               final RexToLixTranslator.InputGetter inputGetter =
-                  new WindowRelInputGetter(row, inputPhysTypeFinal,
+                  new WindowRelInputGetter(row, inputPhysType,
                       result.physType.getRowType().getFieldCount(),
                       translatedConstants);
 
@@ -2502,16 +2513,6 @@ public class JavaRules {
                   block, inputGetter);
             }
 
-            public List<RexNode> rexArguments() {
-              throw new UnsupportedOperationException(
-                  "Should not be used");
-            }
-
-            public List<Expression> arguments(Expression rowIndex) {
-              throw new UnsupportedOperationException(
-                  "Should not be used");
-            }
-
             public Expression computeIndex(Expression offset,
                 WinAggImplementor.SeekType seekType) {
               Expression index;
@@ -2528,15 +2529,35 @@ public class JavaRules {
                     + " is not supported");
               }
               if (!Expressions.constant(0).equals(offset)) {
-                index = Expressions.add(index, offset);
-                index = Expressions.call(
-                    BuiltinMethod.MATH_MIN.method, index, endX);
-                index = Expressions.call(
-                    BuiltinMethod.MATH_MAX.method, index, startX);
+                index = block.append("idx", Expressions.add(index, offset));
               }
               return index;
             }
 
+            private Expression checkBounds(Expression rowIndex,
+                Expression minIndex, Expression maxIndex) {
+              if (rowIndex == i_ || rowIndex == startX || rowIndex == endX) {
+                // No additional bounds check required
+                return hasRows;
+              }
+
+              //noinspection UnnecessaryLocalVariable
+              Expression res = block.append("rowInFrame", Expressions.foldAnd(
+                  ImmutableList.of(hasRows,
+                      Expressions.greaterThanOrEqual(rowIndex, minIndex),
+                      Expressions.lessThanOrEqual(rowIndex, maxIndex))));
+
+              return res;
+            }
+
+            public Expression rowInFrame(Expression rowIndex) {
+              return checkBounds(rowIndex, startX, endX);
+            }
+
+            public Expression rowInPartition(Expression rowIndex) {
+              return checkBounds(rowIndex, minX, maxX);
+            }
+
             public Expression compareRows(Expression a, Expression b) {
               return Expressions.call(comparator_,
                   BuiltinMethod.COMPARATOR_COMPARE.method,
@@ -2548,7 +2569,31 @@ public class JavaRules {
                   "jRow",
                   RexToLixTranslator.convert(
                       Expressions.arrayIndex(rows_, rowIndex),
-                      inputPhysTypeFinal.getJavaRowType()));
+                      inputPhysType.getJavaRowType()));
+            }
+
+            public Expression index() {
+              return i_;
+            }
+
+            public Expression startIndex() {
+              return startX;
+            }
+
+            public Expression endIndex() {
+              return endX;
+            }
+
+            public Expression hasRows() {
+              return hasRows;
+            }
+
+            public Expression getFrameRowCount() {
+              return frameRowCount;
+            }
+
+            public Expression getPartitionRowCount() {
+              return partitionRowCount;
             }
           };
         }
@@ -2668,7 +2713,7 @@ public class JavaRules {
         List<Expression> outputRow) {
       for (final AggImpState agg: aggs) {
         agg.context =
-            new WinAggImplementor.WinAggContext() {
+            new WinAggContext() {
               public Aggregation aggregation() {
                 return agg.call.getAggregation();
               }
@@ -2727,68 +2772,23 @@ public class JavaRules {
         agg.result = aggRes;
         outputRow.add(aggRes);
         agg.implementor.implementReset(agg.context,
-            new WinAggResetContext(builder, agg.state,
-                null, null, null, null, null));
+            new WinAggResetContextImpl(builder, agg.state,
+                null, null, null, null, null, null));
       }
     }
 
     private void implementAdd(List<AggImpState> aggs,
-        final ParameterExpression i_,
-        final Expression startX, final Expression endX,
-        final Expression hasRows,
-        final Expression partitionRowCount, final BlockBuilder builder7,
-        final DeclarationStatement jDecl,
-        final Function<BlockBuilder, WinAggImplementor
-            .WinAggFrameResultContext> resultContextBuilder,
-        final Function<AggImpState, List<RexNode>> rexArguments) {
+        final BlockBuilder builder7,
+        final Function<BlockBuilder, WinAggFrameResultContext> frame,
+        final Function<AggImpState, List<RexNode>> rexArguments,
+        final DeclarationStatement jDecl) {
       for (final AggImpState agg : aggs) {
         final WinAggAddContext addContext =
-            new WinAggAddContext(builder7, agg.state) {
-              public Expression computeIndex(Expression offset,
-                  WinAggImplementor.SeekType seekType) {
-                WinAggImplementor.WinAggFrameResultContext context =
-                    resultContextBuilder.apply(currentBlock());
-                return context.computeIndex(offset, seekType);
-              }
-
-              public RexToLixTranslator rowTranslator(Expression rowIndex) {
-                WinAggImplementor.WinAggFrameResultContext context =
-                    resultContextBuilder.apply(currentBlock());
-                return context.rowTranslator(rowIndex)
-                    .setNullable(currentNullables());
-              }
-
-              public Expression compareRows(Expression a, Expression b) {
-                WinAggImplementor.WinAggFrameResultContext context =
-                    resultContextBuilder.apply(currentBlock());
-                return context.compareRows(a, b);
-              }
-
+            new WinAggAddContextImpl(builder7, agg.state, frame) {
               public Expression currentPosition() {
                 return jDecl.parameter;
               }
 
-              public Expression index() {
-                return i_;
-              }
-
-              public Expression startIndex() {
-                return startX;
-              }
-
-              public Expression endIndex() {
-                return endX;
-              }
-
-              public Expression hasRows() {
-                return hasRows;
-              }
-
-              public Expression getPartitionRowCount() {
-                return partitionRowCount;
-              }
-
-              @Override
               public List<RexNode> rexArguments() {
                 return rexArguments.apply(agg);
               }
@@ -2797,67 +2797,37 @@ public class JavaRules {
       }
     }
 
-    private void implementResult(List<AggImpState> aggs,
-        final ParameterExpression i_,
-        final Expression startX, final Expression endX,
-        final Expression hasRows,
-        final BlockBuilder builder5, final Expression partitionRowCount,
-        final Function<BlockBuilder, WinAggImplementor
-                    .WinAggFrameResultContext> resultContextBuilder,
-        final Function<AggImpState, List<RexNode>> rexArguments) {
+    private boolean implementResult(List<AggImpState> aggs,
+        final BlockBuilder builder,
+        final Function<BlockBuilder, WinAggFrameResultContext> frame,
+        final Function<AggImpState, List<RexNode>> rexArguments,
+        boolean cachedBlock) {
+      boolean nonEmpty = false;
       for (final AggImpState agg : aggs) {
+        boolean needCache = true;
+        if (agg.implementor instanceof WinAggImplementor) {
+          WinAggImplementor imp = (WinAggImplementor) agg.implementor;
+          needCache = imp.needCacheWhenFrameIntact();
+        }
+        if (needCache ^ cachedBlock) {
+          // Regular aggregates do not change when the windowing frame keeps
+          // the same. Ths
+          continue;
+        }
+        nonEmpty = true;
         Expression res = agg.implementor.implementResult(agg.context,
-            new WinAggResultContext(builder5, agg.state) {
+            new WinAggResultContextImpl(builder, agg.state, frame) {
               public List<RexNode> rexArguments() {
                 return rexArguments.apply(agg);
               }
-
-              public Expression computeIndex(Expression offset,
-                  WinAggImplementor.SeekType seekType) {
-                WinAggImplementor.WinAggFrameResultContext context =
-                    resultContextBuilder.apply(currentBlock());
-                return context.computeIndex(offset, seekType);
-              }
-
-              public RexToLixTranslator rowTranslator(Expression rowIndex) {
-                WinAggImplementor.WinAggFrameResultContext context =
-                    resultContextBuilder.apply(currentBlock());
-                return context.rowTranslator(rowIndex)
-                    .setNullable(currentNullables());
-              }
-
-              public Expression compareRows(Expression a, Expression b) {
-                WinAggImplementor.WinAggFrameResultContext context =
-                    resultContextBuilder.apply(currentBlock());
-                return context.compareRows(a, b);
-              }
-
-              public Expression index() {
-                return i_;
-              }
-
-              public Expression startIndex() {
-                return startX;
-              }
-
-              public Expression endIndex() {
-                return endX;
-              }
-
-              public Expression hasRows() {
-                return hasRows;
-              }
-
-              public Expression getPartitionRowCount() {
-                return partitionRowCount;
-              }
             });
         // Several count(a) and count(b) might share the result
-        Expression aggRes = builder5.append("a" + agg.aggIdx + "res",
+        Expression aggRes = builder.append("a" + agg.aggIdx + "res",
             RexToLixTranslator.convert(res, agg.result.getType()));
-        builder5.add(Expressions.statement(
+        builder.add(Expressions.statement(
             Expressions.assign(agg.result, aggRes)));
       }
+      return nonEmpty;
     }
 
     private Expression translateBound(RexToLixTranslator translator,

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/net/hydromatic/optiq/rules/java/NestedBlockBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/NestedBlockBuilder.java b/core/src/main/java/net/hydromatic/optiq/rules/java/NestedBlockBuilder.java
index dac5f59..7371e93 100644
--- a/core/src/main/java/net/hydromatic/optiq/rules/java/NestedBlockBuilder.java
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/NestedBlockBuilder.java
@@ -21,37 +21,21 @@ import net.hydromatic.linq4j.expressions.BlockBuilder;
 
 import org.eigenbase.rex.RexNode;
 
-import java.util.*;
+import java.util.Map;
 
 /**
  * Allows to build nested code blocks with tracking of current context and
  * the nullability of particular {@link org.eigenbase.rex.RexNode} expressions.
  * @see net.hydromatic.optiq.rules.java.StrictAggImplementor#implementAdd(AggContext, AggAddContext)
  */
-public class NestedBlockBuilder {
-  private final List<BlockBuilder> blocks = new ArrayList<BlockBuilder>();
-  private final List<Map<RexNode, Boolean>> nullables =
-      new ArrayList<Map<RexNode, Boolean>>();
-
-  /**
-   * Constructs nested block builders starting of a given code block.
-   * @param block root code block
-   */
-  public NestedBlockBuilder(BlockBuilder block) {
-    nestBlock(block);
-  }
-
+public interface NestedBlockBuilder {
   /**
    * Starts nested code block. The resulting block can optimize expressions
    * and reuse already calculated values from the parent blocks.
    * @return new code block that can optimize expressions and reuse already
    * calculated values from the parent blocks.
    */
-  public final BlockBuilder nestBlock() {
-    BlockBuilder block = new BlockBuilder(true, currentBlock());
-    nestBlock(block, Collections.<RexNode, Boolean>emptyMap());
-    return block;
-  }
+  BlockBuilder nestBlock();
 
   /**
    * Uses given block as the new code context.
@@ -59,9 +43,7 @@ public class NestedBlockBuilder {
    * @param block new code block
    * @see #exitBlock()
    */
-  public final void nestBlock(BlockBuilder block) {
-    nestBlock(block, Collections.<RexNode, Boolean>emptyMap());
-  }
+  void nestBlock(BlockBuilder block);
 
   /**
    * Uses given block as the new code context and the map of nullability.
@@ -70,48 +52,27 @@ public class NestedBlockBuilder {
    * @param nullables map of expression to its nullability state
    * @see #exitBlock()
    */
-  public final void nestBlock(BlockBuilder block,
-      Map<RexNode, Boolean> nullables) {
-    blocks.add(block);
-    Map<RexNode, Boolean> prev = this.nullables.isEmpty()
-        ? Collections.<RexNode, Boolean>emptyMap()
-        : this.nullables.get(this.nullables.size() - 1);
-    Map<RexNode, Boolean> next;
-    if (nullables == null || nullables.isEmpty()) {
-      next = prev;
-    } else {
-      next = new HashMap<RexNode, Boolean>(nullables);
-      next.putAll(prev);
-      next = Collections.unmodifiableMap(next);
-    }
-    this.nullables.add(next);
-  }
+  void nestBlock(BlockBuilder block,
+      Map<RexNode, Boolean> nullables);
 
   /**
    * Returns the current code block
    * @return current code block
    */
-  public final BlockBuilder currentBlock() {
-    return blocks.get(blocks.size() - 1);
-  }
+  BlockBuilder currentBlock();
 
   /**
    * Returns the current nullability state of rex nodes.
    * The resulting value is the summary of all the maps in the block hierarchy.
    * @return current nullability state of rex nodes
    */
-  public final Map<RexNode, Boolean> currentNullables() {
-    return nullables.get(nullables.size() - 1);
-  }
+  Map<RexNode, Boolean> currentNullables();
 
   /**
    * Leaves the current code block.
    * @see #nestBlock()
    */
-  public final void exitBlock() {
-    blocks.remove(blocks.size() - 1);
-    nullables.remove(nullables.size() - 1);
-  }
+  void exitBlock();
 }
 
 // End NestedBlockBuilder.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/net/hydromatic/optiq/rules/java/NestedBlockBuilderImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/NestedBlockBuilderImpl.java b/core/src/main/java/net/hydromatic/optiq/rules/java/NestedBlockBuilderImpl.java
new file mode 100644
index 0000000..0fee5ed
--- /dev/null
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/NestedBlockBuilderImpl.java
@@ -0,0 +1,117 @@
+/*
+// Licensed to Julian Hyde under one or more contributor license
+// agreements. See the NOTICE file distributed with this work for
+// additional information regarding copyright ownership.
+//
+// Julian Hyde licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+package net.hydromatic.optiq.rules.java;
+
+import net.hydromatic.linq4j.expressions.BlockBuilder;
+
+import org.eigenbase.rex.RexNode;
+
+import java.util.*;
+
+/**
+ * Allows to build nested code blocks with tracking of current context and
+ * the nullability of particular {@link org.eigenbase.rex.RexNode} expressions.
+ * @see net.hydromatic.optiq.rules.java.StrictAggImplementor#implementAdd(AggContext, AggAddContext)
+ */
+public class NestedBlockBuilderImpl implements NestedBlockBuilder {
+  private final List<BlockBuilder> blocks = new ArrayList<BlockBuilder>();
+  private final List<Map<RexNode, Boolean>> nullables =
+      new ArrayList<Map<RexNode, Boolean>>();
+
+  /**
+   * Constructs nested block builders starting of a given code block.
+   * @param block root code block
+   */
+  public NestedBlockBuilderImpl(BlockBuilder block) {
+    nestBlock(block);
+  }
+
+  /**
+   * Starts nested code block. The resulting block can optimize expressions
+   * and reuse already calculated values from the parent blocks.
+   * @return new code block that can optimize expressions and reuse already
+   * calculated values from the parent blocks.
+   */
+  public final BlockBuilder nestBlock() {
+    BlockBuilder block = new BlockBuilder(true, currentBlock());
+    nestBlock(block, Collections.<RexNode, Boolean>emptyMap());
+    return block;
+  }
+
+  /**
+   * Uses given block as the new code context.
+   * The current block will be restored after {@link #exitBlock()} call.
+   * @param block new code block
+   * @see #exitBlock()
+   */
+  public final void nestBlock(BlockBuilder block) {
+    nestBlock(block, Collections.<RexNode, Boolean>emptyMap());
+  }
+
+  /**
+   * Uses given block as the new code context and the map of nullability.
+   * The current block will be restored after {@link #exitBlock()} call.
+   * @param block new code block
+   * @param nullables map of expression to its nullability state
+   * @see #exitBlock()
+   */
+  public final void nestBlock(BlockBuilder block,
+      Map<RexNode, Boolean> nullables) {
+    blocks.add(block);
+    Map<RexNode, Boolean> prev = this.nullables.isEmpty()
+        ? Collections.<RexNode, Boolean>emptyMap()
+        : this.nullables.get(this.nullables.size() - 1);
+    Map<RexNode, Boolean> next;
+    if (nullables == null || nullables.isEmpty()) {
+      next = prev;
+    } else {
+      next = new HashMap<RexNode, Boolean>(nullables);
+      next.putAll(prev);
+      next = Collections.unmodifiableMap(next);
+    }
+    this.nullables.add(next);
+  }
+
+  /**
+   * Returns the current code block
+   * @return current code block
+   */
+  public final BlockBuilder currentBlock() {
+    return blocks.get(blocks.size() - 1);
+  }
+
+  /**
+   * Returns the current nullability state of rex nodes.
+   * The resulting value is the summary of all the maps in the block hierarchy.
+   * @return current nullability state of rex nodes
+   */
+  public final Map<RexNode, Boolean> currentNullables() {
+    return nullables.get(nullables.size() - 1);
+  }
+
+  /**
+   * Leaves the current code block.
+   * @see #nestBlock()
+   */
+  public final void exitBlock() {
+    blocks.remove(blocks.size() - 1);
+    nullables.remove(nullables.size() - 1);
+  }
+}
+
+// End NestedBlockBuilder.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/net/hydromatic/optiq/rules/java/RexImpTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/RexImpTable.java b/core/src/main/java/net/hydromatic/optiq/rules/java/RexImpTable.java
index e80eeb0..45fc0a0 100644
--- a/core/src/main/java/net/hydromatic/optiq/rules/java/RexImpTable.java
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/RexImpTable.java
@@ -194,6 +194,9 @@ public class RexImpTable {
     winAggMap.put(FIRST_VALUE,
         constructorSupplier(FirstValueImplementor.class));
     winAggMap.put(LAST_VALUE, constructorSupplier(LastValueImplementor.class));
+    winAggMap.put(LEAD, constructorSupplier(LeadImplementor.class));
+    winAggMap.put(LAG, constructorSupplier(LagImplementor.class));
+    winAggMap.put(NTILE, constructorSupplier(NtileImplementor.class));
     winAggMap.put(COUNT, constructorSupplier(CountWinImplementor.class));
   }
 
@@ -774,7 +777,7 @@ public class RexImpTable {
   }
 
   static class CountWinImplementor extends StrictWinAggImplementor {
-    boolean justPartitionRowCount;
+    boolean justFrameRowCount;
 
     @Override
     public List<Type> getNotNullState(WinAggContext info) {
@@ -786,7 +789,7 @@ public class RexImpTable {
         }
       }
       if (!hasNullable) {
-        justPartitionRowCount = true;
+        justFrameRowCount = true;
         return Collections.emptyList();
       }
       return super.getNotNullState(info);
@@ -794,7 +797,7 @@ public class RexImpTable {
 
     @Override
     public void implementNotNullAdd(WinAggContext info, WinAggAddContext add) {
-      if (justPartitionRowCount) {
+      if (justFrameRowCount) {
         return;
       }
       add.currentBlock().add(Expressions.statement(
@@ -804,8 +807,8 @@ public class RexImpTable {
     @Override
     protected Expression implementNotNullResult(WinAggContext info,
         WinAggResultContext result) {
-      if (justPartitionRowCount) {
-        return result.getPartitionRowCount();
+      if (justFrameRowCount) {
+        return result.getFrameRowCount();
       }
       return super.implementNotNullResult(info, result);
     }
@@ -1034,13 +1037,18 @@ public class RexImpTable {
       // no op
     }
 
+    public boolean needCacheWhenFrameIntact() {
+      return true;
+    }
+
     public Expression implementResult(AggContext info,
         AggResultContext result) {
       WinAggResultContext winResult = (WinAggResultContext) result;
+
       return Expressions.condition(winResult.hasRows(),
-          RexToLixTranslator.convert(
-              winResult.arguments(winResult.computeIndex(
-              Expressions.constant(0), seekType)).get(0), info.returnType()),
+          winResult.rowTranslator(winResult.computeIndex(
+              Expressions.constant(0), seekType)).translate(
+              winResult.rexArguments().get(0), info.returnType()),
           getDefaultValue(info.returnType()));
     }
   }
@@ -1057,6 +1065,126 @@ public class RexImpTable {
     }
   }
 
+  static class LeadLagImplementor implements WinAggImplementor {
+    private final boolean isLead;
+
+    protected LeadLagImplementor(boolean isLead) {
+      this.isLead = isLead;
+    }
+
+    public List<Type> getStateType(AggContext info) {
+      return Collections.emptyList();
+    }
+
+    public void implementReset(AggContext info, AggResetContext reset) {
+      // no op
+    }
+
+    public void implementAdd(AggContext info, AggAddContext add) {
+      // no op
+    }
+
+    public boolean needCacheWhenFrameIntact() {
+      return false;
+    }
+
+    public Expression implementResult(AggContext info,
+        AggResultContext result) {
+      WinAggResultContext winResult = (WinAggResultContext) result;
+
+      List<RexNode> rexArgs = winResult.rexArguments();
+
+      ParameterExpression res = Expressions.parameter(0, info.returnType(),
+          result.currentBlock().newName(isLead ? "lead" : "lag"));
+
+      Expression offset;
+      RexToLixTranslator currentRowTranslator =
+          winResult.rowTranslator(winResult.computeIndex(
+              Expressions.constant(0), SeekType.SET));
+      if (rexArgs.size() >= 2) {
+        // lead(x, offset) or lead(x, offset, default)
+        offset = currentRowTranslator.translate(
+            rexArgs.get(1), int.class);
+      } else {
+        offset = Expressions.constant(1);
+      }
+      if (!isLead) {
+        offset = Expressions.negate(offset);
+      }
+      Expression dstIndex = winResult.computeIndex(offset, SeekType.SET);
+
+      Expression rowInRange = winResult.rowInPartition(dstIndex);
+
+      BlockBuilder thenBlock = result.nestBlock();
+      Expression lagResult = winResult.rowTranslator(dstIndex).translate(
+          rexArgs.get(0), res.type);
+      thenBlock.add(Expressions.statement(Expressions.assign(res, lagResult)));
+      result.exitBlock();
+      BlockStatement thenBranch = thenBlock.toBlock();
+
+      Expression defaultValue = rexArgs.size() == 3
+          ? currentRowTranslator.translate(rexArgs.get(2), res.type)
+          : getDefaultValue(res.type);
+
+      result.currentBlock().add(Expressions.declare(0, res, null));
+      result.currentBlock().add(Expressions.ifThenElse(rowInRange, thenBranch,
+          Expressions.statement(Expressions.assign(res, defaultValue))));
+      return res;
+    }
+  }
+
+  public static class LeadImplementor extends LeadLagImplementor {
+    protected LeadImplementor() {
+      super(true);
+    }
+  }
+
+  public static class LagImplementor extends LeadLagImplementor {
+    protected LagImplementor() {
+      super(false);
+    }
+  }
+
+  static class NtileImplementor implements WinAggImplementor {
+    public List<Type> getStateType(AggContext info) {
+      return Collections.emptyList();
+    }
+
+    public void implementReset(AggContext info, AggResetContext reset) {
+      // no op
+    }
+
+    public void implementAdd(AggContext info, AggAddContext add) {
+      // no op
+    }
+
+    public boolean needCacheWhenFrameIntact() {
+      return false;
+    }
+
+    public Expression implementResult(AggContext info,
+        AggResultContext result) {
+      WinAggResultContext winResult = (WinAggResultContext) result;
+
+      List<RexNode> rexArgs = winResult.rexArguments();
+
+      Expression tiles =
+          winResult.rowTranslator(winResult.index()).translate(
+              rexArgs.get(0), int.class);
+
+      Expression ntile =
+          Expressions.add(Expressions.constant(1),
+              Expressions.divide(
+                  Expressions.multiply(
+                      tiles,
+                      Expressions.subtract(
+                          winResult.index(), winResult.startIndex())),
+                  winResult.getPartitionRowCount()));
+
+      return ntile;
+    }
+  }
+
   static class RowNumberImplementor extends StrictWinAggImplementor {
     @Override
     public List<Type> getNotNullState(WinAggContext info) {

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/net/hydromatic/optiq/rules/java/RexToLixTranslator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/RexToLixTranslator.java b/core/src/main/java/net/hydromatic/optiq/rules/java/RexToLixTranslator.java
index d15e140..34cf83e 100644
--- a/core/src/main/java/net/hydromatic/optiq/rules/java/RexToLixTranslator.java
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/RexToLixTranslator.java
@@ -328,6 +328,12 @@ public class RexToLixTranslator {
       Expression x = inputGetter.field(list, index, storageType);
 
       Expression input = list.append("inp" + index + "_", x); // safe to share
+      if (nullAs == RexImpTable.NullAs.NOT_POSSIBLE
+          && input.type.equals(storageType)) {
+        // When we asked for not null input that would be stored as box, avoid
+        // unboxing via nullAs.handle below.
+        return input;
+      }
       Expression nullHandled = nullAs.handle(input);
 
       // If we get ConstantExpression, just return it (i.e. primitive false)
@@ -525,7 +531,7 @@ public class RexToLixTranslator {
    *
    * @return translated expressions
    */
-  List<Expression> translateList(List<? extends RexNode> operandList) {
+  public List<Expression> translateList(List<? extends RexNode> operandList) {
     return translateList(operandList, null);
   }
 
@@ -543,7 +549,7 @@ public class RexToLixTranslator {
    *
    * @return translated expressions
    */
-  List<Expression> translateList(List<? extends RexNode> operandList,
+  public List<Expression> translateList(List<? extends RexNode> operandList,
       List<? extends Type> storageTypes) {
     final List<Expression> list = new ArrayList<Expression>(operandList.size());
 

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/net/hydromatic/optiq/rules/java/StrictAggImplementor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/StrictAggImplementor.java b/core/src/main/java/net/hydromatic/optiq/rules/java/StrictAggImplementor.java
index c973e56..d1e96ae 100644
--- a/core/src/main/java/net/hydromatic/optiq/rules/java/StrictAggImplementor.java
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/StrictAggImplementor.java
@@ -64,9 +64,7 @@ public abstract class StrictAggImplementor implements AggImplementor {
         break;
       }
     }
-    trackNullsPerRow =
-        !(info instanceof WinAggImplementor.WinAggContext)
-            || hasNullableArgs;
+    trackNullsPerRow = !(info instanceof WinAggContext) || hasNullableArgs;
 
     List<Type> res = new ArrayList<Type>(subState.size() + 1);
     res.addAll(subState);

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/net/hydromatic/optiq/rules/java/StrictWinAggImplementor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/StrictWinAggImplementor.java b/core/src/main/java/net/hydromatic/optiq/rules/java/StrictWinAggImplementor.java
index 805b557..56257c6 100644
--- a/core/src/main/java/net/hydromatic/optiq/rules/java/StrictWinAggImplementor.java
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/StrictWinAggImplementor.java
@@ -78,4 +78,8 @@ public abstract class StrictWinAggImplementor extends StrictAggImplementor
     return implementNotNullResult((WinAggContext) info,
         (WinAggResultContext) result);
   }
+
+  public boolean needCacheWhenFrameIntact() {
+    return true;
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggAddContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggAddContext.java b/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggAddContext.java
index 41cf6c6..e00587f 100644
--- a/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggAddContext.java
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggAddContext.java
@@ -17,51 +17,27 @@
 */
 package net.hydromatic.optiq.rules.java;
 
-import net.hydromatic.linq4j.expressions.BlockBuilder;
 import net.hydromatic.linq4j.expressions.Expression;
-import net.hydromatic.linq4j.expressions.Expressions;
-
-import java.util.List;
 
 /**
  * Information for a call to {@link AggImplementor#implementAdd(AggContext, AggAddContext)}.
  * {@link WinAggAddContext} is used when implementing windowed aggregate.
- * Note: logically, {@link WinAggAddContext} should extend {@link WinAggResultContext},
- * however this would prohibit usage of the same {@link AggImplementor} for both
- * regular aggregate and window aggregate.
  * Typically, the aggregation implementation will use {@link #arguments()}
  * or {@link #rexArguments()} to update aggregate value.
- * @see net.hydromatic.optiq.rules.java.AggAddContext
+ * @see AggAddContext
  */
-public abstract class WinAggAddContext
-    extends AggAddContext
-    implements WinAggImplementor.WinAggFrameContext,
-      WinAggImplementor.WinAggFrameResultContext {
-  public WinAggAddContext(BlockBuilder block, List<Expression> accumulator) {
-    super(block, accumulator);
-  }
-
+public interface WinAggAddContext extends AggAddContext, WinAggResultContext {
   /**
    * Returns current position inside for-loop of window aggregate.
-   * Note, the position is relative to {@link WinAggImplementor.WinAggFrameContext#startIndex()}.
+   * Note, the position is relative to {@link WinAggFrameContext#startIndex()}.
    * This is NOT current row as in "rows between current row".
    * If you need to know the relative index of the current row in the partition,
-   * use {@link WinAggImplementor.WinAggFrameContext#index()}.
+   * use {@link WinAggFrameContext#index()}.
    * @return current position inside for-loop of window aggregate.
-   * @see WinAggImplementor.WinAggFrameContext#index()
-   * @see WinAggImplementor.WinAggFrameContext#startIndex()
+   * @see WinAggFrameContext#index()
+   * @see WinAggFrameContext#startIndex()
    */
-  public abstract Expression currentPosition();
-
-  public List<Expression> arguments(Expression rowIndex) {
-    return rowTranslator(rowIndex).translateList(rexArguments());
-  }
-
-  @Override
-  public final RexToLixTranslator rowTranslator() {
-    return rowTranslator(computeIndex(Expressions.constant(0),
-        WinAggImplementor.SeekType.AGG_INDEX));
-  }
+  Expression currentPosition();
 }
 
 // End WinAggAddContext.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggContext.java b/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggContext.java
new file mode 100644
index 0000000..281aade
--- /dev/null
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggContext.java
@@ -0,0 +1,27 @@
+/*
+// Licensed to Julian Hyde under one or more contributor license
+// agreements. See the NOTICE file distributed with this work for
+// additional information regarding copyright ownership.
+//
+// Julian Hyde licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+package net.hydromatic.optiq.rules.java;
+
+/**
+ * Marker interface to allow {@link net.hydromatic.optiq.rules.java.AggImplementor} to tell if it is used in
+ * regular or windowed context.
+ */
+public interface WinAggContext extends AggContext {
+}
+
+// End WinAggContext.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggFrameContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggFrameContext.java b/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggFrameContext.java
new file mode 100644
index 0000000..c5db249
--- /dev/null
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggFrameContext.java
@@ -0,0 +1,73 @@
+/*
+// Licensed to Julian Hyde under one or more contributor license
+// agreements. See the NOTICE file distributed with this work for
+// additional information regarding copyright ownership.
+//
+// Julian Hyde licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+package net.hydromatic.optiq.rules.java;
+
+import net.hydromatic.linq4j.expressions.Expression;
+
+/**
+ * Provides information on the current window.
+ * All the indexes are ready to be used in {@link WinAggFrameResultContext#arguments(net.hydromatic.linq4j.expressions.Expression)},
+ * {@link WinAggFrameResultContext#rowTranslator(net.hydromatic.linq4j.expressions.Expression)} and similar methods.
+ */
+public interface WinAggFrameContext {
+  /**
+   * Returns the index of the current row in the partition.
+   * In other words, it is close to ~ROWS BETWEEN CURRENT ROW.
+   * Note to use {@link #startIndex()} when you need zero-based row position.
+   * @return the index of the very first row in partition
+   */
+  Expression index();
+
+  /**
+   * Returns the index of the very first row in partition.
+   * @return index of the very first row in partition
+   */
+  Expression startIndex();
+
+  /**
+   * Returns the index of the very last row in partition.
+   * @return index of the very last row in partition
+   */
+  Expression endIndex();
+
+  /**
+   * Returns the boolean expression that tells if the partition has rows.
+   * The partition might lack rows in cases like ROWS BETWEEN 1000 PRECEDING
+   * AND 900 PRECEDING.
+   * @return boolean expression that tells if the partition has rows
+   */
+  Expression hasRows();
+
+  /**
+   * Returns the number of rows in the current frame (subject to framing
+   * clause).
+   * @return number of rows in the current partition or 0 if the partition
+   *   is empty
+   */
+  Expression getFrameRowCount();
+
+  /**
+   * Returns the number of rows in the current partition (as determined by
+   * PARTITION BY clause).
+   * @return number of rows in the current partition or 0 if the partition
+   *   is empty
+   */
+  Expression getPartitionRowCount();
+}
+
+// End WinAggFrameContext.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggFrameResultContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggFrameResultContext.java b/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggFrameResultContext.java
new file mode 100644
index 0000000..d648fb4
--- /dev/null
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggFrameResultContext.java
@@ -0,0 +1,69 @@
+/*
+// Licensed to Julian Hyde under one or more contributor license
+// agreements. See the NOTICE file distributed with this work for
+// additional information regarding copyright ownership.
+//
+// Julian Hyde licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+package net.hydromatic.optiq.rules.java;
+
+import net.hydromatic.linq4j.expressions.Expression;
+
+/**
+ * Provides information on the current window when computing the result of
+ * the aggregation.
+ */
+public interface WinAggFrameResultContext extends WinAggFrameContext {
+  /**
+   * Converts absolute index position of the given relative position.
+   * @param offset offset of the requested row
+   * @param seekType the type of offset (start of window, end of window, etc)
+   * @return absolute position of the requested row
+   */
+  Expression computeIndex(Expression offset,
+      WinAggImplementor.SeekType seekType);
+
+  /**
+   * Returns boolean the expression that checks if the given index is in
+   * the frame bounds.
+   * @param rowIndex index if the row to check
+   * @return expression that validates frame bounds for the given index
+   */
+  Expression rowInFrame(Expression rowIndex);
+
+  /**
+   * Returns boolean the expression that checks if the given index is in
+   * the partition bounds.
+   * @param rowIndex index if the row to check
+   * @return expression that validates partition bounds for the given index
+   */
+  Expression rowInPartition(Expression rowIndex);
+
+  /**
+   * Returns row translator for given absolute row position.
+   * @param rowIndex absolute index of the row.
+   * @return translator for the requested row
+   */
+  RexToLixTranslator rowTranslator(Expression rowIndex);
+
+  /**
+   * Compares two rows given by absolute positions according to the order
+   * collation of the current window.
+   * @param a absolute index of the first row
+   * @param b absolute index of the second row
+   * @return result of comparison as as in {@link Comparable#compareTo}
+   */
+  Expression compareRows(Expression a, Expression b);
+}
+
+// End WinAggFrameResultContext.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggImplementor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggImplementor.java b/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggImplementor.java
index 5190a30..34f8389 100644
--- a/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggImplementor.java
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggImplementor.java
@@ -17,18 +17,14 @@
 */
 package net.hydromatic.optiq.rules.java;
 
-import net.hydromatic.linq4j.expressions.Expression;
-
-import org.eigenbase.rex.RexNode;
-
-import java.util.List;
-
 /**
  * Implements a windowed aggregate function by generating expressions to
  * initialize, add to, and get a result from, an accumulator.
  * Windowed aggregate is more powerful than regular aggregate since it can
  * access rows in the current partition by row indices.
  * Regular aggregate can be used to implement windowed aggregate.
+ * <p>This interface does not define new methods: window-specific
+ * sub-interfaces are passed when implementing window aggregate.
  *
  * @see net.hydromatic.optiq.rules.java.StrictWinAggImplementor
  * @see net.hydromatic.optiq.rules.java.RexImpTable.FirstLastValueImplementor
@@ -64,103 +60,7 @@ public interface WinAggImplementor extends AggImplementor {
     END
   }
 
-  /**
-   * Marker interface to allow {@link AggImplementor} to tell if it is used in
-   * regular or windowed context.
-   */
-  public interface WinAggContext extends AggContext {
-  }
-
-  /**
-   * Provides information on the current window.
-   * All the indexes are ready to be used in {@link WinAggFrameResultContext#arguments(Expression)},
-   * {@link WinAggFrameResultContext#rowTranslator(Expression)} and similar methods.
-   */
-  public interface WinAggFrameContext {
-    /**
-     * Returns the index of the current row in the partition.
-     * In other words, it is close to ~ROWS BETWEEN CURRENT ROW.
-     * Note to use {@link #startIndex()} when you need zero-based row position.
-     * @return the index of the very first row in partition
-     */
-    Expression index();
-
-    /**
-     * Returns the index of the very first row in partition.
-     * @return index of the very first row in partition
-     */
-    Expression startIndex();
-
-    /**
-     * Returns the index of the very last row in partition.
-     * @return index of the very last row in partition
-     */
-    Expression endIndex();
-
-    /**
-     * Returns the boolean expression that tells if the partition has rows.
-     * The partition might lack rows in cases like ROWS BETWEEN 1000 PRECEDING
-     * AND 900 PRECEDING.
-     * @return boolean expression that tells if the partition has rows
-     */
-    Expression hasRows();
-
-    /**
-     * Returns the number of rows in the current partition.
-     * @return number of rows in the current partition or 0 if the partition
-     *   is empty
-     */
-    Expression getPartitionRowCount();
-  }
-
-  /**
-   * Provides information on the current window when computing the result of
-   * the aggregation.
-   */
-  public interface WinAggFrameResultContext {
-    /**
-     * Returns {@link RexNode} representation of arguments.
-     * This can be useful for manual translation of required arguments with
-     * different {@link net.hydromatic.optiq.rules.java.NullPolicy}.
-     * @return {@link RexNode} representation of arguments
-     */
-    List<RexNode> rexArguments();
-
-    /**
-     * Returns Linq4j form of arguments.
-     * The resulting value is equivalent to
-     * {@code rowTranslator().translateList(rexArguments())}.
-     * This is handy if you need just operate on argument.
-     * @param rowIndex index of the requested row. The index must be in range
-     *                 of partition's startIndex and endIndex.
-     * @return Linq4j form of arguments of the particular row
-     */
-    List<Expression> arguments(Expression rowIndex);
-
-    /**
-     * Converts absolute index position of the given relative position.
-     * @param offset offset of the requested row
-     * @param seekType the type of offset (start of window, end of window, etc)
-     * @return absolute position of the requested row
-     */
-    Expression computeIndex(Expression offset, SeekType seekType);
-
-    /**
-     * Returns row translator for given absolute row position.
-     * @param rowIndex absolute index of the row.
-     * @return translator for the requested row
-     */
-    RexToLixTranslator rowTranslator(Expression rowIndex);
-
-    /**
-     * Compares two rows given by absolute positions according to the order
-     * collation of the current window.
-     * @param a absolute index of the first row
-     * @param b absolute index of the second row
-     * @return result of comparison as as in {@link Comparable#compareTo}
-     */
-    Expression compareRows(Expression a, Expression b);
-  }
+  boolean needCacheWhenFrameIntact();
 }
 
 // End WinAggImplementor.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggResetContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggResetContext.java b/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggResetContext.java
index bfbe5ab..0baff8b 100644
--- a/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggResetContext.java
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggResetContext.java
@@ -17,11 +17,6 @@
 */
 package net.hydromatic.optiq.rules.java;
 
-import net.hydromatic.linq4j.expressions.BlockBuilder;
-import net.hydromatic.linq4j.expressions.Expression;
-
-import java.util.List;
-
 /**
  * Information for a call to {@link AggImplementor#implementReset(AggContext, AggResetContext)}.
  * {@link AggResetContext} provides access to the accumulator variables
@@ -31,57 +26,8 @@ import java.util.List;
  * In other words, the implementation should treat indices and partition row
  * count as a hint to pre-size the collections.
  */
-public class WinAggResetContext extends AggResetContext
-    implements WinAggImplementor.WinAggFrameContext {
-  private final Expression index;
-  private final Expression startIndex;
-  private final Expression endIndex;
-  private final Expression partitionRowCount;
-  private final Expression hasRows;
-
-  /**
-   * Creates window aggregate reset context.
-   * @param block code block that will contain the added initialization
-   * @param accumulator accumulator variables that store the intermediate
-   *                    aggregate state
-   * @param index index of the current row in the partition
-   * @param startIndex index of the very first row in partition
-   * @param endIndex index of the very last row in partition
-   * @param hasRows boolean expression that tells if the partition has rows
-   * @param partitionRowCount number of rows in the current partition or
-   *                          0 if the partition is empty
-   *
-   */
-  public WinAggResetContext(BlockBuilder block,
-      List<Expression> accumulator, Expression index,
-      Expression startIndex, Expression endIndex,
-      Expression hasRows, Expression partitionRowCount) {
-    super(block, accumulator);
-    this.index = index;
-    this.startIndex = startIndex;
-    this.endIndex = endIndex;
-    this.partitionRowCount = partitionRowCount;
-    this.hasRows = hasRows;
-  }
-
-  public Expression index() {
-    return index;
-  }
-
-  public Expression startIndex() {
-    return startIndex;
-  }
-
-  public Expression endIndex() {
-    return endIndex;
-  }
-
-  public Expression hasRows() {
-    return hasRows;
-  }
-
-  public Expression getPartitionRowCount() {
-    return partitionRowCount;
-  }
+public interface WinAggResetContext
+    extends AggResetContext, WinAggFrameContext {
 }
 
+// End WinAggResetContext.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggResultContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggResultContext.java b/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggResultContext.java
index 9aa5a68..7d4131f 100644
--- a/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggResultContext.java
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/WinAggResultContext.java
@@ -17,39 +17,38 @@
 */
 package net.hydromatic.optiq.rules.java;
 
-import net.hydromatic.linq4j.expressions.BlockBuilder;
 import net.hydromatic.linq4j.expressions.Expression;
 
+import org.eigenbase.rex.RexNode;
+
 import java.util.List;
 
 /**
  * Information for a call to {@link AggImplementor#implementResult(AggContext, AggResultContext)}
  * Typically, the aggregation implementation will convert {@link #accumulator()}
  * to the resulting value of the aggregation.
- * The implementation MUST NOT destroy the cotents of {@link #accumulator()}.
- * Note: logically, {@link WinAggResultContext} should extend {@link WinAggResetContext},
- * however this would prohibit usage of the same {@link AggImplementor} for both
- * regular aggregate and window aggregate.
+ * The implementation MUST NOT destroy the contents of {@link #accumulator()}.
  */
-public abstract class WinAggResultContext
-    extends AggResultContext
-    implements WinAggImplementor.WinAggFrameContext,
-      WinAggImplementor.WinAggFrameResultContext {
-
+public interface WinAggResultContext extends AggResultContext,
+    WinAggFrameResultContext {
   /**
-   * Creates window aggregate result context.
-   * @param block code block that will contain the added initialization
-   * @param accumulator accumulator variables that store the intermediate
-   *                    aggregate state
+   * Returns {@link org.eigenbase.rex.RexNode} representation of arguments.
+   * This can be useful for manual translation of required arguments with
+   * different {@link NullPolicy}.
+   * @return {@link org.eigenbase.rex.RexNode} representation of arguments
    */
-  public WinAggResultContext(BlockBuilder block,
-      List<Expression> accumulator) {
-    super(block, accumulator);
-  }
+  List<RexNode> rexArguments();
 
-  public final List<Expression> arguments(Expression rowIndex) {
-    return rowTranslator(rowIndex).translateList(rexArguments());
-  }
+  /**
+   * Returns Linq4j form of arguments.
+   * The resulting value is equivalent to
+   * {@code rowTranslator().translateList(rexArguments())}.
+   * This is handy if you need just operate on argument.
+   * @param rowIndex index of the requested row. The index must be in range
+   *                 of partition's startIndex and endIndex.
+   * @return Linq4j form of arguments of the particular row
+   */
+  List<Expression> arguments(Expression rowIndex);
 }
 
 // End WinAggResultContext.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/net/hydromatic/optiq/rules/java/impl/AggAddContextImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/impl/AggAddContextImpl.java b/core/src/main/java/net/hydromatic/optiq/rules/java/impl/AggAddContextImpl.java
new file mode 100644
index 0000000..a88ce18
--- /dev/null
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/impl/AggAddContextImpl.java
@@ -0,0 +1,39 @@
+/*
+// Licensed to Julian Hyde under one or more contributor license
+// agreements. See the NOTICE file distributed with this work for
+// additional information regarding copyright ownership.
+//
+// Julian Hyde licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+package net.hydromatic.optiq.rules.java.impl;
+
+import net.hydromatic.linq4j.expressions.BlockBuilder;
+import net.hydromatic.linq4j.expressions.Expression;
+
+import net.hydromatic.optiq.rules.java.AggAddContext;
+
+import java.util.List;
+
+/**
+ * Implementation of {@link net.hydromatic.optiq.rules.java.AggAddContext}.
+ */
+public abstract class AggAddContextImpl extends AggResultContextImpl
+    implements AggAddContext {
+  public AggAddContextImpl(BlockBuilder block, List<Expression> accumulator) {
+    super(block, accumulator);
+  }
+
+  public final List<Expression> arguments() {
+    return rowTranslator().translateList(rexArguments());
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/net/hydromatic/optiq/rules/java/impl/AggResetContextImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/impl/AggResetContextImpl.java b/core/src/main/java/net/hydromatic/optiq/rules/java/impl/AggResetContextImpl.java
new file mode 100644
index 0000000..93d518f
--- /dev/null
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/impl/AggResetContextImpl.java
@@ -0,0 +1,51 @@
+/*
+// Licensed to Julian Hyde under one or more contributor license
+// agreements. See the NOTICE file distributed with this work for
+// additional information regarding copyright ownership.
+//
+// Julian Hyde licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+package net.hydromatic.optiq.rules.java.impl;
+
+import net.hydromatic.linq4j.expressions.BlockBuilder;
+import net.hydromatic.linq4j.expressions.Expression;
+
+import net.hydromatic.optiq.rules.java.AggResetContext;
+import net.hydromatic.optiq.rules.java.NestedBlockBuilderImpl;
+
+import java.util.List;
+
+/**
+ * Implementation of {@link net.hydromatic.optiq.rules.java.AggResetContext}
+ */
+public class AggResetContextImpl extends NestedBlockBuilderImpl
+    implements AggResetContext {
+  private final List<Expression> accumulator;
+
+  /**
+   * Creates aggregate reset context
+   * @param block code block that will contain the added initialization
+   * @param accumulator accumulator variables that store the intermediate
+   *                    aggregate state
+   */
+  public AggResetContextImpl(BlockBuilder block, List<Expression> accumulator) {
+    super(block);
+    this.accumulator = accumulator;
+  }
+
+  public List<Expression> accumulator() {
+    return accumulator;
+  }
+}
+
+// End AggResetContext.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/net/hydromatic/optiq/rules/java/impl/AggResultContextImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/impl/AggResultContextImpl.java b/core/src/main/java/net/hydromatic/optiq/rules/java/impl/AggResultContextImpl.java
new file mode 100644
index 0000000..43d9190
--- /dev/null
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/impl/AggResultContextImpl.java
@@ -0,0 +1,44 @@
+/*
+// Licensed to Julian Hyde under one or more contributor license
+// agreements. See the NOTICE file distributed with this work for
+// additional information regarding copyright ownership.
+//
+// Julian Hyde licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+package net.hydromatic.optiq.rules.java.impl;
+
+import net.hydromatic.linq4j.expressions.BlockBuilder;
+import net.hydromatic.linq4j.expressions.Expression;
+
+import net.hydromatic.optiq.rules.java.AggResultContext;
+
+import java.util.List;
+
+/**
+ * Implementation of {@link net.hydromatic.optiq.rules.java.AggResultContext}
+ */
+public class AggResultContextImpl extends AggResetContextImpl
+    implements AggResultContext {
+  /**
+   * Creates aggregate result context
+   * @param block code block that will contain the result calculation statements
+   * @param accumulator accumulator variables that store the intermediate
+   *                    aggregate state
+   */
+  public AggResultContextImpl(BlockBuilder block,
+      List<Expression> accumulator) {
+    super(block, accumulator);
+  }
+}
+
+// End AggResultContext.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/net/hydromatic/optiq/rules/java/impl/WinAggAddContextImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/impl/WinAggAddContextImpl.java b/core/src/main/java/net/hydromatic/optiq/rules/java/impl/WinAggAddContextImpl.java
new file mode 100644
index 0000000..1533415
--- /dev/null
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/impl/WinAggAddContextImpl.java
@@ -0,0 +1,53 @@
+/*
+// Licensed to Julian Hyde under one or more contributor license
+// agreements. See the NOTICE file distributed with this work for
+// additional information regarding copyright ownership.
+//
+// Julian Hyde licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+package net.hydromatic.optiq.rules.java.impl;
+
+import net.hydromatic.linq4j.expressions.BlockBuilder;
+import net.hydromatic.linq4j.expressions.Expression;
+import net.hydromatic.linq4j.expressions.Expressions;
+
+import net.hydromatic.optiq.rules.java.RexToLixTranslator;
+import net.hydromatic.optiq.rules.java.WinAggAddContext;
+import net.hydromatic.optiq.rules.java.WinAggFrameResultContext;
+import net.hydromatic.optiq.rules.java.WinAggImplementor;
+
+import com.google.common.base.Function;
+
+import java.util.List;
+
+/**
+ * Implementation of {@link net.hydromatic.optiq.rules.java.WinAggAddContext}.
+ */
+public abstract class WinAggAddContextImpl extends WinAggResultContextImpl
+    implements WinAggAddContext {
+  public WinAggAddContextImpl(BlockBuilder block, List<Expression> accumulator,
+      Function<BlockBuilder, WinAggFrameResultContext> frame) {
+    super(block, accumulator, frame);
+  }
+
+  public final RexToLixTranslator rowTranslator() {
+    return rowTranslator(computeIndex(Expressions.constant(0),
+        WinAggImplementor.SeekType.AGG_INDEX));
+  }
+
+  public final List<Expression> arguments() {
+    return rowTranslator().translateList(rexArguments());
+  }
+}
+
+// End WinAggAddContext.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/net/hydromatic/optiq/rules/java/impl/WinAggResetContextImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/impl/WinAggResetContextImpl.java b/core/src/main/java/net/hydromatic/optiq/rules/java/impl/WinAggResetContextImpl.java
new file mode 100644
index 0000000..15ed040
--- /dev/null
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/impl/WinAggResetContextImpl.java
@@ -0,0 +1,89 @@
+/*
+// Licensed to Julian Hyde under one or more contributor license
+// agreements. See the NOTICE file distributed with this work for
+// additional information regarding copyright ownership.
+//
+// Julian Hyde licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+package net.hydromatic.optiq.rules.java.impl;
+
+import net.hydromatic.linq4j.expressions.BlockBuilder;
+import net.hydromatic.linq4j.expressions.Expression;
+
+import net.hydromatic.optiq.rules.java.WinAggResetContext;
+
+import java.util.List;
+
+/**
+ * Implementation of {@link net.hydromatic.optiq.rules.java.WinAggResetContext}.
+ */
+public class WinAggResetContextImpl extends AggResetContextImpl
+    implements WinAggResetContext {
+  private final Expression index;
+  private final Expression startIndex;
+  private final Expression endIndex;
+  private final Expression frameRowCount;
+  private final Expression partitionRowCount;
+  private final Expression hasRows;
+
+  /**
+   * Creates window aggregate reset context.
+   * @param block code block that will contain the added initialization
+   * @param accumulator accumulator variables that store the intermediate
+   *                    aggregate state
+   * @param index index of the current row in the partition
+   * @param startIndex index of the very first row in partition
+   * @param endIndex index of the very last row in partition
+   * @param hasRows boolean expression that tells if the partition has rows
+   * @param frameRowCount number of rows in the current frame
+   * @param partitionRowCount number of rows in the current partition
+   */
+  public WinAggResetContextImpl(BlockBuilder block,
+      List<Expression> accumulator, Expression index,
+      Expression startIndex, Expression endIndex,
+      Expression hasRows,
+      Expression frameRowCount, Expression partitionRowCount) {
+    super(block, accumulator);
+    this.index = index;
+    this.startIndex = startIndex;
+    this.endIndex = endIndex;
+    this.frameRowCount = frameRowCount;
+    this.partitionRowCount = partitionRowCount;
+    this.hasRows = hasRows;
+  }
+
+  public Expression index() {
+    return index;
+  }
+
+  public Expression startIndex() {
+    return startIndex;
+  }
+
+  public Expression endIndex() {
+    return endIndex;
+  }
+
+  public Expression hasRows() {
+    return hasRows;
+  }
+
+  public Expression getFrameRowCount() {
+    return frameRowCount;
+  }
+
+  public Expression getPartitionRowCount() {
+    return partitionRowCount;
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/net/hydromatic/optiq/rules/java/impl/WinAggResultContextImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/impl/WinAggResultContextImpl.java b/core/src/main/java/net/hydromatic/optiq/rules/java/impl/WinAggResultContextImpl.java
new file mode 100644
index 0000000..f29cbd4
--- /dev/null
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/impl/WinAggResultContextImpl.java
@@ -0,0 +1,108 @@
+/*
+// Licensed to Julian Hyde under one or more contributor license
+// agreements. See the NOTICE file distributed with this work for
+// additional information regarding copyright ownership.
+//
+// Julian Hyde licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+package net.hydromatic.optiq.rules.java.impl;
+
+import net.hydromatic.linq4j.expressions.BlockBuilder;
+import net.hydromatic.linq4j.expressions.Expression;
+
+import net.hydromatic.optiq.rules.java.RexToLixTranslator;
+import net.hydromatic.optiq.rules.java.WinAggFrameResultContext;
+import net.hydromatic.optiq.rules.java.WinAggImplementor;
+import net.hydromatic.optiq.rules.java.WinAggResultContext;
+
+import com.google.common.base.Function;
+
+import java.util.List;
+
+/**
+ * Implementation of {@link net.hydromatic.optiq.rules.java.WinAggResultContext}.
+ */
+public abstract class WinAggResultContextImpl extends AggResultContextImpl
+    implements WinAggResultContext {
+
+  private final Function<BlockBuilder, WinAggFrameResultContext> frame;
+
+  /**
+   * Creates window aggregate result context.
+   * @param block code block that will contain the added initialization
+   * @param accumulator accumulator variables that store the intermediate
+   *                    aggregate state
+   */
+  public WinAggResultContextImpl(BlockBuilder block,
+      List<Expression> accumulator,
+      Function<BlockBuilder, WinAggFrameResultContext> frameContextBuilder) {
+    super(block, accumulator);
+    this.frame = frameContextBuilder;
+  }
+
+  private WinAggFrameResultContext getFrame() {
+    return frame.apply(currentBlock());
+  }
+
+  public final List<Expression> arguments(Expression rowIndex) {
+    return rowTranslator(rowIndex).translateList(rexArguments());
+  }
+
+  public Expression computeIndex(Expression offset,
+      WinAggImplementor.SeekType seekType) {
+    return getFrame().computeIndex(offset, seekType);
+  }
+
+  public Expression rowInFrame(Expression rowIndex) {
+    return getFrame().rowInFrame(rowIndex);
+  }
+
+  public Expression rowInPartition(Expression rowIndex) {
+    return getFrame().rowInPartition(rowIndex);
+  }
+
+  public RexToLixTranslator rowTranslator(Expression rowIndex) {
+    return getFrame().rowTranslator(rowIndex)
+        .setNullable(currentNullables());
+  }
+
+  public Expression compareRows(Expression a, Expression b) {
+    return getFrame().compareRows(a, b);
+  }
+
+  public Expression index() {
+    return getFrame().index();
+  }
+
+  public Expression startIndex() {
+    return getFrame().startIndex();
+  }
+
+  public Expression endIndex() {
+    return getFrame().endIndex();
+  }
+
+  public Expression hasRows() {
+    return getFrame().hasRows();
+  }
+
+  public Expression getFrameRowCount() {
+    return getFrame().getFrameRowCount();
+  }
+
+  public Expression getPartitionRowCount() {
+    return getFrame().getPartitionRowCount();
+  }
+}
+
+// End WinAggResultContext.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/net/hydromatic/optiq/rules/java/impl/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/impl/package-info.java b/core/src/main/java/net/hydromatic/optiq/rules/java/impl/package-info.java
new file mode 100644
index 0000000..1c019c8
--- /dev/null
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/impl/package-info.java
@@ -0,0 +1,24 @@
+/*
+// Licensed to Julian Hyde under one or more contributor license
+// agreements. See the NOTICE file distributed with this work for
+// additional information regarding copyright ownership.
+//
+// Julian Hyde licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+/**
+ * Optiq-specific classes for implementation of regular and window aggregates.
+ */
+package net.hydromatic.optiq.rules.java.impl;
+
+// End package-info.java