uqa_sql/catalog/
errors.rs1use crate::SQLError;
9
10pub fn storage_error(action: &str, err: &(dyn std::error::Error + 'static)) -> SQLError {
11 let mut source: Option<&(dyn std::error::Error + 'static)> = Some(err);
12 while let Some(error) = source {
13 if let Some(error) = error.downcast_ref::<SQLError>() {
14 if matches!(error, SQLError::Diagnostic { .. }) {
16 return error.clone();
17 }
18 return SQLError::Routine {
19 sqlstate: error.sqlstate().unwrap_or("XX000").into(),
20 message: error.to_string(),
21 };
22 }
23 source = error.source();
24 }
25 SQLError::Internal(format!("{action} failed in storage backend: {err}"))
26}
27
28pub fn dml_storage_error(action: &str, err: impl std::fmt::Display) -> SQLError {
29 SQLError::Internal(format!("{action} failed in storage backend: {err}"))
30}
31
32#[cfg(test)]
33mod tests {
34 use super::*;
35 #[derive(Debug)]
36 struct CatalogFailure(SQLError);
37 impl std::fmt::Display for CatalogFailure {
38 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39 formatter.write_str("catalog lookup failed")
40 }
41 }
42 impl std::error::Error for CatalogFailure {
43 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
44 Some(&self.0)
45 }
46 }
47 #[test]
48 fn catalog_error_chain_preserves_the_embedded_sql_diagnostic() {
49 let original = SQLError::Routine {
50 sqlstate: "42501".into(),
51 message: "permission denied for schema secret".into(),
52 };
53 let expected = original.to_string();
54 let error = storage_error("column type coercion", &CatalogFailure(original));
55 assert_eq!(error.sqlstate(), Some("42501"));
56 assert_eq!(error.to_string(), expected);
57 }
58 #[test]
59 fn catalog_error_chain_keeps_diagnostic_detail_and_hint() {
60 let original = SQLError::Diagnostic {
61 sqlstate: "42501".into(),
62 message: "permission denied to create \"pg_catalog.t\"".into(),
63 detail: Some("System catalog modifications are currently disallowed.".into()),
64 hint: None,
65 };
66 let error = storage_error("CREATE TABLE", &CatalogFailure(original));
67 assert!(matches!(
68 error,
69 SQLError::Diagnostic { sqlstate, detail: Some(detail), .. }
70 if sqlstate == "42501" && detail == "System catalog modifications are currently disallowed."
71 ));
72 }
73 #[test]
74 fn plain_catalog_errors_retain_the_operation_context() {
75 let error = std::io::Error::other("unavailable");
76 assert!(
77 matches!(storage_error("column type coercion", &error), SQLError::Internal(message) if message == "column type coercion failed in storage backend: unavailable")
78 );
79 }
80}