mz_postgres_client/
error.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10//! [PostgresClient](crate::PostgresClient)-related errors.
11
12use std::fmt;
13
14/// An error coming from Postgres.
15#[derive(Debug)]
16pub enum PostgresError {
17    /// A determinate error from Postgres.
18    Determinate(anyhow::Error),
19    /// An indeterminate error from Postgres.
20    Indeterminate(anyhow::Error),
21}
22
23impl std::fmt::Display for PostgresError {
24    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25        match self {
26            PostgresError::Determinate(x) => std::fmt::Display::fmt(x, f),
27            PostgresError::Indeterminate(x) => std::fmt::Display::fmt(x, f),
28        }
29    }
30}
31
32impl std::error::Error for PostgresError {}
33
34/// An impl of PartialEq purely for convenience in tests and debug assertions.
35#[cfg(any(test, debug_assertions))]
36impl PartialEq for PostgresError {
37    fn eq(&self, other: &Self) -> bool {
38        self.to_string() == other.to_string()
39    }
40}
41
42impl From<anyhow::Error> for PostgresError {
43    fn from(inner: anyhow::Error) -> Self {
44        PostgresError::Indeterminate(inner)
45    }
46}
47
48impl From<std::io::Error> for PostgresError {
49    fn from(x: std::io::Error) -> Self {
50        PostgresError::Indeterminate(anyhow::Error::new(x))
51    }
52}
53
54impl From<deadpool_postgres::tokio_postgres::Error> for PostgresError {
55    fn from(e: deadpool_postgres::tokio_postgres::Error) -> Self {
56        let code = match e.as_db_error().map(|x| x.code()) {
57            Some(x) => x,
58            None => return PostgresError::Indeterminate(anyhow::Error::new(e)),
59        };
60        match code {
61            // Feel free to add more things to this allowlist as we encounter
62            // them as long as you're certain they're determinate.
63            &deadpool_postgres::tokio_postgres::error::SqlState::T_R_SERIALIZATION_FAILURE => {
64                PostgresError::Determinate(anyhow::Error::new(e))
65            }
66            _ => PostgresError::Indeterminate(anyhow::Error::new(e)),
67        }
68    }
69}
70
71impl From<deadpool_postgres::PoolError> for PostgresError {
72    fn from(x: deadpool_postgres::PoolError) -> Self {
73        match x {
74            // We have logic for turning a postgres Error into an ExternalError,
75            // so use it.
76            deadpool_postgres::PoolError::Backend(x) => PostgresError::from(x),
77            x => PostgresError::Indeterminate(anyhow::Error::new(x)),
78        }
79    }
80}
81
82impl From<tokio::task::JoinError> for PostgresError {
83    fn from(x: tokio::task::JoinError) -> Self {
84        PostgresError::Indeterminate(anyhow::Error::new(x))
85    }
86}