test(sql): cover rangeFrameEntirelyPastThePartitionEdgeAggregatesToNu...
This commit is contained in:
1 parent
613cb1ecef
commit
5d49c4c96d
1 file changed
+162
@@ -2534,3 +2534,165 @@ class DiskExecutorTest {
|
|||||||
assertEquals(listOf(2L, 2L, 2L, 2L, 1L), result.rows.map { (it[1] as Value.IntegerValue).value })
|
assertEquals(listOf(2L, 2L, 2L, 2L, 1L), result.rows.map { (it[1] as Value.IntegerValue).value })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun rangeFrameEntirelyPastThePartitionEdgeAggregatesToNullAndCountsZero() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedWindowSales()
|
||||||
|
val result = db.select(
|
||||||
|
"SELECT id, SUM(amount) OVER (ORDER BY amount RANGE BETWEEN 100 FOLLOWING AND 200 FOLLOWING) AS s, " +
|
||||||
|
"COUNT(*) OVER (ORDER BY amount RANGE BETWEEN 100 FOLLOWING AND 200 FOLLOWING) AS c " +
|
||||||
|
"FROM sales ORDER BY id ASC"
|
||||||
|
)
|
||||||
|
assertEquals((1L..5L).map { listOf(int(it), Value.NullValue, int(0)) }, result.rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun rangeFrameWithAPrecedingBoundRequiresExactlyOneOrderByColumn() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedWindowSales()
|
||||||
|
val error = assertFailsWith<DiskExecutorException> {
|
||||||
|
db.run("SELECT SUM(amount) OVER (ORDER BY amount, id RANGE BETWEEN 10 PRECEDING AND 10 FOLLOWING) FROM sales")
|
||||||
|
}
|
||||||
|
assertTrue(error.message!!.contains("exactly one ORDER BY column"), error.message!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun rangeFrameWithAPrecedingBoundRequiresANumericOrDateOrderColumn() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedWindowEmployees()
|
||||||
|
val error = assertFailsWith<DiskExecutorException> {
|
||||||
|
db.run("SELECT SUM(salary) OVER (ORDER BY name RANGE BETWEEN 1 PRECEDING AND CURRENT ROW) FROM employees")
|
||||||
|
}
|
||||||
|
assertTrue(error.message!!.contains("numeric or DATE"), error.message!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun rangeFrameOffsetMustBeNumeric() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedWindowSales()
|
||||||
|
val error = assertFailsWith<DiskExecutorException> {
|
||||||
|
db.run("SELECT SUM(amount) OVER (ORDER BY amount RANGE BETWEEN 'x' PRECEDING AND CURRENT ROW) FROM sales")
|
||||||
|
}
|
||||||
|
assertTrue(error.message!!.contains("numeric"), error.message!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun rangeFrameOffsetMustNotBeNegative() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedWindowSales()
|
||||||
|
val error = assertFailsWith<DiskExecutorException> {
|
||||||
|
db.run("SELECT SUM(amount) OVER (ORDER BY amount RANGE BETWEEN -1 PRECEDING AND CURRENT ROW) FROM sales")
|
||||||
|
}
|
||||||
|
assertTrue(error.message!!.contains("negative"), error.message!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun groupsBetweenPrecedingAndFollowingCountsPeerGroupsNotPhysicalRows() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedWindowSales()
|
||||||
|
val groups = db.select(
|
||||||
|
"SELECT id, SUM(amount) OVER (ORDER BY amount GROUPS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS s FROM sales ORDER BY id ASC"
|
||||||
|
)
|
||||||
|
val rows = db.select(
|
||||||
|
"SELECT id, SUM(amount) OVER (ORDER BY amount ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS s FROM sales ORDER BY id ASC"
|
||||||
|
)
|
||||||
|
assertEquals(listOf(50L, 80L, 80L, 120L, 80L), groups.rows.map { (it[1] as Value.IntegerValue).value })
|
||||||
|
assertEquals(listOf(30L, 50L, 70L, 100L, 80L), rows.rows.map { (it[1] as Value.IntegerValue).value })
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun groupsCurrentRowExpandsToTheWholePeerGroupJustLikeRangeCurrentRow() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedWindowSales()
|
||||||
|
val groups = db.select(
|
||||||
|
"SELECT id, SUM(amount) OVER (ORDER BY amount GROUPS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS s FROM sales ORDER BY id ASC"
|
||||||
|
)
|
||||||
|
val range = db.select(
|
||||||
|
"SELECT id, SUM(amount) OVER (ORDER BY amount RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS s FROM sales ORDER BY id ASC"
|
||||||
|
)
|
||||||
|
assertEquals(listOf(10L, 50L, 50L, 80L, 130L), groups.rows.map { (it[1] as Value.IntegerValue).value })
|
||||||
|
assertEquals(groups.rows, range.rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun groupsFrameWorksWithAMultiColumnNonNumericOrderByUnlikeRange() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedWindowEmployees()
|
||||||
|
val result = db.select(
|
||||||
|
"SELECT id, COUNT(*) OVER (ORDER BY deptId, name GROUPS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS c " +
|
||||||
|
"FROM employees ORDER BY deptId ASC, name ASC"
|
||||||
|
)
|
||||||
|
assertEquals(listOf(int(1), int(3), int(2), int(5), int(6), int(4)), result.rows.map { it[0] })
|
||||||
|
assertEquals(listOf(2L, 3L, 3L, 3L, 3L, 2L), result.rows.map { (it[1] as Value.IntegerValue).value })
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun groupsFrameEntirelyPastThePartitionEdgeAggregatesToNullAndCountsZero() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedWindowSales()
|
||||||
|
val result = db.select(
|
||||||
|
"SELECT id, SUM(amount) OVER (ORDER BY amount GROUPS BETWEEN 100 FOLLOWING AND 200 FOLLOWING) AS s, " +
|
||||||
|
"COUNT(*) OVER (ORDER BY amount GROUPS BETWEEN 100 FOLLOWING AND 200 FOLLOWING) AS c " +
|
||||||
|
"FROM sales ORDER BY id ASC"
|
||||||
|
)
|
||||||
|
assertEquals((1L..5L).map { listOf(int(it), Value.NullValue, int(0)) }, result.rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun groupsFrameIsRejectedOnRankingAndOffsetWindowFunctions() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedWindowEmployees()
|
||||||
|
val error = assertFailsWith<DiskExecutorException> {
|
||||||
|
db.run("SELECT ROW_NUMBER() OVER (ORDER BY id GROUPS BETWEEN 1 PRECEDING AND CURRENT ROW) FROM employees")
|
||||||
|
}
|
||||||
|
assertTrue(error.message!!.contains("GROUPS"), error.message!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun excludeCurrentRowRemovesOnlyTheCurrentRowFromTheWholePartitionFrame() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedWindowSales()
|
||||||
|
val result = db.select(
|
||||||
|
"SELECT id, SUM(amount) OVER (" +
|
||||||
|
"ORDER BY amount ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW" +
|
||||||
|
") AS s FROM sales ORDER BY id ASC"
|
||||||
|
)
|
||||||
|
assertEquals(listOf(120L, 110L, 110L, 100L, 80L), result.rows.map { (it[1] as Value.IntegerValue).value })
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun excludeGroupRemovesTheWholePeerGroupIncludingTheCurrentRow() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedWindowSales()
|
||||||
|
val result = db.select(
|
||||||
|
"SELECT id, SUM(amount) OVER (" +
|
||||||
|
"ORDER BY amount RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE GROUP" +
|
||||||
|
") AS s FROM sales ORDER BY id ASC"
|
||||||
|
)
|
||||||
|
assertEquals(listOf(120L, 90L, 90L, 100L, 80L), result.rows.map { (it[1] as Value.IntegerValue).value })
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun excludeTiesRemovesOnlyTheOtherTiedRowsAndKeepsTheCurrentRow() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedWindowSales()
|
||||||
|
val result = db.select(
|
||||||
|
"SELECT id, SUM(amount) OVER (" +
|
||||||
|
"ORDER BY amount RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE TIES" +
|
||||||
|
") AS s FROM sales ORDER BY id ASC"
|
||||||
|
)
|
||||||
|
assertEquals(listOf(130L, 110L, 110L, 130L, 130L), result.rows.map { (it[1] as Value.IntegerValue).value })
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun excludeCurrentRowInteractsWithABoundedFrameInsteadOfOnlyTheWholePartition() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedWindowSales()
|
||||||
|
val result = db.select(
|
||||||
|
"SELECT id, SUM(amount) OVER (" +
|
||||||
|
"ORDER BY amount ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING EXCLUDE CURRENT ROW" +
|
||||||
|
") AS s FROM sales ORDER BY id ASC"
|
||||||
|
)
|
||||||
|
assertEquals(listOf(20L, 30L, 50L, 70L, 30L), result.rows.map { (it[1] as Value.IntegerValue).value })
|
||||||
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user