alopex_sql/executor/
error.rs

1//! Error types for the Executor module.
2//!
3//! This module defines error types for SQL execution:
4//! - [`ExecutorError`]: Top-level executor errors
5//! - [`ConstraintViolation`]: Constraint violation details
6//! - [`EvaluationError`]: Expression evaluation errors
7
8use crate::executor::evaluator::VectorError;
9use crate::storage::StorageError;
10use thiserror::Error;
11
12/// Errors that can occur during SQL execution.
13#[derive(Debug, Error)]
14pub enum ExecutorError {
15    /// Underlying HNSW/kv error.
16    #[error("hnsw error: {0}")]
17    Core(#[from] alopex_core::Error),
18
19    /// Table not found in catalog.
20    #[error("table not found: {0}")]
21    TableNotFound(String),
22
23    /// Table already exists in catalog.
24    #[error("table already exists: {0}")]
25    TableAlreadyExists(String),
26
27    /// Index not found in catalog.
28    #[error("index not found: {0}")]
29    IndexNotFound(String),
30
31    /// Index already exists in catalog.
32    #[error("index already exists: {0}")]
33    IndexAlreadyExists(String),
34
35    /// Column not found in table.
36    #[error("column not found: {0}")]
37    ColumnNotFound(String),
38
39    /// Constraint violation during DML operation.
40    #[error("constraint violation: {0}")]
41    ConstraintViolation(#[from] ConstraintViolation),
42
43    /// Expression evaluation error.
44    #[error("evaluation error: {0}")]
45    Evaluation(#[from] EvaluationError),
46
47    /// Unsupported SQL operation.
48    #[error("unsupported operation: {0}")]
49    UnsupportedOperation(String),
50
51    /// Transaction conflict (concurrent modification).
52    #[error("transaction conflict")]
53    TransactionConflict,
54
55    /// Storage layer error.
56    #[error("storage error: {0}")]
57    Storage(#[from] StorageError),
58
59    /// Column value required (DEFAULT not supported in v0.1.2).
60    #[error("column required: {column} (DEFAULT not supported in v0.1.2)")]
61    ColumnRequired { column: String },
62
63    /// Invalid index name (reserved prefix).
64    #[error("invalid index name: {name} - {reason}")]
65    InvalidIndexName { name: String, reason: String },
66
67    /// Invalid operation.
68    #[error("invalid operation: {operation} - {reason}")]
69    InvalidOperation { operation: String, reason: String },
70
71    /// Input file not found.
72    #[error("file not found: {0}")]
73    FileNotFound(String),
74
75    /// File path failed validation.
76    #[error("path validation failed for '{path}': {reason}")]
77    PathValidationFailed { path: String, reason: String },
78
79    /// Unsupported file format.
80    #[error("unsupported format: {0}")]
81    UnsupportedFormat(String),
82
83    /// Schema mismatch between input and table.
84    #[error("schema mismatch: expected {expected} columns, got {actual} - {reason}")]
85    SchemaMismatch {
86        expected: usize,
87        actual: usize,
88        reason: String,
89    },
90
91    /// Invalid storage type option.
92    #[error("invalid storage type: {0}")]
93    InvalidStorageType(String),
94
95    /// Invalid compression option.
96    #[error("invalid compression: {0}")]
97    InvalidCompression(String),
98
99    /// Invalid row group size option.
100    #[error("invalid row_group_size: {0}")]
101    InvalidRowGroupSize(String),
102
103    /// Invalid rowid_mode option.
104    #[error("invalid rowid_mode: {0}")]
105    InvalidRowIdMode(String),
106
107    /// Unknown table option key.
108    #[error("unknown table option: {0}")]
109    UnknownTableOption(String),
110
111    /// Duplicate option key.
112    #[error("duplicate option: {0}")]
113    DuplicateOption(String),
114
115    /// Vector processing error.
116    #[error("vector error: {0}")]
117    Vector(#[from] VectorError),
118
119    /// Bulk load generic error.
120    #[error("bulk load error: {0}")]
121    BulkLoad(String),
122
123    /// Columnar engine error.
124    #[error("columnar engine error: {0}")]
125    Columnar(String),
126
127    /// Planner error (wrapped for convenience).
128    #[error("planner error: {0}")]
129    Planner(#[from] crate::planner::PlannerError),
130}
131
132/// Constraint violation details.
133#[derive(Debug, Error, Clone, PartialEq, Eq)]
134pub enum ConstraintViolation {
135    /// NOT NULL constraint violated.
136    #[error("NOT NULL constraint violated on column: {column}")]
137    NotNull { column: String },
138
139    /// PRIMARY KEY constraint violated.
140    #[error("PRIMARY KEY constraint violated on columns: {columns:?}, value: {value:?}")]
141    PrimaryKey {
142        columns: Vec<String>,
143        value: Option<String>,
144    },
145
146    /// UNIQUE constraint violated.
147    #[error(
148        "UNIQUE constraint violated on index: {index_name}, columns: {columns:?}, value: {value:?}"
149    )]
150    Unique {
151        index_name: String,
152        columns: Vec<String>,
153        value: Option<String>,
154    },
155}
156
157/// Expression evaluation errors.
158#[derive(Debug, Error, Clone, PartialEq, Eq)]
159pub enum EvaluationError {
160    /// Division by zero.
161    #[error("division by zero")]
162    DivisionByZero,
163
164    /// Integer overflow.
165    #[error("integer overflow")]
166    Overflow,
167
168    /// Type mismatch during evaluation.
169    #[error("type mismatch: expected {expected}, got {actual}")]
170    TypeMismatch { expected: String, actual: String },
171
172    /// Invalid column reference (index out of bounds).
173    #[error("invalid column reference: index {index}")]
174    InvalidColumnRef { index: usize },
175
176    /// Unsupported expression type.
177    #[error("unsupported expression: {0}")]
178    UnsupportedExpression(String),
179
180    /// Unsupported function call.
181    #[error("unsupported function: {0}")]
182    UnsupportedFunction(String),
183
184    /// Vector evaluation error.
185    #[error("vector error: {0}")]
186    Vector(#[from] VectorError),
187}
188
189/// Type alias for executor results.
190pub type Result<T> = std::result::Result<T, ExecutorError>;
191
192#[cfg(test)]
193mod tests {
194    use super::*;
195
196    #[test]
197    fn test_executor_error_display() {
198        let err = ExecutorError::TableNotFound("users".into());
199        assert_eq!(err.to_string(), "table not found: users");
200    }
201
202    #[test]
203    fn test_constraint_violation_display() {
204        let err = ConstraintViolation::NotNull {
205            column: "name".into(),
206        };
207        assert_eq!(
208            err.to_string(),
209            "NOT NULL constraint violated on column: name"
210        );
211    }
212
213    #[test]
214    fn test_evaluation_error_display() {
215        let err = EvaluationError::DivisionByZero;
216        assert_eq!(err.to_string(), "division by zero");
217    }
218
219    #[test]
220    fn test_constraint_violation_from() {
221        let violation = ConstraintViolation::NotNull {
222            column: "age".into(),
223        };
224        let err: ExecutorError = violation.into();
225        assert!(matches!(err, ExecutorError::ConstraintViolation(_)));
226    }
227
228    #[test]
229    fn test_evaluation_error_from() {
230        let eval_err = EvaluationError::Overflow;
231        let err: ExecutorError = eval_err.into();
232        assert!(matches!(err, ExecutorError::Evaluation(_)));
233    }
234
235    #[test]
236    fn test_vector_error_conversion() {
237        let vector_err = VectorError::ZeroNormVector;
238        let eval_err: EvaluationError = vector_err.clone().into();
239        assert!(matches!(eval_err, EvaluationError::Vector(_)));
240
241        let exec_err: ExecutorError = vector_err.into();
242        assert!(matches!(exec_err, ExecutorError::Vector(_)));
243    }
244
245    #[test]
246    fn test_path_validation_failed_display() {
247        let err = ExecutorError::PathValidationFailed {
248            path: "/tmp/data.parquet".into(),
249            reason: "symbolic links not allowed".into(),
250        };
251        assert_eq!(
252            err.to_string(),
253            "path validation failed for '/tmp/data.parquet': symbolic links not allowed"
254        );
255    }
256}