Skip to content

Commit b7952ee

Browse files
committed
sqlx-postgres: add support to abstract sockets
PostgreSQL treats hosts starting by @ as abstract sockets (linux only). This patch modifies parse to correctly read host parameter as socket in these cases. It also modifies fetch_socket to provide the proper argument to net::connect_uds.
1 parent f5cdf33 commit b7952ee

File tree

3 files changed

+36
-6
lines changed

3 files changed

+36
-6
lines changed

sqlx-postgres/src/options/mod.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -455,10 +455,13 @@ impl PgConnectOptions {
455455
/// We try using a socket if hostname starts with `/` or if socket parameter
456456
/// is specified.
457457
pub(crate) fn fetch_socket(&self) -> Option<String> {
458-
match self.socket {
459-
Some(ref socket) => {
460-
let full_path = format!("{}/.s.PGSQL.{}", socket.display(), self.port);
461-
Some(full_path)
458+
match self.socket.to_str() {
459+
Some(socket_str) => {
460+
if let Some(abstract_dir) = socket_str.strip_prefix('@') {
461+
Some(format!("\0{}/.s.PGSQL.{}", abstract_dir, self.port));
462+
} else {
463+
Some(format!("{}/.s.PGSQL.{}", socket_str, self.port));
464+
};
462465
}
463466
None if self.host.starts_with('/') => {
464467
let full_path = format!("{}/.s.PGSQL.{}", self.host, self.port);

sqlx-postgres/src/options/parse.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ impl PgConnectOptions {
1212
if let Some(host) = url.host_str() {
1313
let host_decoded = percent_decode_str(host);
1414
options = match host_decoded.clone().next() {
15-
Some(b'/') => options.socket(&*host_decoded.decode_utf8().map_err(Error::config)?),
15+
Some(b'/') | Some(b'@') => {
16+
options.socket(&*host_decoded.decode_utf8().map_err(Error::config)?)
17+
}
1618
_ => options.host(host),
1719
}
1820
}
@@ -67,7 +69,7 @@ impl PgConnectOptions {
6769
}
6870

6971
"host" => {
70-
if value.starts_with('/') {
72+
if value.starts_with('/') || value.starts_with('@') {
7173
options = options.socket(&*value);
7274
} else {
7375
options = options.host(&value);
@@ -188,6 +190,14 @@ fn it_parses_socket_correctly_from_parameter() {
188190
assert_eq!(Some("/var/run/postgres/".into()), opts.socket);
189191
}
190192

193+
#[test]
194+
fn it_parses_abstract_socket_correctly_from_parameter() {
195+
let url = "postgres:///?host=@pgdata";
196+
let opts = PgConnectOptions::from_str(url).unwrap();
197+
198+
assert_eq!(Some("@pgdata".into()), opts.socket);
199+
}
200+
191201
#[test]
192202
fn it_parses_host_correctly_from_parameter() {
193203
let url = "postgres:///?host=google.database.com";

tests/postgres/postgres.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,23 @@ async fn it_connects() -> anyhow::Result<()> {
2828
Ok(())
2929
}
3030

31+
#[cfg(any(target_os = "linux", target_os = "android"))]
32+
#[ignore = "requires a PostgreSQL instance listening on the abstract Unix socket @pg_data"]
33+
#[sqlx_macros::test]
34+
async fn it_connects_via_abstract_socket() -> anyhow::Result<()> {
35+
setup_if_needed();
36+
37+
let opts: PgConnectOptions = env::var("DATABASE_URL")?.parse().unwrap();
38+
let opts = opts.socket("@pg_data");
39+
40+
let mut conn = PgConnection::connect_with(&opts).await?;
41+
42+
let value: i32 = sqlx::query_scalar("SELECT 1").fetch_one(&mut conn).await?;
43+
assert_eq!(1, value);
44+
45+
Ok(())
46+
}
47+
3148
#[sqlx_macros::test]
3249
async fn it_can_select_void() -> anyhow::Result<()> {
3350
let mut conn = new::<Postgres>().await?;

0 commit comments

Comments
 (0)