mod common;
#[tokio::test(flavor = "multi_thread")]
async fn composite_primary_key_enforces_uniqueness() {
let ctx = common::start().await;
ctx.client
.execute(
"create table pk_demo(a int, b int, primary key (a, b))",
&[],
)
.await
.expect("create pk_demo");
ctx.client
.execute("insert into pk_demo values (1, 2)", &[])
.await
.expect("insert first row");
let err = ctx
.client
.execute("insert into pk_demo values (1, 2)", &[])
.await
.expect_err("duplicate composite key");
common::assert_db_error_contains(&err, "duplicate key");
let _ = ctx.shutdown.send(());
}
#[tokio::test(flavor = "multi_thread")]
async fn composite_foreign_key_requires_parent() {
let ctx = common::start().await;
ctx.client
.execute(
"create table parents(a int, b int, primary key (a, b))",
&[],
)
.await
.expect("create parents");
ctx.client
.execute(
"create table children(x int, y int, foreign key (x, y) references parents(a, b))",
&[],
)
.await
.expect("create children");
let err = ctx
.client
.execute("insert into children values (1, 1)", &[])
.await
.expect_err("insert without parent");
common::assert_db_error_contains(&err, "foreign key");
ctx.client
.execute("insert into parents values (1, 1)", &[])
.await
.expect("insert parent");
ctx.client
.execute("insert into children values (1, 1)", &[])
.await
.expect("insert child");
let _ = ctx.shutdown.send(());
}
#[tokio::test(flavor = "multi_thread")]
async fn update_primary_key_collision_rejected() {
let ctx = common::start().await;
ctx.client
.execute(
"create table pk_updates(a int, b int, primary key (a, b))",
&[],
)
.await
.expect("create pk_updates");
ctx.client
.execute("insert into pk_updates values (1, 1), (2, 2)", &[])
.await
.expect("insert initial rows");
let err = ctx
.client
.execute("update pk_updates set a = 1, b = 1 where a = 2", &[])
.await
.expect_err("update into duplicate key");
common::assert_db_error_contains(&err, "duplicate key");
let _ = ctx.shutdown.send(());
}
#[tokio::test(flavor = "multi_thread")]
async fn update_foreign_key_requires_existing_parent() {
let ctx = common::start().await;
ctx.client
.execute(
"create table updates_parent(a int, b int, primary key (a, b))",
&[],
)
.await
.expect("create parents");
ctx.client
.execute(
"create table updates_child(id int primary key, x int, y int, foreign key (x, y) references updates_parent(a, b))",
&[],
)
.await
.expect("create child");
ctx.client
.execute("insert into updates_parent values (1, 1)", &[])
.await
.expect("insert parent");
ctx.client
.execute("insert into updates_child values (1, 1, 1)", &[])
.await
.expect("insert child");
let err = ctx
.client
.execute("update updates_child set x = 2 where id = 1", &[])
.await
.expect_err("update to missing parent");
common::assert_db_error_contains(&err, "foreign key");
let _ = ctx.shutdown.send(());
}
#[tokio::test(flavor = "multi_thread")]
async fn delete_parent_blocked_by_child_composite_fk() {
let ctx = common::start().await;
ctx.client
.execute(
"create table del_parent(a int, b int, primary key (a, b))",
&[],
)
.await
.expect("create parent");
ctx.client
.execute(
"create table del_child(id int primary key, x int, y int, foreign key (x, y) references del_parent(a, b))",
&[],
)
.await
.expect("create child");
ctx.client
.execute("insert into del_parent values (1, 1)", &[])
.await
.expect("insert parent");
ctx.client
.execute("insert into del_child values (1, 1, 1)", &[])
.await
.expect("insert child");
let err = ctx
.client
.execute("delete from del_parent where a = 1 and b = 1", &[])
.await
.expect_err("delete referenced parent");
common::assert_db_error_contains(&err, "foreign key");
let _ = ctx.shutdown.send(());
}