sqlx_postgres/options/mod.rs
1use std::borrow::Cow;
2use std::env::var;
3use std::fmt::{Display, Write};
4use std::path::{Path, PathBuf};
5
6pub use ssl_mode::PgSslMode;
7
8use crate::{connection::LogSettings, net::tls::CertificateInput};
9
10mod connect;
11mod parse;
12mod pgpass;
13mod ssl_mode;
14
15/// Options and flags which can be used to configure a PostgreSQL connection.
16///
17/// A value of `PgConnectOptions` can be parsed from a connection URL,
18/// as described by [libpq](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING).
19///
20/// The general form for a connection URL is:
21///
22/// ```text
23/// postgresql://[user[:password]@][host][:port][/dbname][?param1=value1&...]
24/// ```
25///
26/// This type also implements [`FromStr`][std::str::FromStr] so you can parse it from a string
27/// containing a connection URL and then further adjust options if necessary (see example below).
28///
29/// ## Parameters
30///
31/// |Parameter|Default|Description|
32/// |---------|-------|-----------|
33/// | `sslmode` | `prefer` | Determines whether or with what priority a secure SSL TCP/IP connection will be negotiated. See [`PgSslMode`]. |
34/// | `sslrootcert` | `None` | Sets the name of a file containing a list of trusted SSL Certificate Authorities. |
35/// | `statement-cache-capacity` | `100` | The maximum number of prepared statements stored in the cache. Set to `0` to disable. |
36/// | `host` | `None` | Path to the directory containing a PostgreSQL unix domain socket, which will be used instead of TCP if set. |
37/// | `hostaddr` | `None` | Same as `host`, but only accepts IP addresses. |
38/// | `application-name` | `None` | The name will be displayed in the pg_stat_activity view and included in CSV log entries. |
39/// | `user` | result of `whoami` | PostgreSQL user name to connect as. |
40/// | `password` | `None` | Password to be used if the server demands password authentication. |
41/// | `port` | `5432` | Port number to connect to at the server host, or socket file name extension for Unix-domain connections. |
42/// | `dbname` | `None` | The database name. |
43/// | `options` | `None` | The runtime parameters to send to the server at connection start. |
44///
45/// The URL scheme designator can be either `postgresql://` or `postgres://`.
46/// Each of the URL parts is optional.
47///
48/// ```text
49/// postgresql://
50/// postgresql://localhost
51/// postgresql://localhost:5433
52/// postgresql://localhost/mydb
53/// postgresql://user@localhost
54/// postgresql://user:secret@localhost
55/// postgresql://localhost?dbname=mydb&user=postgres&password=postgres
56/// ```
57///
58/// # Example
59///
60/// ```rust,no_run
61/// use sqlx::{Connection, ConnectOptions};
62/// use sqlx::postgres::{PgConnectOptions, PgConnection, PgPool, PgSslMode};
63///
64/// # async fn example() -> sqlx::Result<()> {
65/// // URL connection string
66/// let conn = PgConnection::connect("postgres://localhost/mydb").await?;
67///
68/// // Manually-constructed options
69/// let conn = PgConnectOptions::new()
70/// .host("secret-host")
71/// .port(2525)
72/// .username("secret-user")
73/// .password("secret-password")
74/// .ssl_mode(PgSslMode::Require)
75/// .connect()
76/// .await?;
77///
78/// // Modifying options parsed from a string
79/// let mut opts: PgConnectOptions = "postgres://localhost/mydb".parse()?;
80///
81/// // Change the log verbosity level for queries.
82/// // Information about SQL queries is logged at `DEBUG` level by default.
83/// opts = opts.log_statements(log::LevelFilter::Trace);
84///
85/// let pool = PgPool::connect_with(opts).await?;
86/// # Ok(())
87/// # }
88/// ```
89#[derive(Debug, Clone)]
90pub struct PgConnectOptions {
91 pub(crate) host: String,
92 pub(crate) port: u16,
93 pub(crate) socket: Option<PathBuf>,
94 pub(crate) username: String,
95 pub(crate) password: Option<String>,
96 pub(crate) database: Option<String>,
97 pub(crate) ssl_mode: PgSslMode,
98 pub(crate) ssl_root_cert: Option<CertificateInput>,
99 pub(crate) ssl_client_cert: Option<CertificateInput>,
100 pub(crate) ssl_client_key: Option<CertificateInput>,
101 pub(crate) statement_cache_capacity: usize,
102 pub(crate) application_name: Option<String>,
103 pub(crate) log_settings: LogSettings,
104 pub(crate) extra_float_digits: Option<Cow<'static, str>>,
105 pub(crate) options: Option<String>,
106}
107
108impl Default for PgConnectOptions {
109 fn default() -> Self {
110 Self::new_without_pgpass().apply_pgpass()
111 }
112}
113
114impl PgConnectOptions {
115 /// Creates a new, default set of options ready for configuration.
116 ///
117 /// By default, this reads the following environment variables and sets their
118 /// equivalent options.
119 ///
120 /// * `PGHOST`
121 /// * `PGPORT`
122 /// * `PGUSER`
123 /// * `PGPASSWORD`
124 /// * `PGDATABASE`
125 /// * `PGSSLROOTCERT`
126 /// * `PGSSLCERT`
127 /// * `PGSSLKEY`
128 /// * `PGSSLMODE`
129 /// * `PGAPPNAME`
130 ///
131 /// # Example
132 ///
133 /// ```rust
134 /// # use sqlx_postgres::PgConnectOptions;
135 /// let options = PgConnectOptions::new();
136 /// ```
137 pub fn new() -> Self {
138 Self::new_without_pgpass().apply_pgpass()
139 }
140
141 pub fn new_without_pgpass() -> Self {
142 let port = var("PGPORT")
143 .ok()
144 .and_then(|v| v.parse().ok())
145 .unwrap_or(5432);
146
147 let host = var("PGHOST").ok().unwrap_or_else(|| default_host(port));
148
149 let username = var("PGUSER").ok().unwrap_or_else(whoami::username);
150
151 let database = var("PGDATABASE").ok();
152
153 PgConnectOptions {
154 port,
155 host,
156 socket: None,
157 username,
158 password: var("PGPASSWORD").ok(),
159 database,
160 ssl_root_cert: var("PGSSLROOTCERT").ok().map(CertificateInput::from),
161 ssl_client_cert: var("PGSSLCERT").ok().map(CertificateInput::from),
162 ssl_client_key: var("PGSSLKEY").ok().map(CertificateInput::from),
163 ssl_mode: var("PGSSLMODE")
164 .ok()
165 .and_then(|v| v.parse().ok())
166 .unwrap_or_default(),
167 statement_cache_capacity: 100,
168 application_name: var("PGAPPNAME").ok(),
169 extra_float_digits: Some("2".into()),
170 log_settings: Default::default(),
171 options: var("PGOPTIONS").ok(),
172 }
173 }
174
175 pub(crate) fn apply_pgpass(mut self) -> Self {
176 if self.password.is_none() {
177 self.password = pgpass::load_password(
178 &self.host,
179 self.port,
180 &self.username,
181 self.database.as_deref(),
182 );
183 }
184
185 self
186 }
187
188 /// Sets the name of the host to connect to.
189 ///
190 /// If a host name begins with a slash, it specifies
191 /// Unix-domain communication rather than TCP/IP communication; the value is the name of
192 /// the directory in which the socket file is stored.
193 ///
194 /// The default behavior when host is not specified, or is empty,
195 /// is to connect to a Unix-domain socket
196 ///
197 /// # Example
198 ///
199 /// ```rust
200 /// # use sqlx_postgres::PgConnectOptions;
201 /// let options = PgConnectOptions::new()
202 /// .host("localhost");
203 /// ```
204 pub fn host(mut self, host: &str) -> Self {
205 host.clone_into(&mut self.host);
206 self
207 }
208
209 /// Sets the port to connect to at the server host.
210 ///
211 /// The default port for PostgreSQL is `5432`.
212 ///
213 /// # Example
214 ///
215 /// ```rust
216 /// # use sqlx_postgres::PgConnectOptions;
217 /// let options = PgConnectOptions::new()
218 /// .port(5432);
219 /// ```
220 pub fn port(mut self, port: u16) -> Self {
221 self.port = port;
222 self
223 }
224
225 /// Sets a custom path to a directory containing a unix domain socket,
226 /// switching the connection method from TCP to the corresponding socket.
227 ///
228 /// By default set to `None`.
229 pub fn socket(mut self, path: impl AsRef<Path>) -> Self {
230 self.socket = Some(path.as_ref().to_path_buf());
231 self
232 }
233
234 /// Sets the username to connect as.
235 ///
236 /// Defaults to be the same as the operating system name of
237 /// the user running the application.
238 ///
239 /// # Example
240 ///
241 /// ```rust
242 /// # use sqlx_postgres::PgConnectOptions;
243 /// let options = PgConnectOptions::new()
244 /// .username("postgres");
245 /// ```
246 pub fn username(mut self, username: &str) -> Self {
247 username.clone_into(&mut self.username);
248 self
249 }
250
251 /// Sets the password to use if the server demands password authentication.
252 ///
253 /// # Example
254 ///
255 /// ```rust
256 /// # use sqlx_postgres::PgConnectOptions;
257 /// let options = PgConnectOptions::new()
258 /// .username("root")
259 /// .password("safe-and-secure");
260 /// ```
261 pub fn password(mut self, password: &str) -> Self {
262 self.password = Some(password.to_owned());
263 self
264 }
265
266 /// Sets the database name. Defaults to be the same as the user name.
267 ///
268 /// # Example
269 ///
270 /// ```rust
271 /// # use sqlx_postgres::PgConnectOptions;
272 /// let options = PgConnectOptions::new()
273 /// .database("postgres");
274 /// ```
275 pub fn database(mut self, database: &str) -> Self {
276 self.database = Some(database.to_owned());
277 self
278 }
279
280 /// Sets whether or with what priority a secure SSL TCP/IP connection will be negotiated
281 /// with the server.
282 ///
283 /// By default, the SSL mode is [`Prefer`](PgSslMode::Prefer), and the client will
284 /// first attempt an SSL connection but fallback to a non-SSL connection on failure.
285 ///
286 /// Ignored for Unix domain socket communication.
287 ///
288 /// # Example
289 ///
290 /// ```rust
291 /// # use sqlx_postgres::{PgSslMode, PgConnectOptions};
292 /// let options = PgConnectOptions::new()
293 /// .ssl_mode(PgSslMode::Require);
294 /// ```
295 pub fn ssl_mode(mut self, mode: PgSslMode) -> Self {
296 self.ssl_mode = mode;
297 self
298 }
299
300 /// Sets the name of a file containing SSL certificate authority (CA) certificate(s).
301 /// If the file exists, the server's certificate will be verified to be signed by
302 /// one of these authorities.
303 ///
304 /// # Example
305 ///
306 /// ```rust
307 /// # use sqlx_postgres::{PgSslMode, PgConnectOptions};
308 /// let options = PgConnectOptions::new()
309 /// // Providing a CA certificate with less than VerifyCa is pointless
310 /// .ssl_mode(PgSslMode::VerifyCa)
311 /// .ssl_root_cert("./ca-certificate.crt");
312 /// ```
313 pub fn ssl_root_cert(mut self, cert: impl AsRef<Path>) -> Self {
314 self.ssl_root_cert = Some(CertificateInput::File(cert.as_ref().to_path_buf()));
315 self
316 }
317
318 /// Sets the name of a file containing SSL client certificate.
319 ///
320 /// # Example
321 ///
322 /// ```rust
323 /// # use sqlx_postgres::{PgSslMode, PgConnectOptions};
324 /// let options = PgConnectOptions::new()
325 /// // Providing a CA certificate with less than VerifyCa is pointless
326 /// .ssl_mode(PgSslMode::VerifyCa)
327 /// .ssl_client_cert("./client.crt");
328 /// ```
329 pub fn ssl_client_cert(mut self, cert: impl AsRef<Path>) -> Self {
330 self.ssl_client_cert = Some(CertificateInput::File(cert.as_ref().to_path_buf()));
331 self
332 }
333
334 /// Sets the SSL client certificate as a PEM-encoded byte slice.
335 ///
336 /// This should be an ASCII-encoded blob that starts with `-----BEGIN CERTIFICATE-----`.
337 ///
338 /// # Example
339 /// Note: embedding SSL certificates and keys in the binary is not advised.
340 /// This is for illustration purposes only.
341 ///
342 /// ```rust
343 /// # use sqlx_postgres::{PgSslMode, PgConnectOptions};
344 ///
345 /// const CERT: &[u8] = b"\
346 /// -----BEGIN CERTIFICATE-----
347 /// <Certificate data here.>
348 /// -----END CERTIFICATE-----";
349 ///
350 /// let options = PgConnectOptions::new()
351 /// // Providing a CA certificate with less than VerifyCa is pointless
352 /// .ssl_mode(PgSslMode::VerifyCa)
353 /// .ssl_client_cert_from_pem(CERT);
354 /// ```
355 pub fn ssl_client_cert_from_pem(mut self, cert: impl AsRef<[u8]>) -> Self {
356 self.ssl_client_cert = Some(CertificateInput::Inline(cert.as_ref().to_vec()));
357 self
358 }
359
360 /// Sets the name of a file containing SSL client key.
361 ///
362 /// # Example
363 ///
364 /// ```rust
365 /// # use sqlx_postgres::{PgSslMode, PgConnectOptions};
366 /// let options = PgConnectOptions::new()
367 /// // Providing a CA certificate with less than VerifyCa is pointless
368 /// .ssl_mode(PgSslMode::VerifyCa)
369 /// .ssl_client_key("./client.key");
370 /// ```
371 pub fn ssl_client_key(mut self, key: impl AsRef<Path>) -> Self {
372 self.ssl_client_key = Some(CertificateInput::File(key.as_ref().to_path_buf()));
373 self
374 }
375
376 /// Sets the SSL client key as a PEM-encoded byte slice.
377 ///
378 /// This should be an ASCII-encoded blob that starts with `-----BEGIN PRIVATE KEY-----`.
379 ///
380 /// # Example
381 /// Note: embedding SSL certificates and keys in the binary is not advised.
382 /// This is for illustration purposes only.
383 ///
384 /// ```rust
385 /// # use sqlx_postgres::{PgSslMode, PgConnectOptions};
386 ///
387 /// const KEY: &[u8] = b"\
388 /// -----BEGIN PRIVATE KEY-----
389 /// <Private key data here.>
390 /// -----END PRIVATE KEY-----";
391 ///
392 /// let options = PgConnectOptions::new()
393 /// // Providing a CA certificate with less than VerifyCa is pointless
394 /// .ssl_mode(PgSslMode::VerifyCa)
395 /// .ssl_client_key_from_pem(KEY);
396 /// ```
397 pub fn ssl_client_key_from_pem(mut self, key: impl AsRef<[u8]>) -> Self {
398 self.ssl_client_key = Some(CertificateInput::Inline(key.as_ref().to_vec()));
399 self
400 }
401
402 /// Sets PEM encoded trusted SSL Certificate Authorities (CA).
403 ///
404 /// # Example
405 ///
406 /// ```rust
407 /// # use sqlx_postgres::{PgSslMode, PgConnectOptions};
408 /// let options = PgConnectOptions::new()
409 /// // Providing a CA certificate with less than VerifyCa is pointless
410 /// .ssl_mode(PgSslMode::VerifyCa)
411 /// .ssl_root_cert_from_pem(vec![]);
412 /// ```
413 pub fn ssl_root_cert_from_pem(mut self, pem_certificate: Vec<u8>) -> Self {
414 self.ssl_root_cert = Some(CertificateInput::Inline(pem_certificate));
415 self
416 }
417
418 /// Sets the capacity of the connection's statement cache in a number of stored
419 /// distinct statements. Caching is handled using LRU, meaning when the
420 /// amount of queries hits the defined limit, the oldest statement will get
421 /// dropped.
422 ///
423 /// The default cache capacity is 100 statements.
424 pub fn statement_cache_capacity(mut self, capacity: usize) -> Self {
425 self.statement_cache_capacity = capacity;
426 self
427 }
428
429 /// Sets the application name. Defaults to None
430 ///
431 /// # Example
432 ///
433 /// ```rust
434 /// # use sqlx_postgres::PgConnectOptions;
435 /// let options = PgConnectOptions::new()
436 /// .application_name("my-app");
437 /// ```
438 pub fn application_name(mut self, application_name: &str) -> Self {
439 self.application_name = Some(application_name.to_owned());
440 self
441 }
442
443 /// Sets or removes the `extra_float_digits` connection option.
444 ///
445 /// This changes the default precision of floating-point values returned in text mode (when
446 /// not using prepared statements such as calling methods of [`Executor`] directly).
447 ///
448 /// Historically, Postgres would by default round floating-point values to 6 and 15 digits
449 /// for `float4`/`REAL` (`f32`) and `float8`/`DOUBLE` (`f64`), respectively, which would mean
450 /// that the returned value may not be exactly the same as its representation in Postgres.
451 ///
452 /// The nominal range for this value is `-15` to `3`, where negative values for this option
453 /// cause floating-points to be rounded to that many fewer digits than normal (`-1` causes
454 /// `float4` to be rounded to 5 digits instead of six, or 14 instead of 15 for `float8`),
455 /// positive values cause Postgres to emit that many extra digits of precision over default
456 /// (or simply use maximum precision in Postgres 12 and later),
457 /// and 0 means keep the default behavior (or the "old" behavior described above
458 /// as of Postgres 12).
459 ///
460 /// SQLx sets this value to 3 by default, which tells Postgres to return floating-point values
461 /// at their maximum precision in the hope that the parsed value will be identical to its
462 /// counterpart in Postgres. This is also the default in Postgres 12 and later anyway.
463 ///
464 /// However, older versions of Postgres and alternative implementations that talk the Postgres
465 /// protocol may not support this option, or the full range of values.
466 ///
467 /// If you get an error like "unknown option `extra_float_digits`" when connecting, try
468 /// setting this to `None` or consult the manual of your database for the allowed range
469 /// of values.
470 ///
471 /// For more information, see:
472 /// * [Postgres manual, 20.11.2: Client Connection Defaults; Locale and Formatting][20.11.2]
473 /// * [Postgres manual, 8.1.3: Numeric Types; Floating-point Types][8.1.3]
474 ///
475 /// [`Executor`]: crate::executor::Executor
476 /// [20.11.2]: https://www.postgresql.org/docs/current/runtime-config-client.html#RUNTIME-CONFIG-CLIENT-FORMAT
477 /// [8.1.3]: https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-FLOAT
478 ///
479 /// ### Examples
480 /// ```rust
481 /// # use sqlx_postgres::PgConnectOptions;
482 ///
483 /// let mut options = PgConnectOptions::new()
484 /// // for Redshift and Postgres 10
485 /// .extra_float_digits(2);
486 ///
487 /// let mut options = PgConnectOptions::new()
488 /// // don't send the option at all (Postgres 9 and older)
489 /// .extra_float_digits(None);
490 /// ```
491 pub fn extra_float_digits(mut self, extra_float_digits: impl Into<Option<i8>>) -> Self {
492 self.extra_float_digits = extra_float_digits.into().map(|it| it.to_string().into());
493 self
494 }
495
496 /// Set additional startup options for the connection as a list of key-value pairs.
497 ///
498 /// # Example
499 ///
500 /// ```rust
501 /// # use sqlx_postgres::PgConnectOptions;
502 /// let options = PgConnectOptions::new()
503 /// .options([("geqo", "off"), ("statement_timeout", "5min")]);
504 /// ```
505 pub fn options<K, V, I>(mut self, options: I) -> Self
506 where
507 K: Display,
508 V: Display,
509 I: IntoIterator<Item = (K, V)>,
510 {
511 // Do this in here so `options_str` is only set if we have an option to insert
512 let options_str = self.options.get_or_insert_with(String::new);
513 for (k, v) in options {
514 if !options_str.is_empty() {
515 options_str.push(' ');
516 }
517
518 write!(options_str, "-c {k}={v}").expect("failed to write an option to the string");
519 }
520 self
521 }
522
523 /// We try using a socket if hostname starts with `/` or if socket parameter
524 /// is specified.
525 pub(crate) fn fetch_socket(&self) -> Option<String> {
526 match self.socket {
527 Some(ref socket) => {
528 let full_path = format!("{}/.s.PGSQL.{}", socket.display(), self.port);
529 Some(full_path)
530 }
531 None if self.host.starts_with('/') => {
532 let full_path = format!("{}/.s.PGSQL.{}", self.host, self.port);
533 Some(full_path)
534 }
535 _ => None,
536 }
537 }
538}
539
540impl PgConnectOptions {
541 /// Get the current host.
542 ///
543 /// # Example
544 ///
545 /// ```rust
546 /// # use sqlx_postgres::PgConnectOptions;
547 /// let options = PgConnectOptions::new()
548 /// .host("127.0.0.1");
549 /// assert_eq!(options.get_host(), "127.0.0.1");
550 /// ```
551 pub fn get_host(&self) -> &str {
552 &self.host
553 }
554
555 /// Get the server's port.
556 ///
557 /// # Example
558 ///
559 /// ```rust
560 /// # use sqlx_postgres::PgConnectOptions;
561 /// let options = PgConnectOptions::new()
562 /// .port(6543);
563 /// assert_eq!(options.get_port(), 6543);
564 /// ```
565 pub fn get_port(&self) -> u16 {
566 self.port
567 }
568
569 /// Get the socket path.
570 ///
571 /// # Example
572 ///
573 /// ```rust
574 /// # use sqlx_postgres::PgConnectOptions;
575 /// let options = PgConnectOptions::new()
576 /// .socket("/tmp");
577 /// assert!(options.get_socket().is_some());
578 /// ```
579 pub fn get_socket(&self) -> Option<&PathBuf> {
580 self.socket.as_ref()
581 }
582
583 /// Get the server's port.
584 ///
585 /// # Example
586 ///
587 /// ```rust
588 /// # use sqlx_postgres::PgConnectOptions;
589 /// let options = PgConnectOptions::new()
590 /// .username("foo");
591 /// assert_eq!(options.get_username(), "foo");
592 /// ```
593 pub fn get_username(&self) -> &str {
594 &self.username
595 }
596
597 /// Get the current database name.
598 ///
599 /// # Example
600 ///
601 /// ```rust
602 /// # use sqlx_postgres::PgConnectOptions;
603 /// let options = PgConnectOptions::new()
604 /// .database("postgres");
605 /// assert!(options.get_database().is_some());
606 /// ```
607 pub fn get_database(&self) -> Option<&str> {
608 self.database.as_deref()
609 }
610
611 /// Get the SSL mode.
612 ///
613 /// # Example
614 ///
615 /// ```rust
616 /// # use sqlx_postgres::{PgConnectOptions, PgSslMode};
617 /// let options = PgConnectOptions::new();
618 /// assert!(matches!(options.get_ssl_mode(), PgSslMode::Prefer));
619 /// ```
620 pub fn get_ssl_mode(&self) -> PgSslMode {
621 self.ssl_mode
622 }
623
624 /// Get the application name.
625 ///
626 /// # Example
627 ///
628 /// ```rust
629 /// # use sqlx_postgres::PgConnectOptions;
630 /// let options = PgConnectOptions::new()
631 /// .application_name("service");
632 /// assert!(options.get_application_name().is_some());
633 /// ```
634 pub fn get_application_name(&self) -> Option<&str> {
635 self.application_name.as_deref()
636 }
637
638 /// Get the options.
639 ///
640 /// # Example
641 ///
642 /// ```rust
643 /// # use sqlx_postgres::PgConnectOptions;
644 /// let options = PgConnectOptions::new()
645 /// .options([("foo", "bar")]);
646 /// assert!(options.get_options().is_some());
647 /// ```
648 pub fn get_options(&self) -> Option<&str> {
649 self.options.as_deref()
650 }
651}
652
653fn default_host(port: u16) -> String {
654 // try to check for the existence of a unix socket and uses that
655 let socket = format!(".s.PGSQL.{port}");
656 let candidates = [
657 "/var/run/postgresql", // Debian
658 "/private/tmp", // OSX (homebrew)
659 "/tmp", // Default
660 ];
661
662 for candidate in &candidates {
663 if Path::new(candidate).join(&socket).exists() {
664 return candidate.to_string();
665 }
666 }
667
668 // fallback to localhost if no socket was found
669 "localhost".to_owned()
670}
671
672#[test]
673fn test_options_formatting() {
674 let options = PgConnectOptions::new().options([("geqo", "off")]);
675 assert_eq!(options.options, Some("-c geqo=off".to_string()));
676 let options = options.options([("search_path", "sqlx")]);
677 assert_eq!(
678 options.options,
679 Some("-c geqo=off -c search_path=sqlx".to_string())
680 );
681 let options = PgConnectOptions::new().options([("geqo", "off"), ("statement_timeout", "5min")]);
682 assert_eq!(
683 options.options,
684 Some("-c geqo=off -c statement_timeout=5min".to_string())
685 );
686 let options = PgConnectOptions::new();
687 assert_eq!(options.options, None);
688}