test(sql): cover insertUpdateDeleteAgainstAViewAreRejected
This commit is contained in:
1 parent
8533598961
commit
bac0b33caf
1 file changed
+156
@@ -2856,3 +2856,159 @@ class DiskExecutorTest {
|
||||
assertFailsWith<DiskCatalogException> { db.run("DROP VIEW users") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun insertUpdateDeleteAgainstAViewAreRejected() {
|
||||
val db = newDatabase()
|
||||
db.seedUsersForViews()
|
||||
db.run("CREATE VIEW adults AS SELECT id, name FROM users WHERE age >= 18")
|
||||
assertFailsWith<DiskCatalogException> { db.run("INSERT INTO adults VALUES (9, 'x')") }
|
||||
assertFailsWith<DiskCatalogException> { db.run("UPDATE adults SET name = 'x'") }
|
||||
assertFailsWith<DiskCatalogException> { db.run("DELETE FROM adults") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun creatingAnIndexOnAViewIsRejected() {
|
||||
val db = newDatabase()
|
||||
db.seedUsersForViews()
|
||||
db.run("CREATE VIEW adults AS SELECT id, name FROM users WHERE age >= 18")
|
||||
assertFailsWith<DiskCatalogException> { db.run("CREATE INDEX idx ON adults (id)") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun mutuallyRecursiveViewsFailInsteadOfOverflowingTheStack() {
|
||||
val db = newDatabase()
|
||||
db.seedUsersForViews()
|
||||
db.run("CREATE VIEW a AS SELECT id FROM users")
|
||||
db.run("CREATE VIEW b AS SELECT id FROM a")
|
||||
db.run("CREATE OR REPLACE VIEW a AS SELECT id FROM b")
|
||||
assertFailsWith<DiskExecutorException> { db.run("SELECT * FROM a") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun selfReferencingViewFailsCleanly() {
|
||||
val db = newDatabase()
|
||||
db.seedUsersForViews()
|
||||
db.run("CREATE VIEW a AS SELECT id FROM users")
|
||||
db.run("CREATE OR REPLACE VIEW a AS SELECT id FROM a")
|
||||
assertFailsWith<DiskExecutorException> { db.run("SELECT * FROM a") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dropTableWithADependentViewFailsByDefaultAndAlsoWithExplicitRestrict() {
|
||||
val db = newDatabase()
|
||||
db.seedUsersForViews()
|
||||
db.run("CREATE VIEW adults AS SELECT id FROM users WHERE age >= 18")
|
||||
assertFailsWith<DiskCatalogException> { db.run("DROP TABLE users") }
|
||||
assertFailsWith<DiskCatalogException> { db.run("DROP TABLE users RESTRICT") }
|
||||
assertEquals(listOf("users"), db.catalog.tableNames)
|
||||
assertEquals(listOf("adults"), db.catalog.viewNames)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dropViewWithADependentViewFailsByDefault() {
|
||||
val db = newDatabase()
|
||||
db.seedUsersForViews()
|
||||
db.run("CREATE VIEW adults AS SELECT id FROM users WHERE age >= 18")
|
||||
db.run("CREATE VIEW seniorAdults AS SELECT id FROM adults WHERE id > 0")
|
||||
assertFailsWith<DiskCatalogException> { db.run("DROP VIEW adults") }
|
||||
assertEquals(listOf("adults", "seniorAdults"), db.catalog.viewNames)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dropViewCascadeDropsATransitiveChainOfDependentViews() {
|
||||
val db = newDatabase()
|
||||
db.seedUsersForViews()
|
||||
db.run("CREATE VIEW a AS SELECT id FROM users WHERE age >= 18")
|
||||
db.run("CREATE VIEW b AS SELECT id FROM a WHERE id > 0")
|
||||
db.run("CREATE VIEW c AS SELECT id FROM b WHERE id > 0")
|
||||
db.run("DROP VIEW a CASCADE")
|
||||
assertTrue(db.catalog.viewNames.isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dropTableWithADiamondOfDependentViewsIsBlockedByEveryDirectDependent() {
|
||||
val db = newDatabase()
|
||||
db.seedUsersForViews()
|
||||
db.run("CREATE VIEW b AS SELECT id FROM users WHERE age >= 18")
|
||||
db.run("CREATE VIEW c AS SELECT id FROM users WHERE age >= 21")
|
||||
assertFailsWith<DiskCatalogException> { db.run("DROP TABLE users") }
|
||||
assertEquals(listOf("users"), db.catalog.tableNames)
|
||||
assertEquals(listOf("b", "c"), db.catalog.viewNames)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dropTableCascadeDropsTheTableAndItsDependentView() {
|
||||
val db = newDatabase()
|
||||
db.seedUsersForViews()
|
||||
db.run("CREATE VIEW adults AS SELECT id FROM users WHERE age >= 18")
|
||||
db.run("DROP TABLE users CASCADE")
|
||||
assertTrue(db.catalog.tableNames.isEmpty())
|
||||
assertTrue(db.catalog.viewNames.isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dropTableCascadeHandlesADiamondOfDependentViewsWithoutFailing() {
|
||||
val db = newDatabase()
|
||||
db.seedUsersForViews()
|
||||
db.run("CREATE VIEW b AS SELECT id FROM users WHERE age >= 18")
|
||||
db.run("CREATE VIEW c AS SELECT id FROM users WHERE age >= 21")
|
||||
db.run("CREATE VIEW d AS SELECT b.id FROM b JOIN c ON b.id = c.id")
|
||||
db.run("DROP TABLE users CASCADE")
|
||||
assertTrue(db.catalog.tableNames.isEmpty())
|
||||
assertTrue(db.catalog.viewNames.isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dropTableCascadeDroppedViewsSurviveClosingAndReopeningTheCatalog() {
|
||||
val db = newDatabase()
|
||||
db.seedUsersForViews()
|
||||
db.run("CREATE VIEW adults AS SELECT id FROM users WHERE age >= 18")
|
||||
db.run("DROP TABLE users CASCADE")
|
||||
db.reopen()
|
||||
assertTrue(db.catalog.tableNames.isEmpty())
|
||||
assertTrue(db.catalog.viewNames.isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun columnTypeOfAViewIsInferredFromActualData() {
|
||||
val db = newDatabase()
|
||||
db.seedUsersForViews()
|
||||
db.run("CREATE VIEW names AS SELECT name FROM users")
|
||||
val result = db.select("SELECT name FROM names WHERE name = 'ada'")
|
||||
assertEquals(listOf(listOf(text("ada"))), result.rows)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun viewDefinitionSurvivesClosingAndReopeningTheCatalog() {
|
||||
val db = newDatabase()
|
||||
db.seedUsersForViews()
|
||||
db.run("CREATE VIEW adults AS SELECT id, name FROM users WHERE age >= 40")
|
||||
db.reopen()
|
||||
assertEquals(listOf("adults"), db.catalog.viewNames)
|
||||
val result = db.select("SELECT name FROM adults ORDER BY id ASC")
|
||||
assertEquals(listOf(text("linus"), text("grace"), text("alan")), result.rows.map { it.single() })
|
||||
|
||||
db.run("INSERT INTO users VALUES (5, 'margaret', 61, 'navy')")
|
||||
db.reopen()
|
||||
val afterInsertAndReopen = db.select("SELECT name FROM adults ORDER BY id ASC")
|
||||
assertEquals(
|
||||
listOf(text("linus"), text("grace"), text("alan"), text("margaret")),
|
||||
afterInsertAndReopen.rows.map { it.single() }
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun viewOverViewAndDropViewSurviveReopen() {
|
||||
val db = newDatabase()
|
||||
db.seedUsersForViews()
|
||||
db.run("CREATE VIEW adults AS SELECT id, name, age FROM users WHERE age >= 40")
|
||||
db.run("CREATE VIEW seniors AS SELECT id, name FROM adults WHERE age >= 60")
|
||||
db.reopen()
|
||||
assertEquals(listOf(listOf(text("grace"))), db.select("SELECT name FROM seniors").rows)
|
||||
|
||||
db.run("DROP VIEW seniors")
|
||||
db.reopen()
|
||||
assertEquals(listOf("adults"), db.catalog.viewNames)
|
||||
assertFailsWith<KestrelException> { db.run("SELECT * FROM seniors") }
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user