@@ -13,6 +13,7 @@ use crate::{Client, Connection, Error};
13
13
use std:: borrow:: Cow ;
14
14
#[ cfg( unix) ]
15
15
use std:: ffi:: OsStr ;
16
+ use std:: ops:: Deref ;
16
17
#[ cfg( unix) ]
17
18
use std:: os:: unix:: ffi:: OsStrExt ;
18
19
#[ cfg( unix) ]
@@ -91,6 +92,17 @@ pub enum Host {
91
92
/// path to the directory containing Unix domain sockets. Otherwise, it is treated as a hostname. Multiple hosts
92
93
/// can be specified, separated by commas. Each host will be tried in turn when connecting. Required if connecting
93
94
/// with the `connect` method.
95
+ /// * `hostaddr` - Numeric IP address of host to connect to. This should be in the standard IPv4 address format,
96
+ /// e.g., 172.28.40.9. If your machine supports IPv6, you can also use those addresses.
97
+ /// If this parameter is not specified, the value of `host` will be looked up to find the corresponding IP address,
98
+ /// - or if host specifies an IP address, that value will be used directly.
99
+ /// Using `hostaddr` allows the application to avoid a host name look-up, which might be important in applications
100
+ /// with time constraints. However, a host name is required for verify-full SSL certificate verification.
101
+ /// Note that `host` is always required regardless of whether `hostaddr` is present.
102
+ /// * If `host` is specified without `hostaddr`, a host name lookup occurs;
103
+ /// * If both `host` and `hostaddr` are specified, the value for `hostaddr` gives the server network address.
104
+ /// The value for `host` is ignored unless the authentication method requires it,
105
+ /// in which case it will be used as the host name.
94
106
/// * `port` - The port to connect to. Multiple ports can be specified, separated by commas. The number of ports must be
95
107
/// either 1, in which case it will be used for all hosts, or the same as the number of hosts. Defaults to 5432 if
96
108
/// omitted or the empty string.
@@ -122,6 +134,10 @@ pub enum Host {
122
134
/// ```
123
135
///
124
136
/// ```not_rust
137
+ /// host=host1,host2,host3 port=1234,,5678 hostaddr=127.0.0.1,127.0.0.2,127.0.0.3 user=postgres target_session_attrs=read-write
138
+ /// ```
139
+ ///
140
+ /// ```not_rust
125
141
/// host=host1,host2,host3 port=1234,,5678 user=postgres target_session_attrs=read-write
126
142
/// ```
127
143
///
@@ -158,6 +174,7 @@ pub struct Config {
158
174
pub ( crate ) application_name : Option < String > ,
159
175
pub ( crate ) ssl_mode : SslMode ,
160
176
pub ( crate ) host : Vec < Host > ,
177
+ pub ( crate ) hostaddr : Vec < String > ,
161
178
pub ( crate ) port : Vec < u16 > ,
162
179
pub ( crate ) connect_timeout : Option < Duration > ,
163
180
pub ( crate ) keepalives : bool ,
@@ -188,6 +205,7 @@ impl Config {
188
205
application_name : None ,
189
206
ssl_mode : SslMode :: Prefer ,
190
207
host : vec ! [ ] ,
208
+ hostaddr : vec ! [ ] ,
191
209
port : vec ! [ ] ,
192
210
connect_timeout : None ,
193
211
keepalives : true ,
@@ -298,6 +316,11 @@ impl Config {
298
316
& self . host
299
317
}
300
318
319
+ /// Gets the hostaddrs that have been added to the configuration with `hostaddr`.
320
+ pub fn get_hostaddrs ( & self ) -> & [ String ] {
321
+ self . hostaddr . deref ( )
322
+ }
323
+
301
324
/// Adds a Unix socket host to the configuration.
302
325
///
303
326
/// Unlike `host`, this method allows non-UTF8 paths.
@@ -310,6 +333,15 @@ impl Config {
310
333
self
311
334
}
312
335
336
+ /// Adds a hostaddr to the configuration.
337
+ ///
338
+ /// Multiple hostaddrs can be specified by calling this method multiple times, and each will be tried in order.
339
+ /// There must be either no hostaddrs, or the same number of hostaddrs as hosts.
340
+ pub fn hostaddr ( & mut self , hostaddr : & str ) -> & mut Config {
341
+ self . hostaddr . push ( hostaddr. to_string ( ) ) ;
342
+ self
343
+ }
344
+
313
345
/// Adds a port to the configuration.
314
346
///
315
347
/// Multiple ports can be specified by calling this method multiple times. There must either be no ports, in which
@@ -455,6 +487,11 @@ impl Config {
455
487
self . host ( host) ;
456
488
}
457
489
}
490
+ "hostaddr" => {
491
+ for hostaddr in value. split ( ',' ) {
492
+ self . hostaddr ( hostaddr) ;
493
+ }
494
+ }
458
495
"port" => {
459
496
for port in value. split ( ',' ) {
460
497
let port = if port. is_empty ( ) {
@@ -593,6 +630,7 @@ impl fmt::Debug for Config {
593
630
. field ( "application_name" , & self . application_name )
594
631
. field ( "ssl_mode" , & self . ssl_mode )
595
632
. field ( "host" , & self . host )
633
+ . field ( "hostaddr" , & self . hostaddr )
596
634
. field ( "port" , & self . port )
597
635
. field ( "connect_timeout" , & self . connect_timeout )
598
636
. field ( "keepalives" , & self . keepalives )
@@ -975,3 +1013,35 @@ impl<'a> UrlParser<'a> {
975
1013
. map_err ( |e| Error :: config_parse ( e. into ( ) ) )
976
1014
}
977
1015
}
1016
+
1017
+ #[ cfg( test) ]
1018
+ mod tests {
1019
+ use crate :: { config:: Host , Config } ;
1020
+
1021
+ #[ test]
1022
+ fn test_simple_parsing ( ) {
1023
+ let s = "user=pass_user dbname=postgres host=host1,host2 hostaddr=127.0.0.1,127.0.0.2 port=26257" ;
1024
+ let config = s. parse :: < Config > ( ) . unwrap ( ) ;
1025
+ assert_eq ! ( Some ( "pass_user" ) , config. get_user( ) ) ;
1026
+ assert_eq ! ( Some ( "postgres" ) , config. get_dbname( ) ) ;
1027
+ assert_eq ! (
1028
+ [
1029
+ Host :: Tcp ( "host1" . to_string( ) ) ,
1030
+ Host :: Tcp ( "host2" . to_string( ) )
1031
+ ] ,
1032
+ config. get_hosts( ) ,
1033
+ ) ;
1034
+
1035
+ assert_eq ! ( [ "127.0.0.1" , "127.0.0.2" ] , config. get_hostaddrs( ) , ) ;
1036
+
1037
+ assert_eq ! ( 1 , 1 ) ;
1038
+ }
1039
+
1040
+ #[ test]
1041
+ fn test_empty_hostaddrs ( ) {
1042
+ let s =
1043
+ "user=pass_user dbname=postgres host=host1,host2,host3 hostaddr=127.0.0.1,,127.0.0.2" ;
1044
+ let config = s. parse :: < Config > ( ) . unwrap ( ) ;
1045
+ assert_eq ! ( [ "127.0.0.1" , "" , "127.0.0.2" ] , config. get_hostaddrs( ) , ) ;
1046
+ }
1047
+ }
0 commit comments