test(sql): cover frameEntirelyPastThePartitionEdgeAggregatesToNullAnd...
This commit is contained in:
1 parent
f5cf5f187c
commit
613cb1ecef
1 file changed
+161
@@ -2373,3 +2373,164 @@ class DiskExecutorTest {
|
||||
assertEquals(implicit.rows, explicit.rows)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun frameEntirelyPastThePartitionEdgeAggregatesToNullAndCountsZero() {
|
||||
val db = newDatabase()
|
||||
db.seedWindowEmployees()
|
||||
val result = db.select(
|
||||
"SELECT id, SUM(salary) OVER (PARTITION BY deptId ORDER BY id ROWS BETWEEN 5 FOLLOWING AND 9 FOLLOWING) AS s, " +
|
||||
"COUNT(*) OVER (PARTITION BY deptId ORDER BY id ROWS BETWEEN 5 FOLLOWING AND 9 FOLLOWING) AS c " +
|
||||
"FROM employees WHERE deptId = 1 ORDER BY id ASC"
|
||||
)
|
||||
assertEquals(
|
||||
listOf(listOf(int(1), Value.NullValue, int(0)), listOf(int(2), Value.NullValue, int(0)), listOf(int(3), Value.NullValue, int(0))),
|
||||
result.rows
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun firstValueAndLastValueRespectAnExplicitFrameInsteadOfThePeerGroupDefault() {
|
||||
val db = newDatabase()
|
||||
db.seedWindowEmployees()
|
||||
val result = db.select(
|
||||
"SELECT id, " +
|
||||
"FIRST_VALUE(salary) OVER (PARTITION BY deptId ORDER BY id ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS f, " +
|
||||
"LAST_VALUE(salary) OVER (PARTITION BY deptId ORDER BY id ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING) AS l " +
|
||||
"FROM employees ORDER BY id ASC"
|
||||
)
|
||||
assertEquals(
|
||||
listOf(
|
||||
listOf(int(1), int(400), int(400)),
|
||||
listOf(int(2), int(400), int(300)),
|
||||
listOf(int(3), int(400), int(300)),
|
||||
listOf(int(4), int(200), int(200)),
|
||||
listOf(int(5), int(200), int(100)),
|
||||
listOf(int(6), int(200), int(100))
|
||||
),
|
||||
result.rows
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun rowsFrameShorthandWithoutBetweenEndsAtCurrentRow() {
|
||||
val db = newDatabase()
|
||||
db.seedWindowEmployees()
|
||||
val explicit = db.select(
|
||||
"SELECT id, SUM(salary) OVER (PARTITION BY deptId ORDER BY id ROWS 1 PRECEDING) AS s FROM employees ORDER BY id ASC"
|
||||
)
|
||||
val spelledOut = db.select(
|
||||
"SELECT id, SUM(salary) OVER (PARTITION BY deptId ORDER BY id ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS s " +
|
||||
"FROM employees ORDER BY id ASC"
|
||||
)
|
||||
assertEquals(spelledOut.rows, explicit.rows)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun rowsFrameOffsetMustNotBeNegative() {
|
||||
val db = newDatabase()
|
||||
db.seedWindowEmployees()
|
||||
val error = assertFailsWith<DiskExecutorException> {
|
||||
db.run("SELECT SUM(salary) OVER (ORDER BY id ROWS BETWEEN -1 PRECEDING AND CURRENT ROW) FROM employees")
|
||||
}
|
||||
assertTrue(error.message!!.contains("negative"), error.message!!)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun rowsFrameOffsetMustBeAnInteger() {
|
||||
val db = newDatabase()
|
||||
db.seedWindowEmployees()
|
||||
val error = assertFailsWith<DiskExecutorException> {
|
||||
db.run("SELECT SUM(salary) OVER (ORDER BY id ROWS BETWEEN 1.5 PRECEDING AND CURRENT ROW) FROM employees")
|
||||
}
|
||||
assertTrue(error.message!!.contains("integer"), error.message!!)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun rowsFrameIsRejectedOnRankingAndOffsetWindowFunctions() {
|
||||
val db = newDatabase()
|
||||
db.seedWindowEmployees()
|
||||
val error = assertFailsWith<DiskExecutorException> {
|
||||
db.run("SELECT ROW_NUMBER() OVER (ORDER BY id ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) FROM employees")
|
||||
}
|
||||
assertTrue(error.message!!.contains("frame"), error.message!!)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun windowFunctionNestedInsideAFrameOffsetIsRejected() {
|
||||
val db = newDatabase()
|
||||
db.seedWindowEmployees()
|
||||
val error = assertFailsWith<DiskExecutorException> {
|
||||
db.run(
|
||||
"SELECT SUM(salary) OVER (ORDER BY id ROWS BETWEEN ROW_NUMBER() OVER (ORDER BY id) PRECEDING AND CURRENT ROW) " +
|
||||
"FROM employees"
|
||||
)
|
||||
}
|
||||
assertTrue(error.message!!.contains("nested"), error.message!!)
|
||||
}
|
||||
|
||||
/** amount is monotonic in id (10, 20, 20, 30, 50) so `ORDER BY id` and `ORDER BY amount` agree, with a tie at 20. */
|
||||
private fun Database.seedWindowSales() {
|
||||
run("CREATE TABLE sales (id INTEGER PRIMARY KEY, amount INTEGER)")
|
||||
run("INSERT INTO sales VALUES (1, 10), (2, 20), (3, 20), (4, 30), (5, 50)")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun rangeBetweenPrecedingAndFollowingIncludesRowsWithinValueDistanceRegardlessOfPhysicalRowCount() {
|
||||
val db = newDatabase()
|
||||
db.seedWindowSales()
|
||||
val result = db.select(
|
||||
"SELECT id, SUM(amount) OVER (ORDER BY amount RANGE BETWEEN 10 PRECEDING AND 10 FOLLOWING) AS s FROM sales ORDER BY id ASC"
|
||||
)
|
||||
assertEquals(listOf(50L, 80L, 80L, 70L, 50L), result.rows.map { (it[1] as Value.IntegerValue).value })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun rangeBetweenPrecedingAndFollowingOnADescendingOrderByFlipsWhichDirectionIsPreceding() {
|
||||
val db = newDatabase()
|
||||
db.seedWindowSales()
|
||||
val result = db.select(
|
||||
"SELECT id, SUM(amount) OVER (ORDER BY amount DESC RANGE BETWEEN 15 PRECEDING AND 5 FOLLOWING) AS s FROM sales ORDER BY id ASC"
|
||||
)
|
||||
assertEquals(listOf(50L, 70L, 70L, 30L, 50L), result.rows.map { (it[1] as Value.IntegerValue).value })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun rangeCurrentRowExpandsToTheWholePeerGroupUnlikeRowsCurrentRow() {
|
||||
val db = newDatabase()
|
||||
db.seedWindowSales()
|
||||
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"
|
||||
)
|
||||
val rows = db.select(
|
||||
"SELECT id, SUM(amount) OVER (ORDER BY amount ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS s FROM sales ORDER BY id ASC"
|
||||
)
|
||||
assertEquals(listOf(10L, 50L, 50L, 80L, 130L), range.rows.map { (it[1] as Value.IntegerValue).value })
|
||||
assertEquals(listOf(10L, 30L, 50L, 80L, 130L), rows.rows.map { (it[1] as Value.IntegerValue).value })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun rangeFrameMeasuresDistanceOnADecimalColumn() {
|
||||
val db = newDatabase()
|
||||
db.run("CREATE TABLE prices (id INTEGER PRIMARY KEY, price DECIMAL(10, 2))")
|
||||
db.run("INSERT INTO prices VALUES (1, 1.00), (2, 1.40), (3, 1.50), (4, 2.00)")
|
||||
val result = db.select(
|
||||
"SELECT id, COUNT(*) OVER (ORDER BY price RANGE BETWEEN 0.5 PRECEDING AND 0.5 FOLLOWING) AS c FROM prices ORDER BY id ASC"
|
||||
)
|
||||
assertEquals(listOf(3L, 3L, 4L, 2L), result.rows.map { (it[1] as Value.IntegerValue).value })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun rangeFrameMeasuresDistanceInDaysOnADateColumn() {
|
||||
val db = newDatabase()
|
||||
db.run("CREATE TABLE events (id INTEGER PRIMARY KEY, day DATE)")
|
||||
db.run(
|
||||
"INSERT INTO events VALUES " +
|
||||
"(1, CAST('2024-01-01' AS DATE)), (2, CAST('2024-01-02' AS DATE)), " +
|
||||
"(3, CAST('2024-01-05' AS DATE)), (4, CAST('2024-01-06' AS DATE)), (5, CAST('2024-01-10' AS DATE))"
|
||||
)
|
||||
val result = db.select(
|
||||
"SELECT id, COUNT(*) OVER (ORDER BY day RANGE BETWEEN 2 PRECEDING AND 2 FOLLOWING) AS c FROM events ORDER BY id ASC"
|
||||
)
|
||||
assertEquals(listOf(2L, 2L, 2L, 2L, 1L), result.rows.map { (it[1] as Value.IntegerValue).value })
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user