postgres/
config.rs

1//! Connection configuration.
2
3#![allow(clippy::doc_overindented_list_items)]
4
5use crate::connection::Connection;
6use crate::Client;
7use log::info;
8use std::fmt;
9use std::net::IpAddr;
10use std::path::Path;
11use std::str::FromStr;
12use std::sync::Arc;
13use std::time::Duration;
14use tokio::runtime;
15#[doc(inline)]
16pub use tokio_postgres::config::{
17    ChannelBinding, Host, LoadBalanceHosts, SslMode, SslNegotiation, TargetSessionAttrs,
18};
19use tokio_postgres::error::DbError;
20use tokio_postgres::tls::{MakeTlsConnect, TlsConnect};
21use tokio_postgres::{Error, Socket};
22
23/// Connection configuration.
24///
25/// Configuration can be parsed from libpq-style connection strings. These strings come in two formats:
26///
27/// # Key-Value
28///
29/// This format consists of space-separated key-value pairs. Values which are either the empty string or contain
30/// whitespace should be wrapped in `'`. `'` and `\` characters should be backslash-escaped.
31///
32/// ## Keys
33///
34/// * `user` - The username to authenticate with. Defaults to the user executing this process.
35/// * `password` - The password to authenticate with.
36/// * `dbname` - The name of the database to connect to. Defaults to the username.
37/// * `options` - Command line options used to configure the server.
38/// * `application_name` - Sets the `application_name` parameter on the server.
39/// * `sslmode` - Controls usage of TLS. If set to `disable`, TLS will not be used. If set to `prefer`, TLS will be used
40///     if available, but not used otherwise. If set to `require`, TLS will be forced to be used. Defaults to `prefer`.
41/// * `host` - The host to connect to. On Unix platforms, if the host starts with a `/` character it is treated as the
42///     path to the directory containing Unix domain sockets. Otherwise, it is treated as a hostname. Multiple hosts
43///     can be specified, separated by commas. Each host will be tried in turn when connecting. Required if connecting
44///     with the `connect` method.
45/// * `sslnegotiation` - TLS negotiation method. If set to `direct`, the client will perform direct TLS handshake, this only works for PostgreSQL 17 and newer.
46///     Note that you will need to setup ALPN of TLS client configuration to `postgresql` when using direct TLS.
47///     If set to `postgres`, the default value, it follows original postgres wire protocol to perform the negotiation.
48/// * `hostaddr` - Numeric IP address of host to connect to. This should be in the standard IPv4 address format,
49///     e.g., 172.28.40.9. If your machine supports IPv6, you can also use those addresses.
50///     If this parameter is not specified, the value of `host` will be looked up to find the corresponding IP address,
51///     or if host specifies an IP address, that value will be used directly.
52///     Using `hostaddr` allows the application to avoid a host name look-up, which might be important in applications
53///     with time constraints. However, a host name is required for TLS certificate verification.
54///     Specifically:
55///         * If `hostaddr` is specified without `host`, the value for `hostaddr` gives the server network address.
56///             The connection attempt will fail if the authentication method requires a host name;
57///         * If `host` is specified without `hostaddr`, a host name lookup occurs;
58///         * If both `host` and `hostaddr` are specified, the value for `hostaddr` gives the server network address.
59///             The value for `host` is ignored unless the authentication method requires it,
60///             in which case it will be used as the host name.
61/// * `port` - The port to connect to. Multiple ports can be specified, separated by commas. The number of ports must be
62///     either 1, in which case it will be used for all hosts, or the same as the number of hosts. Defaults to 5432 if
63///     omitted or the empty string.
64/// * `connect_timeout` - The time limit in seconds applied to each socket-level connection attempt. Note that hostnames
65///     can resolve to multiple IP addresses, and this limit is applied to each address. Defaults to no timeout.
66/// * `tcp_user_timeout` - The time limit that transmitted data may remain unacknowledged before a connection is forcibly closed.
67///     This is ignored for Unix domain socket connections. It is only supported on systems where TCP_USER_TIMEOUT is available
68///     and will default to the system default if omitted or set to 0; on other systems, it has no effect.
69/// * `keepalives` - Controls the use of TCP keepalive. A value of 0 disables keepalive and nonzero integers enable it.
70///     This option is ignored when connecting with Unix sockets. Defaults to on.
71/// * `keepalives_idle` - The number of seconds of inactivity after which a keepalive message is sent to the server.
72///     This option is ignored when connecting with Unix sockets. Defaults to 2 hours.
73/// * `keepalives_interval` - The time interval between TCP keepalive probes.
74///     This option is ignored when connecting with Unix sockets.
75/// * `keepalives_retries` - The maximum number of TCP keepalive probes that will be sent before dropping a connection.
76///     This option is ignored when connecting with Unix sockets.
77/// * `target_session_attrs` - Specifies requirements of the session. If set to `read-write`, the client will check that
78///     the `transaction_read_write` session parameter is set to `on`. This can be used to connect to the primary server
79///     in a database cluster as opposed to the secondary read-only mirrors. Defaults to `all`.
80/// * `channel_binding` - Controls usage of channel binding in the authentication process. If set to `disable`, channel
81///     binding will not be used. If set to `prefer`, channel binding will be used if available, but not used otherwise.
82///     If set to `require`, the authentication process will fail if channel binding is not used. Defaults to `prefer`.
83/// * `load_balance_hosts` - Controls the order in which the client tries to connect to the available hosts and
84///     addresses. Once a connection attempt is successful no other hosts and addresses will be tried. This parameter
85///     is typically used in combination with multiple host names or a DNS record that returns multiple IPs. If set to
86///     `disable`, hosts and addresses will be tried in the order provided. If set to `random`, hosts will be tried
87///     in a random order, and the IP addresses resolved from a hostname will also be tried in a random order. Defaults
88///     to `disable`.
89///
90/// ## Examples
91///
92/// ```not_rust
93/// host=localhost user=postgres connect_timeout=10 keepalives=0
94/// ```
95///
96/// ```not_rust
97/// host=/var/run/postgresql,localhost port=1234 user=postgres password='password with spaces'
98/// ```
99///
100/// ```not_rust
101/// 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
102/// ```
103///
104/// ```not_rust
105/// host=host1,host2,host3 port=1234,,5678 user=postgres target_session_attrs=read-write
106/// ```
107///
108/// # Url
109///
110/// This format resembles a URL with a scheme of either `postgres://` or `postgresql://`. All components are optional,
111/// and the format accepts query parameters for all of the key-value pairs described in the section above. Multiple
112/// host/port pairs can be comma-separated. Unix socket paths in the host section of the URL should be percent-encoded,
113/// as the path component of the URL specifies the database name.
114///
115/// ## Examples
116///
117/// ```not_rust
118/// postgresql://user@localhost
119/// ```
120///
121/// ```not_rust
122/// postgresql://user:password@%2Fvar%2Frun%2Fpostgresql/mydb?connect_timeout=10
123/// ```
124///
125/// ```not_rust
126/// postgresql://user@host1:1234,host2,host3:5678?target_session_attrs=read-write
127/// ```
128///
129/// ```not_rust
130/// postgresql:///mydb?user=user&host=/var/run/postgresql
131/// ```
132#[derive(Clone)]
133pub struct Config {
134    config: tokio_postgres::Config,
135    notice_callback: Arc<dyn Fn(DbError) + Send + Sync>,
136}
137
138impl fmt::Debug for Config {
139    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
140        fmt.debug_struct("Config")
141            .field("config", &self.config)
142            .finish()
143    }
144}
145
146impl Default for Config {
147    fn default() -> Config {
148        Config::new()
149    }
150}
151
152impl Config {
153    /// Creates a new configuration.
154    pub fn new() -> Config {
155        tokio_postgres::Config::new().into()
156    }
157
158    /// Sets the user to authenticate with.
159    ///
160    /// If the user is not set, then this defaults to the user executing this process.
161    pub fn user(&mut self, user: &str) -> &mut Config {
162        self.config.user(user);
163        self
164    }
165
166    /// Gets the user to authenticate with, if one has been configured with
167    /// the `user` method.
168    pub fn get_user(&self) -> Option<&str> {
169        self.config.get_user()
170    }
171
172    /// Sets the password to authenticate with.
173    pub fn password<T>(&mut self, password: T) -> &mut Config
174    where
175        T: AsRef<[u8]>,
176    {
177        self.config.password(password);
178        self
179    }
180
181    /// Gets the password to authenticate with, if one has been configured with
182    /// the `password` method.
183    pub fn get_password(&self) -> Option<&[u8]> {
184        self.config.get_password()
185    }
186
187    /// Sets the name of the database to connect to.
188    ///
189    /// Defaults to the user.
190    pub fn dbname(&mut self, dbname: &str) -> &mut Config {
191        self.config.dbname(dbname);
192        self
193    }
194
195    /// Gets the name of the database to connect to, if one has been configured
196    /// with the `dbname` method.
197    pub fn get_dbname(&self) -> Option<&str> {
198        self.config.get_dbname()
199    }
200
201    /// Sets command line options used to configure the server.
202    pub fn options(&mut self, options: &str) -> &mut Config {
203        self.config.options(options);
204        self
205    }
206
207    /// Gets the command line options used to configure the server, if the
208    /// options have been set with the `options` method.
209    pub fn get_options(&self) -> Option<&str> {
210        self.config.get_options()
211    }
212
213    /// Sets the value of the `application_name` runtime parameter.
214    pub fn application_name(&mut self, application_name: &str) -> &mut Config {
215        self.config.application_name(application_name);
216        self
217    }
218
219    /// Gets the value of the `application_name` runtime parameter, if it has
220    /// been set with the `application_name` method.
221    pub fn get_application_name(&self) -> Option<&str> {
222        self.config.get_application_name()
223    }
224
225    /// Sets the SSL configuration.
226    ///
227    /// Defaults to `prefer`.
228    pub fn ssl_mode(&mut self, ssl_mode: SslMode) -> &mut Config {
229        self.config.ssl_mode(ssl_mode);
230        self
231    }
232
233    /// Gets the SSL configuration.
234    pub fn get_ssl_mode(&self) -> SslMode {
235        self.config.get_ssl_mode()
236    }
237
238    /// Sets the SSL negotiation method
239    pub fn ssl_negotiation(&mut self, ssl_negotiation: SslNegotiation) -> &mut Config {
240        self.config.ssl_negotiation(ssl_negotiation);
241        self
242    }
243
244    /// Gets the SSL negotiation method
245    pub fn get_ssl_negotiation(&self) -> SslNegotiation {
246        self.config.get_ssl_negotiation()
247    }
248
249    /// Adds a host to the configuration.
250    ///
251    /// Multiple hosts can be specified by calling this method multiple times, and each will be tried in order. On Unix
252    /// systems, a host starting with a `/` is interpreted as a path to a directory containing Unix domain sockets.
253    /// There must be either no hosts, or the same number of hosts as hostaddrs.
254    pub fn host(&mut self, host: &str) -> &mut Config {
255        self.config.host(host);
256        self
257    }
258
259    /// Gets the hosts that have been added to the configuration with `host`.
260    pub fn get_hosts(&self) -> &[Host] {
261        self.config.get_hosts()
262    }
263
264    /// Gets the hostaddrs that have been added to the configuration with `hostaddr`.
265    pub fn get_hostaddrs(&self) -> &[IpAddr] {
266        self.config.get_hostaddrs()
267    }
268
269    /// Adds a Unix socket host to the configuration.
270    ///
271    /// Unlike `host`, this method allows non-UTF8 paths.
272    #[cfg(unix)]
273    pub fn host_path<T>(&mut self, host: T) -> &mut Config
274    where
275        T: AsRef<Path>,
276    {
277        self.config.host_path(host);
278        self
279    }
280
281    /// Adds a hostaddr to the configuration.
282    ///
283    /// Multiple hostaddrs can be specified by calling this method multiple times, and each will be tried in order.
284    /// There must be either no hostaddrs, or the same number of hostaddrs as hosts.
285    pub fn hostaddr(&mut self, hostaddr: IpAddr) -> &mut Config {
286        self.config.hostaddr(hostaddr);
287        self
288    }
289
290    /// Adds a port to the configuration.
291    ///
292    /// Multiple ports can be specified by calling this method multiple times. There must either be no ports, in which
293    /// case the default of 5432 is used, a single port, in which it is used for all hosts, or the same number of ports
294    /// as hosts.
295    pub fn port(&mut self, port: u16) -> &mut Config {
296        self.config.port(port);
297        self
298    }
299
300    /// Gets the ports that have been added to the configuration with `port`.
301    pub fn get_ports(&self) -> &[u16] {
302        self.config.get_ports()
303    }
304
305    /// Sets the timeout applied to socket-level connection attempts.
306    ///
307    /// Note that hostnames can resolve to multiple IP addresses, and this timeout will apply to each address of each
308    /// host separately. Defaults to no limit.
309    pub fn connect_timeout(&mut self, connect_timeout: Duration) -> &mut Config {
310        self.config.connect_timeout(connect_timeout);
311        self
312    }
313
314    /// Gets the connection timeout, if one has been set with the
315    /// `connect_timeout` method.
316    pub fn get_connect_timeout(&self) -> Option<&Duration> {
317        self.config.get_connect_timeout()
318    }
319
320    /// Sets the TCP user timeout.
321    ///
322    /// This is ignored for Unix domain socket connections. It is only supported on systems where
323    /// TCP_USER_TIMEOUT is available and will default to the system default if omitted or set to 0;
324    /// on other systems, it has no effect.
325    pub fn tcp_user_timeout(&mut self, tcp_user_timeout: Duration) -> &mut Config {
326        self.config.tcp_user_timeout(tcp_user_timeout);
327        self
328    }
329
330    /// Gets the TCP user timeout, if one has been set with the
331    /// `user_timeout` method.
332    pub fn get_tcp_user_timeout(&self) -> Option<&Duration> {
333        self.config.get_tcp_user_timeout()
334    }
335
336    /// Controls the use of TCP keepalive.
337    ///
338    /// This is ignored for Unix domain socket connections. Defaults to `true`.
339    pub fn keepalives(&mut self, keepalives: bool) -> &mut Config {
340        self.config.keepalives(keepalives);
341        self
342    }
343
344    /// Reports whether TCP keepalives will be used.
345    pub fn get_keepalives(&self) -> bool {
346        self.config.get_keepalives()
347    }
348
349    /// Sets the amount of idle time before a keepalive packet is sent on the connection.
350    ///
351    /// This is ignored for Unix domain sockets, or if the `keepalives` option is disabled. Defaults to 2 hours.
352    pub fn keepalives_idle(&mut self, keepalives_idle: Duration) -> &mut Config {
353        self.config.keepalives_idle(keepalives_idle);
354        self
355    }
356
357    /// Gets the configured amount of idle time before a keepalive packet will
358    /// be sent on the connection.
359    pub fn get_keepalives_idle(&self) -> Duration {
360        self.config.get_keepalives_idle()
361    }
362
363    /// Sets the time interval between TCP keepalive probes.
364    /// On Windows, this sets the value of the tcp_keepalive struct’s keepaliveinterval field.
365    ///
366    /// This is ignored for Unix domain sockets, or if the `keepalives` option is disabled.
367    pub fn keepalives_interval(&mut self, keepalives_interval: Duration) -> &mut Config {
368        self.config.keepalives_interval(keepalives_interval);
369        self
370    }
371
372    /// Gets the time interval between TCP keepalive probes.
373    pub fn get_keepalives_interval(&self) -> Option<Duration> {
374        self.config.get_keepalives_interval()
375    }
376
377    /// Sets the maximum number of TCP keepalive probes that will be sent before dropping a connection.
378    ///
379    /// This is ignored for Unix domain sockets, or if the `keepalives` option is disabled.
380    pub fn keepalives_retries(&mut self, keepalives_retries: u32) -> &mut Config {
381        self.config.keepalives_retries(keepalives_retries);
382        self
383    }
384
385    /// Gets the maximum number of TCP keepalive probes that will be sent before dropping a connection.
386    pub fn get_keepalives_retries(&self) -> Option<u32> {
387        self.config.get_keepalives_retries()
388    }
389
390    /// Sets the requirements of the session.
391    ///
392    /// This can be used to connect to the primary server in a clustered database rather than one of the read-only
393    /// secondary servers. Defaults to `Any`.
394    pub fn target_session_attrs(
395        &mut self,
396        target_session_attrs: TargetSessionAttrs,
397    ) -> &mut Config {
398        self.config.target_session_attrs(target_session_attrs);
399        self
400    }
401
402    /// Gets the requirements of the session.
403    pub fn get_target_session_attrs(&self) -> TargetSessionAttrs {
404        self.config.get_target_session_attrs()
405    }
406
407    /// Sets the channel binding behavior.
408    ///
409    /// Defaults to `prefer`.
410    pub fn channel_binding(&mut self, channel_binding: ChannelBinding) -> &mut Config {
411        self.config.channel_binding(channel_binding);
412        self
413    }
414
415    /// Gets the channel binding behavior.
416    pub fn get_channel_binding(&self) -> ChannelBinding {
417        self.config.get_channel_binding()
418    }
419
420    /// Sets the host load balancing behavior.
421    ///
422    /// Defaults to `disable`.
423    pub fn load_balance_hosts(&mut self, load_balance_hosts: LoadBalanceHosts) -> &mut Config {
424        self.config.load_balance_hosts(load_balance_hosts);
425        self
426    }
427
428    /// Gets the host load balancing behavior.
429    pub fn get_load_balance_hosts(&self) -> LoadBalanceHosts {
430        self.config.get_load_balance_hosts()
431    }
432
433    /// Sets the notice callback.
434    ///
435    /// This callback will be invoked with the contents of every
436    /// [`AsyncMessage::Notice`] that is received by the connection. Notices use
437    /// the same structure as errors, but they are not "errors" per-se.
438    ///
439    /// Notices are distinct from notifications, which are instead accessible
440    /// via the [`Notifications`] API.
441    ///
442    /// [`AsyncMessage::Notice`]: tokio_postgres::AsyncMessage::Notice
443    /// [`Notifications`]: crate::Notifications
444    pub fn notice_callback<F>(&mut self, f: F) -> &mut Config
445    where
446        F: Fn(DbError) + Send + Sync + 'static,
447    {
448        self.notice_callback = Arc::new(f);
449        self
450    }
451
452    /// Opens a connection to a PostgreSQL database.
453    pub fn connect<T>(&self, tls: T) -> Result<Client, Error>
454    where
455        T: MakeTlsConnect<Socket> + 'static + Send,
456        T::TlsConnect: Send,
457        T::Stream: Send,
458        <T::TlsConnect as TlsConnect<Socket>>::Future: Send,
459    {
460        let runtime = runtime::Builder::new_current_thread()
461            .enable_all()
462            .build()
463            .unwrap(); // FIXME don't unwrap
464
465        let (client, connection) = runtime.block_on(self.config.connect(tls))?;
466
467        let connection = Connection::new(runtime, connection, self.notice_callback.clone());
468        Ok(Client::new(connection, client))
469    }
470}
471
472impl FromStr for Config {
473    type Err = Error;
474
475    fn from_str(s: &str) -> Result<Config, Error> {
476        s.parse::<tokio_postgres::Config>().map(Config::from)
477    }
478}
479
480impl From<tokio_postgres::Config> for Config {
481    fn from(config: tokio_postgres::Config) -> Config {
482        Config {
483            config,
484            notice_callback: Arc::new(|notice| {
485                info!("{}: {}", notice.severity(), notice.message())
486            }),
487        }
488    }
489}