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 return SQLError::Routine {
15 sqlstate: error.sqlstate().unwrap_or("XX000").into(),
16 message: error.to_string(),
17 };
18 }
19 source = error.source();
20 }
21 SQLError::Internal(format!("{action} failed in storage backend: {err}"))
22}
23
24pub fn dml_storage_error(action: &str, err: impl std::fmt::Display) -> SQLError {
25 SQLError::Internal(format!("{action} failed in storage backend: {err}"))
26}
27
28#[cfg(test)]
29mod tests {
30 use super::*;
31 #[derive(Debug)]
32 struct CatalogFailure(SQLError);
33 impl std::fmt::Display for CatalogFailure {
34 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 formatter.write_str("catalog lookup failed")
36 }
37 }
38 impl std::error::Error for CatalogFailure {
39 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
40 Some(&self.0)
41 }
42 }
43 #[test]
44 fn catalog_error_chain_preserves_the_embedded_sql_diagnostic() {
45 let original = SQLError::Routine {
46 sqlstate: "42501".into(),
47 message: "permission denied for schema secret".into(),
48 };
49 let expected = original.to_string();
50 let error = storage_error("column type coercion", &CatalogFailure(original));
51 assert_eq!(error.sqlstate(), Some("42501"));
52 assert_eq!(error.to_string(), expected);
53 }
54 #[test]
55 fn plain_catalog_errors_retain_the_operation_context() {
56 let error = std::io::Error::other("unavailable");
57 assert!(
58 matches!(storage_error("column type coercion", &error), SQLError::Internal(message) if message == "column type coercion failed in storage backend: unavailable")
59 );
60 }
61}