1#[derive(Debug, thiserror::Error)]
10pub enum SQLError {
11 #[error("{0}")]
12 Parse(String),
13 #[error("{0}")]
14 Unsupported(String),
15 #[error("relation \"{0}\" does not exist")]
16 UnknownTable(String),
17 #[error("column \"{0}\" does not exist")]
18 UnknownColumn(String),
19 #[error("column reference \"{0}\" is ambiguous")]
20 AmbiguousColumn(String),
21 #[error("unknown function: {0}")]
22 UnknownFunction(String),
23 #[error("type mismatch: {0}")]
24 TypeMismatch(String),
25 #[error("invalid argument count for `{name}`: expected {expected}, got {actual}")]
26 BadArity {
27 name: String,
28 expected: String,
29 actual: usize,
30 },
31 #[error("No value supplied for parameter ${0}")]
32 MissingParam(usize),
33 #[error("vector dimension mismatch: expected {expected}, got {actual}")]
34 VectorDimMismatch { expected: usize, actual: usize },
35 #[error("{0}")]
36 Cancelled(#[from] uqa_core::QueryCancelled),
37 #[error("{message}")]
42 Routine { sqlstate: String, message: String },
43 #[error("{message}")]
45 Diagnostic {
46 sqlstate: String,
47 message: String,
48 detail: Option<String>,
49 hint: Option<String>,
50 },
51 #[error("internal error: {0}")]
52 Internal(String),
53}
54
55impl SQLError {
56 pub fn unknown_qualified_column(qualifier: &str, column: &str) -> Self {
57 Self::Routine {
58 sqlstate: "42703".into(),
59 message: format!("column {qualifier}.{column} does not exist"),
60 }
61 }
62
63 pub fn sqlstate(&self) -> Option<&str> {
67 match self {
68 SQLError::Cancelled(_) => Some(uqa_core::SQLSTATE_QUERY_CANCELED),
69 SQLError::Parse(_) => Some("42601"), SQLError::Unsupported(_) => Some("0A000"), SQLError::UnknownTable(_) => Some("42P01"), SQLError::UnknownColumn(_) => Some("42703"), SQLError::AmbiguousColumn(_) => Some("42702"), SQLError::UnknownFunction(_) => Some("42883"), SQLError::TypeMismatch(_) => Some("42804"), SQLError::BadArity { .. } => Some("42883"), SQLError::MissingParam(_) => Some("S1002"), SQLError::VectorDimMismatch { .. } => Some("22023"), SQLError::Routine { sqlstate, .. } | SQLError::Diagnostic { sqlstate, .. } => {
80 Some(sqlstate)
81 }
82 SQLError::Internal(_) => Some("XX000"), }
84 }
85}
86
87pub type Result<T> = std::result::Result<T, SQLError>;
88
89impl From<pg_query::Error> for SQLError {
90 fn from(value: pg_query::Error) -> Self {
91 match value {
92 pg_query::Error::Parse(message)
93 if message == "WITH TIES cannot be specified without ORDER BY clause" =>
94 {
95 SQLError::Routine {
96 sqlstate: "42601".into(),
97 message,
98 }
99 }
100 pg_query::Error::Parse(message)
101 if message.contains("constraints cannot be altered to be NOT VALID") =>
102 {
103 SQLError::Routine {
104 sqlstate: "0A000".into(),
105 message,
106 }
107 }
108 pg_query::Error::Parse(message) => SQLError::Parse(message),
109 other => SQLError::Parse(other.to_string()),
110 }
111 }
112}