diff --git a/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java b/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java index ca6e357469d0..6e52d841e4ad 100644 --- a/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java +++ b/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java @@ -1045,7 +1045,10 @@ public List toSql(Window.Group group, ImmutableList constan }; RexCall aggCall = (RexCall) winAggCall.accept(replaceConstants); List operands = toSql(null, aggCall.operands); - rexOvers.add(createOverCall(aggFunction, operands, sqlWindow, winAggCall.distinct)); + final SqlCall overCall = + createOverCall(aggFunction, operands, sqlWindow, + winAggCall.distinct, winAggCall.ignoreNulls); + rexOvers.add(overCall); } return rexOvers; } @@ -1092,15 +1095,16 @@ private SqlCall toSql(@Nullable RexProgram program, RexOver rexOver) { orderList, isRows, lowerBound, upperBound, allowPartial, exclude, POS); final List nodeList = toSql(program, rexOver.getOperands()); - return createOverCall(sqlAggregateFunction, nodeList, sqlWindow, rexOver.isDistinct()); + return createOverCall(sqlAggregateFunction, nodeList, sqlWindow, + rexOver.isDistinct(), rexOver.ignoreNulls()); } private static SqlCall createOverCall(SqlAggFunction op, List operands, - SqlWindow window, boolean isDistinct) { + SqlWindow window, boolean isDistinct, boolean ignoreNulls) { if (op instanceof SqlSumEmptyIsZeroAggFunction) { // Rewrite "SUM0(x) OVER w" to "COALESCE(SUM(x) OVER w, 0)" final SqlCall node = - createOverCall(SqlStdOperatorTable.SUM, operands, window, isDistinct); + createOverCall(SqlStdOperatorTable.SUM, operands, window, isDistinct, ignoreNulls); return SqlStdOperatorTable.COALESCE.createCall(POS, node, ZERO); } SqlCall aggFunctionCall; @@ -1110,6 +1114,10 @@ private static SqlCall createOverCall(SqlAggFunction op, List operands, } else { aggFunctionCall = op.createCall(POS, operands); } + if (ignoreNulls) { + aggFunctionCall = + SqlStdOperatorTable.IGNORE_NULLS.createCall(null, POS, aggFunctionCall); + } return SqlStdOperatorTable.OVER.createCall(POS, aggFunctionCall, window); } diff --git a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java index d855bb96c380..6eba6a16ccd1 100644 --- a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java +++ b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java @@ -4584,6 +4584,32 @@ private void checkLiteral2(String expression, String expected) { sql(query).ok(expected); } + /** Test case for + * [CALCITE-6569] + * RelToSqlConverter support IGNORE NULLS for window functions. */ + @Test void testIgnoreNullsWindow() { + final String query0 = "SELECT LEAD(\"employee_id\", 2) IGNORE NULLS " + + "OVER (ORDER BY \"hire_date\") FROM \"employee\""; + final String expected0 = "SELECT LEAD(\"employee_id\", 2) IGNORE NULLS OVER (ORDER BY " + + "\"hire_date\")\n" + + "FROM \"foodmart\".\"employee\""; + sql(query0).ok(expected0); + + final String query1 = "SELECT " + + "LAG(\"employee_id\", 1) IGNORE NULLS OVER (ORDER BY \"hire_date\")," + + "FIRST_VALUE(\"employee_id\") IGNORE NULLS OVER (ORDER BY \"hire_date\")," + + "LAST_VALUE(\"employee_id\") IGNORE NULLS OVER (ORDER BY \"hire_date\")" + + "FROM \"employee\""; + final String expected1 = "SELECT " + + "LAG(\"employee_id\", 1) IGNORE NULLS OVER (ORDER BY \"hire_date\"), " + + "FIRST_VALUE(\"employee_id\") IGNORE NULLS OVER (ORDER BY \"hire_date\"" + + " RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW), " + + "LAST_VALUE(\"employee_id\") IGNORE NULLS OVER (ORDER BY \"hire_date\"" + + " RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)\n" + + "FROM \"foodmart\".\"employee\""; + sql(query1).ok(expected1); + } + /** Test case for * [CALCITE-3112] * Support Window in RelToSqlConverter. */