diff --git a/presto-main/src/test/java/com/facebook/presto/operator/window/TestWindowFunctions.java b/presto-main/src/test/java/com/facebook/presto/operator/window/TestWindowFunctions.java index e56df3969a749..a248fdb739889 100644 --- a/presto-main/src/test/java/com/facebook/presto/operator/window/TestWindowFunctions.java +++ b/presto-main/src/test/java/com/facebook/presto/operator/window/TestWindowFunctions.java @@ -15,13 +15,12 @@ import com.facebook.presto.testing.LocalQueryRunner; import com.facebook.presto.testing.MaterializedResult; -import com.facebook.presto.tpch.TpchConnectorFactory; -import com.google.common.collect.ImmutableMap; import org.testng.annotations.AfterClass; import org.testng.annotations.Test; import static com.facebook.presto.SessionTestUtils.TEST_SESSION; import static com.facebook.presto.operator.window.WindowAssertions.assertWindowQuery; +import static com.facebook.presto.operator.window.WindowAssertions.assertWindowQueryWithNulls; import static com.facebook.presto.spi.type.BigintType.BIGINT; import static com.facebook.presto.spi.type.DoubleType.DOUBLE; import static com.facebook.presto.spi.type.VarcharType.VARCHAR; @@ -34,7 +33,6 @@ public class TestWindowFunctions public TestWindowFunctions() { queryRunner = new LocalQueryRunner(TEST_SESSION); - queryRunner.createCatalog("tpch", new TpchConnectorFactory(queryRunner.getNodeManager(), 1), ImmutableMap.of()); } @AfterClass @@ -58,9 +56,24 @@ public void testRowNumber() .row(33, "F", 9) .row(34, "O", 10) .build(); + MaterializedResult expectedWithNulls = resultBuilder(TEST_SESSION, BIGINT, VARCHAR, BIGINT) + .row(1, null, 1) + .row(3, "F", 2) + .row(5, "F", 3) + .row(7, null, 4) + .row(34, "O", 5) + .row(null, "F", 6) + .row(null, "F", 7) + .row(null, "O", 8) + .row(null, null, 9) + .row(null, null, 10) + .build(); assertWindowQuery("row_number() OVER ()", expected, queryRunner); assertWindowQuery("row_number() OVER (ORDER BY orderkey)", expected, queryRunner); + + assertWindowQueryWithNulls("row_number() OVER ()", expectedWithNulls, queryRunner); + assertWindowQueryWithNulls("row_number() OVER (ORDER BY orderkey)", expectedWithNulls, queryRunner); } @Test @@ -80,6 +93,20 @@ public void testRank() .row(34, "O", 5) .build(), queryRunner ); + assertWindowQueryWithNulls("rank() OVER (ORDER BY orderstatus)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, BIGINT) + .row(3, "F", 1) + .row(5, "F", 1) + .row(null, "F", 1) + .row(null, "F", 1) + .row(34, "O", 5) + .row(null, "O", 5) + .row(1, null, 7) + .row(7, null, 7) + .row(null, null, 7) + .row(null, null, 7) + .build(), queryRunner + ); } @Test @@ -99,6 +126,20 @@ public void testDenseRank() .row(34, "O", 2) .build(), queryRunner ); + assertWindowQueryWithNulls("dense_rank() OVER (ORDER BY orderstatus)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, BIGINT) + .row(3, "F", 1) + .row(5, "F", 1) + .row(null, "F", 1) + .row(null, "F", 1) + .row(34, "O", 2) + .row(null, "O", 2) + .row(1, null, 3) + .row(7, null, 3) + .row(null, null, 3) + .row(null, null, 3) + .build(), queryRunner + ); } @Test @@ -118,6 +159,20 @@ public void testPercentRank() .row(34, "O", 1.0) .build(), queryRunner ); + assertWindowQueryWithNulls("percent_rank() OVER (PARTITION BY orderstatus ORDER BY orderkey)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, BIGINT) + .row(3, "F", 0.0) + .row(5, "F", 1 / 3.0) + .row(null, "F", 2 / 3.0) + .row(null, "F", 2 / 3.0) + .row(34, "O", 0.0) + .row(null, "O", 1.0) + .row(1, null, 0.0) + .row(7, null, 1 / 3.0) + .row(null, null, 2 / 3.0) + .row(null, null, 2 / 3.0) + .build(), queryRunner + ); assertWindowQuery("percent_rank() OVER (ORDER BY orderkey)", resultBuilder(TEST_SESSION, BIGINT, VARCHAR, DOUBLE) @@ -133,6 +188,20 @@ public void testPercentRank() .row(34, "O", 1.0) .build(), queryRunner ); + assertWindowQueryWithNulls("percent_rank() OVER (ORDER BY orderkey)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, BIGINT) + .row(1, null, 0.0) + .row(3, "F", 1 / 9.0) + .row(5, "F", 2 / 9.0) + .row(7, null, 3 / 9.0) + .row(34, "O", 4 / 9.0) + .row(null, "F", 5 / 9.0) + .row(null, "F", 5 / 9.0) + .row(null, "O", 5 / 9.0) + .row(null, null, 5 / 9.0) + .row(null, null, 5 / 9.0) + .build(), queryRunner + ); assertWindowQuery("percent_rank() OVER (ORDER BY orderstatus)", resultBuilder(TEST_SESSION, BIGINT, VARCHAR, DOUBLE) @@ -148,6 +217,20 @@ public void testPercentRank() .row(34, "O", 4 / 9.0) .build(), queryRunner ); + assertWindowQueryWithNulls("percent_rank() OVER (ORDER BY orderstatus)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, BIGINT) + .row(3, "F", 0.0) + .row(5, "F", 0.0) + .row(null, "F", 0.0) + .row(null, "F", 0.0) + .row(34, "O", 4 / 9.0) + .row(null, "O", 4 / 9.0) + .row(1, null, 6 / 9.0) + .row(7, null, 6 / 9.0) + .row(null, null, 6 / 9.0) + .row(null, null, 6 / 9.0) + .build(), queryRunner + ); assertWindowQuery("percent_rank() OVER (PARTITION BY orderkey)", resultBuilder(TEST_SESSION, BIGINT, VARCHAR, DOUBLE) @@ -163,6 +246,20 @@ public void testPercentRank() .row(34, "O", 0.0) .build(), queryRunner ); + assertWindowQueryWithNulls("percent_rank() OVER (PARTITION BY orderkey)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, BIGINT) + .row(1, null, 0.0) + .row(3, "F", 0.0) + .row(5, "F", 0.0) + .row(7, null, 0.0) + .row(34, "O", 0.0) + .row(null, "F", 0.0) + .row(null, "F", 0.0) + .row(null, "O", 0.0) + .row(null, null, 0.0) + .row(null, null, 0.0) + .build(), queryRunner + ); } @Test @@ -182,6 +279,20 @@ public void testCumulativeDistribution() .row(34, "O", 1.0) .build(), queryRunner ); + assertWindowQueryWithNulls("cume_dist() OVER (PARTITION BY orderstatus ORDER BY orderkey)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, DOUBLE) + .row(3, "F", 0.25) + .row(5, "F", 0.5) + .row(null, "F", 1.0) + .row(null, "F", 1.0) + .row(34, "O", 0.5) + .row(null, "O", 1.0) + .row(1, null, 0.25) + .row(7, null, 0.5) + .row(null, null, 1.0) + .row(null, null, 1.0) + .build(), queryRunner + ); assertWindowQuery("cume_dist() OVER (ORDER BY orderkey)", resultBuilder(TEST_SESSION, BIGINT, VARCHAR, DOUBLE) @@ -197,6 +308,20 @@ public void testCumulativeDistribution() .row(34, "O", 1.0) .build(), queryRunner ); + assertWindowQueryWithNulls("cume_dist() OVER (ORDER BY orderkey)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, DOUBLE) + .row(1, null, 0.1) + .row(3, "F", 0.2) + .row(5, "F", 0.3) + .row(7, null, 0.4) + .row(34, "O", 0.5) + .row(null, "F", 1.0) + .row(null, "F", 1.0) + .row(null, "O", 1.0) + .row(null, null, 1.0) + .row(null, null, 1.0) + .build(), queryRunner + ); assertWindowQuery("cume_dist() OVER (ORDER BY orderstatus)", resultBuilder(TEST_SESSION, BIGINT, VARCHAR, DOUBLE) @@ -212,6 +337,20 @@ public void testCumulativeDistribution() .row(34, "O", 1.0) .build(), queryRunner ); + assertWindowQueryWithNulls("cume_dist() OVER (ORDER BY orderstatus)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, DOUBLE) + .row(3, "F", 0.4) + .row(5, "F", 0.4) + .row(null, "F", 0.4) + .row(null, "F", 0.4) + .row(34, "O", 0.6) + .row(null, "O", 0.6) + .row(1, null, 1.0) + .row(7, null, 1.0) + .row(null, null, 1.0) + .row(null, null, 1.0) + .build(), queryRunner + ); assertWindowQuery("cume_dist() OVER (PARTITION BY orderkey)", resultBuilder(TEST_SESSION, BIGINT, VARCHAR, DOUBLE) @@ -227,6 +366,20 @@ public void testCumulativeDistribution() .row(34, "O", 1.0) .build(), queryRunner ); + assertWindowQueryWithNulls("cume_dist() OVER (PARTITION BY orderkey)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, DOUBLE) + .row(1, null, 1.0) + .row(3, "F", 1.0) + .row(5, "F", 1.0) + .row(7, null, 1.0) + .row(34, "O", 1.0) + .row(null, "F", 1.0) + .row(null, "F", 1.0) + .row(null, "O", 1.0) + .row(null, null, 1.0) + .row(null, null, 1.0) + .build(), queryRunner + ); } @Test @@ -245,6 +398,19 @@ public void testFirstValue() .row(32, "O", "1996-01-02") .row(34, "O", "1996-01-02") .build(), queryRunner); + assertWindowQueryWithNulls("first_value(orderdate) OVER (PARTITION BY orderstatus ORDER BY orderkey)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, VARCHAR) + .row(3, "F", "1993-10-14") + .row(5, "F", "1993-10-14") + .row(null, "F", "1993-10-14") + .row(null, "F", "1993-10-14") + .row(34, "O", "1998-07-21") + .row(null, "O", "1998-07-21") + .row(1, null, null) + .row(7, null, null) + .row(null, null, null) + .row(null, null, null) + .build(), queryRunner); assertWindowQuery("first_value(orderkey) OVER (PARTITION BY orderstatus ORDER BY orderkey)", resultBuilder(TEST_SESSION, BIGINT, VARCHAR, BIGINT) @@ -259,7 +425,19 @@ public void testFirstValue() .row(32, "O", 1) .row(34, "O", 1) .build(), queryRunner); - + assertWindowQueryWithNulls("first_value(orderkey) OVER (PARTITION BY orderstatus ORDER BY orderkey)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, BIGINT) + .row(3, "F", 3) + .row(5, "F", 3) + .row(null, "F", 3) + .row(null, "F", 3) + .row(34, "O", 34) + .row(null, "O", 34) + .row(1, null, 1) + .row(7, null, 1) + .row(null, null, 1) + .row(null, null, 1) + .build(), queryRunner); } @Test @@ -278,6 +456,19 @@ public void testLastValue() .row(32, "O", "1998-07-21") .row(34, "O", "1998-07-21") .build(), queryRunner); + assertWindowQueryWithNulls("last_value(orderdate) OVER (PARTITION BY orderstatus ORDER BY orderkey)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, VARCHAR) + .row(3, "F", "1992-02-21") + .row(5, "F", "1992-02-21") + .row(null, "F", "1992-02-21") + .row(null, "F", "1992-02-21") + .row(34, "O", "1996-12-01") + .row(null, "O", "1996-12-01") + .row(1, null, "1995-07-16") + .row(7, null, "1995-07-16") + .row(null, null, "1995-07-16") + .row(null, null, "1995-07-16") + .build(), queryRunner); assertWindowQuery("last_value(orderkey) OVER (PARTITION BY orderstatus ORDER BY orderkey)", resultBuilder(TEST_SESSION, BIGINT, VARCHAR, BIGINT) @@ -292,7 +483,19 @@ public void testLastValue() .row(32, "O", 34) .row(34, "O", 34) .build(), queryRunner); - + assertWindowQueryWithNulls("last_value(orderkey) OVER (PARTITION BY orderstatus ORDER BY orderkey)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, BIGINT) + .row(3, "F", null) + .row(5, "F", null) + .row(null, "F", null) + .row(null, "F", null) + .row(34, "O", null) + .row(null, "O", null) + .row(1, null, null) + .row(7, null, null) + .row(null, null, null) + .row(null, null, null) + .build(), queryRunner); } @Test @@ -311,6 +514,46 @@ public void testLagFunction() .row(32, "O", "1996-01-10") .row(34, "O", "1995-07-16") .build(), queryRunner); + assertWindowQueryWithNulls("lag(orderdate) OVER (PARTITION BY orderstatus ORDER BY orderkey)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, VARCHAR) + .row(3, "F", null) + .row(5, "F", "1993-10-14") + .row(null, "F", null) + .row(null, "F", "1993-10-27") + .row(34, "O", null) + .row(null, "O", "1998-07-21") + .row(1, null, null) + .row(7, null, null) + .row(null, null, "1996-01-10") + .row(null, null, null) + .build(), queryRunner); + + assertWindowQuery("lag(orderkey) OVER (PARTITION BY orderstatus ORDER BY orderkey)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, BIGINT) + .row(3, "F", null) + .row(5, "F", 3) + .row(6, "F", 5) + .row(33, "F", 6) + .row(1, "O", null) + .row(2, "O", 1) + .row(4, "O", 2) + .row(7, "O", 4) + .row(32, "O", 7) + .row(34, "O", 32) + .build(), queryRunner); + assertWindowQueryWithNulls("lag(orderkey) OVER (PARTITION BY orderstatus ORDER BY orderkey)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, BIGINT) + .row(3, "F", null) + .row(5, "F", 3) + .row(null, "F", 5) + .row(null, "F", null) + .row(34, "O", null) + .row(null, "O", 34) + .row(1, null, null) + .row(7, null, 1) + .row(null, null, 7) + .row(null, null, null) + .build(), queryRunner); assertWindowQuery("lag(orderdate, 2, '1977-01-01') OVER (PARTITION BY orderstatus ORDER BY orderkey)", resultBuilder(TEST_SESSION, BIGINT, VARCHAR, VARCHAR) @@ -325,7 +568,46 @@ public void testLagFunction() .row(32, "O", "1995-10-11") .row(34, "O", "1996-01-10") .build(), queryRunner); + assertWindowQueryWithNulls("lag(orderdate, 2, '1977-01-01') OVER (PARTITION BY orderstatus ORDER BY orderkey)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, VARCHAR) + .row(3, "F", "1977-01-01") + .row(5, "F", "1977-01-01") + .row(null, "F", "1993-10-14") + .row(null, "F", null) + .row(34, "O", "1977-01-01") + .row(null, "O", "1977-01-01") + .row(1, null, "1977-01-01") + .row(7, null, "1977-01-01") + .row(null, null, null) + .row(null, null, "1996-01-10") + .build(), queryRunner); + assertWindowQuery("lag(orderkey, 2, -1) OVER (PARTITION BY orderstatus ORDER BY orderkey)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, BIGINT) + .row(3, "F", -1) + .row(5, "F", -1) + .row(6, "F", 3) + .row(33, "F", 5) + .row(1, "O", -1) + .row(2, "O", -1) + .row(4, "O", 1) + .row(7, "O", 2) + .row(32, "O", 4) + .row(34, "O", 7) + .build(), queryRunner); + assertWindowQueryWithNulls("lag(orderkey, 2, -1) OVER (PARTITION BY orderstatus ORDER BY orderkey)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, BIGINT) + .row(3, "F", -1) + .row(5, "F", -1) + .row(null, "F", 3) + .row(null, "F", 5) + .row(34, "O", -1) + .row(null, "O", -1) + .row(1, null, -1) + .row(7, null, -1) + .row(null, null, 1) + .row(null, null, 7) + .build(), queryRunner); } @Test @@ -344,6 +626,46 @@ public void testLeadFunction() .row(32, "O", "1998-07-21") .row(34, "O", null) .build(), queryRunner); + assertWindowQueryWithNulls("lead(orderdate) OVER (PARTITION BY orderstatus ORDER BY orderkey)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, VARCHAR) + .row(3, "F", null) + .row(5, "F", "1993-10-27") + .row(null, "F", "1992-02-21") + .row(null, "F", null) + .row(34, "O", "1996-12-01") + .row(null, "O", null) + .row(1, null, "1996-01-10") + .row(7, null, null) + .row(null, null, "1995-07-16") + .row(null, null, null) + .build(), queryRunner); + + assertWindowQuery("lead(orderkey) OVER (PARTITION BY orderstatus ORDER BY orderkey)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, BIGINT) + .row(3, "F", 5) + .row(5, "F", 6) + .row(6, "F", 33) + .row(33, "F", null) + .row(1, "O", 2) + .row(2, "O", 4) + .row(4, "O", 7) + .row(7, "O", 32) + .row(32, "O", 34) + .row(34, "O", null) + .build(), queryRunner); + assertWindowQueryWithNulls("lead(orderkey) OVER (PARTITION BY orderstatus ORDER BY orderkey)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, BIGINT) + .row(3, "F", 5) + .row(5, "F", null) + .row(null, "F", null) + .row(null, "F", null) + .row(34, "O", null) + .row(null, "O", null) + .row(1, null, 7) + .row(7, null, null) + .row(null, null, null) + .row(null, null, null) + .build(), queryRunner); assertWindowQuery("lead(orderdate, 2, '1977-01-01') OVER (PARTITION BY orderstatus ORDER BY orderkey)", resultBuilder(TEST_SESSION, BIGINT, VARCHAR, VARCHAR) @@ -358,6 +680,45 @@ public void testLeadFunction() .row(32, "O", "1977-01-01") .row(34, "O", "1977-01-01") .build(), queryRunner); + assertWindowQueryWithNulls("lead(orderdate, 2, '1977-01-01') OVER (PARTITION BY orderstatus ORDER BY orderkey)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, VARCHAR) + .row(3, "F", "1993-10-27") + .row(5, "F", "1992-02-21") + .row(null, "F", "1977-01-01") + .row(null, "F", "1977-01-01") + .row(34, "O", "1977-01-01") + .row(null, "O", "1977-01-01") + .row(1, null, null) + .row(7, null, "1995-07-16") + .row(null, null, "1977-01-01") + .row(null, null, "1977-01-01") + .build(), queryRunner); + assertWindowQuery("lead(orderkey, 2, -1) OVER (PARTITION BY orderstatus ORDER BY orderkey)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, BIGINT) + .row(3, "F", 6) + .row(5, "F", 33) + .row(6, "F", -1) + .row(33, "F", -1) + .row(1, "O", 4) + .row(2, "O", 7) + .row(4, "O", 32) + .row(7, "O", 34) + .row(32, "O", -1) + .row(34, "O", -1) + .build(), queryRunner); + assertWindowQueryWithNulls("lead(orderkey, 2, -1) OVER (PARTITION BY orderstatus ORDER BY orderkey)", + resultBuilder(TEST_SESSION, BIGINT, VARCHAR, BIGINT) + .row(3, "F", null) + .row(5, "F", null) + .row(null, "F", -1) + .row(null, "F", -1) + .row(34, "O", -1) + .row(null, "O", -1) + .row(1, null, null) + .row(7, null, null) + .row(null, null, -1) + .row(null, null, -1) + .build(), queryRunner); } } diff --git a/presto-main/src/test/java/com/facebook/presto/operator/window/WindowAssertions.java b/presto-main/src/test/java/com/facebook/presto/operator/window/WindowAssertions.java index 3ee5b48fc7233..816b99009c42b 100644 --- a/presto-main/src/test/java/com/facebook/presto/operator/window/WindowAssertions.java +++ b/presto-main/src/test/java/com/facebook/presto/operator/window/WindowAssertions.java @@ -22,14 +22,57 @@ public final class WindowAssertions { + private static final String VALUES = "" + + "SELECT *\n" + + "FROM (\n" + + " VALUES\n" + + " ( 1, 'O', '1996-01-02'),\n" + + " ( 2, 'O', '1996-12-01'),\n" + + " ( 3, 'F', '1993-10-14'),\n" + + " ( 4, 'O', '1995-10-11'),\n" + + " ( 5, 'F', '1994-07-30'),\n" + + " ( 6, 'F', '1992-02-21'),\n" + + " ( 7, 'O', '1996-01-10'),\n" + + " (32, 'O', '1995-07-16'),\n" + + " (33, 'F', '1993-10-27'),\n" + + " (34, 'O', '1998-07-21')\n" + + ") AS orders (orderkey, orderstatus, orderdate)"; + + private static final String VALUES_WITH_NULLS = "" + + "SELECT *\n" + + "FROM (\n" + + " VALUES\n" + + " ( 1, CAST(NULL AS VARCHAR), CAST(NULL AS VARCHAR)),\n" + + " ( 3, 'F', '1993-10-14'),\n" + + " ( 5, 'F', CAST(NULL AS VARCHAR)),\n" + + " ( 7, CAST(NULL AS VARCHAR), '1996-01-10'),\n" + + " (34, 'O', '1998-07-21'),\n" + + " (CAST(NULL AS BIGINT), 'F', '1992-02-21'),\n" + + " (CAST(NULL AS BIGINT), 'F', '1993-10-27'),\n" + + " (CAST(NULL AS BIGINT), 'O', '1996-12-01'),\n" + + " (CAST(NULL AS BIGINT), CAST(NULL AS VARCHAR), CAST(NULL AS VARCHAR)),\n" + + " (CAST(NULL AS BIGINT), CAST(NULL AS VARCHAR), '1995-07-16')\n" + + ") AS orders (orderkey, orderstatus, orderdate)"; + private WindowAssertions() {} public static void assertWindowQuery(@Language("SQL") String sql, MaterializedResult expected, LocalQueryRunner localQueryRunner) { @Language("SQL") String query = format("" + "SELECT orderkey, orderstatus,\n%s\n" + - "FROM (SELECT * FROM orders ORDER BY orderkey LIMIT 10) x\n" + - "ORDER BY orderkey", sql); + "FROM (%s) x\n" + + "ORDER BY orderkey", sql, VALUES); + + MaterializedResult actual = localQueryRunner.execute(query); + assertEqualsIgnoreOrder(actual.getMaterializedRows(), expected.getMaterializedRows()); + } + + public static void assertWindowQueryWithNulls(@Language("SQL") String sql, MaterializedResult expected, LocalQueryRunner localQueryRunner) + { + @Language("SQL") String query = format("" + + "SELECT orderkey, orderstatus,\n%s\n" + + "FROM (%s) x\n" + + "ORDER BY orderkey", sql, VALUES_WITH_NULLS); MaterializedResult actual = localQueryRunner.execute(query); assertEqualsIgnoreOrder(actual.getMaterializedRows(), expected.getMaterializedRows());