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:48 UTC
[1/7] git commit: [OPTIQ-309] WITH ... ORDER BY query gives
AssertionError
Repository: incubator-optiq
Updated Branches:
refs/heads/master 90d0d79ec -> 99f396828
[OPTIQ-309] WITH ... ORDER BY query gives AssertionError
Project: http://git-wip-us.apache.org/repos/asf/incubator-optiq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-optiq/commit/a1557c29
Tree: http://git-wip-us.apache.org/repos/asf/incubator-optiq/tree/a1557c29
Diff: http://git-wip-us.apache.org/repos/asf/incubator-optiq/diff/a1557c29
Branch: refs/heads/master
Commit: a1557c2927b446feebc1895208fc7a84451e2e95
Parents: 90d0d79
Author: Vladimir Sitnikov <si...@gmail.com>
Authored: Mon Jun 23 00:42:57 2014 +0400
Committer: Julian Hyde <ju...@gmail.com>
Committed: Sun Jun 22 21:41:04 2014 -0700
----------------------------------------------------------------------
.../org/eigenbase/sql/validate/SqlValidatorImpl.java | 3 +++
.../java/org/eigenbase/sql2rel/SqlToRelConverter.java | 4 ++++
.../test/java/net/hydromatic/optiq/test/JdbcTest.java | 14 ++++++++++++++
3 files changed, 21 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/a1557c29/core/src/main/java/org/eigenbase/sql/validate/SqlValidatorImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/sql/validate/SqlValidatorImpl.java b/core/src/main/java/org/eigenbase/sql/validate/SqlValidatorImpl.java
index 938ea56..54febe5 100644
--- a/core/src/main/java/org/eigenbase/sql/validate/SqlValidatorImpl.java
+++ b/core/src/main/java/org/eigenbase/sql/validate/SqlValidatorImpl.java
@@ -1812,6 +1812,9 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
case WITH:
case UNNEST:
case OTHER_FUNCTION:
+ if (alias == null) {
+ alias = deriveAlias(node, nextGeneratedId++);
+ }
registerQuery(
parentScope,
usingScope,
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/a1557c29/core/src/main/java/org/eigenbase/sql2rel/SqlToRelConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/sql2rel/SqlToRelConverter.java b/core/src/main/java/org/eigenbase/sql2rel/SqlToRelConverter.java
index 7514518..07f4650 100644
--- a/core/src/main/java/org/eigenbase/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/eigenbase/sql2rel/SqlToRelConverter.java
@@ -1651,6 +1651,10 @@ public class SqlToRelConverter {
convertFrom(bb, ((SqlWithItem) from).query);
return;
+ case WITH:
+ convertFrom(bb, ((SqlWith) from).body);
+ return;
+
case TABLESAMPLE:
operands = ((SqlBasicCall) from).getOperands();
SqlSampleSpec sampleSpec = SqlLiteral.sampleValue(operands[1]);
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/a1557c29/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java b/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
index 04803f5..dcbe60c 100644
--- a/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
+++ b/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
@@ -2847,6 +2847,20 @@ public class JdbcTest {
"deptno=10");
}
+ @Test public void testWithOrderBy() {
+ OptiqAssert.that()
+ .with(OptiqAssert.Config.REGULAR)
+ .query(
+ "with emp2 as (select * from \"hr\".\"emps\")\n"
+ + "select * from emp2\n"
+ + "order by \"deptno\" desc, \"empid\" desc")
+ .returns(
+ "empid=200; deptno=20; name=Eric; salary=8000.0; commission=500\n"
+ + "empid=150; deptno=10; name=Sebastian; salary=7000.0; commission=null\n"
+ + "empid=110; deptno=10; name=Theodore; salary=11500.0; commission=250\n"
+ + "empid=100; deptno=10; name=Bill; salary=10000.0; commission=1000\n");
+ }
+
/** Tests windowed aggregation. */
@Test public void testWinAgg() {
OptiqAssert.that()
[3/7] git commit: Reduce count(not null) to count()
Posted by jh...@apache.org.
Reduce count(not null) to count()
Project: http://git-wip-us.apache.org/repos/asf/incubator-optiq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-optiq/commit/4621db7e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-optiq/tree/4621db7e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-optiq/diff/4621db7e
Branch: refs/heads/master
Commit: 4621db7e4ee80dd84b14d448d05c093abb8a82f1
Parents: 347eabd
Author: Vladimir Sitnikov <si...@gmail.com>
Authored: Mon Jun 23 09:53:11 2014 +0400
Committer: Julian Hyde <ju...@gmail.com>
Committed: Sun Jun 22 23:54:38 2014 -0700
----------------------------------------------------------------------
.../rel/rules/ReduceAggregatesRule.java | 42 ++++++++++++++-----
.../main/java/org/eigenbase/rex/RexBuilder.java | 44 ++++++++++++++++++++
.../eigenbase/sql2rel/SqlToRelConverter.java | 10 ++++-
.../net/hydromatic/optiq/test/JdbcTest.java | 23 ++++++++++
.../org/eigenbase/test/RelMetadataTest.java | 13 ++++--
.../org/eigenbase/test/RelOptRulesTest.xml | 2 +-
.../eigenbase/test/SqlToRelConverterTest.xml | 4 +-
7 files changed, 119 insertions(+), 19 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/4621db7e/core/src/main/java/org/eigenbase/rel/rules/ReduceAggregatesRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/rules/ReduceAggregatesRule.java b/core/src/main/java/org/eigenbase/rel/rules/ReduceAggregatesRule.java
index 4dc29b9..be9020b 100644
--- a/core/src/main/java/org/eigenbase/rel/rules/ReduceAggregatesRule.java
+++ b/core/src/main/java/org/eigenbase/rel/rules/ReduceAggregatesRule.java
@@ -26,8 +26,11 @@ import org.eigenbase.reltype.*;
import org.eigenbase.rex.*;
import org.eigenbase.sql.*;
import org.eigenbase.sql.fun.*;
+import org.eigenbase.sql.type.SqlTypeUtil;
import org.eigenbase.util.*;
+import com.google.common.collect.ImmutableList;
+
/**
* Rule to reduce aggregates to simpler forms. Currently only AVG(x) to
* SUM(x)/COUNT(x), but eventually will handle others such as STDDEV.
@@ -49,11 +52,18 @@ public class ReduceAggregatesRule extends RelOptRule {
//~ Methods ----------------------------------------------------------------
+ @Override
+ public boolean matches(RelOptRuleCall call) {
+ if (!super.matches(call)) {
+ return false;
+ }
+ AggregateRelBase oldAggRel = (AggregateRelBase) call.rels[0];
+ return containsAvgStddevVarCall(oldAggRel.getAggCallList());
+ }
+
public void onMatch(RelOptRuleCall ruleCall) {
AggregateRelBase oldAggRel = (AggregateRelBase) ruleCall.rels[0];
- if (containsAvgStddevVarCall(oldAggRel.getAggCallList())) {
- reduceAggs(ruleCall, oldAggRel);
- }
+ reduceAggs(ruleCall, oldAggRel);
}
/**
@@ -200,11 +210,14 @@ public class ReduceAggregatesRule extends RelOptRule {
// anything else: preserve original call
RexBuilder rexBuilder = oldAggRel.getCluster().getRexBuilder();
final int nGroups = oldAggRel.getGroupCount();
+ List<RelDataType> oldArgTypes = SqlTypeUtil
+ .projectTypes(oldAggRel.getRowType(), oldCall.getArgList());
return rexBuilder.addAggCall(
oldCall,
nGroups,
newCalls,
- aggCallMapping);
+ aggCallMapping,
+ oldArgTypes);
}
}
@@ -251,13 +264,15 @@ public class ReduceAggregatesRule extends RelOptRule {
sumCall,
nGroups,
newCalls,
- aggCallMapping);
+ aggCallMapping,
+ ImmutableList.of(avgInputType));
RexNode denominatorRef =
rexBuilder.addAggCall(
countCall,
nGroups,
newCalls,
- aggCallMapping);
+ aggCallMapping,
+ ImmutableList.of(avgInputType));
final RexNode divideRef =
rexBuilder.makeCall(
SqlStdOperatorTable.DIVIDE,
@@ -309,7 +324,8 @@ public class ReduceAggregatesRule extends RelOptRule {
sumZeroCall,
nGroups,
newCalls,
- aggCallMapping);
+ aggCallMapping,
+ ImmutableList.of(argType));
if (!oldCall.getType().isNullable()) {
// If SUM(x) is not nullable, the validator must have determined that
// nulls are impossible (because the group is never empty and x is never
@@ -321,7 +337,8 @@ public class ReduceAggregatesRule extends RelOptRule {
countCall,
nGroups,
newCalls,
- aggCallMapping);
+ aggCallMapping,
+ ImmutableList.of(argType));
return rexBuilder.makeCall(SqlStdOperatorTable.CASE,
rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
countRef, rexBuilder.makeExactLiteral(BigDecimal.ZERO)),
@@ -382,7 +399,8 @@ public class ReduceAggregatesRule extends RelOptRule {
sumArgSquaredAggCall,
nGroups,
newCalls,
- aggCallMapping);
+ aggCallMapping,
+ ImmutableList.of(argType));
final AggregateCall sumArgAggCall =
new AggregateCall(
@@ -396,7 +414,8 @@ public class ReduceAggregatesRule extends RelOptRule {
sumArgAggCall,
nGroups,
newCalls,
- aggCallMapping);
+ aggCallMapping,
+ ImmutableList.of(argType));
final RexNode sumSquaredArg =
rexBuilder.makeCall(
@@ -416,7 +435,8 @@ public class ReduceAggregatesRule extends RelOptRule {
countArgAggCall,
nGroups,
newCalls,
- aggCallMapping);
+ aggCallMapping,
+ ImmutableList.of(argType));
final RexNode avgSumSquaredArg =
rexBuilder.makeCall(
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/4621db7e/core/src/main/java/org/eigenbase/rex/RexBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rex/RexBuilder.java b/core/src/main/java/org/eigenbase/rex/RexBuilder.java
index 6a848bc..a05df07 100644
--- a/core/src/main/java/org/eigenbase/rex/RexBuilder.java
+++ b/core/src/main/java/org/eigenbase/rex/RexBuilder.java
@@ -262,12 +262,56 @@ public class RexBuilder {
/**
* Creates a reference to an aggregate call, checking for repeated calls.
+ * @param aggCall aggregate call to be added
+ * @param groupCount number of groups in the aggregate relation
+ * @param aggCalls destination list of aggregate calls
+ * @param aggCallMapping the dictionary of already added calls
+ * @return Rex expression for the given aggregate call
+ * @deprecated Use {@link #addAggCall(org.eigenbase.rel.AggregateCall, int, java.util.List, java.util.Map, java.util.List)}
+ * Will be removed before optiq-0.9.
*/
+ @Deprecated
public RexNode addAggCall(
AggregateCall aggCall,
int groupCount,
List<AggregateCall> aggCalls,
Map<AggregateCall, RexNode> aggCallMapping) {
+ Bug.upgrade("remove before optiq-0.9");
+ return addAggCall(aggCall, groupCount, aggCalls, aggCallMapping, null);
+ }
+
+ /**
+ * Creates a reference to an aggregate call, checking for repeated calls.
+ * Argument types help to optimize for repeated aggregates.
+ * For instance count(42) is equivalent to count(*)
+ * @param aggCall aggregate call to be added
+ * @param groupCount number of groups in the aggregate relation
+ * @param aggCalls destination list of aggregate calls
+ * @param aggCallMapping the dictionary of already added calls
+ * @return Rex expression for the given aggregate call
+ */
+ public RexNode addAggCall(
+ AggregateCall aggCall,
+ int groupCount,
+ List<AggregateCall> aggCalls,
+ Map<AggregateCall, RexNode> aggCallMapping,
+ List<RelDataType> aggArgTypes) {
+ if (aggCall.getAggregation() instanceof SqlCountAggFunction
+ && aggArgTypes != null && !aggArgTypes.isEmpty()
+ && !aggCall.isDistinct()) {
+ boolean hasNotNullArg = false;
+ for (RelDataType type : aggArgTypes) {
+ if (!type.isNullable()) {
+ hasNotNullArg = true;
+ break;
+ }
+ }
+ if (hasNotNullArg) {
+ aggCall = new AggregateCall(aggCall.getAggregation(),
+ aggCall.isDistinct(), ImmutableList.<Integer>of(),
+ aggCall.getType(), aggCall.getName());
+ }
+ }
RexNode rex = aggCallMapping.get(aggCall);
if (rex == null) {
int index = aggCalls.size() + groupCount;
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/4621db7e/core/src/main/java/org/eigenbase/sql2rel/SqlToRelConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/sql2rel/SqlToRelConverter.java b/core/src/main/java/org/eigenbase/sql2rel/SqlToRelConverter.java
index 07f4650..682914d 100644
--- a/core/src/main/java/org/eigenbase/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/eigenbase/sql2rel/SqlToRelConverter.java
@@ -4556,6 +4556,10 @@ public class SqlToRelConverter {
if (call.getOperator().isAggregator()) {
assert bb.agg == this;
List<Integer> args = new ArrayList<Integer>();
+ List<RelDataType> argTypes =
+ call.getOperator() instanceof SqlCountAggFunction
+ ? new ArrayList<RelDataType>(call.getOperandList().size())
+ : null;
try {
// switch out of agg mode
bb.agg = null;
@@ -4573,6 +4577,9 @@ public class SqlToRelConverter {
}
convertedExpr = bb.convertExpression(operand);
assert convertedExpr != null;
+ if (argTypes != null) {
+ argTypes.add(convertedExpr.getType());
+ }
args.add(lookupOrCreateGroupExpr(convertedExpr));
}
} finally {
@@ -4601,7 +4608,8 @@ public class SqlToRelConverter {
aggCall,
groupExprs.size(),
aggCalls,
- aggCallMapping);
+ aggCallMapping,
+ argTypes);
aggMapping.put(call, rex);
} else if (call instanceof SqlSelect) {
// rchen 2006-10-17:
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/4621db7e/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java b/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
index 0fdf109..e02c19d 100644
--- a/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
+++ b/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
@@ -2800,9 +2800,32 @@ public class JdbcTest {
+ " avg(\"deptno\") as a\n"
+ "from \"hr\".\"emps\"\n"
+ "where \"deptno\" < 0")
+ .explainContains(
+ "PLAN=EnumerableCalcRel(expr#0..2=[{inputs}], expr#3=[0], expr#4=[=($t0, $t3)], expr#5=[null], expr#6=[CASE($t4, $t5, $t1)], expr#7=[/($t2, $t0)], expr#8=[CAST($t7):JavaType(class java.lang.Integer)], CS=[$t0], C=[$t0], S=[$t6], A=[$t8])\n"
+ + " EnumerableAggregateRel(group=[{}], CS=[COUNT()], agg#1=[$SUM0($0)], agg#2=[SUM($0)])\n"
+ + " EnumerableCalcRel(expr#0..4=[{inputs}], expr#5=[0], expr#6=[<($t1, $t5)], deptno=[$t1], $condition=[$t6])\n"
+ + " EnumerableTableAccessRel(table=[[hr, emps]])\n")
.returns("CS=0; C=0; S=null; A=null\n");
}
+ /** Tests that count(deptno) is reduced to count(). */
+ @Test public void testReduceCountNotNullable() {
+ OptiqAssert.that()
+ .with(OptiqAssert.Config.REGULAR)
+ .query(
+ "select\n"
+ + " count(\"deptno\") as cs,\n"
+ + " count(*) as cs2\n"
+ + "from \"hr\".\"emps\"\n"
+ + "where \"deptno\" < 0")
+ .explainContains(
+ "PLAN=EnumerableCalcRel(expr#0=[{inputs}], CS=[$t0], CS2=[$t0])\n"
+ + " EnumerableAggregateRel(group=[{}], CS=[COUNT()])\n"
+ + " EnumerableCalcRel(expr#0..4=[{inputs}], expr#5=[0], expr#6=[<($t1, $t5)], DUMMY=[$t5], $condition=[$t6])\n"
+ + " EnumerableTableAccessRel(table=[[hr, emps]])\n")
+ .returns("CS=0; CS2=0\n");
+ }
+
/** Tests sorting by a column that is already sorted. */
@Test public void testOrderByOnSortedTable() {
OptiqAssert.that()
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/4621db7e/core/src/test/java/org/eigenbase/test/RelMetadataTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/eigenbase/test/RelMetadataTest.java b/core/src/test/java/org/eigenbase/test/RelMetadataTest.java
index 7b587fe..63be2f9 100644
--- a/core/src/test/java/org/eigenbase/test/RelMetadataTest.java
+++ b/core/src/test/java/org/eigenbase/test/RelMetadataTest.java
@@ -330,11 +330,16 @@ public class RelMetadataTest extends SqlToRelTestBase {
false);
}
- @Test public void testColumnOriginsAggMeasure() {
+ @Test public void testColumnOriginsAggReduced() {
+ checkNoColumnOrigin(
+ "select count(deptno),name from dept group by name");
+ }
+
+ @Test public void testColumnOriginsAggCountNullable() {
checkSingleColumnOrigin(
- "select count(deptno),name from dept group by name",
- "DEPT",
- "DEPTNO",
+ "select count(mgr),ename from emp group by ename",
+ "EMP",
+ "MGR",
true);
}
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/4621db7e/core/src/test/resources/org/eigenbase/test/RelOptRulesTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/eigenbase/test/RelOptRulesTest.xml b/core/src/test/resources/org/eigenbase/test/RelOptRulesTest.xml
index 5976cc7..68ba466 100644
--- a/core/src/test/resources/org/eigenbase/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/eigenbase/test/RelOptRulesTest.xml
@@ -107,7 +107,7 @@ AggregateRel(group=[{0}], EXPR$1=[MAX($0)], EXPR$2=[AVG($1)], EXPR$3=[MIN($0)])
<![CDATA[
ProjectRel(NAME=[$0], EXPR$1=[$1], EXPR$2=[CAST(/($2, $3)):INTEGER NOT NULL], EXPR$3=[$4])
ProjectRel(NAME=[$0], EXPR$1=[$1], $f2=[$2], $f3=[$3], EXPR$3=[$4])
- AggregateRel(group=[{0}], EXPR$1=[MAX($0)], agg#1=[$SUM0($1)], agg#2=[COUNT($1)], EXPR$3=[MIN($0)])
+ AggregateRel(group=[{0}], EXPR$1=[MAX($0)], agg#1=[$SUM0($1)], agg#2=[COUNT()], EXPR$3=[MIN($0)])
ProjectRel(NAME=[$1], DEPTNO=[$0])
TableAccessRel(table=[[CATALOG, SALES, DEPT]])
]]>
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/4621db7e/core/src/test/resources/org/eigenbase/test/SqlToRelConverterTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/eigenbase/test/SqlToRelConverterTest.xml b/core/src/test/resources/org/eigenbase/test/SqlToRelConverterTest.xml
index c7bbdd5..c2cc97d 100644
--- a/core/src/test/resources/org/eigenbase/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/eigenbase/test/SqlToRelConverterTest.xml
@@ -63,7 +63,7 @@ ProjectRel(DEPTNO=[$0], EXPR$1=[$1])
<Resource name="plan">
<![CDATA[
ProjectRel(EXPR$0=[+($0, 4)], EXPR$1=[$1], EXPR$2=[$2], EXPR$3=[*(2, $3)])
- AggregateRel(group=[{0}], EXPR$1=[SUM($1)], EXPR$2=[SUM($2)], agg#2=[COUNT($1)])
+ AggregateRel(group=[{0}], EXPR$1=[SUM($1)], EXPR$2=[SUM($2)], agg#2=[COUNT()])
ProjectRel(DEPTNO=[$7], SAL=[$5], $f2=[+(3, $5)])
TableAccessRel(table=[[CATALOG, SALES, EMP]])
]]>
@@ -130,7 +130,7 @@ ProjectRel(NAME=[$0])
<![CDATA[
ProjectRel(NAME=[$1], FOO=[$2])
ProjectRel(DEPTNO=[$1], NAME=[$0], FOO=[$2])
- AggregateRel(group=[{0, 1}], FOO=[COUNT($1)])
+ AggregateRel(group=[{0, 1}], FOO=[COUNT()])
ProjectRel(NAME=[$1], DEPTNO=[$0])
TableAccessRel(table=[[CATALOG, SALES, DEPT]])
]]>
[2/7] git commit: More tests for WITH ... ORDER BY.
Posted by jh...@apache.org.
More tests for WITH ... ORDER BY.
Project: http://git-wip-us.apache.org/repos/asf/incubator-optiq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-optiq/commit/347eabdd
Tree: http://git-wip-us.apache.org/repos/asf/incubator-optiq/tree/347eabdd
Diff: http://git-wip-us.apache.org/repos/asf/incubator-optiq/diff/347eabdd
Branch: refs/heads/master
Commit: 347eabdd6ea600bcd17df607bdae90ea57ea221a
Parents: a1557c2
Author: Julian Hyde <ju...@gmail.com>
Authored: Sun Jun 22 21:44:29 2014 -0700
Committer: Julian Hyde <ju...@gmail.com>
Committed: Sun Jun 22 21:44:29 2014 -0700
----------------------------------------------------------------------
.../net/hydromatic/optiq/test/JdbcTest.java | 10 +++---
.../eigenbase/test/SqlToRelConverterTest.java | 18 ++++++++++
.../eigenbase/test/SqlToRelConverterTest.xml | 38 ++++++++++++++++++++
.../hydromatic/optiq/impl/tpcds/TpcdsTest.java | 12 +++----
4 files changed, 67 insertions(+), 11 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/347eabdd/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java b/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
index dcbe60c..0fdf109 100644
--- a/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
+++ b/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
@@ -2852,8 +2852,8 @@ public class JdbcTest {
.with(OptiqAssert.Config.REGULAR)
.query(
"with emp2 as (select * from \"hr\".\"emps\")\n"
- + "select * from emp2\n"
- + "order by \"deptno\" desc, \"empid\" desc")
+ + "select * from emp2\n"
+ + "order by \"deptno\" desc, \"empid\" desc")
.returns(
"empid=200; deptno=20; name=Eric; salary=8000.0; commission=500\n"
+ "empid=150; deptno=10; name=Sebastian; salary=7000.0; commission=null\n"
@@ -4524,7 +4524,8 @@ public class JdbcTest {
.returns("P0=0; P1=1; P2=2\n");
}
- /** Test for {@link EigenbaseNewResource#requireDefaultConstructor(String)}. */
+ /** Test for
+ * {@link org.eigenbase.resource.EigenbaseNewResource#requireDefaultConstructor(String)}. */
@Test public void testUserDefinedFunction2() throws Exception {
withBadUdf(AwkwardFunction.class)
.connectThrows(
@@ -4595,7 +4596,8 @@ public class JdbcTest {
.returnsUnordered("deptno=20; P=20", "deptno=10; P=30");
}
- /** Test for {@link EigenbaseNewResource#firstParameterOfAdd(String)}. */
+ /** Test for
+ * {@link org.eigenbase.resource.EigenbaseNewResource#firstParameterOfAdd(String)}. */
@Test public void testUserDefinedAggregateFunction3() throws Exception {
withBadUdf(SumFunctionBadIAdd.class).connectThrows(
"Caused by: java.lang.RuntimeException: In user-defined aggregate class 'net.hydromatic.optiq.test.JdbcTest$SumFunctionBadIAdd', first parameter to 'add' method must be the accumulator (the return type of the 'init' method)");
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/347eabdd/core/src/test/java/org/eigenbase/test/SqlToRelConverterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/eigenbase/test/SqlToRelConverterTest.java b/core/src/test/java/org/eigenbase/test/SqlToRelConverterTest.java
index f474b1f..03600c4 100644
--- a/core/src/test/java/org/eigenbase/test/SqlToRelConverterTest.java
+++ b/core/src/test/java/org/eigenbase/test/SqlToRelConverterTest.java
@@ -436,6 +436,24 @@ public class SqlToRelConverterTest extends SqlToRelTestBase {
"${plan}");
}
+ /** Test case for
+ * <a href="https://issues.apache.org/jira/browse/OPTIQ-309">[OPTIQ-309]
+ * WITH ... ORDER BY query gives AssertionError</a>. */
+ @Test public void testWithOrder() {
+ check("with emp2 as (select * from emp)\n"
+ + "select * from emp2 order by deptno",
+ "${plan}");
+ }
+
+ @Test public void testWithUnionOrder() {
+ check("with emp2 as (select empno, deptno as x from emp)\n"
+ + "select * from emp2\n"
+ + "union all\n"
+ + "select * from emp2\n"
+ + "order by empno + x",
+ "${plan}");
+ }
+
@Test public void testWithUnion() {
check("with emp2 as (select * from emp where deptno > 10)\n"
+ "select empno from emp2 where deptno < 30 union all select deptno from emp",
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/347eabdd/core/src/test/resources/org/eigenbase/test/SqlToRelConverterTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/eigenbase/test/SqlToRelConverterTest.xml b/core/src/test/resources/org/eigenbase/test/SqlToRelConverterTest.xml
index 56733e6..c7bbdd5 100644
--- a/core/src/test/resources/org/eigenbase/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/eigenbase/test/SqlToRelConverterTest.xml
@@ -1807,4 +1807,42 @@ UnionRel(all=[true])
]]>
</Resource>
</TestCase>
+ <TestCase name="testWithOrder">
+ <Resource name="sql">
+ <![CDATA[with emp2 as (select * from emp)
+select * from emp2 order by deptno]]>
+ </Resource>
+ <Resource name="plan">
+ <![CDATA[
+SortRel(sort0=[$7], dir0=[ASC])
+ ProjectRel(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
+ ProjectRel(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
+ ProjectRel(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
+ TableAccessRel(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testWithUnionOrder">
+ <Resource name="sql">
+ <![CDATA[with emp2 as (select empno, deptno as x from emp)
+select * from emp2
+union all
+select * from emp2
+order by empno + x]]>
+ </Resource>
+ <Resource name="plan">
+ <![CDATA[
+ProjectRel(EMPNO=[$0], X=[$1])
+ SortRel(sort0=[$2], dir0=[ASC])
+ ProjectRel(EMPNO=[$0], X=[$1], EXPR$2=[+($0, $1)])
+ UnionRel(all=[true])
+ ProjectRel(EMPNO=[$0], X=[$1])
+ ProjectRel(EMPNO=[$0], X=[$7])
+ TableAccessRel(table=[[CATALOG, SALES, EMP]])
+ ProjectRel(EMPNO=[$0], X=[$1])
+ ProjectRel(EMPNO=[$0], X=[$7])
+ TableAccessRel(table=[[CATALOG, SALES, EMP]])
+]]>
+ </Resource>
+ </TestCase>
</Root>
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/347eabdd/plus/src/test/java/net/hydromatic/optiq/impl/tpcds/TpcdsTest.java
----------------------------------------------------------------------
diff --git a/plus/src/test/java/net/hydromatic/optiq/impl/tpcds/TpcdsTest.java b/plus/src/test/java/net/hydromatic/optiq/impl/tpcds/TpcdsTest.java
index fb90a87..17319e5 100644
--- a/plus/src/test/java/net/hydromatic/optiq/impl/tpcds/TpcdsTest.java
+++ b/plus/src/test/java/net/hydromatic/optiq/impl/tpcds/TpcdsTest.java
@@ -83,17 +83,16 @@ public class TpcdsTest {
.returnsCount(750000);
}
- @Ignore("assert fail in registerQuery")
@Test public void testQuery01() {
- checkQuery(1);
+ checkQuery(1).runs();
}
@Ignore("takes too long to optimize")
@Test public void testQuery72() {
- checkQuery(72);
+ checkQuery(72).runs();
}
- private void checkQuery(int i) {
+ private OptiqAssert.AssertQuery checkQuery(int i) {
final Query query = Query.of(i);
String sql = query.sql(-1, new Random(0));
switch (i) {
@@ -101,9 +100,8 @@ public class TpcdsTest {
// Work around OPTIQ-304: Support '<DATE> + <INTEGER>'.
sql = sql.replace("+ 5", "+ interval '5' day");
}
- with()
- .query(sql.replaceAll("tpcds\\.", "tpcds_01."))
- .runs();
+ return with()
+ .query(sql.replaceAll("tpcds\\.", "tpcds_01."));
}
}
[7/7] git commit: [OPTIQ-310] Implement LEAD,
LAG and NTILE windowed aggregates.
Posted by jh...@apache.org.
[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
[4/7] git commit: Add test case for [OPTIQ-307]
Posted by jh...@apache.org.
Add test case for [OPTIQ-307]
Project: http://git-wip-us.apache.org/repos/asf/incubator-optiq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-optiq/commit/548cf39b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-optiq/tree/548cf39b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-optiq/diff/548cf39b
Branch: refs/heads/master
Commit: 548cf39b1895bb1c50323cb265076757e80119f0
Parents: 4621db7
Author: julianhyde <ju...@gmail.com>
Authored: Fri Jun 20 15:39:02 2014 -0700
Committer: julianhyde <ju...@gmail.com>
Committed: Mon Jun 23 01:06:25 2014 -0700
----------------------------------------------------------------------
.../net/hydromatic/optiq/test/JdbcTest.java | 4 ++
core/src/test/resources/sql/misc.oq | 64 ++++++++++++++++++++
2 files changed, 68 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/548cf39b/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java b/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
index e02c19d..26f72bd 100644
--- a/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
+++ b/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
@@ -3855,6 +3855,10 @@ public class JdbcTest {
checkRun("sql/winagg.oq");
}
+ @Test public void testRunMisc() throws Exception {
+ checkRun("sql/misc.oq");
+ }
+
private void checkRun(String path) throws Exception {
// e.g. "file:/home/fred/optiq/core/target/test-classes/sql/outer.oq"
final URL inUrl = JdbcTest.class.getResource("/" + path);
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/548cf39b/core/src/test/resources/sql/misc.oq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/misc.oq b/core/src/test/resources/sql/misc.oq
new file mode 100644
index 0000000..c41560e
--- /dev/null
+++ b/core/src/test/resources/sql/misc.oq
@@ -0,0 +1,64 @@
+# misc.oq - Miscellaneous queries
+!use post
+!set outputformat mysql
+
+# OPTIQ-307 CAST(timestamp AS DATE) gives ClassCastException
+# Based on DRILL-1051
+!if (false) {
+with data(c_row, c_timestamp) as (select * from (values
+ (1, TIMESTAMP '1997-01-02 03:04:05'),
+ (2, TIMESTAMP '1997-01-02 00:00:00'),
+ (3, TIMESTAMP '2001-09-22 18:19:20'),
+ (4, TIMESTAMP '1997-02-10 17:32:01'),
+ (5, TIMESTAMP '1997-02-10 17:32:00'),
+ (6, TIMESTAMP '1997-02-11 17:32:01'),
+ (7, TIMESTAMP '1997-02-12 17:32:01'),
+ (8, TIMESTAMP '1997-02-13 17:32:01'),
+ (9, TIMESTAMP '1997-02-14 17:32:01'),
+ (10, TIMESTAMP '1997-02-15 17:32:01'),
+ (11, TIMESTAMP '1997-02-16 17:32:01'),
+ (13, TIMESTAMP '0097-02-16 17:32:01'),
+ (14, TIMESTAMP '0597-02-16 17:32:01'),
+ (15, TIMESTAMP '1097-02-16 17:32:01'),
+ (16, TIMESTAMP '1697-02-16 17:32:01'),
+ (17, TIMESTAMP '1797-02-16 17:32:01'),
+ (18, TIMESTAMP '1897-02-16 17:32:01'),
+ (19, TIMESTAMP '1997-02-16 17:32:01'),
+ (20, TIMESTAMP '2097-02-16 17:32:01'),
+ (21, TIMESTAMP '1996-02-28 17:32:01'),
+ (22, TIMESTAMP '1996-02-29 17:32:01'),
+ (23, TIMESTAMP '1996-03-01 17:32:01')))
+select cast(c_timestamp as varchar(20)), cast(c_timestamp as date) from data where c_row <> 12;
+
++------------+------------+
+| EXPR$0 | EXPR$1 |
++------------+------------+
+| 1997-01-02 03:04:05 | 1997-01-02 |
+| 1997-01-02 00:00:00 | 1997-01-02 |
+| 2001-09-22 18:19:20 | 2001-09-22 |
+| 1997-02-10 17:32:01 | 1997-02-10 |
+| 1997-02-10 17:32:00 | 1997-02-10 |
+| 1997-02-11 17:32:01 | 1997-02-11 |
+| 1997-02-12 17:32:01 | 1997-02-12 |
+| 1997-02-13 17:32:01 | 1997-02-13 |
+| 1997-02-14 17:32:01 | 1997-02-14 |
+| 1997-02-15 17:32:01 | 1997-02-15 |
+| 1997-02-16 17:32:01 | 1997-02-16 |
+| 0097-02-16 17:32:01 | 0097-02-17 |
+| 0597-02-16 17:32:01 | 0597-02-13 |
+| 1097-02-16 17:32:01 | 1097-02-09 |
+| 1697-02-16 17:32:01 | 1697-02-15 |
+| 1797-02-16 17:32:01 | 1797-02-15 |
+| 1897-02-16 17:32:01 | 1897-02-16 |
+| 1997-02-16 17:32:01 | 1997-02-16 |
+| 2097-02-16 17:32:01 | 2097-02-16 |
+| 1996-02-28 17:32:01 | 1996-02-28 |
+| 1996-02-29 17:32:01 | 1996-02-29 |
+| 1996-03-01 17:32:01 | 1996-03-01 |
++------------+------------+
+22 rows selected
+
+!ok
+!}
+
+# End misc.oq
[5/7] git commit: Re-organize planner initialization,
to make it easier to use heuristic join order.
Posted by jh...@apache.org.
Re-organize planner initialization, to make it easier to use heuristic join order.
Project: http://git-wip-us.apache.org/repos/asf/incubator-optiq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-optiq/commit/e34e6e12
Tree: http://git-wip-us.apache.org/repos/asf/incubator-optiq/tree/e34e6e12
Diff: http://git-wip-us.apache.org/repos/asf/incubator-optiq/diff/e34e6e12
Branch: refs/heads/master
Commit: e34e6e12006b7a6f6fa16c610961089b3c3c3778
Parents: 548cf39
Author: julianhyde <ju...@gmail.com>
Authored: Mon Jun 23 01:14:03 2014 -0700
Committer: julianhyde <ju...@gmail.com>
Committed: Mon Jun 23 01:14:03 2014 -0700
----------------------------------------------------------------------
.../net/hydromatic/optiq/jdbc/OptiqPrepare.java | 12 +-
.../optiq/prepare/OptiqPrepareImpl.java | 91 ++++++++++------
.../net/hydromatic/optiq/prepare/Prepare.java | 109 +++++++++----------
.../net/hydromatic/optiq/tools/Programs.java | 81 ++++++++++++--
.../net/hydromatic/optiq/tools/PlannerTest.java | 99 +++++------------
.../hydromatic/optiq/impl/tpcds/TpcdsTest.java | 5 +
.../optiq/impl/spark/SparkHandlerImpl.java | 7 +-
7 files changed, 226 insertions(+), 178 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e34e6e12/core/src/main/java/net/hydromatic/optiq/jdbc/OptiqPrepare.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/jdbc/OptiqPrepare.java b/core/src/main/java/net/hydromatic/optiq/jdbc/OptiqPrepare.java
index 3e9b15b..41f44f6 100644
--- a/core/src/main/java/net/hydromatic/optiq/jdbc/OptiqPrepare.java
+++ b/core/src/main/java/net/hydromatic/optiq/jdbc/OptiqPrepare.java
@@ -31,7 +31,7 @@ import net.hydromatic.optiq.runtime.*;
import org.eigenbase.rel.RelNode;
import org.eigenbase.relopt.RelOptPlanner;
-import org.eigenbase.relopt.volcano.VolcanoPlanner;
+import org.eigenbase.relopt.RelOptRule;
import org.eigenbase.reltype.RelDataType;
import org.eigenbase.reltype.RelDataTypeFactory;
import org.eigenbase.sql.SqlNode;
@@ -96,13 +96,19 @@ public interface OptiqPrepare {
RelNode flattenTypes(RelOptPlanner planner, RelNode rootRel,
boolean restructure);
- void registerRules(VolcanoPlanner planner);
+ void registerRules(RuleSetBuilder builder);
boolean enabled();
Bindable compile(ClassDeclaration expr, String s);
Object sparkContext();
+
+ /** Allows Spark to declare the rules it needs. */
+ interface RuleSetBuilder {
+ void addRule(RelOptRule rule);
+ void removeRule(RelOptRule rule);
+ }
}
/** Namespace that allows us to define non-abstract methods inside an
@@ -160,7 +166,7 @@ public interface OptiqPrepare {
return rootRel;
}
- public void registerRules(VolcanoPlanner planner) {
+ public void registerRules(RuleSetBuilder builder) {
}
public boolean enabled() {
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e34e6e12/core/src/main/java/net/hydromatic/optiq/prepare/OptiqPrepareImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/prepare/OptiqPrepareImpl.java b/core/src/main/java/net/hydromatic/optiq/prepare/OptiqPrepareImpl.java
index d19024a..b11780d 100644
--- a/core/src/main/java/net/hydromatic/optiq/prepare/OptiqPrepareImpl.java
+++ b/core/src/main/java/net/hydromatic/optiq/prepare/OptiqPrepareImpl.java
@@ -98,6 +98,46 @@ public class OptiqPrepareImpl implements OptiqPrepare {
"values 1",
"VALUES 1");
+ private static final List<RelOptRule> DEFAULT_RULES =
+ ImmutableList.of(
+ JavaRules.ENUMERABLE_JOIN_RULE,
+ JavaRules.ENUMERABLE_PROJECT_RULE,
+ JavaRules.ENUMERABLE_FILTER_RULE,
+ JavaRules.ENUMERABLE_AGGREGATE_RULE,
+ JavaRules.ENUMERABLE_SORT_RULE,
+ JavaRules.ENUMERABLE_LIMIT_RULE,
+ JavaRules.ENUMERABLE_COLLECT_RULE,
+ JavaRules.ENUMERABLE_UNCOLLECT_RULE,
+ JavaRules.ENUMERABLE_UNION_RULE,
+ JavaRules.ENUMERABLE_INTERSECT_RULE,
+ JavaRules.ENUMERABLE_MINUS_RULE,
+ JavaRules.ENUMERABLE_TABLE_MODIFICATION_RULE,
+ JavaRules.ENUMERABLE_VALUES_RULE,
+ JavaRules.ENUMERABLE_WINDOW_RULE,
+ JavaRules.ENUMERABLE_ONE_ROW_RULE,
+ JavaRules.ENUMERABLE_EMPTY_RULE,
+ JavaRules.ENUMERABLE_TABLE_FUNCTION_RULE,
+ TableAccessRule.INSTANCE,
+ MergeProjectRule.INSTANCE,
+ PushFilterPastProjectRule.INSTANCE,
+ PushFilterPastJoinRule.FILTER_ON_JOIN,
+ RemoveDistinctAggregateRule.INSTANCE,
+ ReduceAggregatesRule.INSTANCE,
+ SwapJoinRule.INSTANCE,
+ PushJoinThroughJoinRule.RIGHT,
+ PushJoinThroughJoinRule.LEFT,
+ PushSortPastProjectRule.INSTANCE);
+
+ private static final List<RelOptRule> CONSTANT_REDUCTION_RULES =
+ ImmutableList.of(
+ ReduceExpressionsRule.PROJECT_INSTANCE,
+ ReduceExpressionsRule.FILTER_INSTANCE,
+ ReduceExpressionsRule.CALC_INSTANCE,
+ ReduceExpressionsRule.JOIN_INSTANCE,
+ ReduceValuesRule.FILTER_INSTANCE,
+ ReduceValuesRule.PROJECT_FILTER_INSTANCE,
+ ReduceValuesRule.PROJECT_INSTANCE);
+
public OptiqPrepareImpl() {
}
@@ -157,48 +197,29 @@ public class OptiqPrepareImpl implements OptiqPrepare {
planner.registerAbstractRelationalRules();
}
RelOptUtil.registerAbstractRels(planner);
- planner.addRule(JavaRules.ENUMERABLE_JOIN_RULE);
- planner.addRule(JavaRules.ENUMERABLE_PROJECT_RULE);
- planner.addRule(JavaRules.ENUMERABLE_FILTER_RULE);
- planner.addRule(JavaRules.ENUMERABLE_AGGREGATE_RULE);
- planner.addRule(JavaRules.ENUMERABLE_SORT_RULE);
- planner.addRule(JavaRules.ENUMERABLE_LIMIT_RULE);
- planner.addRule(JavaRules.ENUMERABLE_COLLECT_RULE);
- planner.addRule(JavaRules.ENUMERABLE_UNCOLLECT_RULE);
- planner.addRule(JavaRules.ENUMERABLE_UNION_RULE);
- planner.addRule(JavaRules.ENUMERABLE_INTERSECT_RULE);
- planner.addRule(JavaRules.ENUMERABLE_MINUS_RULE);
- planner.addRule(JavaRules.ENUMERABLE_TABLE_MODIFICATION_RULE);
- planner.addRule(JavaRules.ENUMERABLE_VALUES_RULE);
- planner.addRule(JavaRules.ENUMERABLE_WINDOW_RULE);
- planner.addRule(JavaRules.ENUMERABLE_ONE_ROW_RULE);
- planner.addRule(JavaRules.ENUMERABLE_EMPTY_RULE);
- planner.addRule(JavaRules.ENUMERABLE_TABLE_FUNCTION_RULE);
- planner.addRule(TableAccessRule.INSTANCE);
- planner.addRule(MergeProjectRule.INSTANCE);
- planner.addRule(PushFilterPastProjectRule.INSTANCE);
- planner.addRule(PushFilterPastJoinRule.FILTER_ON_JOIN);
- planner.addRule(RemoveDistinctAggregateRule.INSTANCE);
- planner.addRule(ReduceAggregatesRule.INSTANCE);
- planner.addRule(SwapJoinRule.INSTANCE);
- planner.addRule(PushJoinThroughJoinRule.RIGHT);
- planner.addRule(PushJoinThroughJoinRule.LEFT);
- planner.addRule(PushSortPastProjectRule.INSTANCE);
+ for (RelOptRule rule : DEFAULT_RULES) {
+ planner.addRule(rule);
+ }
// Change the below to enable constant-reduction.
if (false) {
- planner.addRule(ReduceExpressionsRule.PROJECT_INSTANCE);
- planner.addRule(ReduceExpressionsRule.FILTER_INSTANCE);
- planner.addRule(ReduceExpressionsRule.CALC_INSTANCE);
- planner.addRule(ReduceExpressionsRule.JOIN_INSTANCE);
- planner.addRule(ReduceValuesRule.FILTER_INSTANCE);
- planner.addRule(ReduceValuesRule.PROJECT_FILTER_INSTANCE);
- planner.addRule(ReduceValuesRule.PROJECT_INSTANCE);
+ for (RelOptRule rule : CONSTANT_REDUCTION_RULES) {
+ planner.addRule(rule);
+ }
}
final SparkHandler spark = context.spark();
if (spark.enabled()) {
- spark.registerRules(planner);
+ spark.registerRules(
+ new SparkHandler.RuleSetBuilder() {
+ public void addRule(RelOptRule rule) {
+ // TODO:
+ }
+
+ public void removeRule(RelOptRule rule) {
+ // TODO:
+ }
+ });
}
return planner;
}
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e34e6e12/core/src/main/java/net/hydromatic/optiq/prepare/Prepare.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/prepare/Prepare.java b/core/src/main/java/net/hydromatic/optiq/prepare/Prepare.java
index aad8a01..026f436 100644
--- a/core/src/main/java/net/hydromatic/optiq/prepare/Prepare.java
+++ b/core/src/main/java/net/hydromatic/optiq/prepare/Prepare.java
@@ -17,8 +17,6 @@
*/
package net.hydromatic.optiq.prepare;
-import net.hydromatic.linq4j.function.Functions;
-
import net.hydromatic.optiq.DataContext;
import net.hydromatic.optiq.impl.StarTable;
import net.hydromatic.optiq.jdbc.OptiqPrepare;
@@ -26,12 +24,13 @@ import net.hydromatic.optiq.jdbc.OptiqSchema;
import net.hydromatic.optiq.rules.java.JavaRules;
import net.hydromatic.optiq.runtime.Bindable;
import net.hydromatic.optiq.runtime.Typed;
+import net.hydromatic.optiq.tools.Program;
+import net.hydromatic.optiq.tools.Programs;
import org.eigenbase.rel.*;
import org.eigenbase.rel.metadata.*;
import org.eigenbase.rel.rules.*;
import org.eigenbase.relopt.*;
-import org.eigenbase.relopt.hep.*;
import org.eigenbase.reltype.RelDataType;
import org.eigenbase.rex.RexBuilder;
import org.eigenbase.rex.RexExecutorImpl;
@@ -41,7 +40,7 @@ import org.eigenbase.sql2rel.SqlToRelConverter;
import org.eigenbase.trace.EigenbaseTimingTracer;
import org.eigenbase.trace.EigenbaseTrace;
-import com.google.common.collect.Lists;
+import com.google.common.collect.ImmutableList;
import java.lang.reflect.Type;
import java.util.*;
@@ -55,6 +54,24 @@ import java.util.logging.Logger;
public abstract class Prepare {
protected static final Logger LOGGER = EigenbaseTrace.getStatementTracer();
+ private static final ImmutableList<RelOptRule> CALC_RULES =
+ ImmutableList.of(
+ JavaRules.ENUMERABLE_CALC_RULE,
+ JavaRules.ENUMERABLE_FILTER_TO_CALC_RULE,
+ JavaRules.ENUMERABLE_PROJECT_TO_CALC_RULE,
+ MergeCalcRule.INSTANCE,
+ MergeFilterOntoCalcRule.INSTANCE,
+ MergeProjectOntoCalcRule.INSTANCE,
+ FilterToCalcRule.INSTANCE,
+ ProjectToCalcRule.INSTANCE,
+ MergeCalcRule.INSTANCE,
+
+ // REVIEW jvs 9-Apr-2006: Do we still need these two? Doesn't the
+ // combination of MergeCalcRule, FilterToCalcRule, and
+ // ProjectToCalcRule have the same effect?
+ MergeFilterOntoCalcRule.INSTANCE,
+ MergeProjectOntoCalcRule.INSTANCE);
+
protected final OptiqPrepare.Context context;
protected final CatalogReader catalogReader;
protected String queryString = null;
@@ -93,64 +110,46 @@ public abstract class Prepare {
* @param materializations Tables known to be populated with a given query
* @return an equivalent optimized relational expression
*/
- protected RelNode optimize(RelDataType logicalRowType, RelNode rootRel,
- List<Materialization> materializations) {
+ protected RelNode optimize(RelDataType logicalRowType, final RelNode rootRel,
+ final List<Materialization> materializations) {
final RelOptPlanner planner = rootRel.getCluster().getPlanner();
- final DataContext dataContext = context.getDataContext();
- planner.setExecutor(new RexExecutorImpl(dataContext));
-
planner.setRoot(rootRel);
- for (Materialization materialization : materializations) {
- planner.addMaterialization(
- new RelOptMaterialization(materialization.tableRel,
- materialization.queryRel, materialization.starRelOptTable));
- }
-
- RelTraitSet desiredTraits = getDesiredRootTraitSet(rootRel);
-
- final RelNode rootRel2 = planner.changeTraits(rootRel, desiredTraits);
- assert rootRel2 != null;
- planner.setRoot(rootRel2);
- final RelOptPlanner planner2 = planner.chooseDelegate();
- final RelNode rootRel3 = planner2.findBestExp();
- assert rootRel3 != null : "could not implement exp";
+ final RelTraitSet desiredTraits = getDesiredRootTraitSet(rootRel);
+ final Program program1 =
+ new Program() {
+ public RelNode run(RelOptPlanner planner, RelNode rel,
+ RelTraitSet requiredOutputTraits) {
+ final DataContext dataContext = context.getDataContext();
+ planner.setExecutor(new RexExecutorImpl(dataContext));
+
+ for (Materialization materialization : materializations) {
+ planner.addMaterialization(
+ new RelOptMaterialization(materialization.tableRel,
+ materialization.queryRel,
+ materialization.starRelOptTable));
+ }
+
+ final RelNode rootRel2 =
+ planner.changeTraits(rel, requiredOutputTraits);
+ assert rootRel2 != null;
+
+ planner.setRoot(rootRel2);
+ final RelOptPlanner planner2 = planner.chooseDelegate();
+ final RelNode rootRel3 = planner2.findBestExp();
+ assert rootRel3 != null : "could not implement exp";
+ return rootRel3;
+ }
+ };
+
+ final RelNode rootRel3 = program1.run(planner, rootRel, desiredTraits);
// Second planner pass to do physical "tweaks". This the first time that
// EnumerableCalcRel is introduced.
- final HepProgram program = HepProgram.builder()
- .addRuleInstance(JavaRules.ENUMERABLE_CALC_RULE)
- .addRuleInstance(JavaRules.ENUMERABLE_FILTER_TO_CALC_RULE)
- .addRuleInstance(JavaRules.ENUMERABLE_PROJECT_TO_CALC_RULE)
- .addRuleInstance(MergeCalcRule.INSTANCE)
- .addRuleInstance(MergeFilterOntoCalcRule.INSTANCE)
- .addRuleInstance(MergeProjectOntoCalcRule.INSTANCE)
- .addRuleInstance(FilterToCalcRule.INSTANCE)
- .addRuleInstance(ProjectToCalcRule.INSTANCE)
- .addRuleInstance(MergeCalcRule.INSTANCE)
-
- // REVIEW jvs 9-Apr-2006: Do we still need these two? Doesn't the
- // combination of MergeCalcRule, FilterToCalcRule, and
- // ProjectToCalcRule have the same effect?
- .addRuleInstance(MergeFilterOntoCalcRule.INSTANCE)
- .addRuleInstance(MergeProjectOntoCalcRule.INSTANCE)
- .build();
- final HepPlanner planner3 =
- new HepPlanner(program, true,
- Functions.<RelNode, RelNode, Void>ignore2(),
- RelOptCostImpl.FACTORY);
- List<RelMetadataProvider> list = Lists.newArrayList();
- DefaultRelMetadataProvider defaultProvider =
- new DefaultRelMetadataProvider();
- list.add(defaultProvider);
- planner3.registerMetadataProviders(list);
- RelMetadataProvider plannerChain =
- ChainedRelMetadataProvider.of(list);
- rootRel3.getCluster().setMetadataProvider(plannerChain);
- planner3.setRoot(rootRel3);
-
- final RelNode rootRel4 = planner3.findBestExp();
+ final Program program2 =
+ Programs.hep(CALC_RULES, true, new DefaultRelMetadataProvider());
+ final RelNode rootRel4 = program2.run(null, rootRel3, null);
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine(
"Plan after physical tweaks: "
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e34e6e12/core/src/main/java/net/hydromatic/optiq/tools/Programs.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/tools/Programs.java b/core/src/main/java/net/hydromatic/optiq/tools/Programs.java
index 42f4ed6..4996fda 100644
--- a/core/src/main/java/net/hydromatic/optiq/tools/Programs.java
+++ b/core/src/main/java/net/hydromatic/optiq/tools/Programs.java
@@ -18,19 +18,17 @@
package net.hydromatic.optiq.tools;
import org.eigenbase.rel.RelNode;
-import org.eigenbase.relopt.RelOptPlanner;
-import org.eigenbase.relopt.RelOptRule;
-import org.eigenbase.relopt.RelTraitSet;
-import org.eigenbase.relopt.hep.HepPlanner;
-import org.eigenbase.relopt.hep.HepProgram;
+import org.eigenbase.rel.metadata.ChainedRelMetadataProvider;
+import org.eigenbase.rel.metadata.RelMetadataProvider;
+import org.eigenbase.rel.rules.*;
+import org.eigenbase.relopt.*;
+import org.eigenbase.relopt.hep.*;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
+import java.util.*;
/**
* Utilities for creating {@link Program}s.
@@ -71,18 +69,81 @@ public class Programs {
return new SequenceProgram(ImmutableList.copyOf(programs));
}
+ /** Creates a program that executes a list of rules in a HEP planner. */
+ public static Program hep(ImmutableList<RelOptRule> rules, boolean noDag,
+ RelMetadataProvider metadataProvider) {
+ final HepProgramBuilder builder = HepProgram.builder();
+ for (RelOptRule rule : rules) {
+ builder.addRuleInstance(rule);
+ }
+ return of(builder.build(), noDag, metadataProvider);
+ }
+
/** Creates a program that executes a {@link HepProgram}. */
- public static Program of(final HepProgram hepProgram) {
+ public static Program of(final HepProgram hepProgram, final boolean noDag,
+ final RelMetadataProvider metadataProvider) {
return new Program() {
public RelNode run(RelOptPlanner planner, RelNode rel,
RelTraitSet requiredOutputTraits) {
- final HepPlanner hepPlanner = new HepPlanner(hepProgram);
+ final HepPlanner hepPlanner = new HepPlanner(hepProgram,
+ noDag, null, RelOptCostImpl.FACTORY);
+
+ if (metadataProvider != null) {
+ List<RelMetadataProvider> list = Lists.newArrayList();
+ list.add(metadataProvider);
+ hepPlanner.registerMetadataProviders(list);
+ RelMetadataProvider plannerChain =
+ ChainedRelMetadataProvider.of(list);
+ rel.getCluster().setMetadataProvider(plannerChain);
+ }
+
hepPlanner.setRoot(rel);
return hepPlanner.findBestExp();
}
};
}
+ /** Creates a program that invokes heuristic join-order optimization
+ * (via {@link org.eigenbase.rel.rules.ConvertMultiJoinRule},
+ * {@link org.eigenbase.rel.rules.MultiJoinRel} and
+ * {@link org.eigenbase.rel.rules.LoptOptimizeJoinRule})
+ * if there are 6 or more joins (7 or more relations). */
+ public static Program heuristicJoinOrder(final Collection<RelOptRule> rules) {
+ return new Program() {
+ public RelNode run(RelOptPlanner planner, RelNode rel,
+ RelTraitSet requiredOutputTraits) {
+ final int joinCount = RelOptUtil.countJoins(rel);
+ final Program program;
+ if (joinCount < 6) {
+ program = ofRules(rules);
+ } else {
+ // Create a program that gathers together joins as a MultiJoinRel.
+ final HepProgram hep = new HepProgramBuilder()
+ .addRuleInstance(PushFilterPastJoinRule.FILTER_ON_JOIN)
+ .addMatchOrder(HepMatchOrder.BOTTOM_UP)
+ .addRuleInstance(ConvertMultiJoinRule.INSTANCE)
+ .build();
+ final Program program1 = of(hep, false, null);
+
+ // Create a program that contains a rule to expand a MultiJoinRel
+ // into heuristically ordered joins.
+ // We use the rule set passed in, but remove SwapJoinRule and
+ // PushJoinThroughJoinRule, because they cause exhaustive search.
+ final List<RelOptRule> list = new ArrayList<RelOptRule>(rules);
+ list.removeAll(
+ ImmutableList.of(SwapJoinRule.INSTANCE,
+ PushJoinThroughJoinRule.LEFT,
+ PushJoinThroughJoinRule.RIGHT));
+ list.add(LoptOptimizeJoinRule.INSTANCE);
+ final Program program2 = ofRules(list);
+
+ program = sequence(program1, program2);
+ }
+ return program.run(planner, rel, requiredOutputTraits);
+ }
+ };
+ }
+
/** Program backed by a {@link RuleSet}. */
static class RuleSetProgram implements Program {
final RuleSet ruleSet;
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e34e6e12/core/src/test/java/net/hydromatic/optiq/tools/PlannerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/net/hydromatic/optiq/tools/PlannerTest.java b/core/src/test/java/net/hydromatic/optiq/tools/PlannerTest.java
index eb244af..354f9e6 100644
--- a/core/src/test/java/net/hydromatic/optiq/tools/PlannerTest.java
+++ b/core/src/test/java/net/hydromatic/optiq/tools/PlannerTest.java
@@ -32,7 +32,6 @@ import org.eigenbase.rel.*;
import org.eigenbase.rel.convert.ConverterRule;
import org.eigenbase.rel.rules.*;
import org.eigenbase.relopt.*;
-import org.eigenbase.relopt.hep.*;
import org.eigenbase.reltype.RelDataType;
import org.eigenbase.reltype.RelDataTypeFactory;
import org.eigenbase.sql.*;
@@ -49,7 +48,6 @@ import org.eigenbase.util.Util;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
import org.junit.Test;
@@ -442,7 +440,7 @@ public class PlannerTest {
.append(i).append(".\"deptno\" = d")
.append(i - 1).append(".\"deptno\"");
}
- Planner planner = getPlanner(null, adaptiveJoinProgram(RULE_SET));
+ Planner planner = getPlanner(null, Programs.heuristicJoinOrder(RULE_SET));
SqlNode parse = planner.parse(buf.toString());
SqlNode validate = planner.validate(parse);
@@ -454,40 +452,6 @@ public class PlannerTest {
"EnumerableJoinRel(condition=[=($3, $0)], joinType=[inner])"));
}
- /** Creates a program that invokes heuristic join-order optimization
- * (via {@link org.eigenbase.rel.rules.ConvertMultiJoinRule},
- * {@link org.eigenbase.rel.rules.MultiJoinRel} and
- * {@link org.eigenbase.rel.rules.LoptOptimizeJoinRule})
- * if there are 6 or more joins (7 or more relations). */
- private static Program adaptiveJoinProgram(final RuleSet ruleSet) {
- return new Program() {
- public RelNode run(RelOptPlanner planner, RelNode rel,
- RelTraitSet requiredOutputTraits) {
- final int joinCount = RelOptUtil.countJoins(rel);
- final Program program;
- if (joinCount < 6) {
- program = Programs.of(ruleSet);
- } else {
- final HepProgram hep = new HepProgramBuilder()
- .addRuleInstance(PushFilterPastJoinRule.FILTER_ON_JOIN)
- .addMatchOrder(HepMatchOrder.BOTTOM_UP)
- .addRuleInstance(ConvertMultiJoinRule.INSTANCE)
- .build();
- final List<RelOptRule> list = new ArrayList<RelOptRule>();
- Iterables.addAll(list, ruleSet);
- list.removeAll(
- ImmutableList.of(SwapJoinRule.INSTANCE,
- PushJoinThroughJoinRule.LEFT,
- PushJoinThroughJoinRule.RIGHT));
- list.add(LoptOptimizeJoinRule.INSTANCE);
- program =
- Programs.sequence(Programs.of(hep), Programs.ofRules(list));
- }
- return program.run(planner, rel, requiredOutputTraits);
- }
- };
- }
-
/**
* Rule to convert a {@link EnumerableProjectRel} to an
* {@link JdbcProjectRel}.
@@ -560,39 +524,32 @@ public class PlannerTest {
}
}
- private static final RuleSet RULE_SET =
- new RuleSet() {
- final Set<RelOptRule> setOfRules =
- ImmutableSet.of(
- JavaRules.ENUMERABLE_JOIN_RULE,
- JavaRules.ENUMERABLE_PROJECT_RULE,
- JavaRules.ENUMERABLE_FILTER_RULE,
- JavaRules.ENUMERABLE_AGGREGATE_RULE,
- JavaRules.ENUMERABLE_SORT_RULE,
- JavaRules.ENUMERABLE_LIMIT_RULE,
- JavaRules.ENUMERABLE_UNION_RULE,
- JavaRules.ENUMERABLE_INTERSECT_RULE,
- JavaRules.ENUMERABLE_MINUS_RULE,
- JavaRules.ENUMERABLE_TABLE_MODIFICATION_RULE,
- JavaRules.ENUMERABLE_VALUES_RULE,
- JavaRules.ENUMERABLE_WINDOW_RULE,
- JavaRules.ENUMERABLE_ONE_ROW_RULE,
- JavaRules.ENUMERABLE_EMPTY_RULE,
- TableAccessRule.INSTANCE,
- MergeProjectRule.INSTANCE,
- PushFilterPastProjectRule.INSTANCE,
- PushFilterPastJoinRule.FILTER_ON_JOIN,
- RemoveDistinctAggregateRule.INSTANCE,
- ReduceAggregatesRule.INSTANCE,
- SwapJoinRule.INSTANCE,
- PushJoinThroughJoinRule.RIGHT,
- PushJoinThroughJoinRule.LEFT,
- PushSortPastProjectRule.INSTANCE);
-
- public Iterator<RelOptRule> iterator() {
- return setOfRules.iterator();
- }
- };
+ private static final ImmutableSet<RelOptRule> RULE_SET =
+ ImmutableSet.of(
+ JavaRules.ENUMERABLE_JOIN_RULE,
+ JavaRules.ENUMERABLE_PROJECT_RULE,
+ JavaRules.ENUMERABLE_FILTER_RULE,
+ JavaRules.ENUMERABLE_AGGREGATE_RULE,
+ JavaRules.ENUMERABLE_SORT_RULE,
+ JavaRules.ENUMERABLE_LIMIT_RULE,
+ JavaRules.ENUMERABLE_UNION_RULE,
+ JavaRules.ENUMERABLE_INTERSECT_RULE,
+ JavaRules.ENUMERABLE_MINUS_RULE,
+ JavaRules.ENUMERABLE_TABLE_MODIFICATION_RULE,
+ JavaRules.ENUMERABLE_VALUES_RULE,
+ JavaRules.ENUMERABLE_WINDOW_RULE,
+ JavaRules.ENUMERABLE_ONE_ROW_RULE,
+ JavaRules.ENUMERABLE_EMPTY_RULE,
+ TableAccessRule.INSTANCE,
+ MergeProjectRule.INSTANCE,
+ PushFilterPastProjectRule.INSTANCE,
+ PushFilterPastJoinRule.FILTER_ON_JOIN,
+ RemoveDistinctAggregateRule.INSTANCE,
+ ReduceAggregatesRule.INSTANCE,
+ SwapJoinRule.INSTANCE,
+ PushJoinThroughJoinRule.RIGHT,
+ PushJoinThroughJoinRule.LEFT,
+ PushSortPastProjectRule.INSTANCE);
/**
* Test to determine whether de-correlation correctly removes CorrelatorRel.
@@ -622,7 +579,7 @@ public class PlannerTest {
new ReflectiveSchema(new TpchSchema()));
Planner p = Frameworks.getPlanner(Lex.MYSQL, schema,
- SqlStdOperatorTable.instance(), RULE_SET);
+ SqlStdOperatorTable.instance(), RuleSets.ofList(RULE_SET));
SqlNode n = p.parse(tpchTestQuery);
n = p.validate(n);
RelNode r = p.convert(n);
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e34e6e12/plus/src/test/java/net/hydromatic/optiq/impl/tpcds/TpcdsTest.java
----------------------------------------------------------------------
diff --git a/plus/src/test/java/net/hydromatic/optiq/impl/tpcds/TpcdsTest.java b/plus/src/test/java/net/hydromatic/optiq/impl/tpcds/TpcdsTest.java
index 17319e5..dbae507 100644
--- a/plus/src/test/java/net/hydromatic/optiq/impl/tpcds/TpcdsTest.java
+++ b/plus/src/test/java/net/hydromatic/optiq/impl/tpcds/TpcdsTest.java
@@ -92,6 +92,11 @@ public class TpcdsTest {
checkQuery(72).runs();
}
+ @Ignore("work in progress")
+ @Test public void testQuery72Plan() {
+ checkQuery(72).planContains("xx");
+ }
+
private OptiqAssert.AssertQuery checkQuery(int i) {
final Query query = Query.of(i);
String sql = query.sql(-1, new Random(0));
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/e34e6e12/spark/src/main/java/net/hydromatic/optiq/impl/spark/SparkHandlerImpl.java
----------------------------------------------------------------------
diff --git a/spark/src/main/java/net/hydromatic/optiq/impl/spark/SparkHandlerImpl.java b/spark/src/main/java/net/hydromatic/optiq/impl/spark/SparkHandlerImpl.java
index 3e2e7c2..b2c0c5a 100644
--- a/spark/src/main/java/net/hydromatic/optiq/impl/spark/SparkHandlerImpl.java
+++ b/spark/src/main/java/net/hydromatic/optiq/impl/spark/SparkHandlerImpl.java
@@ -27,7 +27,6 @@ import net.hydromatic.optiq.runtime.Typed;
import org.eigenbase.javac.JaninoCompiler;
import org.eigenbase.rel.RelNode;
import org.eigenbase.relopt.*;
-import org.eigenbase.relopt.volcano.VolcanoPlanner;
import org.apache.spark.api.java.JavaSparkContext;
@@ -89,11 +88,11 @@ public class SparkHandlerImpl implements OptiqPrepare.SparkHandler {
return planner.changeTraits(root2, rootRel.getTraitSet());
}
- public void registerRules(VolcanoPlanner planner) {
+ public void registerRules(RuleSetBuilder builder) {
for (RelOptRule rule : SparkRules.rules()) {
- planner.addRule(rule);
+ builder.addRule(rule);
}
- planner.removeRule(JavaRules.ENUMERABLE_VALUES_RULE);
+ builder.removeRule(JavaRules.ENUMERABLE_VALUES_RULE);
}
public Object sparkContext() {
[6/7] [OPTIQ-310] Implement LEAD, LAG and NTILE windowed aggregates.
Posted by jh...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/org/eigenbase/sql/fun/SqlLeadLagAggFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/sql/fun/SqlLeadLagAggFunction.java b/core/src/main/java/org/eigenbase/sql/fun/SqlLeadLagAggFunction.java
new file mode 100644
index 0000000..f996300
--- /dev/null
+++ b/core/src/main/java/org/eigenbase/sql/fun/SqlLeadLagAggFunction.java
@@ -0,0 +1,94 @@
+/*
+// 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 org.eigenbase.sql.fun;
+
+import java.util.List;
+
+import org.eigenbase.reltype.RelDataType;
+import org.eigenbase.reltype.RelDataTypeFactory;
+import org.eigenbase.sql.*;
+import org.eigenbase.sql.type.*;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * <code>LEAD</code> and <code>LAG</code> aggregate functions
+ * return the value of given expression evaluated at given offset.
+ */
+public class SqlLeadLagAggFunction extends SqlAggFunction {
+ private static final SqlSingleOperandTypeChecker OPERAND_TYPES =
+ OperandTypes.or(
+ OperandTypes.ANY,
+ OperandTypes.family(SqlTypeFamily.ANY, SqlTypeFamily.NUMERIC),
+ OperandTypes.and(
+ OperandTypes.family(
+ SqlTypeFamily.ANY, SqlTypeFamily.NUMERIC, SqlTypeFamily.ANY)
+ // Arguments 1 and 3 must have same type
+ , new SameOperandTypeChecker(3) {
+ @Override
+ protected List<Integer> getOperandList(int operandCount) {
+ return ImmutableList.of(0, 2);
+ }
+ }));
+
+ private static final SqlReturnTypeInference RETURN_TYPE =
+ ReturnTypes.cascade(ReturnTypes.ARG0, new SqlTypeTransform() {
+ public RelDataType transformType(SqlOperatorBinding binding,
+ RelDataType type) {
+ // Result is NOT NULL if NOT NULL default value is provided
+ SqlTypeTransform transform;
+ if (binding.getOperandCount() < 3) {
+ transform = SqlTypeTransforms.FORCE_NULLABLE;
+ } else {
+ RelDataType defValueType = binding.getOperandType(2);
+ transform = defValueType.isNullable()
+ ? SqlTypeTransforms.FORCE_NULLABLE
+ : SqlTypeTransforms.TO_NOT_NULLABLE;
+ }
+ return transform.transformType(binding, type);
+ }
+ });
+
+ public SqlLeadLagAggFunction(boolean isLead) {
+ super(
+ isLead ? "LEAD" : "LAG",
+ SqlKind.OTHER_FUNCTION,
+ RETURN_TYPE,
+ null,
+ OPERAND_TYPES,
+ SqlFunctionCategory.NUMERIC);
+ }
+
+ @Override public boolean requiresOrder() {
+ return true;
+ }
+
+ @Override public boolean allowsFraming() {
+ return false;
+ }
+
+ public List<RelDataType> getParameterTypes(RelDataTypeFactory typeFactory) {
+ throw new UnsupportedOperationException("remove before optiq-0.9");
+ }
+
+ public RelDataType getReturnType(RelDataTypeFactory typeFactory) {
+ throw new UnsupportedOperationException("remove before optiq-0.9");
+ }
+}
+
+// End SqlLeadLagAggFunction.java
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/org/eigenbase/sql/fun/SqlNtileAggFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/sql/fun/SqlNtileAggFunction.java b/core/src/main/java/org/eigenbase/sql/fun/SqlNtileAggFunction.java
new file mode 100644
index 0000000..ed13608
--- /dev/null
+++ b/core/src/main/java/org/eigenbase/sql/fun/SqlNtileAggFunction.java
@@ -0,0 +1,58 @@
+/*
+// 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 org.eigenbase.sql.fun;
+
+import java.util.List;
+
+import org.eigenbase.reltype.RelDataType;
+import org.eigenbase.reltype.RelDataTypeFactory;
+import org.eigenbase.sql.SqlAggFunction;
+import org.eigenbase.sql.SqlFunctionCategory;
+import org.eigenbase.sql.SqlKind;
+import org.eigenbase.sql.type.OperandTypes;
+import org.eigenbase.sql.type.ReturnTypes;
+
+/**
+ * <code>NTILE</code> aggregate function
+ * return the value of given expression evaluated at given offset.
+ */
+public class SqlNtileAggFunction extends SqlAggFunction {
+ public SqlNtileAggFunction() {
+ super(
+ "NTILE",
+ SqlKind.OTHER_FUNCTION,
+ ReturnTypes.INTEGER,
+ null,
+ OperandTypes.POSITIVE_INTEGER_LITERAL,
+ SqlFunctionCategory.NUMERIC);
+ }
+
+ @Override public boolean requiresOrder() {
+ return true;
+ }
+
+ public List<RelDataType> getParameterTypes(RelDataTypeFactory typeFactory) {
+ throw new UnsupportedOperationException("remove before optiq-0.9");
+ }
+
+ public RelDataType getReturnType(RelDataTypeFactory typeFactory) {
+ throw new UnsupportedOperationException("remove before optiq-0.9");
+ }
+}
+
+// End SqlNtileAggFunction.java
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/org/eigenbase/sql/fun/SqlStdOperatorTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/sql/fun/SqlStdOperatorTable.java b/core/src/main/java/org/eigenbase/sql/fun/SqlStdOperatorTable.java
index afb062d..87f9177 100644
--- a/core/src/main/java/org/eigenbase/sql/fun/SqlStdOperatorTable.java
+++ b/core/src/main/java/org/eigenbase/sql/fun/SqlStdOperatorTable.java
@@ -624,6 +624,24 @@ public class SqlStdOperatorTable extends ReflectiveSqlOperatorTable {
new SqlFirstLastValueAggFunction(true);
/**
+ * <code>LEAD</code> aggregate function.
+ */
+ public static final SqlAggFunction LEAD =
+ new SqlLeadLagAggFunction(true);
+
+ /**
+ * <code>LAG</code> aggregate function.
+ */
+ public static final SqlAggFunction LAG =
+ new SqlLeadLagAggFunction(false);
+
+ /**
+ * <code>NTILE</code> aggregate function.
+ */
+ public static final SqlAggFunction NTILE =
+ new SqlNtileAggFunction();
+
+ /**
* <code>SINGLE_VALUE</code> aggregate function.
*/
public static final SqlAggFunction SINGLE_VALUE =
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/org/eigenbase/sql/type/CompositeOperandTypeChecker.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/sql/type/CompositeOperandTypeChecker.java b/core/src/main/java/org/eigenbase/sql/type/CompositeOperandTypeChecker.java
index 7bb4996..e1e3f9e 100644
--- a/core/src/main/java/org/eigenbase/sql/type/CompositeOperandTypeChecker.java
+++ b/core/src/main/java/org/eigenbase/sql/type/CompositeOperandTypeChecker.java
@@ -294,6 +294,12 @@ public class CompositeOperandTypeChecker
default:
if (!rule.checkOperandTypes(callBinding, false)) {
typeErrorCount++;
+ if (composition == Composition.AND) {
+ // Avoid trying other rules in AND if the first one fails.
+ break label;
+ }
+ } else if (composition == Composition.OR) {
+ break label; // true OR any == true, just break
}
break;
}
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/main/java/org/eigenbase/sql/type/SqlSingleOperandTypeChecker.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/sql/type/SqlSingleOperandTypeChecker.java b/core/src/main/java/org/eigenbase/sql/type/SqlSingleOperandTypeChecker.java
index 323d7b0..f81c916 100644
--- a/core/src/main/java/org/eigenbase/sql/type/SqlSingleOperandTypeChecker.java
+++ b/core/src/main/java/org/eigenbase/sql/type/SqlSingleOperandTypeChecker.java
@@ -21,7 +21,7 @@ import org.eigenbase.sql.*;
/**
* SqlSingleOperandTypeChecker is an extension of {@link SqlOperandTypeChecker}
- * for implementations which are cabable of checking the type of a single
+ * for implementations which are capable of checking the type of a single
* operand in isolation. This isn't meaningful for all type-checking rules (e.g.
* SameOperandTypeChecker requires two operands to have matching types, so
* checking one in isolation is meaningless).
http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/99f39682/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java b/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
index 26f72bd..76d54a2 100644
--- a/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
+++ b/core/src/test/java/net/hydromatic/optiq/test/JdbcTest.java
@@ -146,7 +146,7 @@ public class JdbcTest {
public static final String START_OF_GROUP_DATA =
- "values"
+ "(values"
+ "(1,0,1),\n"
+ "(2,0,1),\n"
+ "(3,1,2),\n"
@@ -3142,20 +3142,16 @@ public class JdbcTest {
"deptno=20; R=4"); // 4 for rank and 2 for dense_rank
}
- /**
- * Tests start_of_group approach for grouping of adjacent intervals.
- * This is a step1, implemented as last_value.
- * http://timurakhmadeev.wordpress.com/2013/07/21/start_of_group/
- */
- @Test public void testStartOfGroupLastValueStep1() {
+ private void startOfGroupStep1(String startOfGroup) {
OptiqAssert.that()
.with(OptiqAssert.Config.REGULAR)
.query(
- "select t.*\n"
+ "select t.*\n"
+ " from (\n"
+ " select t.*,\n"
- + " case when val = last_value(val) over (order by rn rows between 1 preceding and 1 preceding) then 0 else 1 end start_of_group\n"
- + " from ("
+ + " case when " + startOfGroup
+ + " then 0 else 1 end start_of_group\n"
+ + " from "
+ START_OF_GROUP_DATA
+ ") t\n")
.typeIs(
@@ -3169,25 +3165,20 @@ public class JdbcTest {
"RN=6; VAL=0; EXPECTED=3; START_OF_GROUP=0",
"RN=7; VAL=1; EXPECTED=4; START_OF_GROUP=1",
"RN=8; VAL=1; EXPECTED=4; START_OF_GROUP=0");
-
}
- /**
- * Tests start_of_group approach for grouping of adjacent intervals.
- * This is a step2, that gets the final group numbers
- * http://timurakhmadeev.wordpress.com/2013/07/21/start_of_group/
- */
- @Test public void testStartOfGroupLastValueStep2() {
+ private void startOfGroupStep2(String startOfGroup) {
OptiqAssert.that()
.with(OptiqAssert.Config.REGULAR)
.query(
- "select t.*\n"
+ "select t.*\n"
// current row is assumed, group_id should be NOT NULL
+ " ,sum(start_of_group) over (order by rn rows unbounded preceding) group_id\n"
+ " from (\n"
+ " select t.*,\n"
- + " case when val = last_value(val) over (order by rn rows between 1 preceding and 1 preceding) then 0 else 1 end start_of_group\n"
- + " from ("
+ + " case when " + startOfGroup
+ + " then 0 else 1 end start_of_group\n"
+ + " from "
+ START_OF_GROUP_DATA
+ ") t\n")
.typeIs(
@@ -3201,27 +3192,22 @@ public class JdbcTest {
"RN=6; VAL=0; EXPECTED=3; START_OF_GROUP=0; GROUP_ID=3",
"RN=7; VAL=1; EXPECTED=4; START_OF_GROUP=1; GROUP_ID=4",
"RN=8; VAL=1; EXPECTED=4; START_OF_GROUP=0; GROUP_ID=4");
-
}
- /**
- * Tests start_of_group approach for grouping of adjacent intervals.
- * This is a step3, that aggregates the computed groups
- * http://timurakhmadeev.wordpress.com/2013/07/21/start_of_group/
- */
- @Test public void testStartOfGroupLastValueStep3() {
+ private void startOfGroupStep3(String startOfGroup) {
OptiqAssert.that()
.with(OptiqAssert.Config.REGULAR)
.query(
- "select group_id, min(rn) min_rn, max(rn) max_rn, count(rn) cnt_rn, avg(val) avg_val"
+ "select group_id, min(rn) min_rn, max(rn) max_rn, count(rn) cnt_rn, avg(val) avg_val"
+ " from (\n"
+ "select t.*\n"
// current row is assumed, group_id should be NOT NULL
+ " ,sum(start_of_group) over (order by rn rows unbounded preceding) group_id\n"
+ " from (\n"
+ " select t.*,\n"
- + " case when val = last_value(val) over (order by rn rows between 1 preceding and 1 preceding) then 0 else 1 end start_of_group\n"
- + " from ("
+ + " case when " + startOfGroup
+ + " then 0 else 1 end start_of_group\n"
+ + " from "
+ START_OF_GROUP_DATA
+ ") t\n"
+ ") group by group_id\n")
@@ -3232,7 +3218,36 @@ public class JdbcTest {
"GROUP_ID=2; MIN_RN=3; MAX_RN=3; CNT_RN=1; AVG_VAL=1",
"GROUP_ID=3; MIN_RN=4; MAX_RN=6; CNT_RN=3; AVG_VAL=0",
"GROUP_ID=4; MIN_RN=7; MAX_RN=8; CNT_RN=2; AVG_VAL=1");
+ }
+
+ /**
+ * Tests start_of_group approach for grouping of adjacent intervals.
+ * This is a step1, implemented as last_value.
+ * http://timurakhmadeev.wordpress.com/2013/07/21/start_of_group/
+ */
+ @Test public void testStartOfGroupLastValueStep1() {
+ startOfGroupStep1(
+ "val = last_value(val) over (order by rn rows between 1 preceding and 1 preceding)");
+ }
+ /**
+ * Tests start_of_group approach for grouping of adjacent intervals.
+ * This is a step2, that gets the final group numbers
+ * http://timurakhmadeev.wordpress.com/2013/07/21/start_of_group/
+ */
+ @Test public void testStartOfGroupLastValueStep2() {
+ startOfGroupStep2(
+ "val = last_value(val) over (order by rn rows between 1 preceding and 1 preceding)");
+ }
+
+ /**
+ * Tests start_of_group approach for grouping of adjacent intervals.
+ * This is a step3, that aggregates the computed groups
+ * http://timurakhmadeev.wordpress.com/2013/07/21/start_of_group/
+ */
+ @Test public void testStartOfGroupLastValueStep3() {
+ startOfGroupStep3(
+ "val = last_value(val) over (order by rn rows between 1 preceding and 1 preceding)");
}
/**
@@ -3240,94 +3255,225 @@ public class JdbcTest {
* This is a step1, implemented as last_value.
* http://timurakhmadeev.wordpress.com/2013/07/21/start_of_group/
*/
- @Ignore("LEAD/LAG is not implemented yet")
@Test public void testStartOfGroupLagStep1() {
+ startOfGroupStep1("val = lag(val) over (order by rn)");
+ }
+
+ /**
+ * Tests start_of_group approach for grouping of adjacent intervals.
+ * This is a step2, that gets the final group numbers
+ * http://timurakhmadeev.wordpress.com/2013/07/21/start_of_group/
+ */
+ @Test public void testStartOfGroupLagValueStep2() {
+ startOfGroupStep2("val = lag(val) over (order by rn)");
+ }
+
+ /**
+ * Tests start_of_group approach for grouping of adjacent intervals.
+ * This is a step3, that aggregates the computed groups
+ * http://timurakhmadeev.wordpress.com/2013/07/21/start_of_group/
+ */
+ @Test public void testStartOfGroupLagStep3() {
+ startOfGroupStep3("val = lag(val) over (order by rn)");
+ }
+
+ /**
+ * Tests start_of_group approach for grouping of adjacent intervals.
+ * This is a step1, implemented as last_value.
+ * http://timurakhmadeev.wordpress.com/2013/07/21/start_of_group/
+ */
+ @Test public void testStartOfGroupLeadStep1() {
+ startOfGroupStep1("val = lead(val, -1) over (order by rn)");
+ }
+
+ /**
+ * Tests start_of_group approach for grouping of adjacent intervals.
+ * This is a step2, that gets the final group numbers
+ * http://timurakhmadeev.wordpress.com/2013/07/21/start_of_group/
+ */
+ @Test public void testStartOfGroupLeadValueStep2() {
+ startOfGroupStep2("val = lead(val, -1) over (order by rn)");
+ }
+
+ /**
+ * Tests start_of_group approach for grouping of adjacent intervals.
+ * This is a step3, that aggregates the computed groups
+ * http://timurakhmadeev.wordpress.com/2013/07/21/start_of_group/
+ */
+ @Test public void testStartOfGroupLeadStep3() {
+ startOfGroupStep3("val = lead(val, -1) over (order by rn)");
+ }
+
+ /**
+ * Tests default value of LAG function.
+ */
+ @Test public void testLagDefaultValue() {
OptiqAssert.that()
.with(OptiqAssert.Config.REGULAR)
.query(
- "select t.*\n"
- + " from (\n"
- + " select t.*,\n"
- + " case when val = lag(val) over (order by rn) then 0 else 1 end start_of_group\n"
- + " from ("
- + START_OF_GROUP_DATA
- + ") t\n")
+ "select t.*, lag(rn+expected,1,42) over (order by rn) l\n"
+ + " from " + START_OF_GROUP_DATA)
.typeIs(
- "[RN INTEGER NOT NULL, VAL INTEGER NOT NULL, EXPECTED INTEGER NOT NULL, START_OF_GROUP INTEGER NOT NULL]")
+ "[RN INTEGER NOT NULL, VAL INTEGER NOT NULL, EXPECTED INTEGER NOT NULL, L INTEGER NOT NULL]")
.returnsUnordered(
- "RN=1; VAL=0; EXPECTED=1; START_OF_GROUP=1",
- "RN=2; VAL=0; EXPECTED=1; START_OF_GROUP=0",
- "RN=3; VAL=1; EXPECTED=2; START_OF_GROUP=1",
- "RN=4; VAL=0; EXPECTED=3; START_OF_GROUP=1",
- "RN=5; VAL=0; EXPECTED=3; START_OF_GROUP=0",
- "RN=6; VAL=0; EXPECTED=3; START_OF_GROUP=0",
- "RN=7; VAL=1; EXPECTED=4; START_OF_GROUP=1",
- "RN=8; VAL=1; EXPECTED=4; START_OF_GROUP=0");
+ "RN=1; VAL=0; EXPECTED=1; L=42",
+ "RN=2; VAL=0; EXPECTED=1; L=2",
+ "RN=3; VAL=1; EXPECTED=2; L=3",
+ "RN=4; VAL=0; EXPECTED=3; L=5",
+ "RN=5; VAL=0; EXPECTED=3; L=7",
+ "RN=6; VAL=0; EXPECTED=3; L=8",
+ "RN=7; VAL=1; EXPECTED=4; L=9",
+ "RN=8; VAL=1; EXPECTED=4; L=11");
+ }
+ /**
+ * Tests default value of LEAD function.
+ */
+ @Test public void testLeadDefaultValue() {
+ OptiqAssert.that()
+ .with(OptiqAssert.Config.REGULAR)
+ .query(
+ "select t.*, lead(rn+expected,1,42) over (order by rn) l\n"
+ + " from " + START_OF_GROUP_DATA)
+ .typeIs(
+ "[RN INTEGER NOT NULL, VAL INTEGER NOT NULL, EXPECTED INTEGER NOT NULL, L INTEGER NOT NULL]")
+ .returnsUnordered(
+ "RN=1; VAL=0; EXPECTED=1; L=3",
+ "RN=2; VAL=0; EXPECTED=1; L=5",
+ "RN=3; VAL=1; EXPECTED=2; L=7",
+ "RN=4; VAL=0; EXPECTED=3; L=8",
+ "RN=5; VAL=0; EXPECTED=3; L=9",
+ "RN=6; VAL=0; EXPECTED=3; L=11",
+ "RN=7; VAL=1; EXPECTED=4; L=12",
+ "RN=8; VAL=1; EXPECTED=4; L=42");
}
/**
- * Tests start_of_group approach for grouping of adjacent intervals.
- * This is a step2, that gets the final group numbers
- * http://timurakhmadeev.wordpress.com/2013/07/21/start_of_group/
+ * Tests expression in offset value of LAG function.
*/
- @Ignore("LEAD/LAG is not implemented yet")
- @Test public void testStartOfGroupLagValueStep2() {
+ @Test public void testLagExpressionOffset() {
OptiqAssert.that()
.with(OptiqAssert.Config.REGULAR)
.query(
- "select t.*\n"
- + " ,sum(start_of_group) over (order by rn rows between unbounded preceding and current row) group_id\n"
- + " from (\n"
- + " select t.*,\n"
- + " case when val = lag(val) over (order by rn) then 0 else 1 end start_of_group\n"
- + " from ("
- + START_OF_GROUP_DATA
- + ") t\n")
+ "select t.*, lag(rn, expected, 42) over (order by rn) l\n"
+ + " from " + START_OF_GROUP_DATA)
.typeIs(
- "[RN INTEGER NOT NULL, VAL INTEGER NOT NULL, EXPECTED INTEGER NOT NULL, START_OF_GROUP INTEGER NOT NULL, GROUP_ID INTEGER NOT NULL]")
+ "[RN INTEGER NOT NULL, VAL INTEGER NOT NULL, EXPECTED INTEGER NOT NULL, L INTEGER NOT NULL]")
.returnsUnordered(
- "RN=1; VAL=0; EXPECTED=1; START_OF_GROUP=1; GROUP_ID=1",
- "RN=2; VAL=0; EXPECTED=1; START_OF_GROUP=0; GROUP_ID=1",
- "RN=3; VAL=1; EXPECTED=2; START_OF_GROUP=1; GROUP_ID=2",
- "RN=4; VAL=0; EXPECTED=3; START_OF_GROUP=1; GROUP_ID=3",
- "RN=5; VAL=0; EXPECTED=3; START_OF_GROUP=0; GROUP_ID=3",
- "RN=6; VAL=0; EXPECTED=3; START_OF_GROUP=0; GROUP_ID=3",
- "RN=7; VAL=1; EXPECTED=4; START_OF_GROUP=1; GROUP_ID=4",
- "RN=8; VAL=1; EXPECTED=4; START_OF_GROUP=0; GROUP_ID=4");
+ "RN=1; VAL=0; EXPECTED=1; L=42",
+ "RN=2; VAL=0; EXPECTED=1; L=1",
+ "RN=3; VAL=1; EXPECTED=2; L=1",
+ "RN=4; VAL=0; EXPECTED=3; L=1",
+ "RN=5; VAL=0; EXPECTED=3; L=2",
+ "RN=6; VAL=0; EXPECTED=3; L=3",
+ "RN=7; VAL=1; EXPECTED=4; L=3",
+ "RN=8; VAL=1; EXPECTED=4; L=4");
+ }
+ /**
+ * Tests DATE as offset argument of LAG function.
+ */
+ @Test public void testLagInvalidOffsetArgument() {
+ OptiqAssert.that()
+ .with(OptiqAssert.Config.REGULAR)
+ .query(
+ "select t.*, lag(rn, DATE '2014-06-20', 42) over (order by rn) l\n"
+ + " from " + START_OF_GROUP_DATA)
+ .throws_(
+ "Cannot apply 'LAG' to arguments of type 'LAG(<INTEGER>, <DATE>, <INTEGER>)'");
}
/**
- * Tests start_of_group approach for grouping of adjacent intervals.
- * This is a step3, that aggregates the computed groups
- * http://timurakhmadeev.wordpress.com/2013/07/21/start_of_group/
+ * Tests NTILE(2).
*/
- @Ignore("LEAD/LAG is not implemented yet")
- @Test public void testStartOfGroupLagStep3() {
+ @Test public void testNtile1() {
OptiqAssert.that()
.with(OptiqAssert.Config.REGULAR)
.query(
- "select group_id, min(rn) min_rn, max(rn) max_rn, count(rn) cnt_rn, avg(val) avg_val"
- + " from (\n"
- + "select t.*\n"
- // current row is assumed, group_id should be NOT NULL
- + " ,sum(start_of_group) over (order by rn rows unbounded preceding) group_id\n"
- + " from (\n"
- + " select t.*,\n"
- + " case when val = lag(val) over (order by rn) then 0 else 1 end start_of_group\n"
- + " from ("
- + START_OF_GROUP_DATA
- + ") t\n"
- + ") group by group_id\n")
+ "select rn, ntile(1) over (order by rn) l\n"
+ + " from " + START_OF_GROUP_DATA)
.typeIs(
- "[GROUP_ID INTEGER NOT NULL, MIN_RN INTEGER NOT NULL, MAX_RN INTEGER NOT NULL, CNT_RN BIGINT NOT NULL, AVG_VAL INTEGER NOT NULL]")
+ "[RN INTEGER NOT NULL, L INTEGER NOT NULL]")
.returnsUnordered(
- "GROUP_ID=1; MIN_RN=1; MAX_RN=2; CNT_RN=2; AVG_VAL=0",
- "GROUP_ID=2; MIN_RN=3; MAX_RN=3; CNT_RN=1; AVG_VAL=1",
- "GROUP_ID=3; MIN_RN=4; MAX_RN=6; CNT_RN=3; AVG_VAL=0",
- "GROUP_ID=4; MIN_RN=7; MAX_RN=8; CNT_RN=2; AVG_VAL=1");
+ "RN=1; L=1",
+ "RN=2; L=1",
+ "RN=3; L=1",
+ "RN=4; L=1",
+ "RN=5; L=1",
+ "RN=6; L=1",
+ "RN=7; L=1",
+ "RN=8; L=1");
+ }
+ /**
+ * Tests NTILE(2).
+ */
+ @Test public void testNtile2() {
+ OptiqAssert.that()
+ .with(OptiqAssert.Config.REGULAR)
+ .query(
+ "select rn, ntile(2) over (order by rn) l\n"
+ + " from " + START_OF_GROUP_DATA)
+ .typeIs(
+ "[RN INTEGER NOT NULL, L INTEGER NOT NULL]")
+ .returnsUnordered(
+ "RN=1; L=1",
+ "RN=2; L=1",
+ "RN=3; L=1",
+ "RN=4; L=1",
+ "RN=5; L=2",
+ "RN=6; L=2",
+ "RN=7; L=2",
+ "RN=8; L=2");
+ }
+
+ /**
+ * Tests expression in offset value of LAG function.
+ */
+ @Ignore("Have no idea how to validate that expression is constant")
+ @Test public void testNtileConstantArgs() {
+ OptiqAssert.that()
+ .with(OptiqAssert.Config.REGULAR)
+ .query(
+ "select rn, ntile(1+1) over (order by rn) l\n"
+ + " from " + START_OF_GROUP_DATA)
+ .typeIs(
+ "[RN INTEGER NOT NULL, VAL INTEGER NOT NULL, EXPECTED INTEGER NOT NULL, L INTEGER NOT NULL]")
+ .returnsUnordered(
+ "RN=1; L=1",
+ "RN=2; L=1",
+ "RN=3; L=1",
+ "RN=4; L=1",
+ "RN=5; L=2",
+ "RN=6; L=2",
+ "RN=7; L=2",
+ "RN=8; L=2");
+ }
+
+ /**
+ * Tests expression in offset value of LAG function.
+ */
+ @Test public void testNtileNegativeArg() {
+ OptiqAssert.that()
+ .with(OptiqAssert.Config.REGULAR)
+ .query(
+ "select rn, ntile(-1) over (order by rn) l\n"
+ + " from " + START_OF_GROUP_DATA)
+ .throws_(
+ "Argument to function 'NTILE' must be a positive integer literal");
+ }
+
+ /**
+ * Tests expression in offset value of LAG function.
+ */
+ @Test public void testNtileDecimalArg() {
+ OptiqAssert.that()
+ .with(OptiqAssert.Config.REGULAR)
+ .query(
+ "select rn, ntile(3.141592653) over (order by rn) l\n"
+ + " from " + START_OF_GROUP_DATA)
+ .throws_(
+ "Cannot apply 'NTILE' to arguments of type 'NTILE(<DECIMAL(10, 9)>)'");
}
/** Tests for FIRST_VALUE */