Skip to main content

dbmcp_sql/
error.rs

1//! SQL-layer error types for validation, timeout, and query failures.
2
3/// Errors produced by SQL validation, identifier checking, and query execution.
4#[derive(Debug, thiserror::Error)]
5pub enum SqlError {
6    /// Query blocked by read-only mode.
7    #[error("Query blocked: only SELECT, SHOW, DESC, DESCRIBE, USE queries are allowed in read-only mode")]
8    ReadOnlyViolation,
9
10    /// `LOAD_FILE()` function blocked for security.
11    #[error("Operation forbidden: LOAD_FILE() is not allowed for security reasons")]
12    LoadFileBlocked,
13
14    /// Dangerous function (file access, large objects, sequences, extensions) blocked.
15    #[error("Operation forbidden: {0}() is not allowed for security reasons")]
16    DangerousFunctionBlocked(String),
17
18    /// INTO OUTFILE/DUMPFILE blocked for security.
19    #[error("Operation forbidden: SELECT INTO OUTFILE/DUMPFILE is not allowed for security reasons")]
20    IntoOutfileBlocked,
21
22    /// Multiple SQL statements blocked.
23    #[error("Query blocked: only single statements are allowed")]
24    MultiStatement,
25
26    /// Invalid database or table name identifier.
27    #[error("Invalid identifier '{0}': must not be empty, whitespace-only, or contain control characters")]
28    InvalidIdentifier(String),
29
30    /// Query exceeded the configured timeout.
31    #[error("Query timed out after {elapsed_secs:.1}s: {sql}")]
32    QueryTimeout {
33        /// Wall-clock seconds elapsed before cancellation.
34        elapsed_secs: f64,
35        /// The SQL statement that was cancelled.
36        sql: String,
37    },
38
39    /// Database query execution failed.
40    #[error("Database error: {0}")]
41    Query(String),
42
43    /// Table not found in database.
44    #[error("Table not found: {0}")]
45    TableNotFound(String),
46}
47
48impl From<SqlError> for rmcp::model::ErrorData {
49    fn from(e: SqlError) -> Self {
50        Self::internal_error(e.to_string(), None)
51    }
52}