Skip to main content

sqlx_sqlserver/
error.rs

1//! SQL Server database errors.
2
3use crate::protocol::token::ServerError;
4use sqlx_core::error::{DatabaseError, ErrorKind};
5use sqlx_core::Error;
6
7/// An error reported by SQL Server.
8#[derive(Debug)]
9pub struct MssqlDatabaseError(pub(crate) ServerError);
10
11impl MssqlDatabaseError {
12    /// SQL Server error number.
13    pub fn number(&self) -> i32 {
14        self.0.number
15    }
16
17    /// SQL Server error state.
18    pub fn state(&self) -> u8 {
19        self.0.state
20    }
21
22    /// SQL Server error class, also known as severity.
23    pub fn class(&self) -> u8 {
24        self.0.class
25    }
26
27    /// Human-readable error message returned by SQL Server.
28    pub fn message(&self) -> &str {
29        &self.0.message
30    }
31
32    /// Server name reported with the error.
33    pub fn server_name(&self) -> &str {
34        &self.0.server_name
35    }
36
37    /// Stored procedure name reported with the error, if any.
38    pub fn procedure_name(&self) -> &str {
39        &self.0.procedure_name
40    }
41
42    /// Line number reported by SQL Server.
43    pub fn line_number(&self) -> u32 {
44        self.0.line_number
45    }
46}
47
48impl std::fmt::Display for MssqlDatabaseError {
49    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50        write!(
51            f,
52            "SQL Server error {} (state {}, class {}): {}",
53            self.0.number, self.0.state, self.0.class, self.0.message
54        )
55    }
56}
57
58impl std::error::Error for MssqlDatabaseError {}
59
60impl DatabaseError for MssqlDatabaseError {
61    fn message(&self) -> &str {
62        self.message()
63    }
64
65    fn as_error(&self) -> &(dyn std::error::Error + Send + Sync + 'static) {
66        self
67    }
68
69    fn as_error_mut(&mut self) -> &mut (dyn std::error::Error + Send + Sync + 'static) {
70        self
71    }
72
73    fn into_error(self: Box<Self>) -> Box<dyn std::error::Error + Send + Sync + 'static> {
74        self
75    }
76
77    fn kind(&self) -> ErrorKind {
78        ErrorKind::Other
79    }
80}
81
82pub(crate) fn server_error(error: ServerError) -> Error {
83    Error::database(MssqlDatabaseError(error))
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89
90    #[test]
91    fn server_error_returns_database_error() {
92        let error = server_error(ServerError {
93            number: 18456,
94            state: 1,
95            class: 14,
96            message: "Login failed".to_owned(),
97            server_name: "dbhost".to_owned(),
98            procedure_name: "login_proc".to_owned(),
99            line_number: 9,
100        });
101
102        let db_error = error.as_database_error().unwrap();
103        let mssql_error = db_error
104            .as_error()
105            .downcast_ref::<MssqlDatabaseError>()
106            .unwrap();
107
108        assert_eq!(18456, mssql_error.number());
109        assert_eq!(1, mssql_error.state());
110        assert_eq!(14, mssql_error.class());
111        assert_eq!("Login failed", mssql_error.message());
112        assert_eq!("dbhost", mssql_error.server_name());
113        assert_eq!("login_proc", mssql_error.procedure_name());
114        assert_eq!(9, mssql_error.line_number());
115        assert_eq!(None, db_error.code());
116        assert_eq!(ErrorKind::Other, db_error.kind());
117    }
118}