From 282d63a159add267ec9c44ce8182651de7fadbee Mon Sep 17 00:00:00 2001 From: futile Date: Wed, 28 Jan 2026 20:23:49 +0000 Subject: [PATCH 1/2] add maintenance_database option to postgres urls --- sqlx-postgres/src/migrate.rs | 42 +++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/sqlx-postgres/src/migrate.rs b/sqlx-postgres/src/migrate.rs index f4e55a36e6..4ecb636831 100644 --- a/sqlx-postgres/src/migrate.rs +++ b/sqlx-postgres/src/migrate.rs @@ -1,4 +1,3 @@ -use std::str::FromStr; use std::time::Duration; use std::time::Instant; @@ -8,6 +7,7 @@ pub(crate) use sqlx_core::migrate::MigrateError; pub(crate) use sqlx_core::migrate::{AppliedMigration, Migration}; pub(crate) use sqlx_core::migrate::{Migrate, MigrateDatabase}; use sqlx_core::sql_str::AssertSqlSafe; +use sqlx_core::Url; use crate::connection::{ConnectOptions, Connection}; use crate::error::Error; @@ -18,7 +18,29 @@ use crate::query_scalar::query_scalar; use crate::{PgConnectOptions, PgConnection, Postgres}; fn parse_for_maintenance(url: &str) -> Result<(PgConnectOptions, String), Error> { - let mut options = PgConnectOptions::from_str(url)?; + let mut url: Url = url.parse().map_err(Error::config)?; + + // check for user provided `?maintenance_database=example` + let mut maintenance_database = None; + if url.query_pairs().any(|(k, _)| k == "maintenance_database") { + let remaining: Vec<(String, String)> = url + .query_pairs() + .into_owned() + .filter_map(|(k, v)| { + if k == "maintenance_database" { + if maintenance_database.is_none() { + maintenance_database = Some(v); + } + None + } else { + Some((k, v)) + } + }) + .collect(); + url.query_pairs_mut().clear().extend_pairs(remaining); + } + + let mut options = PgConnectOptions::parse_from_url(&url)?; // pull out the name of the database to create let database = options @@ -28,13 +50,17 @@ fn parse_for_maintenance(url: &str) -> Result<(PgConnectOptions, String), Error> .to_owned(); // switch us to the maintenance database - // use `postgres` _unless_ the database is postgres, in which case, use `template1` - // this matches the behavior of the `createdb` util - options.database = if database == "postgres" { - Some("template1".into()) + if maintenance_database.is_some() { + options.database = maintenance_database; } else { - Some("postgres".into()) - }; + // use `postgres` _unless_ the database is postgres, in which case, use `template1` + // this matches the behavior of the `createdb` util + options.database = if database == "postgres" { + Some("template1".into()) + } else { + Some("postgres".into()) + }; + } Ok((options, database)) } From 89a22e31c3ca51bc8b0b9bb78f54b6f80ddb759f Mon Sep 17 00:00:00 2001 From: futile Date: Wed, 28 Jan 2026 20:24:01 +0000 Subject: [PATCH 2/2] add tests --- sqlx-postgres/src/migrate.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/sqlx-postgres/src/migrate.rs b/sqlx-postgres/src/migrate.rs index 4ecb636831..8dd13b72af 100644 --- a/sqlx-postgres/src/migrate.rs +++ b/sqlx-postgres/src/migrate.rs @@ -376,3 +376,32 @@ fn generate_lock_id(database_name: &str) -> i64 { // 0x3d32ad9e chosen by fair dice roll 0x3d32ad9e * (CRC_IEEE.checksum(database_name.as_bytes()) as i64) } + +#[cfg(test)] +mod tests { + use super::parse_for_maintenance; + + #[test] + fn test_parse_for_maintenance() { + let (opts, db) = parse_for_maintenance("postgres://user:pass@host/mydb").unwrap(); + assert_eq!(opts.database.as_deref(), Some("postgres")); + assert_eq!(db, "mydb"); + + let (opts, db) = parse_for_maintenance("postgres://user:pass@host/postgres").unwrap(); + assert_eq!(opts.database.as_deref(), Some("template1")); + assert_eq!(db, "postgres"); + + let (opts, db) = + parse_for_maintenance("postgres://user:pass@host/mydb?maintenance_database=defaultdb") + .unwrap(); + assert_eq!(opts.database.as_deref(), Some("defaultdb")); + assert_eq!(db, "mydb"); + + let (opts, db) = parse_for_maintenance( + "postgres://user:pass@host/mydb?sslmode=require&maintenance_database=defaultdb", + ) + .unwrap(); + assert_eq!(opts.database.as_deref(), Some("defaultdb")); + assert_eq!(db, "mydb"); + } +}