Skip to main content

martin_core/tiles/postgres/
errors.rs

1//! Error types for `PostgreSQL` operations.
2
3use std::io;
4use std::path::PathBuf;
5
6use deadpool_postgres::tokio_postgres::Error as TokioPostgresError;
7use deadpool_postgres::tokio_postgres::config::SslMode;
8use deadpool_postgres::{BuildError, PoolError};
9use martin_tile_utils::TileCoord;
10use semver::Version;
11
12use crate::tiles::UrlQuery;
13use crate::tiles::postgres::RedactedConnectionString;
14use crate::tiles::postgres::utils::query_to_json;
15
16/// Result type for `PostgreSQL` operations.
17pub type PostgresResult<T> = Result<T, PostgresError>;
18
19/// Errors that can occur when working with `PostgreSQL` databases.
20#[non_exhaustive]
21#[derive(thiserror::Error, Debug)]
22pub enum PostgresError {
23    /// The configured filter is not valid CQL2
24    #[error("Filter '{0}' is not valid CQL2: {1}")]
25    InvalidFilter(String, String),
26
27    /// Cannot load platform root certificates.
28    #[error("Cannot load platform root certificates: {0:?}")]
29    CannotLoadRoots(Vec<rustls_native_certs::Error>),
30
31    /// Cannot open SSL certificate file.
32    #[error("Cannot open certificate file {1}: {0}")]
33    CannotOpenCert(#[source] io::Error, PathBuf),
34
35    /// Cannot parse SSL certificate file.
36    #[error("Cannot parse certificate file {1}: {0}")]
37    CannotParseCert(#[source] io::Error, PathBuf),
38
39    /// Invalid PEM RSA private key file.
40    #[error("Unable to parse PEM RSA key file {0}")]
41    InvalidPrivateKey(PathBuf),
42
43    /// Cannot use client certificate pair.
44    #[error("Unable to use client certificate pair {cert} / {key}: {source}")]
45    CannotUseClientKey {
46        /// The underlying `rustls` error.
47        #[source]
48        source: rustls::Error,
49        /// Path to the client certificate file.
50        cert: PathBuf,
51        /// Path to the client private key file.
52        key: PathBuf,
53    },
54
55    /// Wrapper for rustls errors.
56    #[error(transparent)]
57    RustlsError(#[from] rustls::Error),
58
59    /// Cannot build the TLS certificate verifier.
60    #[error(transparent)]
61    CannotBuildTlsVerifier(#[from] rustls::client::VerifierBuilderError),
62
63    /// Unknown SSL mode specified.
64    #[error("Unknown SSL mode: {0:?}")]
65    UnknownSslMode(SslMode),
66
67    /// `PostgreSQL` database error.
68    #[error("Postgres error while {1}: {0}")]
69    PostgresError(#[source] TokioPostgresError, &'static str),
70
71    /// Cannot build `PostgreSQL` connection pool.
72    #[error("Unable to build a Postgres connection pool {1}: {0}")]
73    PostgresPoolBuildError(#[source] BuildError, String),
74
75    /// Cannot get connection from `PostgreSQL` pool.
76    #[error("Unable to get a Postgres connection from the pool {1}: {0}")]
77    PostgresPoolConnError(#[source] PoolError, String),
78
79    /// Invalid `PostgreSQL` connection string.
80    #[error("Unable to parse connection string {1}: {0}")]
81    BadConnectionString(#[source] TokioPostgresError, RedactedConnectionString),
82
83    /// Cannot parse `PostGIS` version.
84    #[error("Unable to parse PostGIS version {1}: {0}")]
85    BadPostgisVersion(#[source] semver::Error, String),
86
87    /// Cannot parse `PostgreSQL` version.
88    #[error("Unable to parse PostgreSQL version {version_num}")]
89    BadPostgresVersion {
90        /// The `server_version_num` setting reported by the server.
91        version_num: i32,
92    },
93
94    /// `PostGIS` version too old.
95    #[error("PostGIS version {current} is too old, minimum required is {minimum}")]
96    PostgisTooOld {
97        /// The detected `PostGIS` version.
98        current: Version,
99        /// The minimum required `PostGIS` version.
100        minimum: Version,
101    },
102
103    /// `PostgreSQL` version too old.
104    #[error("PostgreSQL version {current} is too old, minimum required is {minimum}")]
105    PostgresqlTooOld {
106        /// The detected `PostgreSQL` version.
107        current: Version,
108        /// The minimum required `PostgreSQL` version.
109        minimum: Version,
110    },
111
112    /// Query preparation error.
113    #[error("Error preparing a query for the tile '{source_id}' ({signature}): {query} {source}")]
114    PrepareQueryError {
115        /// The underlying `PostgreSQL` error.
116        #[source]
117        source: TokioPostgresError,
118        /// The id of the tile source the query was prepared for.
119        source_id: String,
120        /// The source's query signature (parameter types).
121        signature: String,
122        /// The SQL query that failed to prepare.
123        query: String,
124    },
125
126    /// Tile retrieval error.
127    #[error(r"Unable to get tile {2:#} from {1}: {0}")]
128    GetTileError(#[source] TokioPostgresError, String, TileCoord),
129
130    /// Tile retrieval error with query parameters.
131    #[error(r"Unable to get tile {2:#} with {json_query:?} params from {1}: {0}", json_query=query_to_json(.3.as_ref()))]
132    GetTileWithQueryError(
133        #[source] TokioPostgresError,
134        String,
135        TileCoord,
136        Option<UrlQuery>,
137    ),
138}
139
140impl crate::Classify for PostgresError {
141    fn kind(&self) -> crate::ErrorKind {
142        use crate::ErrorKind::{Internal, Unavailable};
143        match self {
144            Self::PostgresPoolConnError(..) => Unavailable,
145            Self::InvalidFilter(..)
146            | Self::CannotLoadRoots(_)
147            | Self::CannotOpenCert(..)
148            | Self::CannotParseCert(..)
149            | Self::InvalidPrivateKey(_)
150            | Self::CannotUseClientKey { .. }
151            | Self::RustlsError(_)
152            | Self::CannotBuildTlsVerifier(_)
153            | Self::UnknownSslMode(_)
154            | Self::PostgresError(..)
155            | Self::PostgresPoolBuildError(..)
156            | Self::BadConnectionString(..)
157            | Self::BadPostgisVersion(..)
158            | Self::BadPostgresVersion { .. }
159            | Self::PostgisTooOld { .. }
160            | Self::PostgresqlTooOld { .. }
161            | Self::PrepareQueryError { .. }
162            | Self::GetTileError(..)
163            | Self::GetTileWithQueryError(..) => Internal,
164        }
165    }
166}