fix(datatables): check a fork copy's reservation on the locked transaction's connection

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Diego Imbert
2026-09-21 17:40:50 +02:00
co-authored by Claude Opus 5
parent 6ecfab009c
commit be66635ec8
2 changed files with 10 additions and 7 deletions
@@ -3799,7 +3799,7 @@ async fn import_pg_database(
)
.await?;
windmill_common::ensure_fork_database_available_to(
&db,
&mut tx,
kind,
override_dbname,
&w_id,
@@ -8842,7 +8842,7 @@ async fn apply_forked_datatable(
&& !windmill_api_auth::is_super_admin_authed(db, authed).await?
{
windmill_common::ensure_fork_database_available_to(
db,
&mut **tx,
database.resource_type,
&fdt.new_dbname,
parent_w_id,
+8 -5
View File
@@ -1869,19 +1869,23 @@ async fn finish_custom_instance_database(
/// authorization: every database of a cluster answers to the same `custom_instance_user`, so a name
/// is all it takes to reach another workspace's copy.
///
/// Runs on `conn`: its callers hold a transaction with the fork lock while they check, and a
/// second connection taken from the pool under it is how a small pool deadlocks.
///
/// Authorization: reads the global registries and every workspace's settings, and names other
/// workspaces in its refusal. Callers MUST have authorized `w_id` for the caller first — a member
/// of it forking or importing there — and MUST NOT call it on a workspace the caller is not in.
pub async fn ensure_fork_database_available_to(
db: &DB,
conn: &mut sqlx::PgConnection,
kind: workspaces::DataTableCatalogResourceType,
dbname: &str,
w_id: &str,
) -> error::Result<()> {
let created_for = match kind {
workspaces::DataTableCatalogResourceType::ExternalInstance => {
external_instance_pg::external_instance_databases(db)
external_instance_pg::read_external_instance_pg_state(&mut *conn)
.await?
.databases
.remove(dbname)
.and_then(|entry| entry.workspace_id)
}
@@ -1890,7 +1894,7 @@ pub async fn ensure_fork_database_available_to(
WHERE name = 'custom_instance_pg_databases'",
)
.bind(dbname)
.fetch_optional(db)
.fetch_optional(&mut *conn)
.await?
.flatten(),
};
@@ -1899,8 +1903,7 @@ pub async fn ensure_fork_database_available_to(
"Database '{dbname}' was not created for a fork of workspace '{w_id}'"
)));
}
let uses =
workspaces::managed_database_uses(&mut *db.acquire().await?, kind, dbname, None).await?;
let uses = workspaces::managed_database_uses(conn, kind, dbname, None).await?;
if !uses.is_empty() {
return Err(Error::BadRequest(format!(
"Database '{dbname}' is already in use: {}",