0.8.4 release (#3819)

* chore: prepare 0.8.4 release

* fix(postgres): send `limit: 0` for all `Execute` messages

fixes #3673

* fix: let `CertificateInput::from` infer any PEM-encoded document

https://github.com/launchbadge/sqlx/pull/3809#issuecomment-2800293813

* doc: improve documentation of `PgConnectOptions`

fixes #3740

* chore: update CHANGELOG from PR
This commit is contained in:
Austin Bonander 2025-04-13 21:55:14 -07:00 committed by GitHub
parent 154878547e
commit f9084035d7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 383 additions and 134 deletions

View File

@ -5,6 +5,134 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 0.8.4 - 2025-04-13
50 pull requests were merged this release cycle.
As of this release, development of `0.9.0` has begun on `main`.
Barring urgent hotfixes, this is expected to be the last release of `0.8.x`.
### Added
* [[#3603]]: Added missing special casing for encoding embedded arrays of custom types [[@nico-incubiq]]
* [[#3625]]: feat(sqlite): add preupdate hook [[@aschey]]
* [[#3655]]: docs: add example for postgres enums with type TEXT [[@tisonkun]]
* [[#3677]]: Add json(nullable) macro attribute [[@seanaye]]
* [[#3687]]: Derive clone and debug for postgresql arguments [[@remysaissy]]
* [[#3690]]: feat: add postres geometry line segment [[@jayy-lmao]]
* [[#3707]]: feat(Sqlite): add LockedSqliteHandle::last_error [[@joeydewaal]]
* [[#3710]]: feat: add ipnet support [[@BeauGieskens]]
* [[#3711]]: feat(postgres): add geometry box [[@jayy-lmao]]
* [[#3714]]: chore: expose bstr feature [[@joeydewaal]]
* [[#3716]]: feat(postgres): add geometry path [[@jayy-lmao]]
* [[#3724]]: feat(sqlx-cli): Add flag to disable automatic loading of .env files [[@benwilber]]
* [[#3734]]: QueryBuilder: add debug_assert when `push_values` is passed an empty set of tuples [[@chanmaoganda]]
* [[#3745]]: feat: sqlx sqlite expose de/serialize [[@mattrighetti]]
* [[#3765]]: Merge of #3427 (by @mpyw) and #3614 (by @bonsairobo) [[@abonander]]
* [[#3427]] Expose `transaction_depth` through `get_transaction_depth()` method [[@mpyw]]
* Changed to `Connection::is_in_transaction` in [[#3765]]
* [[#3614]] Add `begin_with` methods to support database-specific transaction options [[@bonsairobo]]
* [[#3769]]: feat(postgres): add geometry polygon [[@jayy-lmao]]
* [[#3773]]: feat(postgres): add geometry circle [[@jayy-lmao]]
### Changed
* [[#3665]]: build(deps): bump semver compatible dependencies [[@paolobarbolini]]
* [[#3669]]: refactor(cli): replace promptly with dialoguer [[@paolobarbolini]]
* [[#3672]]: add `#[track_caller]` to `Row::get()` [[@karambarakat]]
* [[#3708]]: chore(MySql): Remove unnecessary box [[@joeydewaal]]
* [[#3715]]: chore: add pg_copy regression tests [[@joeydewaal]]
* [[#3721]]: Replace some `futures-core` / `futures-util` APIs with `std` variants [[@paolobarbolini]]
* [[#3725]]: chore: replace rustls-pemfile with rustls-pki-types [[@tottoto]]
* [[#3754]]: chore(cli): remove unused async-trait crate from dependencies [[@tottoto]]
* [[#3762]]: docs(pool): recommend actix-web ThinData over Data to avoid two Arcs [[@jonasmalacofilho]]
### Fixed
* [[#3289]]: Always set `SQLITE_OPEN_URI` on in-memory sqlite [[@LecrisUT]]
* [[#3334]]: Fix: nextest cleanup race condition [[@bonega]]
* [[#3666]]: fix(cli): running tests on 32bit platforms [[@paolobarbolini]]
* [[#3686]]: fix: handle nullable values by printing NULL instead of panicking [[@joeydewaal]]
* [[#3700]]: fix(Sqlite): stop sending rows after first error [[@joeydewaal]]
* [[#3701]]: fix(postgres) use signed int for length prefix in `PgCopyIn` [[@joeydewaal]]
* [[#3703]]: fix(Postgres) chunk pg_copy data [[@joeydewaal]]
* [[#3712]]: FromRow: Fix documentation order [[@Turbo87]]
* [[#3720]]: Fix readme: uuid feature is gating for all repos [[@jthacker]]
* [[#3728]]: postgres: Fix tracing span when dropping PgListener [[@chitoku-k]]
* [[#3741]]: Fix example calculation in docs [[@dns2utf8]]
* [[#3749]]: docs: add some missing backticks [[@soulwa]]
* [[#3753]]: Avoid privilege requirements by using an advisory lock in test setup (postgres). [[@kildrens]]
* [[#3755]]: Fix FromRow docs for tuples [[@xvapx]]
* [[#3768]]: chore(Sqlite): remove ci.db from repo [[@joeydewaal]]
* [[#3771]]: fix(ci): breakage from Rustup 1.28 [[@abonander]]
* [[#3786]]: Fix a copy-paste error on get_username docs [[@sulami]]
* [[#3801]]: Fix: Enable Json type when db feature isn't enabled [[@thriller08]]
* [[#3809]]: fix: PgConnectOptions docs [[@mbj]]
* [[#3811]]: Fix error message typo in PgPoint::from_str [[@TeCHiScy]]
* [[#3812]]: mysql: Fix panic on invalid text row length field [[@0xdeafbeef]]
* [[#3815]]: fix(macros): cache macro metadata based on `CARGO_MANIFEST_DIR` [[@joeydewaal]]
* Fixes in release PR [[#3819]] [[@abonander]]:
* fix(postgres): send `limit: 0` for all `Execute` messages
* Addresses [[#3673]]: Parallel workers not used on Postgres
* fix: let `CertificateInput::from` infer any PEM-encoded document
* Fixes `PGSSLKEY` not being parsed correctly when containing a PEM-encoded private key.
* doc: improve documentation of `PgConnectOptions`
* `PGHOSTADDR` now can be used to override `PGHOST`.
* Addresses [[#3740]]: Document the URL syntax for Unix-domain sockets when connecting to postgres
[#3819]: https://github.com/launchbadge/sqlx/pull/3819
[#3673]: https://github.com/launchbadge/sqlx/issues/3673
[#3740]: https://github.com/launchbadge/sqlx/issues/3740
[#3289]: https://github.com/launchbadge/sqlx/pull/3289
[#3334]: https://github.com/launchbadge/sqlx/pull/3334
[#3427]: https://github.com/launchbadge/sqlx/pull/3427
[#3603]: https://github.com/launchbadge/sqlx/pull/3603
[#3614]: https://github.com/launchbadge/sqlx/pull/3614
[#3625]: https://github.com/launchbadge/sqlx/pull/3625
[#3655]: https://github.com/launchbadge/sqlx/pull/3655
[#3665]: https://github.com/launchbadge/sqlx/pull/3665
[#3666]: https://github.com/launchbadge/sqlx/pull/3666
[#3669]: https://github.com/launchbadge/sqlx/pull/3669
[#3672]: https://github.com/launchbadge/sqlx/pull/3672
[#3677]: https://github.com/launchbadge/sqlx/pull/3677
[#3686]: https://github.com/launchbadge/sqlx/pull/3686
[#3687]: https://github.com/launchbadge/sqlx/pull/3687
[#3690]: https://github.com/launchbadge/sqlx/pull/3690
[#3700]: https://github.com/launchbadge/sqlx/pull/3700
[#3701]: https://github.com/launchbadge/sqlx/pull/3701
[#3703]: https://github.com/launchbadge/sqlx/pull/3703
[#3707]: https://github.com/launchbadge/sqlx/pull/3707
[#3708]: https://github.com/launchbadge/sqlx/pull/3708
[#3710]: https://github.com/launchbadge/sqlx/pull/3710
[#3711]: https://github.com/launchbadge/sqlx/pull/3711
[#3712]: https://github.com/launchbadge/sqlx/pull/3712
[#3714]: https://github.com/launchbadge/sqlx/pull/3714
[#3715]: https://github.com/launchbadge/sqlx/pull/3715
[#3716]: https://github.com/launchbadge/sqlx/pull/3716
[#3720]: https://github.com/launchbadge/sqlx/pull/3720
[#3721]: https://github.com/launchbadge/sqlx/pull/3721
[#3724]: https://github.com/launchbadge/sqlx/pull/3724
[#3725]: https://github.com/launchbadge/sqlx/pull/3725
[#3728]: https://github.com/launchbadge/sqlx/pull/3728
[#3734]: https://github.com/launchbadge/sqlx/pull/3734
[#3741]: https://github.com/launchbadge/sqlx/pull/3741
[#3745]: https://github.com/launchbadge/sqlx/pull/3745
[#3749]: https://github.com/launchbadge/sqlx/pull/3749
[#3753]: https://github.com/launchbadge/sqlx/pull/3753
[#3754]: https://github.com/launchbadge/sqlx/pull/3754
[#3755]: https://github.com/launchbadge/sqlx/pull/3755
[#3762]: https://github.com/launchbadge/sqlx/pull/3762
[#3765]: https://github.com/launchbadge/sqlx/pull/3765
[#3768]: https://github.com/launchbadge/sqlx/pull/3768
[#3769]: https://github.com/launchbadge/sqlx/pull/3769
[#3771]: https://github.com/launchbadge/sqlx/pull/3771
[#3773]: https://github.com/launchbadge/sqlx/pull/3773
[#3786]: https://github.com/launchbadge/sqlx/pull/3786
[#3801]: https://github.com/launchbadge/sqlx/pull/3801
[#3809]: https://github.com/launchbadge/sqlx/pull/3809
[#3811]: https://github.com/launchbadge/sqlx/pull/3811
[#3812]: https://github.com/launchbadge/sqlx/pull/3812
[#3815]: https://github.com/launchbadge/sqlx/pull/3815
## 0.8.3 - 2025-01-03
41 pull requests were merged this release cycle.
@ -2700,3 +2828,27 @@ Fix docs.rs build by enabling a runtime feature in the docs.rs metadata in `Carg
[@hsivonen]: https://github.com/hsivonen
[@andreweggleston]: https://github.com/andreweggleston
[@Suficio]: https://github.com/Suficio
[@bonega]: https://github.com/bonega
[@nico-incubiq]: https://github.com/nico-incubiq
[@tisonkun]: https://github.com/tisonkun
[@karambarakat]: https://github.com/karambarakat
[@seanaye]: https://github.com/seanaye
[@remysaissy]: https://github.com/remysaissy
[@BeauGieskens]: https://github.com/BeauGieskens
[@Turbo87]: https://github.com/Turbo87
[@jthacker]: https://github.com/jthacker
[@benwilber]: https://github.com/benwilber
[@chitoku-k]: https://github.com/chitoku-k
[@chanmaoganda]: https://github.com/chanmaoganda
[@dns2utf8]: https://github.com/dns2utf8
[@mattrighetti]: https://github.com/mattrighetti
[@soulwa]: https://github.com/soulwa
[@kildrens]: https://github.com/kildrens
[@xvapx]: https://github.com/xvapx
[@jonasmalacofilho]: https://github.com/jonasmalacofilho
[@sulami]: https://github.com/sulami
[@thriller08]: https://github.com/thriller08
[@mbj]: https://github.com/mbj
[@TeCHiScy]: https://github.com/TeCHiScy
[@mpyw]: https://github.com/mpyw
[@bonsairobo]: https://github.com/bonsairobo

16
Cargo.lock generated
View File

@ -3374,7 +3374,7 @@ dependencies = [
[[package]]
name = "sqlx"
version = "0.8.3"
version = "0.8.4"
dependencies = [
"anyhow",
"async-std",
@ -3404,7 +3404,7 @@ dependencies = [
[[package]]
name = "sqlx-cli"
version = "0.8.3"
version = "0.8.4"
dependencies = [
"anyhow",
"assert_cmd",
@ -3428,7 +3428,7 @@ dependencies = [
[[package]]
name = "sqlx-core"
version = "0.8.3"
version = "0.8.4"
dependencies = [
"async-io 1.13.0",
"async-std",
@ -3604,7 +3604,7 @@ dependencies = [
[[package]]
name = "sqlx-macros"
version = "0.8.3"
version = "0.8.4"
dependencies = [
"proc-macro2",
"quote",
@ -3615,7 +3615,7 @@ dependencies = [
[[package]]
name = "sqlx-macros-core"
version = "0.8.3"
version = "0.8.4"
dependencies = [
"async-std",
"dotenvy",
@ -3640,7 +3640,7 @@ dependencies = [
[[package]]
name = "sqlx-mysql"
version = "0.8.3"
version = "0.8.4"
dependencies = [
"atoi",
"base64 0.22.1",
@ -3686,7 +3686,7 @@ dependencies = [
[[package]]
name = "sqlx-postgres"
version = "0.8.3"
version = "0.8.4"
dependencies = [
"atoi",
"base64 0.22.1",
@ -3732,7 +3732,7 @@ dependencies = [
[[package]]
name = "sqlx-sqlite"
version = "0.8.3"
version = "0.8.4"
dependencies = [
"atoi",
"chrono",

View File

@ -23,7 +23,7 @@ members = [
]
[workspace.package]
version = "0.8.3"
version = "0.8.4"
license = "MIT OR Apache-2.0"
edition = "2021"
repository = "https://github.com/launchbadge/sqlx"
@ -129,17 +129,17 @@ bstr = ["sqlx-core/bstr"]
[workspace.dependencies]
# Core Crates
sqlx-core = { version = "=0.8.3", path = "sqlx-core" }
sqlx-macros-core = { version = "=0.8.3", path = "sqlx-macros-core" }
sqlx-macros = { version = "=0.8.3", path = "sqlx-macros" }
sqlx-core = { version = "=0.8.4", path = "sqlx-core" }
sqlx-macros-core = { version = "=0.8.4", path = "sqlx-macros-core" }
sqlx-macros = { version = "=0.8.4", path = "sqlx-macros" }
# Driver crates
sqlx-mysql = { version = "=0.8.3", path = "sqlx-mysql" }
sqlx-postgres = { version = "=0.8.3", path = "sqlx-postgres" }
sqlx-sqlite = { version = "=0.8.3", path = "sqlx-sqlite" }
sqlx-mysql = { version = "=0.8.4", path = "sqlx-mysql" }
sqlx-postgres = { version = "=0.8.4", path = "sqlx-postgres" }
sqlx-sqlite = { version = "=0.8.4", path = "sqlx-sqlite" }
# Facade crate (for reference from sqlx-cli)
sqlx = { version = "=0.8.3", path = ".", default-features = false }
sqlx = { version = "=0.8.4", path = ".", default-features = false }
# Common type integrations shared by multiple driver crates.
# These are optional unless enabled in a workspace crate.

View File

@ -25,11 +25,12 @@ pub enum CertificateInput {
impl From<String> for CertificateInput {
fn from(value: String) -> Self {
// Leading and trailing whitespace/newlines
let trimmed = value.trim();
// Some heuristics according to https://tools.ietf.org/html/rfc7468
if trimmed.starts_with("-----BEGIN CERTIFICATE-----")
&& trimmed.contains("-----END CERTIFICATE-----")
{
// Heuristic for PEM encoded inputs:
// https://tools.ietf.org/html/rfc7468
if trimmed.starts_with("-----BEGIN") && trimmed.ends_with("-----") {
CertificateInput::Inline(value.as_bytes().to_vec())
} else {
CertificateInput::File(PathBuf::from(value))

View File

@ -97,7 +97,7 @@ impl AnyConnectionBackend for PgConnection {
};
Box::pin(
self.run(query, arguments, 0, persistent, None)
self.run(query, arguments, persistent, None)
.try_flatten_stream()
.map(
move |res: sqlx_core::Result<Either<PgQueryResult, PgRow>>| match res? {
@ -123,7 +123,7 @@ impl AnyConnectionBackend for PgConnection {
Box::pin(async move {
let arguments = arguments?;
let mut stream = pin!(self.run(query, arguments, 1, persistent, None).await?);
let mut stream = pin!(self.run(query, arguments, persistent, None).await?);
if let Some(Either::Right(row)) = stream.try_next().await? {
return Ok(Some(AnyRow::try_from(&row)?));

View File

@ -194,7 +194,6 @@ impl PgConnection {
&'c mut self,
query: &'q str,
arguments: Option<PgArguments>,
limit: u8,
persistent: bool,
metadata_opt: Option<Arc<PgStatementMetadata>>,
) -> Result<impl Stream<Item = Result<Either<PgQueryResult, PgRow>, Error>> + 'e, Error> {
@ -247,7 +246,9 @@ impl PgConnection {
// the protocol-level limit acts nearly identically to the `LIMIT` in SQL
self.inner.stream.write_msg(message::Execute {
portal: PortalId::UNNAMED,
limit: limit.into(),
// Non-zero limits cause query plan pessimization by disabling parallel workers:
// https://github.com/launchbadge/sqlx/issues/3673
limit: 0,
})?;
// From https://www.postgresql.org/docs/current/protocol-flow.html:
//
@ -393,7 +394,7 @@ impl<'c> Executor<'c> for &'c mut PgConnection {
Box::pin(try_stream! {
let arguments = arguments?;
let mut s = pin!(self.run(sql, arguments, 0, persistent, metadata).await?);
let mut s = pin!(self.run(sql, arguments, persistent, metadata).await?);
while let Some(v) = s.try_next().await? {
r#yield!(v);
@ -419,7 +420,7 @@ impl<'c> Executor<'c> for &'c mut PgConnection {
Box::pin(async move {
let arguments = arguments?;
let mut s = pin!(self.run(sql, arguments, 1, persistent, metadata).await?);
let mut s = pin!(self.run(sql, arguments, persistent, metadata).await?);
// With deferred constraints we need to check all responses as we
// could get a OK response (with uncommitted data), only to get an

View File

@ -31,6 +31,8 @@ mod stream;
mod tls;
/// A connection to a PostgreSQL database.
///
/// See [`PgConnectOptions`] for connection URL reference.
pub struct PgConnection {
pub(crate) inner: Box<PgConnectionInner>,
}

View File

@ -0,0 +1,185 @@
Options and flags which can be used to configure a PostgreSQL connection.
A value of `PgConnectOptions` can be parsed from a connection URL,
as described by [libpq][libpq-connstring].
The general form for a connection URL is:
```text
postgresql://[user[:password]@][host][:port][/dbname][?param1=value1&...]
```
The URL scheme designator can be either `postgresql://` or `postgres://`.
Each of the URL parts is optional. For defaults, see the next section.
This type also implements [`FromStr`][std::str::FromStr] so you can parse it from a string
containing a connection URL and then further adjust options if necessary (see example below).
Note that characters not allowed in URLs must be [percent-encoded].
# Parameters
This API accepts many of the same parameters as [libpq][libpq-params];
if a parameter is not passed in via URL, it is populated by reading
[environment variables][libpq-envars] or choosing customary defaults.
| Parameter | Environment Variable | Default / Remarks |
|--------------------|----------------------|-------------------------------------------------------------|
| `user` | `PGUSER` | The `whoami` of the currently running process. |
| `password` | `PGPASSWORD` | Read from [`passfile`], if it exists. |
| [`passfile`] | `PGPASSFILE` | `~/.pgpass` or `%APPDATA%\postgresql\pgpass.conf` (Windows) |
| `host` | `PGHOST` | See [Note: Default Host](#note-default-host). |
| `hostaddr` | `PGHOSTADDR` | See [Note: Default Host](#note-default-host). |
| `port` | `PGPORT` | `5432` |
| `dbname` | `PGDATABASE` | Unset; defaults to the username server-side. |
| `sslmode` | `PGSSLMODE` | `prefer`. See [`PgSslMode`] for details. |
| `sslrootcert` | `PGSSLROOTCERT` | Unset. See [Note: SSL](#note-ssl). |
| `sslcert` | `PGSSLCERT` | Unset. See [Note: SSL](#note-ssl). |
| `sslkey` | `PGSSLKEY` | Unset. See [Note: SSL](#note-ssl). |
| `options` | `PGOPTIONS` | Unset. |
| `application_name` | `PGAPPNAME` | Unset. |
[`passfile`] handling may be bypassed using [`PgConnectOptions::new_without_pgpass()`].
## SQLx-Specific
SQLx also parses some bespoke parameters. These are _not_ configurable by environment variable.
Instead, the name is linked to the method to set the value.
| Parameter | Default |
|--------------------------------------------------------------|-------------------------------|
| [`statement-cache-capacity`][Self::statement_cache_capacity] | `100` |
# Example URLs
```text
postgresql://
postgresql://:5433
postgresql://localhost
postgresql://localhost:5433
postgresql://localhost/mydb
postgresql://user@localhost
postgresql://user:secret@localhost
postgresql://user:correct%20horse%20battery%20staple@localhost
postgresql://localhost?dbname=mydb&user=postgres&password=postgres
```
See also [Note: Unix Domain Sockets](#note-unix-domain-sockets) below.
# Note: Default Host
If the connection URL does not contain a hostname and `PGHOST` is not set,
this constructor looks for an open Unix domain socket in one of a few standard locations
(configured when Postgres is built):
* `/var/run/postgresql/.s.PGSQL.{port}` (Debian)
* `/private/tmp/.s.PGSQL.{port}` (macOS when installed through Homebrew)
* `/tmp/.s.PGSQL.{port}` (default otherwise)
This depends on the value of `port` being correct.
If Postgres is using a port other than the default (`5432`), `port` must be set.
If no Unix domain socket is found, `localhost` is assumed.
Note: this description is updated on a best-effort basis.
See `default_host()` in the same source file as this method for the current behavior.
# Note: SSL
## Root Certs
If `sslrootcert` is not set, the default root certificates used depends on Cargo features:
* If `tls-native-tls` is enabled, the system root certificates are used.
* If `tls-rustls-native-roots` is enabled, the system root certificates are used.
* Otherwise, TLS roots are populated using the [`webpki-roots`] crate.
## Environment Variables
Unlike with `libpq`, the following environment variables may be _either_
a path to a file _or_ a string value containing a [PEM-encoded value][rfc7468]:
* `PGSSLROOTCERT`
* `PGSSLCERT`
* `PGSSLKEY`
If the string begins with the standard `-----BEGIN <CERTIFICATE | PRIVATE KEY>-----` header
and ends with the standard `-----END <CERTIFICATE | PRIVATE KEY>-----` footer,
it is parsed directly.
This behavior is _only_ implemented for the environment variables, not the URL parameters.
Note: passing the SSL private key via environment variable may be a security risk.
# Note: Unix Domain Sockets
If you want to connect to Postgres over a Unix domain socket, you can pass the path
to the _directory_ containing the socket as the `host` parameter.
The final path to the socket will be `{host}/.s.PGSQL.{port}` as is standard for Postgres.
If you're passing the domain socket path as the host segment of the URL, forward slashes
in the path must be [percent-encoded] (replacing `/` with `%2F`), e.g.:
```text
postgres://%2Fvar%2Frun%2Fpostgresql/dbname
Different port:
postgres://%2Fvar%2Frun%2Fpostgresql:5433/dbname
With username and password:
postgres://user:password@%2Fvar%2Frun%2Fpostgresql/dbname
With username and password, and different port:
postgres://user:password@%2Fvar%2Frun%2Fpostgresql:5432/dbname
```
Instead, the hostname can be passed in the query segment of the URL,
which does not require forward-slashes to be percent-encoded
(however, [other characters are][percent-encoded]):
```text
postgres:dbname?host=/var/run/postgresql
Different port:
postgres://:5433/dbname?host=/var/run/postgresql
With username and password:
postgres://user:password@/dbname?host=/var/run/postgresql
With username and password, and different port:
postgres://user:password@:5433/dbname?host=/var/run/postgresql
```
# Example
```rust,no_run
use sqlx::{Connection, ConnectOptions};
use sqlx::postgres::{PgConnectOptions, PgConnection, PgPool, PgSslMode};
# async fn example() -> sqlx::Result<()> {
// URL connection string
let conn = PgConnection::connect("postgres://localhost/mydb").await?;
// Manually-constructed options
let conn = PgConnectOptions::new()
.host("secret-host")
.port(2525)
.username("secret-user")
.password("secret-password")
.ssl_mode(PgSslMode::Require)
.connect()
.await?;
// Modifying options parsed from a string
let mut opts: PgConnectOptions = "postgres://localhost/mydb".parse()?;
// Change the log verbosity level for queries.
// Information about SQL queries is logged at `DEBUG` level by default.
opts = opts.log_statements(log::LevelFilter::Trace);
let pool = PgPool::connect_with(opts).await?;
# Ok(())
# }
```
[percent-encoded]: https://developer.mozilla.org/en-US/docs/Glossary/Percent-encoding
[`passfile`]: https://www.postgresql.org/docs/current/libpq-pgpass.html
[libpq-connstring]: https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING
[libpq-params]: https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS
[libpq-envars]: https://www.postgresql.org/docs/current/libpq-envars.html
[rfc7468]: https://datatracker.ietf.org/doc/html/rfc7468
[`webpki-roots`]: https://docs.rs/webpki-roots

View File

@ -12,80 +12,7 @@ mod parse;
mod pgpass;
mod ssl_mode;
/// Options and flags which can be used to configure a PostgreSQL connection.
///
/// A value of `PgConnectOptions` can be parsed from a connection URL,
/// as described by [libpq](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING).
///
/// The general form for a connection URL is:
///
/// ```text
/// postgresql://[user[:password]@][host][:port][/dbname][?param1=value1&...]
/// ```
///
/// This type also implements [`FromStr`][std::str::FromStr] so you can parse it from a string
/// containing a connection URL and then further adjust options if necessary (see example below).
///
/// ## Parameters
///
/// |Parameter|Default|Description|
/// |---------|-------|-----------|
/// | `sslmode` | `prefer` | Determines whether or with what priority a secure SSL TCP/IP connection will be negotiated. See [`PgSslMode`]. |
/// | `sslrootcert` | `None` | Sets the name of a file containing a list of trusted SSL Certificate Authorities. |
/// | `statement-cache-capacity` | `100` | The maximum number of prepared statements stored in the cache. Set to `0` to disable. |
/// | `host` | `None` | Path to the directory containing a PostgreSQL unix domain socket, which will be used instead of TCP if set. |
/// | `hostaddr` | `None` | Same as `host`, but only accepts IP addresses. |
/// | `application-name` | `None` | The name will be displayed in the pg_stat_activity view and included in CSV log entries. |
/// | `user` | result of `whoami` | PostgreSQL user name to connect as. |
/// | `password` | `None` | Password to be used if the server demands password authentication. |
/// | `port` | `5432` | Port number to connect to at the server host, or socket file name extension for Unix-domain connections. |
/// | `dbname` | `None` | The database name. |
/// | `options` | `None` | The runtime parameters to send to the server at connection start. |
///
/// The URL scheme designator can be either `postgresql://` or `postgres://`.
/// Each of the URL parts is optional.
///
/// ```text
/// postgresql://
/// postgresql://localhost
/// postgresql://localhost:5433
/// postgresql://localhost/mydb
/// postgresql://user@localhost
/// postgresql://user:secret@localhost
/// postgresql://localhost?dbname=mydb&user=postgres&password=postgres
/// ```
///
/// # Example
///
/// ```rust,no_run
/// use sqlx::{Connection, ConnectOptions};
/// use sqlx::postgres::{PgConnectOptions, PgConnection, PgPool, PgSslMode};
///
/// # async fn example() -> sqlx::Result<()> {
/// // URL connection string
/// let conn = PgConnection::connect("postgres://localhost/mydb").await?;
///
/// // Manually-constructed options
/// let conn = PgConnectOptions::new()
/// .host("secret-host")
/// .port(2525)
/// .username("secret-user")
/// .password("secret-password")
/// .ssl_mode(PgSslMode::Require)
/// .connect()
/// .await?;
///
/// // Modifying options parsed from a string
/// let mut opts: PgConnectOptions = "postgres://localhost/mydb".parse()?;
///
/// // Change the log verbosity level for queries.
/// // Information about SQL queries is logged at `DEBUG` level by default.
/// opts = opts.log_statements(log::LevelFilter::Trace);
///
/// let pool = PgPool::connect_with(opts).await?;
/// # Ok(())
/// # }
/// ```
#[doc = include_str!("doc.md")]
#[derive(Debug, Clone)]
pub struct PgConnectOptions {
pub(crate) host: String,
@ -112,52 +39,30 @@ impl Default for PgConnectOptions {
}
impl PgConnectOptions {
/// Creates a new, default set of options ready for configuration.
/// Create a default set of connection options populated from the current environment.
///
/// By default, this reads the following environment variables and sets their
/// equivalent options.
/// This behaves as if parsed from the connection string `postgres://`
///
/// * `PGHOST`
/// * `PGPORT`
/// * `PGUSER`
/// * `PGPASSWORD`
/// * `PGDATABASE`
/// * `PGSSLROOTCERT`
/// * `PGSSLCERT`
/// * `PGSSLKEY`
/// * `PGSSLMODE`
/// * `PGAPPNAME`
///
/// # Example
///
/// ```rust
/// # use sqlx_postgres::PgConnectOptions;
/// let options = PgConnectOptions::new();
/// ```
///
/// Note: that unlike `libpq` the environment variables:
///
/// * `PGSSLROOTCERT`
/// * `PGSSLCERT`
/// * `PGSSLKEY`
///
/// Must not exclusively be path, ´sqlx-postgres` supports these variables
/// encode the certificates / keys directly. Content snooping is done via
/// `CertificateInput::from`.
///
/// Note: Putting key material in environment variables can be subjected to risk as on
/// some platforms environment variables can be recovered by other (non root) users.
/// See the type-level documentation for details.
pub fn new() -> Self {
Self::new_without_pgpass().apply_pgpass()
}
/// Create a default set of connection options _without_ reading from `passfile`.
///
/// Equivalent to [`PgConnectOptions::new()`] but `passfile` is ignored.
///
/// See the type-level documentation for details.
pub fn new_without_pgpass() -> Self {
let port = var("PGPORT")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(5432);
let host = var("PGHOST").ok().unwrap_or_else(|| default_host(port));
let host = var("PGHOSTADDR")
.ok()
.or_else(|| var("PGHOST").ok())
.unwrap_or_else(|| default_host(port));
let username = var("PGUSER").ok().unwrap_or_else(whoami::username);
@ -172,6 +77,9 @@ impl PgConnectOptions {
database,
ssl_root_cert: var("PGSSLROOTCERT").ok().map(CertificateInput::from),
ssl_client_cert: var("PGSSLCERT").ok().map(CertificateInput::from),
// As of writing, the implementation of `From<String>` only looks for
// `-----BEGIN CERTIFICATE-----` and so will not attempt to parse
// a PEM-encoded private key.
ssl_client_key: var("PGSSLKEY").ok().map(CertificateInput::from),
ssl_mode: var("PGSSLMODE")
.ok()