test(sql): cover exceptReturnsRowsOnlyInTheLeftQuery
This commit is contained in:
1 parent
63cb6f5d6a
commit
d32d2a4a08
1 file changed
+157
@@ -1744,3 +1744,160 @@ class DiskExecutorTest {
|
|||||||
assertEquals(listOf(listOf(text("linus"))), db.select("SELECT name FROM t1 INTERSECT SELECT name FROM t2").rows)
|
assertEquals(listOf(listOf(text("linus"))), db.select("SELECT name FROM t1 INTERSECT SELECT name FROM t2").rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun exceptReturnsRowsOnlyInTheLeftQuery() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedCompound()
|
||||||
|
assertEquals(listOf(listOf(text("ada"))), db.select("SELECT name FROM t1 EXCEPT SELECT name FROM t2").rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun intersectAllAndExceptAllPreserveMultisetCounts() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.run("CREATE TABLE bag_a (v INTEGER)")
|
||||||
|
db.run("CREATE TABLE bag_b (v INTEGER)")
|
||||||
|
db.run("INSERT INTO bag_a VALUES (1), (1), (1), (2)")
|
||||||
|
db.run("INSERT INTO bag_b VALUES (1), (1), (2), (2), (3)")
|
||||||
|
assertEquals(
|
||||||
|
listOf(listOf(int(1)), listOf(int(1)), listOf(int(2))),
|
||||||
|
db.select("SELECT v FROM bag_a INTERSECT ALL SELECT v FROM bag_b ORDER BY v").rows
|
||||||
|
)
|
||||||
|
assertEquals(listOf(listOf(int(1))), db.select("SELECT v FROM bag_a EXCEPT ALL SELECT v FROM bag_b ORDER BY v").rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun compoundQueryWithMismatchedColumnCountsFails() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedCompound()
|
||||||
|
assertFailsWith<DiskExecutorException> { db.select("SELECT id, name FROM t1 UNION SELECT id FROM t2") }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun compoundOperatorsChainLeftAssociatively() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedCompound()
|
||||||
|
db.run("CREATE TABLE t3 (id INTEGER PRIMARY KEY, name TEXT NOT NULL)")
|
||||||
|
db.run("INSERT INTO t3 VALUES (2, 'linus')")
|
||||||
|
val result = db.select("SELECT name FROM t1 UNION ALL SELECT name FROM t2 INTERSECT SELECT name FROM t3 ORDER BY name")
|
||||||
|
assertEquals(listOf(listOf(text("linus"))), result.rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun orderByAndLimitApplyToTheWholeCompoundResultNotEachSide() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedCompound()
|
||||||
|
val result = db.select("SELECT name FROM t1 UNION ALL SELECT name FROM t2 ORDER BY name DESC LIMIT 2")
|
||||||
|
assertEquals(listOf(listOf(text("linus")), listOf(text("linus"))), result.rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun offsetSkipsRowsOfTheWholeCompoundResultBeforeLimitApplies() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedCompound()
|
||||||
|
val result = db.select("SELECT name FROM t1 UNION ALL SELECT name FROM t2 ORDER BY name DESC LIMIT 2 OFFSET 1")
|
||||||
|
assertEquals(listOf(listOf(text("linus")), listOf(text("grace"))), result.rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun withClauseMakesACteAvailableInFrom() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedCompound()
|
||||||
|
val result = db.select("WITH recent AS (SELECT id, name FROM t1) SELECT name FROM recent WHERE id = 1")
|
||||||
|
assertEquals(listOf(listOf(text("ada"))), result.rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun aCteShadowsARealTableOfTheSameName() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedCompound()
|
||||||
|
val result = db.select("WITH t1 AS (SELECT id FROM t1 WHERE id = 1) SELECT * FROM t1")
|
||||||
|
assertEquals(listOf("id"), result.columns)
|
||||||
|
assertEquals(listOf(listOf(int(1))), result.rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun laterCteCanReferenceAnEarlierCteInTheSameWithClause() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedCompound()
|
||||||
|
val result = db.select(
|
||||||
|
"WITH first_cte AS (SELECT id, name FROM t1), second_cte AS (SELECT name FROM first_cte WHERE id = 2) " +
|
||||||
|
"SELECT name FROM second_cte"
|
||||||
|
)
|
||||||
|
assertEquals(listOf(listOf(text("linus"))), result.rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun cteCanBeJoinedWithARealDiskTable() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedCompound()
|
||||||
|
val result = db.select("WITH t1_names AS (SELECT id, name FROM t1) SELECT t2.name FROM t1_names JOIN t2 ON t1_names.id = t2.id")
|
||||||
|
assertEquals(listOf(listOf(text("linus"))), result.rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun cteWithExplicitColumnListRenamesOutputColumns() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedCompound()
|
||||||
|
val result = db.select("WITH renamed(label) AS (SELECT name FROM t1) SELECT label FROM renamed ORDER BY label")
|
||||||
|
assertEquals(listOf(listOf(text("ada")), listOf(text("linus"))), result.rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun cteColumnListSizeMustMatchQueryColumnCount() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedCompound()
|
||||||
|
val failure = assertFailsWith<DiskExecutorException> { db.select("WITH bad(a, b, c) AS (SELECT id FROM t1) SELECT * FROM bad") }
|
||||||
|
assertTrue(failure.message!!.contains("bad"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun recursiveCteGeneratesABoundedSequence() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedCompound()
|
||||||
|
val result = db.select(
|
||||||
|
"WITH RECURSIVE counter(n) AS (" +
|
||||||
|
"SELECT 1 FROM dual " +
|
||||||
|
"UNION ALL " +
|
||||||
|
"SELECT n + 1 FROM counter WHERE n < 5" +
|
||||||
|
") SELECT n FROM counter ORDER BY n"
|
||||||
|
)
|
||||||
|
assertEquals((1..5).map { listOf(int(it.toLong())) }, result.rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun recursiveCteWithUnionDeduplicatesAndTerminatesOnACycleThroughARealDiskTable() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedCompound()
|
||||||
|
db.run("CREATE TABLE edges (from_node INTEGER, to_node INTEGER)")
|
||||||
|
db.run("INSERT INTO edges VALUES (1, 2), (2, 3), (3, 1), (3, 4)")
|
||||||
|
val result = db.select(
|
||||||
|
"WITH RECURSIVE reachable(node) AS (" +
|
||||||
|
"SELECT 1 FROM dual " +
|
||||||
|
"UNION " +
|
||||||
|
"SELECT edges.to_node FROM edges JOIN reachable ON edges.from_node = reachable.node" +
|
||||||
|
") SELECT node FROM reachable ORDER BY node"
|
||||||
|
)
|
||||||
|
assertEquals(listOf(1L, 2L, 3L, 4L).map { listOf(int(it)) }, result.rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun recursiveCteWithoutSelfReferenceBehavesAsAPlainCompoundQuery() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedCompound()
|
||||||
|
val result = db.select(
|
||||||
|
"WITH RECURSIVE notActuallyRecursive AS (SELECT 1 AS n FROM dual UNION ALL SELECT 2 FROM dual) " +
|
||||||
|
"SELECT n FROM notActuallyRecursive ORDER BY n"
|
||||||
|
)
|
||||||
|
assertEquals(listOf(listOf(int(1)), listOf(int(2))), result.rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun recursiveCteReferencingItselfOnBothSidesFails() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.seedCompound()
|
||||||
|
val failure = assertFailsWith<DiskExecutorException> {
|
||||||
|
db.select("WITH RECURSIVE bad(n) AS (SELECT n FROM bad UNION ALL SELECT n FROM bad) SELECT n FROM bad")
|
||||||
|
}
|
||||||
|
assertTrue(failure.message!!.contains("bad"))
|
||||||
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user