test: cover rejectsGeneratedExpressionReferencingANonexistentColumn
This commit is contained in:
1 parent
00f08c1bca
commit
0cddb29e0e
1 file changed
+158
@@ -156,3 +156,161 @@ class GeneratedColumnTest {
|
||||
assertFailsWith<KestrelException> { run("INSERT INTO t (a) VALUES (NULL)") }
|
||||
}
|
||||
|
||||
// ---- validation at CREATE TABLE ----
|
||||
|
||||
@Test
|
||||
fun rejectsGeneratedExpressionReferencingANonexistentColumn() {
|
||||
val error = assertFailsWith<KestrelException> {
|
||||
run("CREATE TABLE t (a INTEGER, b INTEGER GENERATED ALWAYS AS (missing) STORED)")
|
||||
}
|
||||
assertTrue(error.message!!.contains("no such column"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun rejectsGeneratedExpressionContainingAnAggregate() {
|
||||
assertFailsWith<KestrelException> {
|
||||
run("CREATE TABLE t (a INTEGER, b INTEGER GENERATED ALWAYS AS (COUNT(a)) STORED)")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun rejectsGeneratedExpressionContainingASubquery() {
|
||||
run("CREATE TABLE other (x INTEGER)")
|
||||
assertFailsWith<KestrelException> {
|
||||
run("CREATE TABLE t (a INTEGER, b INTEGER GENERATED ALWAYS AS ((SELECT x FROM other)) STORED)")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun rejectsGeneratedExpressionContainingNextval() {
|
||||
run("CREATE SEQUENCE seq")
|
||||
assertFailsWith<KestrelException> {
|
||||
run("CREATE TABLE t (a INTEGER, b INTEGER GENERATED ALWAYS AS (NEXTVAL('seq')) STORED)")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun rejectsAGeneratedColumnReferencingAnotherGeneratedColumn() {
|
||||
val error = assertFailsWith<KestrelException> {
|
||||
run(
|
||||
"CREATE TABLE t (a INTEGER, b INTEGER GENERATED ALWAYS AS (a * 2) STORED, " +
|
||||
"c INTEGER GENERATED ALWAYS AS (b + 1) STORED)"
|
||||
)
|
||||
}
|
||||
assertTrue(error.message!!.contains("GENERATED"))
|
||||
}
|
||||
|
||||
// ---- RENAME COLUMN / DROP COLUMN interaction ----
|
||||
|
||||
@Test
|
||||
fun renameColumnPropagatesIntoADependentGeneratedExpression() {
|
||||
run("CREATE TABLE t (a INTEGER, b INTEGER GENERATED ALWAYS AS (a * 2) STORED)")
|
||||
run("ALTER TABLE t RENAME COLUMN a TO a2")
|
||||
run("INSERT INTO t (a2) VALUES (5)")
|
||||
assertEquals(listOf(listOf(int(10))), select("SELECT b FROM t").rows)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dropColumnRestrictsWhenAGeneratedColumnDependsOnIt() {
|
||||
run("CREATE TABLE t (a INTEGER, b INTEGER GENERATED ALWAYS AS (a * 2) STORED)")
|
||||
val error = assertFailsWith<KestrelException> { run("ALTER TABLE t DROP COLUMN a") }
|
||||
assertTrue(error.message!!.contains("GENERATED"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dropColumnCascadeRemovesTheDependentGeneratedColumnToo() {
|
||||
run("CREATE TABLE t (a INTEGER, b INTEGER GENERATED ALWAYS AS (a * 2) STORED, c TEXT)")
|
||||
run("INSERT INTO t (a, c) VALUES (5, 'x')")
|
||||
run("ALTER TABLE t DROP COLUMN a CASCADE")
|
||||
val result = select("SELECT * FROM t")
|
||||
assertEquals(listOf("c"), result.columns)
|
||||
assertEquals(listOf(listOf(text("x"))), result.rows)
|
||||
}
|
||||
|
||||
// ---- ALTER TABLE ADD COLUMN GENERATED ALWAYS AS ----
|
||||
|
||||
@Test
|
||||
fun alterTableAddColumnGeneratedBackfillsEachExistingRowFromItsOwnOtherColumns() {
|
||||
run("CREATE TABLE t (a INTEGER)")
|
||||
run("INSERT INTO t (a) VALUES (1), (2), (3)")
|
||||
run("ALTER TABLE t ADD COLUMN b INTEGER GENERATED ALWAYS AS (a * 2) STORED")
|
||||
assertEquals(
|
||||
listOf(listOf(int(1), int(2)), listOf(int(2), int(4)), listOf(int(3), int(6))),
|
||||
select("SELECT a, b FROM t ORDER BY a ASC").rows
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun alterTableAddColumnGeneratedWorksOnAnEmptyTable() {
|
||||
run("CREATE TABLE t (a INTEGER)")
|
||||
run("ALTER TABLE t ADD COLUMN b INTEGER GENERATED ALWAYS AS (a * 2) STORED")
|
||||
run("INSERT INTO t (a) VALUES (5)")
|
||||
assertEquals(listOf(listOf(int(10))), select("SELECT b FROM t").rows)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun afterAlterTableAddColumnGeneratedAnInsertStillRejectsAnExplicitValue() {
|
||||
run("CREATE TABLE t (a INTEGER)")
|
||||
run("ALTER TABLE t ADD COLUMN b INTEGER GENERATED ALWAYS AS (a * 2) STORED")
|
||||
val error = assertFailsWith<KestrelException> { run("INSERT INTO t (a, b) VALUES (5, 99)") }
|
||||
assertTrue(error.message!!.contains("GENERATED"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun afterAlterTableAddColumnGeneratedUpdatingTheDependencyColumnRecomputesIt() {
|
||||
run("CREATE TABLE t (a INTEGER)")
|
||||
run("INSERT INTO t (a) VALUES (5)")
|
||||
run("ALTER TABLE t ADD COLUMN b INTEGER GENERATED ALWAYS AS (a * 2) STORED")
|
||||
run("UPDATE t SET a = 9")
|
||||
assertEquals(listOf(listOf(int(18))), select("SELECT b FROM t").rows)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun alterTableAddColumnGeneratedNotNullSkipsTheDefaultRequirementOnANonEmptyTable() {
|
||||
run("CREATE TABLE t (a INTEGER)")
|
||||
run("INSERT INTO t (a) VALUES (1), (2)")
|
||||
// A plain NOT NULL column with no DEFAULT would be rejected here (see the DEFAULT-less
|
||||
// ADD COLUMN rule tested elsewhere) - GENERATED has its own per-row value to backfill with
|
||||
// instead, so it needs no DEFAULT at all even though the table already has rows.
|
||||
run("ALTER TABLE t ADD COLUMN b INTEGER NOT NULL GENERATED ALWAYS AS (a * 2) STORED")
|
||||
assertEquals(listOf(listOf(int(2)), listOf(int(4))), select("SELECT b FROM t ORDER BY a ASC").rows)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun alterTableAddColumnGeneratedNotNullRejectsARowWhoseBackfilledValueIsNull() {
|
||||
run("CREATE TABLE t (a INTEGER)")
|
||||
run("INSERT INTO t (a) VALUES (NULL)")
|
||||
val error = assertFailsWith<KestrelException> {
|
||||
run("ALTER TABLE t ADD COLUMN b INTEGER NOT NULL GENERATED ALWAYS AS (a) STORED")
|
||||
}
|
||||
assertTrue(error.message!!.contains("NOT NULL"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun alterTableAddColumnGeneratedRejectsReferencingANonexistentColumn() {
|
||||
run("CREATE TABLE t (a INTEGER)")
|
||||
val error = assertFailsWith<KestrelException> {
|
||||
run("ALTER TABLE t ADD COLUMN b INTEGER GENERATED ALWAYS AS (missing) STORED")
|
||||
}
|
||||
assertTrue(error.message!!.contains("no such column"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun alterTableAddColumnGeneratedRejectsReferencingAnAlreadyExistingGeneratedColumn() {
|
||||
run("CREATE TABLE t (a INTEGER, b INTEGER GENERATED ALWAYS AS (a * 2) STORED)")
|
||||
val error = assertFailsWith<KestrelException> {
|
||||
run("ALTER TABLE t ADD COLUMN c INTEGER GENERATED ALWAYS AS (b + 1) STORED")
|
||||
}
|
||||
assertTrue(error.message!!.contains("GENERATED"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun alterTableAddColumnGeneratedRejectsAnAggregate() {
|
||||
run("CREATE TABLE t (a INTEGER)")
|
||||
assertFailsWith<KestrelException> {
|
||||
run("ALTER TABLE t ADD COLUMN b INTEGER GENERATED ALWAYS AS (COUNT(a)) STORED")
|
||||
}
|
||||
}
|
||||
|
||||
private fun text(value: String) = Value.TextValue(value)
|
||||
}
|
||||
Reference in new issue
Block a user