From 03a78c025eb7529026cca10e9fe346aa9b55582e Mon Sep 17 00:00:00 2001 From: Vraj Shah Date: Fri, 10 Nov 2023 18:15:29 -0500 Subject: [PATCH 01/10] Updated ahash so it can compile on mac --- Cargo.lock | 18 +++++++++--------- sqlx-core/Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e9324a9989..affc85f3b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,9 +30,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72832d73be48bac96a5d7944568f305d829ed55b0ce3b483647089dfaf6cf704" +checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" dependencies = [ "cfg-if", "getrandom", @@ -1503,7 +1503,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.4", + "ahash 0.8.6", ] [[package]] @@ -1512,7 +1512,7 @@ version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" dependencies = [ - "ahash 0.8.4", + "ahash 0.8.6", "allocator-api2", ] @@ -3220,7 +3220,7 @@ dependencies = [ name = "sqlx-core" version = "0.7.2" dependencies = [ - "ahash 0.8.4", + "ahash 0.8.6", "async-io", "async-std", "atoi", @@ -4410,18 +4410,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.11" +version = "0.7.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c19fae0c8a9efc6a8281f2e623db8af1db9e57852e04cde3e754dd2dc29340f" +checksum = "8cd369a67c0edfef15010f980c3cbe45d7f651deac2cd67ce097cd801de16557" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.11" +version = "0.7.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc56589e9ddd1f1c28d4b4b5c773ce232910a6bb67a70133d61c9e347585efe9" +checksum = "c2f140bda219a26ccc0cdb03dba58af72590c53b22642577d88a927bc5c87d6b" dependencies = [ "proc-macro2", "quote", diff --git a/sqlx-core/Cargo.toml b/sqlx-core/Cargo.toml index 31ef5c887a..e638773a1e 100644 --- a/sqlx-core/Cargo.toml +++ b/sqlx-core/Cargo.toml @@ -51,7 +51,7 @@ uuid = { workspace = true, optional = true } async-io = { version = "1.9.0", optional = true } paste = "1.0.6" -ahash = "0.8" +ahash = "0.8.6" atoi = "2.0" bytes = "1.1.0" From 73ab65c6d2317edcda14ad966523b0596a84204e Mon Sep 17 00:00:00 2001 From: Vraj Shah Date: Fri, 10 Nov 2023 18:22:51 -0500 Subject: [PATCH 02/10] Updated MigrateDatabase Trait + related functions --- sqlx-cli/src/database.rs | 7 ++++--- sqlx-cli/src/lib.rs | 6 ++++-- sqlx-cli/src/opt.rs | 8 ++++++++ sqlx-core/src/any/driver.rs | 6 +++--- sqlx-core/src/any/migrate.rs | 6 +++--- sqlx-core/src/migrate/migrate.rs | 2 +- sqlx-mysql/src/migrate.rs | 2 +- sqlx-postgres/src/migrate.rs | 2 +- sqlx-sqlite/src/migrate.rs | 2 +- 9 files changed, 26 insertions(+), 15 deletions(-) diff --git a/sqlx-cli/src/database.rs b/sqlx-cli/src/database.rs index 9c03f85788..d751a3f875 100644 --- a/sqlx-cli/src/database.rs +++ b/sqlx-cli/src/database.rs @@ -23,7 +23,7 @@ pub async fn create(connect_opts: &ConnectOpts) -> anyhow::Result<()> { Ok(()) } -pub async fn drop(connect_opts: &ConnectOpts, confirm: bool) -> anyhow::Result<()> { +pub async fn drop(connect_opts: &ConnectOpts, confirm: bool, force: bool) -> anyhow::Result<()> { if confirm && !ask_to_continue(connect_opts) { return Ok(()); } @@ -33,7 +33,7 @@ pub async fn drop(connect_opts: &ConnectOpts, confirm: bool) -> anyhow::Result<( let exists = crate::retry_connect_errors(connect_opts, Any::database_exists).await?; if exists { - Any::drop_database(&connect_opts.database_url).await?; + Any::drop_database(&connect_opts.database_url, force).await?; } Ok(()) @@ -43,8 +43,9 @@ pub async fn reset( migration_source: &str, connect_opts: &ConnectOpts, confirm: bool, + force: bool, ) -> anyhow::Result<()> { - drop(connect_opts, confirm).await?; + drop(connect_opts, confirm, force).await?; setup(migration_source, connect_opts).await } diff --git a/sqlx-cli/src/lib.rs b/sqlx-cli/src/lib.rs index aec2392f75..2ba150c1f1 100644 --- a/sqlx-cli/src/lib.rs +++ b/sqlx-cli/src/lib.rs @@ -74,12 +74,14 @@ pub async fn run(opt: Opt) -> Result<()> { DatabaseCommand::Drop { confirmation, connect_opts, - } => database::drop(&connect_opts, !confirmation.yes).await?, + force, + } => database::drop(&connect_opts, !confirmation.yes, force).await?, DatabaseCommand::Reset { confirmation, source, connect_opts, - } => database::reset(&source, &connect_opts, !confirmation.yes).await?, + force, + } => database::reset(&source, &connect_opts, !confirmation.yes, force).await?, DatabaseCommand::Setup { source, connect_opts, diff --git a/sqlx-cli/src/opt.rs b/sqlx-cli/src/opt.rs index d2dc0732ef..8ff37d184e 100644 --- a/sqlx-cli/src/opt.rs +++ b/sqlx-cli/src/opt.rs @@ -76,6 +76,10 @@ pub enum DatabaseCommand { #[clap(flatten)] connect_opts: ConnectOpts, + + /// PostgreSQL only: force drops the database. + #[clap(long, short, default_value = "false")] + force: bool, }, /// Drops the database specified in your DATABASE_URL, re-creates it, and runs any pending migrations. @@ -88,6 +92,10 @@ pub enum DatabaseCommand { #[clap(flatten)] connect_opts: ConnectOpts, + + /// PostgreSQL only: force drops the database. + #[clap(long, short, default_value = "false")] + force: bool, }, /// Creates the database specified in your DATABASE_URL and runs any pending migrations. diff --git a/sqlx-core/src/any/driver.rs b/sqlx-core/src/any/driver.rs index b89688d8a1..c3c28acb9c 100644 --- a/sqlx-core/src/any/driver.rs +++ b/sqlx-core/src/any/driver.rs @@ -93,7 +93,7 @@ impl Debug for AnyDriver { pub struct AnyMigrateDatabase { create_database: DebugFn BoxFuture<'_, crate::Result<()>>>, database_exists: DebugFn BoxFuture<'_, crate::Result>>, - drop_database: DebugFn BoxFuture<'_, crate::Result<()>>>, + drop_database: DebugFn BoxFuture<'_, crate::Result<()>>>, } impl AnyMigrateDatabase { @@ -105,8 +105,8 @@ impl AnyMigrateDatabase { (self.database_exists)(url) } - pub fn drop_database<'a>(&self, url: &'a str) -> BoxFuture<'a, crate::Result<()>> { - (self.drop_database)(url) + pub fn drop_database<'a>(&self, url: &'a str, force: bool) -> BoxFuture<'a, crate::Result<()>> { + (self.drop_database)(url, force) } } diff --git a/sqlx-core/src/any/migrate.rs b/sqlx-core/src/any/migrate.rs index 6fd63c79f6..2ef7a4bf99 100644 --- a/sqlx-core/src/any/migrate.rs +++ b/sqlx-core/src/any/migrate.rs @@ -24,11 +24,11 @@ impl MigrateDatabase for Any { }) } - fn drop_database(url: &str) -> BoxFuture<'_, Result<(), Error>> { - Box::pin(async { + fn drop_database(url: &str, force: bool) -> BoxFuture<'_, Result<(), Error>> { + Box::pin(async move { driver::from_url_str(url)? .get_migrate_database()? - .drop_database(url) + .drop_database(url, force) .await }) } diff --git a/sqlx-core/src/migrate/migrate.rs b/sqlx-core/src/migrate/migrate.rs index 1ea64f503e..cf5c147b38 100644 --- a/sqlx-core/src/migrate/migrate.rs +++ b/sqlx-core/src/migrate/migrate.rs @@ -14,7 +14,7 @@ pub trait MigrateDatabase { // drop database in url // uses a maintenance database depending on driver - fn drop_database(url: &str) -> BoxFuture<'_, Result<(), Error>>; + fn drop_database(url: &str, _force: bool) -> BoxFuture<'_, Result<(), Error>>; } // 'e = Executor diff --git a/sqlx-mysql/src/migrate.rs b/sqlx-mysql/src/migrate.rs index dac2753e5f..8269ae167d 100644 --- a/sqlx-mysql/src/migrate.rs +++ b/sqlx-mysql/src/migrate.rs @@ -60,7 +60,7 @@ impl MigrateDatabase for MySql { }) } - fn drop_database(url: &str) -> BoxFuture<'_, Result<(), Error>> { + fn drop_database(url: &str, _force: bool) -> BoxFuture<'_, Result<(), Error>> { Box::pin(async move { let (options, database) = parse_for_maintenance(url)?; let mut conn = options.connect().await?; diff --git a/sqlx-postgres/src/migrate.rs b/sqlx-postgres/src/migrate.rs index de4103bfcc..caa32c671c 100644 --- a/sqlx-postgres/src/migrate.rs +++ b/sqlx-postgres/src/migrate.rs @@ -70,7 +70,7 @@ impl MigrateDatabase for Postgres { }) } - fn drop_database(url: &str) -> BoxFuture<'_, Result<(), Error>> { + fn drop_database(url: &str, force: bool) -> BoxFuture<'_, Result<(), Error>> { Box::pin(async move { let (options, database) = parse_for_maintenance(url)?; let mut conn = options.connect().await?; diff --git a/sqlx-sqlite/src/migrate.rs b/sqlx-sqlite/src/migrate.rs index 94a39a94f0..3ce3f68099 100644 --- a/sqlx-sqlite/src/migrate.rs +++ b/sqlx-sqlite/src/migrate.rs @@ -51,7 +51,7 @@ impl MigrateDatabase for Sqlite { }) } - fn drop_database(url: &str) -> BoxFuture<'_, Result<(), Error>> { + fn drop_database(url: &str, _force: bool) -> BoxFuture<'_, Result<(), Error>> { Box::pin(async move { let options = SqliteConnectOptions::from_str(url)?; From 77c071dd0a1681fb65d1cab3c674daa6b7b2f510 Mon Sep 17 00:00:00 2001 From: Vraj Shah Date: Fri, 10 Nov 2023 18:25:26 -0500 Subject: [PATCH 03/10] Postgres force drop database flag impl --- sqlx-postgres/src/migrate.rs | 37 ++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/sqlx-postgres/src/migrate.rs b/sqlx-postgres/src/migrate.rs index caa32c671c..5ac0d2309f 100644 --- a/sqlx-postgres/src/migrate.rs +++ b/sqlx-postgres/src/migrate.rs @@ -75,12 +75,37 @@ impl MigrateDatabase for Postgres { let (options, database) = parse_for_maintenance(url)?; let mut conn = options.connect().await?; - let _ = conn - .execute(&*format!( - "DROP DATABASE IF EXISTS \"{}\"", - database.replace('"', "\"\"") - )) - .await?; + let with_force = if force { + // language=SQL + let row: (String,) = query_as("SELECT current_setting('server_version_num')") + .fetch_one(&mut conn) + .await?; + + let version = row.0.parse::().unwrap(); + + if version >= 130000 { + "WITH (FORCE)" + } else { + let pid_type = if version > 90200 { "pid" } else { "procpid" }; + + conn.execute(&*format!( + "SELECT pg_terminate_backend(pg_stat_activity.{pid_type}) FROM pg_stat_activity \ + WHERE pg_stat_activity.datname = {} AND {pid_type} <> pg_backend_pid()", + database.replace('"', "\"\""), + )) + .await?; + + "" + } + } else { + "" + }; + + conn.execute(&*format!( + "DROP DATABASE IF EXISTS \"{}\" {with_force}", + database.replace('"', "\"\""), + )) + .await?; Ok(()) }) From d5534a301c147b10a5208c4ba0282889744d2e09 Mon Sep 17 00:00:00 2001 From: Vraj Shah <89588024+Vrajs16@users.noreply.github.com> Date: Fri, 10 Nov 2023 18:59:16 -0500 Subject: [PATCH 04/10] Update migrate.rs --- sqlx-postgres/src/migrate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlx-postgres/src/migrate.rs b/sqlx-postgres/src/migrate.rs index 5ac0d2309f..812ba42a96 100644 --- a/sqlx-postgres/src/migrate.rs +++ b/sqlx-postgres/src/migrate.rs @@ -86,7 +86,7 @@ impl MigrateDatabase for Postgres { if version >= 130000 { "WITH (FORCE)" } else { - let pid_type = if version > 90200 { "pid" } else { "procpid" }; + let pid_type = if version >= 90200 { "pid" } else { "procpid" }; conn.execute(&*format!( "SELECT pg_terminate_backend(pg_stat_activity.{pid_type}) FROM pg_stat_activity \ From cd54110a32463d2b07d993ca3986affaa49e8171 Mon Sep 17 00:00:00 2001 From: Vraj Shah Date: Thu, 16 Nov 2023 15:04:27 -0500 Subject: [PATCH 05/10] Reverted MigrateDatabase Trait --- sqlx-cli/src/database.rs | 2 +- sqlx-core/src/any/driver.rs | 6 ++--- sqlx-core/src/any/migrate.rs | 4 ++-- sqlx-core/src/migrate/migrate.rs | 8 ++++++- sqlx-mysql/src/migrate.rs | 2 +- sqlx-postgres/src/migrate.rs | 39 ++++++-------------------------- sqlx-sqlite/src/migrate.rs | 2 +- 7 files changed, 22 insertions(+), 41 deletions(-) diff --git a/sqlx-cli/src/database.rs b/sqlx-cli/src/database.rs index d751a3f875..6866757d2b 100644 --- a/sqlx-cli/src/database.rs +++ b/sqlx-cli/src/database.rs @@ -33,7 +33,7 @@ pub async fn drop(connect_opts: &ConnectOpts, confirm: bool, force: bool) -> any let exists = crate::retry_connect_errors(connect_opts, Any::database_exists).await?; if exists { - Any::drop_database(&connect_opts.database_url, force).await?; + Any::drop_database(&connect_opts.database_url).await?; } Ok(()) diff --git a/sqlx-core/src/any/driver.rs b/sqlx-core/src/any/driver.rs index c3c28acb9c..b89688d8a1 100644 --- a/sqlx-core/src/any/driver.rs +++ b/sqlx-core/src/any/driver.rs @@ -93,7 +93,7 @@ impl Debug for AnyDriver { pub struct AnyMigrateDatabase { create_database: DebugFn BoxFuture<'_, crate::Result<()>>>, database_exists: DebugFn BoxFuture<'_, crate::Result>>, - drop_database: DebugFn BoxFuture<'_, crate::Result<()>>>, + drop_database: DebugFn BoxFuture<'_, crate::Result<()>>>, } impl AnyMigrateDatabase { @@ -105,8 +105,8 @@ impl AnyMigrateDatabase { (self.database_exists)(url) } - pub fn drop_database<'a>(&self, url: &'a str, force: bool) -> BoxFuture<'a, crate::Result<()>> { - (self.drop_database)(url, force) + pub fn drop_database<'a>(&self, url: &'a str) -> BoxFuture<'a, crate::Result<()>> { + (self.drop_database)(url) } } diff --git a/sqlx-core/src/any/migrate.rs b/sqlx-core/src/any/migrate.rs index 2ef7a4bf99..764212a9b4 100644 --- a/sqlx-core/src/any/migrate.rs +++ b/sqlx-core/src/any/migrate.rs @@ -24,11 +24,11 @@ impl MigrateDatabase for Any { }) } - fn drop_database(url: &str, force: bool) -> BoxFuture<'_, Result<(), Error>> { + fn drop_database(url: &str) -> BoxFuture<'_, Result<(), Error>> { Box::pin(async move { driver::from_url_str(url)? .get_migrate_database()? - .drop_database(url, force) + .drop_database(url) .await }) } diff --git a/sqlx-core/src/migrate/migrate.rs b/sqlx-core/src/migrate/migrate.rs index cf5c147b38..dd82f79621 100644 --- a/sqlx-core/src/migrate/migrate.rs +++ b/sqlx-core/src/migrate/migrate.rs @@ -14,7 +14,13 @@ pub trait MigrateDatabase { // drop database in url // uses a maintenance database depending on driver - fn drop_database(url: &str, _force: bool) -> BoxFuture<'_, Result<(), Error>>; + fn drop_database(url: &str) -> BoxFuture<'_, Result<(), Error>>; + + // force drop database in url + // uses a maintenance database depending on driver + fn force_drop_database(url: &str) -> BoxFuture<'_, Result<(), Error>> { + unimplemented!("Database driver does not support force-dropping a database") + } } // 'e = Executor diff --git a/sqlx-mysql/src/migrate.rs b/sqlx-mysql/src/migrate.rs index 8269ae167d..dac2753e5f 100644 --- a/sqlx-mysql/src/migrate.rs +++ b/sqlx-mysql/src/migrate.rs @@ -60,7 +60,7 @@ impl MigrateDatabase for MySql { }) } - fn drop_database(url: &str, _force: bool) -> BoxFuture<'_, Result<(), Error>> { + fn drop_database(url: &str) -> BoxFuture<'_, Result<(), Error>> { Box::pin(async move { let (options, database) = parse_for_maintenance(url)?; let mut conn = options.connect().await?; diff --git a/sqlx-postgres/src/migrate.rs b/sqlx-postgres/src/migrate.rs index 812ba42a96..78026d377e 100644 --- a/sqlx-postgres/src/migrate.rs +++ b/sqlx-postgres/src/migrate.rs @@ -70,42 +70,17 @@ impl MigrateDatabase for Postgres { }) } - fn drop_database(url: &str, force: bool) -> BoxFuture<'_, Result<(), Error>> { + fn drop_database(url: &str) -> BoxFuture<'_, Result<(), Error>> { Box::pin(async move { let (options, database) = parse_for_maintenance(url)?; let mut conn = options.connect().await?; - let with_force = if force { - // language=SQL - let row: (String,) = query_as("SELECT current_setting('server_version_num')") - .fetch_one(&mut conn) - .await?; - - let version = row.0.parse::().unwrap(); - - if version >= 130000 { - "WITH (FORCE)" - } else { - let pid_type = if version >= 90200 { "pid" } else { "procpid" }; - - conn.execute(&*format!( - "SELECT pg_terminate_backend(pg_stat_activity.{pid_type}) FROM pg_stat_activity \ - WHERE pg_stat_activity.datname = {} AND {pid_type} <> pg_backend_pid()", - database.replace('"', "\"\""), - )) - .await?; - - "" - } - } else { - "" - }; - - conn.execute(&*format!( - "DROP DATABASE IF EXISTS \"{}\" {with_force}", - database.replace('"', "\"\""), - )) - .await?; + let _ = conn + .execute(&*format!( + "DROP DATABASE IF EXISTS \"{}\"", + database.replace('"', "\"\""), + )) + .await?; Ok(()) }) diff --git a/sqlx-sqlite/src/migrate.rs b/sqlx-sqlite/src/migrate.rs index 3ce3f68099..94a39a94f0 100644 --- a/sqlx-sqlite/src/migrate.rs +++ b/sqlx-sqlite/src/migrate.rs @@ -51,7 +51,7 @@ impl MigrateDatabase for Sqlite { }) } - fn drop_database(url: &str, _force: bool) -> BoxFuture<'_, Result<(), Error>> { + fn drop_database(url: &str) -> BoxFuture<'_, Result<(), Error>> { Box::pin(async move { let options = SqliteConnectOptions::from_str(url)?; From 226b6f7b21970d75c5bc746f01f4f4a3a2b13dde Mon Sep 17 00:00:00 2001 From: Vraj Shah <89588024+Vrajs16@users.noreply.github.com> Date: Thu, 16 Nov 2023 15:06:25 -0500 Subject: [PATCH 06/10] Update migrate.rs --- sqlx-core/src/any/migrate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlx-core/src/any/migrate.rs b/sqlx-core/src/any/migrate.rs index 764212a9b4..6fd63c79f6 100644 --- a/sqlx-core/src/any/migrate.rs +++ b/sqlx-core/src/any/migrate.rs @@ -25,7 +25,7 @@ impl MigrateDatabase for Any { } fn drop_database(url: &str) -> BoxFuture<'_, Result<(), Error>> { - Box::pin(async move { + Box::pin(async { driver::from_url_str(url)? .get_migrate_database()? .drop_database(url) From d57c712ac1b522f3ae394783c964b63df04c3034 Mon Sep 17 00:00:00 2001 From: Vraj Shah <89588024+Vrajs16@users.noreply.github.com> Date: Thu, 16 Nov 2023 15:07:08 -0500 Subject: [PATCH 07/10] Update migrate.rs --- sqlx-postgres/src/migrate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlx-postgres/src/migrate.rs b/sqlx-postgres/src/migrate.rs index 78026d377e..de4103bfcc 100644 --- a/sqlx-postgres/src/migrate.rs +++ b/sqlx-postgres/src/migrate.rs @@ -78,7 +78,7 @@ impl MigrateDatabase for Postgres { let _ = conn .execute(&*format!( "DROP DATABASE IF EXISTS \"{}\"", - database.replace('"', "\"\""), + database.replace('"', "\"\"") )) .await?; From 319fb9b001020df04638ffe4ea9e1957b269fca1 Mon Sep 17 00:00:00 2001 From: Vraj Shah Date: Thu, 16 Nov 2023 15:26:35 -0500 Subject: [PATCH 08/10] Added force drop database fn impl --- sqlx-cli/src/database.rs | 6 +++++- sqlx-core/src/any/driver.rs | 6 ++++++ sqlx-core/src/any/migrate.rs | 9 +++++++++ sqlx-core/src/migrate/migrate.rs | 2 +- sqlx-postgres/src/migrate.rs | 24 ++++++++++++++++++++++++ 5 files changed, 45 insertions(+), 2 deletions(-) diff --git a/sqlx-cli/src/database.rs b/sqlx-cli/src/database.rs index 6866757d2b..4b33c225c2 100644 --- a/sqlx-cli/src/database.rs +++ b/sqlx-cli/src/database.rs @@ -33,7 +33,11 @@ pub async fn drop(connect_opts: &ConnectOpts, confirm: bool, force: bool) -> any let exists = crate::retry_connect_errors(connect_opts, Any::database_exists).await?; if exists { - Any::drop_database(&connect_opts.database_url).await?; + if force { + Any::force_drop_database(&connect_opts.database_url).await?; + } else { + Any::drop_database(&connect_opts.database_url).await?; + } } Ok(()) diff --git a/sqlx-core/src/any/driver.rs b/sqlx-core/src/any/driver.rs index b89688d8a1..cf97b84812 100644 --- a/sqlx-core/src/any/driver.rs +++ b/sqlx-core/src/any/driver.rs @@ -70,6 +70,7 @@ impl AnyDriver { create_database: DebugFn(DB::create_database), database_exists: DebugFn(DB::database_exists), drop_database: DebugFn(DB::drop_database), + force_drop_database: DebugFn(DB::force_drop_database), }), ..Self::without_migrate::() } @@ -94,6 +95,7 @@ pub struct AnyMigrateDatabase { create_database: DebugFn BoxFuture<'_, crate::Result<()>>>, database_exists: DebugFn BoxFuture<'_, crate::Result>>, drop_database: DebugFn BoxFuture<'_, crate::Result<()>>>, + force_drop_database: DebugFn BoxFuture<'_, crate::Result<()>>>, } impl AnyMigrateDatabase { @@ -108,6 +110,10 @@ impl AnyMigrateDatabase { pub fn drop_database<'a>(&self, url: &'a str) -> BoxFuture<'a, crate::Result<()>> { (self.drop_database)(url) } + + pub fn force_drop_database<'a>(&self, url: &'a str) -> BoxFuture<'a, crate::Result<()>> { + (self.force_drop_database)(url) + } } /// Install the list of drivers for [`AnyConnection`] to use. diff --git a/sqlx-core/src/any/migrate.rs b/sqlx-core/src/any/migrate.rs index 6fd63c79f6..cb4f72c340 100644 --- a/sqlx-core/src/any/migrate.rs +++ b/sqlx-core/src/any/migrate.rs @@ -32,6 +32,15 @@ impl MigrateDatabase for Any { .await }) } + + fn force_drop_database(url: &str) -> BoxFuture<'_, Result<(), Error>> { + Box::pin(async { + driver::from_url_str(url)? + .get_migrate_database()? + .force_drop_database(url) + .await + }) + } } impl Migrate for AnyConnection { diff --git a/sqlx-core/src/migrate/migrate.rs b/sqlx-core/src/migrate/migrate.rs index dd82f79621..50693aa35b 100644 --- a/sqlx-core/src/migrate/migrate.rs +++ b/sqlx-core/src/migrate/migrate.rs @@ -18,7 +18,7 @@ pub trait MigrateDatabase { // force drop database in url // uses a maintenance database depending on driver - fn force_drop_database(url: &str) -> BoxFuture<'_, Result<(), Error>> { + fn force_drop_database(_url: &str) -> BoxFuture<'_, Result<(), Error>> { unimplemented!("Database driver does not support force-dropping a database") } } diff --git a/sqlx-postgres/src/migrate.rs b/sqlx-postgres/src/migrate.rs index de4103bfcc..20473a7e15 100644 --- a/sqlx-postgres/src/migrate.rs +++ b/sqlx-postgres/src/migrate.rs @@ -85,6 +85,30 @@ impl MigrateDatabase for Postgres { Ok(()) }) } + + fn force_drop_database(url: &str) -> BoxFuture<'_, Result<(), Error>> { + Box::pin(async move { + let (options, database) = parse_for_maintenance(url)?; + let mut conn = options.connect().await?; + + let row: (String,) = query_as("SELECT current_setting('server_version_num')") + .fetch_one(&mut conn) + .await?; + + let version = row.0.parse::().unwrap(); + + let pid_type = if version >= 90200 { "pid" } else { "procpid" }; + + conn.execute(&*format!( + "SELECT pg_terminate_backend(pg_stat_activity.{pid_type}) FROM pg_stat_activity \ + WHERE pg_stat_activity.datname = {} AND {pid_type} <> pg_backend_pid()", + database.replace('"', "\"\""), + )) + .await?; + + Self::drop_database(url).await + }) + } } impl Migrate for PgConnection { From 72dd4a7ea2e682292d398a649430149e3f1f2586 Mon Sep 17 00:00:00 2001 From: Vraj Shah Date: Thu, 16 Nov 2023 15:40:32 -0500 Subject: [PATCH 09/10] Add Migrate Error --- sqlx-core/src/migrate/error.rs | 3 +++ sqlx-core/src/migrate/migrate.rs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/sqlx-core/src/migrate/error.rs b/sqlx-core/src/migrate/error.rs index 0463210cf5..fb5e09e9af 100644 --- a/sqlx-core/src/migrate/error.rs +++ b/sqlx-core/src/migrate/error.rs @@ -24,6 +24,9 @@ pub enum MigrateError { #[error("migration {0} is newer than the latest applied migration {1}")] VersionTooNew(i64, i64), + #[error("database driver does not support force-dropping a database (Only PostgreSQL)")] + ForceNotSupported, + #[deprecated = "migration types are now inferred"] #[error("cannot mix reversible migrations with simple migrations. All migrations should be reversible or simple migrations")] InvalidMixReversibleAndSimple, diff --git a/sqlx-core/src/migrate/migrate.rs b/sqlx-core/src/migrate/migrate.rs index 50693aa35b..0e4448a9bd 100644 --- a/sqlx-core/src/migrate/migrate.rs +++ b/sqlx-core/src/migrate/migrate.rs @@ -19,7 +19,7 @@ pub trait MigrateDatabase { // force drop database in url // uses a maintenance database depending on driver fn force_drop_database(_url: &str) -> BoxFuture<'_, Result<(), Error>> { - unimplemented!("Database driver does not support force-dropping a database") + Box::pin(async { Err(MigrateError::ForceNotSupported)? }) } } From cd905b03d85ef0ea78fd0c26e3420676e07a37bb Mon Sep 17 00:00:00 2001 From: Vraj Shah Date: Tue, 21 Nov 2023 09:07:35 -0500 Subject: [PATCH 10/10] Fixed changed function name --- sqlx-cli/src/database.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlx-cli/src/database.rs b/sqlx-cli/src/database.rs index 549f007000..82dcfcfed9 100644 --- a/sqlx-cli/src/database.rs +++ b/sqlx-cli/src/database.rs @@ -24,7 +24,7 @@ pub async fn create(connect_opts: &ConnectOpts) -> anyhow::Result<()> { } pub async fn drop(connect_opts: &ConnectOpts, confirm: bool, force: bool) -> anyhow::Result<()> { - if confirm && !ask_to_continue(connect_opts.required_db_url()?) { + if confirm && !ask_to_continue_drop(connect_opts.required_db_url()?) { return Ok(()); }