@@ -12,6 +12,7 @@ use crate::{Client, Connection, Error};
12
12
use std:: borrow:: Cow ;
13
13
#[ cfg( unix) ]
14
14
use std:: ffi:: OsStr ;
15
+ use std:: ops:: Deref ;
15
16
#[ cfg( unix) ]
16
17
use std:: os:: unix:: ffi:: OsStrExt ;
17
18
#[ cfg( unix) ]
@@ -90,6 +91,17 @@ pub enum Host {
90
91
/// path to the directory containing Unix domain sockets. Otherwise, it is treated as a hostname. Multiple hosts
91
92
/// can be specified, separated by commas. Each host will be tried in turn when connecting. Required if connecting
92
93
/// with the `connect` method.
94
+ /// * `hostaddr` - Numeric IP address of host to connect to. This should be in the standard IPv4 address format,
95
+ /// e.g., 172.28.40.9. If your machine supports IPv6, you can also use those addresses.
96
+ /// If this parameter is not specified, the value of `host` will be looked up to find the corresponding IP address,
97
+ /// - or if host specifies an IP address, that value will be used directly.
98
+ /// Using `hostaddr` allows the application to avoid a host name look-up, which might be important in applications
99
+ /// with time constraints. However, a host name is required for verify-full SSL certificate verification.
100
+ /// Note that `host` is always required regardless of whether `hostaddr` is present.
101
+ /// * If `host` is specified without `hostaddr`, a host name lookup occurs;
102
+ /// * If both `host` and `hostaddr` are specified, the value for `hostaddr` gives the server network address.
103
+ /// The value for `host` is ignored unless the authentication method requires it,
104
+ /// in which case it will be used as the host name.
93
105
/// * `port` - The port to connect to. Multiple ports can be specified, separated by commas. The number of ports must be
94
106
/// either 1, in which case it will be used for all hosts, or the same as the number of hosts. Defaults to 5432 if
95
107
/// omitted or the empty string.
@@ -117,6 +129,10 @@ pub enum Host {
117
129
/// ```
118
130
///
119
131
/// ```not_rust
132
+ /// 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
133
+ /// ```
134
+ ///
135
+ /// ```not_rust
120
136
/// host=host1,host2,host3 port=1234,,5678 user=postgres target_session_attrs=read-write
121
137
/// ```
122
138
///
@@ -153,6 +169,7 @@ pub struct Config {
153
169
pub ( crate ) application_name : Option < String > ,
154
170
pub ( crate ) ssl_mode : SslMode ,
155
171
pub ( crate ) host : Vec < Host > ,
172
+ pub ( crate ) hostaddr : Vec < String > ,
156
173
pub ( crate ) port : Vec < u16 > ,
157
174
pub ( crate ) connect_timeout : Option < Duration > ,
158
175
pub ( crate ) keepalives : bool ,
@@ -178,6 +195,7 @@ impl Config {
178
195
application_name : None ,
179
196
ssl_mode : SslMode :: Prefer ,
180
197
host : vec ! [ ] ,
198
+ hostaddr : vec ! [ ] ,
181
199
port : vec ! [ ] ,
182
200
connect_timeout : None ,
183
201
keepalives : true ,
@@ -288,6 +306,11 @@ impl Config {
288
306
& self . host
289
307
}
290
308
309
+ /// Gets the hostaddrs that have been added to the configuration with `hostaddr`.
310
+ pub fn get_hostaddrs ( & self ) -> & [ String ] {
311
+ self . hostaddr . deref ( )
312
+ }
313
+
291
314
/// Adds a Unix socket host to the configuration.
292
315
///
293
316
/// Unlike `host`, this method allows non-UTF8 paths.
@@ -300,6 +323,15 @@ impl Config {
300
323
self
301
324
}
302
325
326
+ /// Adds a hostaddr to the configuration.
327
+ ///
328
+ /// Multiple hostaddrs can be specified by calling this method multiple times, and each will be tried in order.
329
+ /// There must be either no hostaddrs, or the same number of hostaddrs as hosts.
330
+ pub fn hostaddr ( & mut self , hostaddr : & str ) -> & mut Config {
331
+ self . hostaddr . push ( hostaddr. to_string ( ) ) ;
332
+ self
333
+ }
334
+
303
335
/// Adds a port to the configuration.
304
336
///
305
337
/// Multiple ports can be specified by calling this method multiple times. There must either be no ports, in which
@@ -418,6 +450,11 @@ impl Config {
418
450
self . host ( host) ;
419
451
}
420
452
}
453
+ "hostaddr" => {
454
+ for hostaddr in value. split ( ',' ) {
455
+ self . hostaddr ( hostaddr) ;
456
+ }
457
+ }
421
458
"port" => {
422
459
for port in value. split ( ',' ) {
423
460
let port = if port. is_empty ( ) {
@@ -542,6 +579,7 @@ impl fmt::Debug for Config {
542
579
. field ( "application_name" , & self . application_name )
543
580
. field ( "ssl_mode" , & self . ssl_mode )
544
581
. field ( "host" , & self . host )
582
+ . field ( "hostaddr" , & self . hostaddr )
545
583
. field ( "port" , & self . port )
546
584
. field ( "connect_timeout" , & self . connect_timeout )
547
585
. field ( "keepalives" , & self . keepalives )
@@ -922,3 +960,35 @@ impl<'a> UrlParser<'a> {
922
960
. map_err ( |e| Error :: config_parse ( e. into ( ) ) )
923
961
}
924
962
}
963
+
964
+ #[ cfg( test) ]
965
+ mod tests {
966
+ use crate :: { config:: Host , Config } ;
967
+
968
+ #[ test]
969
+ fn test_simple_parsing ( ) {
970
+ let s = "user=pass_user dbname=postgres host=host1,host2 hostaddr=127.0.0.1,127.0.0.2 port=26257" ;
971
+ let config = s. parse :: < Config > ( ) . unwrap ( ) ;
972
+ assert_eq ! ( Some ( "pass_user" ) , config. get_user( ) ) ;
973
+ assert_eq ! ( Some ( "postgres" ) , config. get_dbname( ) ) ;
974
+ assert_eq ! (
975
+ [
976
+ Host :: Tcp ( "host1" . to_string( ) ) ,
977
+ Host :: Tcp ( "host2" . to_string( ) )
978
+ ] ,
979
+ config. get_hosts( ) ,
980
+ ) ;
981
+
982
+ assert_eq ! ( [ "127.0.0.1" , "127.0.0.2" ] , config. get_hostaddrs( ) , ) ;
983
+
984
+ assert_eq ! ( 1 , 1 ) ;
985
+ }
986
+
987
+ #[ test]
988
+ fn test_empty_hostaddrs ( ) {
989
+ let s =
990
+ "user=pass_user dbname=postgres host=host1,host2,host3 hostaddr=127.0.0.1,,127.0.0.2" ;
991
+ let config = s. parse :: < Config > ( ) . unwrap ( ) ;
992
+ assert_eq ! ( [ "127.0.0.1" , "" , "127.0.0.2" ] , config. get_hostaddrs( ) , ) ;
993
+ }
994
+ }
0 commit comments