1#[derive(Debug, Clone, PartialEq)]
2pub enum ExecutorError {
3 TableNotFound(String),
4 TableAlreadyExists(String),
5 ColumnNotFound {
6 column_name: String,
7 table_name: String,
8 searched_tables: Vec<String>,
9 available_columns: Vec<String>,
10 },
11 InvalidTableQualifier {
12 qualifier: String,
13 column: String,
14 available_tables: Vec<String>,
15 },
16 ColumnAlreadyExists(String),
17 IndexNotFound(String),
18 IndexAlreadyExists(String),
19 InvalidIndexDefinition(String),
20 TriggerNotFound(String),
21 TriggerAlreadyExists(String),
22 SchemaNotFound(String),
23 SchemaAlreadyExists(String),
24 SchemaNotEmpty(String),
25 RoleNotFound(String),
26 TypeNotFound(String),
27 TypeAlreadyExists(String),
28 TypeInUse(String),
29 DependentPrivilegesExist(String),
30 PermissionDenied {
31 role: String,
32 privilege: String,
33 object: String,
34 },
35 ColumnIndexOutOfBounds {
36 index: usize,
37 },
38 TypeMismatch {
39 left: vibesql_types::SqlValue,
40 op: String,
41 right: vibesql_types::SqlValue,
42 },
43 DivisionByZero,
44 InvalidWhereClause(String),
45 UnsupportedExpression(String),
46 UnsupportedFeature(String),
47 StorageError(String),
48 SubqueryReturnedMultipleRows {
49 expected: usize,
50 actual: usize,
51 },
52 SubqueryColumnCountMismatch {
53 expected: usize,
54 actual: usize,
55 },
56 ColumnCountMismatch {
57 expected: usize,
58 provided: usize,
59 },
60 CastError {
61 from_type: String,
62 to_type: String,
63 },
64 TypeConversionError {
65 from: String,
66 to: String,
67 },
68 ConstraintViolation(String),
69 MultiplePrimaryKeys,
70 CannotDropColumn(String),
71 ConstraintNotFound {
72 constraint_name: String,
73 table_name: String,
74 },
75 ExpressionDepthExceeded {
78 depth: usize,
79 max_depth: usize,
80 },
81 QueryTimeoutExceeded {
83 elapsed_seconds: u64,
84 max_seconds: u64,
85 },
86 RowLimitExceeded {
88 rows_processed: usize,
89 max_rows: usize,
90 },
91 MemoryLimitExceeded {
93 used_bytes: usize,
94 max_bytes: usize,
95 },
96 VariableNotFound {
98 variable_name: String,
99 available_variables: Vec<String>,
100 },
101 LabelNotFound(String),
103 SelectIntoRowCount {
105 expected: usize,
106 actual: usize,
107 },
108 SelectIntoColumnCount {
110 expected: usize,
111 actual: usize,
112 },
113 ProcedureNotFound {
115 procedure_name: String,
116 schema_name: String,
117 available_procedures: Vec<String>,
118 },
119 FunctionNotFound {
121 function_name: String,
122 schema_name: String,
123 available_functions: Vec<String>,
124 },
125 ParameterCountMismatch {
127 routine_name: String,
128 routine_type: String, expected: usize,
130 actual: usize,
131 parameter_signature: String,
132 },
133 ParameterTypeMismatch {
135 parameter_name: String,
136 expected_type: String,
137 actual_type: String,
138 actual_value: String,
139 },
140 TypeError(String),
142 ArgumentCountMismatch {
144 expected: usize,
145 actual: usize,
146 },
147 RecursionLimitExceeded {
149 message: String,
150 call_stack: Vec<String>,
151 max_depth: usize,
152 },
153 FunctionMustReturn,
155 InvalidControlFlow(String),
157 InvalidFunctionBody(String),
159 FunctionReadOnlyViolation(String),
161 ParseError(String),
163 InvalidExtractField {
165 field: String,
166 value_type: String,
167 },
168 ArrowDowncastError {
170 expected_type: String,
171 context: String,
172 },
173 ColumnarTypeMismatch {
175 operation: String,
176 left_type: String,
177 right_type: Option<String>,
178 },
179 SimdOperationFailed {
181 operation: String,
182 reason: String,
183 },
184 ColumnarColumnNotFound {
186 column_index: usize,
187 batch_columns: usize,
188 },
189 ColumnarColumnNotFoundByName {
191 column_name: String,
192 },
193 ColumnarLengthMismatch {
195 context: String,
196 expected: usize,
197 actual: usize,
198 },
199 UnsupportedArrayType {
201 operation: String,
202 array_type: String,
203 },
204 SpatialGeometryError {
206 function_name: String,
207 message: String,
208 },
209 SpatialOperationFailed {
211 function_name: String,
212 message: String,
213 },
214 SpatialArgumentError {
216 function_name: String,
217 expected: String,
218 actual: String,
219 },
220 CursorAlreadyExists(String),
222 CursorNotFound(String),
224 CursorAlreadyOpen(String),
226 CursorNotOpen(String),
228 CursorNotScrollable(String),
230 Other(String),
231}
232
233fn find_closest_match<'a>(target: &str, candidates: &'a [String]) -> Option<&'a String> {
235 if candidates.is_empty() {
236 return None;
237 }
238
239 let target_lower = target.to_lowercase();
240
241 if let Some(exact) = candidates.iter().find(|c| c.to_lowercase() == target_lower) {
243 return Some(exact);
244 }
245
246 let mut best_match: Option<(&String, usize)> = None;
248
249 for candidate in candidates {
250 let distance = levenshtein_distance(&target_lower, &candidate.to_lowercase());
251
252 let max_distance = (target.len() / 3).max(2);
255
256 if distance <= max_distance {
257 if let Some((_, best_distance)) = best_match {
258 if distance < best_distance {
259 best_match = Some((candidate, distance));
260 }
261 } else {
262 best_match = Some((candidate, distance));
263 }
264 }
265 }
266
267 best_match.map(|(s, _)| s)
268}
269
270fn levenshtein_distance(s1: &str, s2: &str) -> usize {
272 let len1 = s1.len();
273 let len2 = s2.len();
274
275 if len1 == 0 {
276 return len2;
277 }
278 if len2 == 0 {
279 return len1;
280 }
281
282 let mut prev_row: Vec<usize> = (0..=len2).collect();
283 let mut curr_row = vec![0; len2 + 1];
284
285 for (i, c1) in s1.chars().enumerate() {
286 curr_row[0] = i + 1;
287
288 for (j, c2) in s2.chars().enumerate() {
289 let cost = if c1 == c2 { 0 } else { 1 };
290 curr_row[j + 1] = (curr_row[j] + 1).min(prev_row[j + 1] + 1).min(prev_row[j] + cost);
291 }
292
293 std::mem::swap(&mut prev_row, &mut curr_row);
294 }
295
296 prev_row[len2]
297}
298
299impl std::fmt::Display for ExecutorError {
300 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
301 use vibesql_l10n::vibe_msg;
302 match self {
303 ExecutorError::TableNotFound(name) => {
304 write!(f, "{}", vibe_msg!("executor-table-not-found", name = name.as_str()))
305 }
306 ExecutorError::TableAlreadyExists(name) => {
307 write!(f, "{}", vibe_msg!("executor-table-already-exists", name = name.as_str()))
308 }
309 ExecutorError::ColumnNotFound {
310 column_name,
311 table_name,
312 searched_tables,
313 available_columns,
314 } => {
315 if searched_tables.is_empty() {
316 write!(f, "{}", vibe_msg!("executor-column-not-found-simple", column_name = column_name.as_str(), table_name = table_name.as_str()))
317 } else if available_columns.is_empty() {
318 let searched = searched_tables.join(", ");
319 write!(f, "{}", vibe_msg!("executor-column-not-found-searched", column_name = column_name.as_str(), searched_tables = searched.as_str()))
320 } else {
321 let searched = searched_tables.join(", ");
322 let available = available_columns.join(", ");
323 write!(f, "{}", vibe_msg!("executor-column-not-found-with-available", column_name = column_name.as_str(), searched_tables = searched.as_str(), available_columns = available.as_str()))
324 }
325 }
326 ExecutorError::InvalidTableQualifier { qualifier, column, available_tables } => {
327 let available = available_tables.join(", ");
328 write!(f, "{}", vibe_msg!("executor-invalid-table-qualifier", qualifier = qualifier.as_str(), column = column.as_str(), available_tables = available.as_str()))
329 }
330 ExecutorError::ColumnAlreadyExists(name) => {
331 write!(f, "{}", vibe_msg!("executor-column-already-exists", name = name.as_str()))
332 }
333 ExecutorError::IndexNotFound(name) => {
334 write!(f, "{}", vibe_msg!("executor-index-not-found", name = name.as_str()))
335 }
336 ExecutorError::IndexAlreadyExists(name) => {
337 write!(f, "{}", vibe_msg!("executor-index-already-exists", name = name.as_str()))
338 }
339 ExecutorError::InvalidIndexDefinition(msg) => {
340 write!(f, "{}", vibe_msg!("executor-invalid-index-definition", message = msg.as_str()))
341 }
342 ExecutorError::TriggerNotFound(name) => {
343 write!(f, "{}", vibe_msg!("executor-trigger-not-found", name = name.as_str()))
344 }
345 ExecutorError::TriggerAlreadyExists(name) => {
346 write!(f, "{}", vibe_msg!("executor-trigger-already-exists", name = name.as_str()))
347 }
348 ExecutorError::SchemaNotFound(name) => {
349 write!(f, "{}", vibe_msg!("executor-schema-not-found", name = name.as_str()))
350 }
351 ExecutorError::SchemaAlreadyExists(name) => {
352 write!(f, "{}", vibe_msg!("executor-schema-already-exists", name = name.as_str()))
353 }
354 ExecutorError::SchemaNotEmpty(name) => {
355 write!(f, "{}", vibe_msg!("executor-schema-not-empty", name = name.as_str()))
356 }
357 ExecutorError::RoleNotFound(name) => {
358 write!(f, "{}", vibe_msg!("executor-role-not-found", name = name.as_str()))
359 }
360 ExecutorError::TypeNotFound(name) => {
361 write!(f, "{}", vibe_msg!("executor-type-not-found", name = name.as_str()))
362 }
363 ExecutorError::TypeAlreadyExists(name) => {
364 write!(f, "{}", vibe_msg!("executor-type-already-exists", name = name.as_str()))
365 }
366 ExecutorError::TypeInUse(name) => {
367 write!(f, "{}", vibe_msg!("executor-type-in-use", name = name.as_str()))
368 }
369 ExecutorError::DependentPrivilegesExist(msg) => {
370 write!(f, "{}", vibe_msg!("executor-dependent-privileges-exist", message = msg.as_str()))
371 }
372 ExecutorError::PermissionDenied { role, privilege, object } => {
373 write!(f, "{}", vibe_msg!("executor-permission-denied", role = role.as_str(), privilege = privilege.as_str(), object = object.as_str()))
374 }
375 ExecutorError::ColumnIndexOutOfBounds { index } => {
376 write!(f, "{}", vibe_msg!("executor-column-index-out-of-bounds", index = *index as i64))
377 }
378 ExecutorError::TypeMismatch { left, op, right } => {
379 let left_str = format!("{:?}", left);
380 let right_str = format!("{:?}", right);
381 write!(f, "{}", vibe_msg!("executor-type-mismatch", left = left_str.as_str(), op = op.as_str(), right = right_str.as_str()))
382 }
383 ExecutorError::DivisionByZero => {
384 write!(f, "{}", vibe_msg!("executor-division-by-zero"))
385 }
386 ExecutorError::InvalidWhereClause(msg) => {
387 write!(f, "{}", vibe_msg!("executor-invalid-where-clause", message = msg.as_str()))
388 }
389 ExecutorError::UnsupportedExpression(msg) => {
390 write!(f, "{}", vibe_msg!("executor-unsupported-expression", message = msg.as_str()))
391 }
392 ExecutorError::UnsupportedFeature(msg) => {
393 write!(f, "{}", vibe_msg!("executor-unsupported-feature", message = msg.as_str()))
394 }
395 ExecutorError::StorageError(msg) => {
396 write!(f, "{}", vibe_msg!("executor-storage-error", message = msg.as_str()))
397 }
398 ExecutorError::SubqueryReturnedMultipleRows { expected, actual } => {
399 write!(f, "{}", vibe_msg!("executor-subquery-returned-multiple-rows", expected = *expected as i64, actual = *actual as i64))
400 }
401 ExecutorError::SubqueryColumnCountMismatch { expected, actual } => {
402 write!(f, "{}", vibe_msg!("executor-subquery-column-count-mismatch", expected = *expected as i64, actual = *actual as i64))
403 }
404 ExecutorError::ColumnCountMismatch { expected, provided } => {
405 write!(f, "{}", vibe_msg!("executor-column-count-mismatch", expected = *expected as i64, provided = *provided as i64))
406 }
407 ExecutorError::CastError { from_type, to_type } => {
408 write!(f, "{}", vibe_msg!("executor-cast-error", from_type = from_type.as_str(), to_type = to_type.as_str()))
409 }
410 ExecutorError::TypeConversionError { from, to } => {
411 write!(f, "{}", vibe_msg!("executor-type-conversion-error", from = from.as_str(), to = to.as_str()))
412 }
413 ExecutorError::ConstraintViolation(msg) => {
414 write!(f, "{}", vibe_msg!("executor-constraint-violation", message = msg.as_str()))
415 }
416 ExecutorError::MultiplePrimaryKeys => {
417 write!(f, "{}", vibe_msg!("executor-multiple-primary-keys"))
418 }
419 ExecutorError::CannotDropColumn(msg) => {
420 write!(f, "{}", vibe_msg!("executor-cannot-drop-column", message = msg.as_str()))
421 }
422 ExecutorError::ConstraintNotFound { constraint_name, table_name } => {
423 write!(f, "{}", vibe_msg!("executor-constraint-not-found", constraint_name = constraint_name.as_str(), table_name = table_name.as_str()))
424 }
425 ExecutorError::ExpressionDepthExceeded { depth, max_depth } => {
426 write!(f, "{}", vibe_msg!("executor-expression-depth-exceeded", depth = *depth as i64, max_depth = *max_depth as i64))
427 }
428 ExecutorError::QueryTimeoutExceeded { elapsed_seconds, max_seconds } => {
429 write!(f, "{}", vibe_msg!("executor-query-timeout-exceeded", elapsed_seconds = *elapsed_seconds as i64, max_seconds = *max_seconds as i64))
430 }
431 ExecutorError::RowLimitExceeded { rows_processed, max_rows } => {
432 write!(f, "{}", vibe_msg!("executor-row-limit-exceeded", rows_processed = *rows_processed as i64, max_rows = *max_rows as i64))
433 }
434 ExecutorError::MemoryLimitExceeded { used_bytes, max_bytes } => {
435 let used_gb = format!("{:.2}", *used_bytes as f64 / 1024.0 / 1024.0 / 1024.0);
436 let max_gb = format!("{:.2}", *max_bytes as f64 / 1024.0 / 1024.0 / 1024.0);
437 write!(f, "{}", vibe_msg!("executor-memory-limit-exceeded", used_gb = used_gb.as_str(), max_gb = max_gb.as_str()))
438 }
439 ExecutorError::VariableNotFound { variable_name, available_variables } => {
440 if available_variables.is_empty() {
441 write!(f, "{}", vibe_msg!("executor-variable-not-found-simple", variable_name = variable_name.as_str()))
442 } else {
443 let available = available_variables.join(", ");
444 write!(f, "{}", vibe_msg!("executor-variable-not-found-with-available", variable_name = variable_name.as_str(), available_variables = available.as_str()))
445 }
446 }
447 ExecutorError::LabelNotFound(name) => {
448 write!(f, "{}", vibe_msg!("executor-label-not-found", name = name.as_str()))
449 }
450 ExecutorError::SelectIntoRowCount { expected, actual } => {
451 let plural = if *actual == 1 { "" } else { "s" };
452 write!(f, "{}", vibe_msg!("executor-select-into-row-count", expected = *expected as i64, actual = *actual as i64, plural = plural))
453 }
454 ExecutorError::SelectIntoColumnCount { expected, actual } => {
455 let expected_plural = if *expected == 1 { "" } else { "s" };
456 let actual_plural = if *actual == 1 { "" } else { "s" };
457 write!(f, "{}", vibe_msg!("executor-select-into-column-count", expected = *expected as i64, expected_plural = expected_plural, actual = *actual as i64, actual_plural = actual_plural))
458 }
459 ExecutorError::ProcedureNotFound {
460 procedure_name,
461 schema_name,
462 available_procedures,
463 } => {
464 if available_procedures.is_empty() {
465 write!(f, "{}", vibe_msg!("executor-procedure-not-found-simple", procedure_name = procedure_name.as_str(), schema_name = schema_name.as_str()))
466 } else {
467 let suggestion = find_closest_match(procedure_name, available_procedures);
468 if let Some(similar) = suggestion {
469 write!(f, "{}\nAvailable procedures: {}\nDid you mean '{}'?",
471 vibe_msg!("executor-procedure-not-found-simple", procedure_name = procedure_name.as_str(), schema_name = schema_name.as_str()),
472 available_procedures.join(", "),
473 similar)
474 } else {
475 write!(f, "{}\nAvailable procedures: {}",
476 vibe_msg!("executor-procedure-not-found-simple", procedure_name = procedure_name.as_str(), schema_name = schema_name.as_str()),
477 available_procedures.join(", "))
478 }
479 }
480 }
481 ExecutorError::FunctionNotFound { function_name, schema_name, available_functions } => {
482 if available_functions.is_empty() {
483 write!(f, "{}", vibe_msg!("executor-function-not-found-simple", function_name = function_name.as_str(), schema_name = schema_name.as_str()))
484 } else {
485 let suggestion = find_closest_match(function_name, available_functions);
486 if let Some(similar) = suggestion {
487 write!(f, "{}\nAvailable functions: {}\nDid you mean '{}'?",
488 vibe_msg!("executor-function-not-found-simple", function_name = function_name.as_str(), schema_name = schema_name.as_str()),
489 available_functions.join(", "),
490 similar)
491 } else {
492 write!(f, "{}\nAvailable functions: {}",
493 vibe_msg!("executor-function-not-found-simple", function_name = function_name.as_str(), schema_name = schema_name.as_str()),
494 available_functions.join(", "))
495 }
496 }
497 }
498 ExecutorError::ParameterCountMismatch {
499 routine_name,
500 routine_type,
501 expected,
502 actual,
503 parameter_signature,
504 } => {
505 let expected_plural = if *expected == 1 { "" } else { "s" };
506 let actual_plural = if *actual == 1 { "" } else { "s" };
507 write!(f, "{}", vibe_msg!("executor-parameter-count-mismatch",
508 routine_type = routine_type.as_str(),
509 routine_name = routine_name.as_str(),
510 expected = *expected as i64,
511 expected_plural = expected_plural,
512 parameter_signature = parameter_signature.as_str(),
513 actual = *actual as i64,
514 actual_plural = actual_plural))
515 }
516 ExecutorError::ParameterTypeMismatch {
517 parameter_name,
518 expected_type,
519 actual_type,
520 actual_value,
521 } => {
522 write!(f, "{}", vibe_msg!("executor-parameter-type-mismatch",
523 parameter_name = parameter_name.as_str(),
524 expected_type = expected_type.as_str(),
525 actual_type = actual_type.as_str(),
526 actual_value = actual_value.as_str()))
527 }
528 ExecutorError::TypeError(msg) => {
529 write!(f, "{}", vibe_msg!("executor-type-error", message = msg.as_str()))
530 }
531 ExecutorError::ArgumentCountMismatch { expected, actual } => {
532 write!(f, "{}", vibe_msg!("executor-argument-count-mismatch", expected = *expected as i64, actual = *actual as i64))
533 }
534 ExecutorError::RecursionLimitExceeded { message, call_stack, max_depth } => {
535 write!(f, "{}", vibe_msg!("executor-recursion-limit-exceeded", max_depth = *max_depth as i64, message = message.as_str()))?;
536 if !call_stack.is_empty() {
537 write!(f, "\n{}", vibe_msg!("executor-recursion-call-stack"))?;
538 for call in call_stack {
539 write!(f, "\n {}", call)?;
540 }
541 }
542 Ok(())
543 }
544 ExecutorError::FunctionMustReturn => {
545 write!(f, "{}", vibe_msg!("executor-function-must-return"))
546 }
547 ExecutorError::InvalidControlFlow(msg) => {
548 write!(f, "{}", vibe_msg!("executor-invalid-control-flow", message = msg.as_str()))
549 }
550 ExecutorError::InvalidFunctionBody(msg) => {
551 write!(f, "{}", vibe_msg!("executor-invalid-function-body", message = msg.as_str()))
552 }
553 ExecutorError::FunctionReadOnlyViolation(msg) => {
554 write!(f, "{}", vibe_msg!("executor-function-read-only-violation", message = msg.as_str()))
555 }
556 ExecutorError::ParseError(msg) => {
557 write!(f, "{}", vibe_msg!("executor-parse-error", message = msg.as_str()))
558 }
559 ExecutorError::InvalidExtractField { field, value_type } => {
560 write!(f, "{}", vibe_msg!("executor-invalid-extract-field", field = field.as_str(), value_type = value_type.as_str()))
561 }
562 ExecutorError::ArrowDowncastError { expected_type, context } => {
563 write!(f, "{}", vibe_msg!("executor-arrow-downcast-error", expected_type = expected_type.as_str(), context = context.as_str()))
564 }
565 ExecutorError::ColumnarTypeMismatch { operation, left_type, right_type } => {
566 if let Some(right) = right_type {
567 write!(f, "{}", vibe_msg!("executor-columnar-type-mismatch-binary", operation = operation.as_str(), left_type = left_type.as_str(), right_type = right.as_str()))
568 } else {
569 write!(f, "{}", vibe_msg!("executor-columnar-type-mismatch-unary", operation = operation.as_str(), left_type = left_type.as_str()))
570 }
571 }
572 ExecutorError::SimdOperationFailed { operation, reason } => {
573 write!(f, "{}", vibe_msg!("executor-simd-operation-failed", operation = operation.as_str(), reason = reason.as_str()))
574 }
575 ExecutorError::ColumnarColumnNotFound { column_index, batch_columns } => {
576 write!(f, "{}", vibe_msg!("executor-columnar-column-not-found", column_index = *column_index as i64, batch_columns = *batch_columns as i64))
577 }
578 ExecutorError::ColumnarColumnNotFoundByName { column_name } => {
579 write!(f, "{}", vibe_msg!("executor-columnar-column-not-found-by-name", column_name = column_name.as_str()))
580 }
581 ExecutorError::ColumnarLengthMismatch { context, expected, actual } => {
582 write!(f, "{}", vibe_msg!("executor-columnar-length-mismatch", context = context.as_str(), expected = *expected as i64, actual = *actual as i64))
583 }
584 ExecutorError::UnsupportedArrayType { operation, array_type } => {
585 write!(f, "{}", vibe_msg!("executor-unsupported-array-type", operation = operation.as_str(), array_type = array_type.as_str()))
586 }
587 ExecutorError::SpatialGeometryError { function_name, message } => {
588 write!(f, "{}", vibe_msg!("executor-spatial-geometry-error", function_name = function_name.as_str(), message = message.as_str()))
589 }
590 ExecutorError::SpatialOperationFailed { function_name, message } => {
591 write!(f, "{}", vibe_msg!("executor-spatial-operation-failed", function_name = function_name.as_str(), message = message.as_str()))
592 }
593 ExecutorError::SpatialArgumentError { function_name, expected, actual } => {
594 write!(f, "{}", vibe_msg!("executor-spatial-argument-error", function_name = function_name.as_str(), expected = expected.as_str(), actual = actual.as_str()))
595 }
596 ExecutorError::CursorAlreadyExists(name) => {
597 write!(f, "{}", vibe_msg!("executor-cursor-already-exists", name = name.as_str()))
598 }
599 ExecutorError::CursorNotFound(name) => {
600 write!(f, "{}", vibe_msg!("executor-cursor-not-found", name = name.as_str()))
601 }
602 ExecutorError::CursorAlreadyOpen(name) => {
603 write!(f, "{}", vibe_msg!("executor-cursor-already-open", name = name.as_str()))
604 }
605 ExecutorError::CursorNotOpen(name) => {
606 write!(f, "{}", vibe_msg!("executor-cursor-not-open", name = name.as_str()))
607 }
608 ExecutorError::CursorNotScrollable(name) => {
609 write!(f, "{}", vibe_msg!("executor-cursor-not-scrollable", name = name.as_str()))
610 }
611 ExecutorError::Other(msg) => {
612 write!(f, "{}", vibe_msg!("executor-other", message = msg.as_str()))
613 }
614 }
615 }
616}
617
618impl std::error::Error for ExecutorError {}
619
620impl From<vibesql_storage::StorageError> for ExecutorError {
621 fn from(err: vibesql_storage::StorageError) -> Self {
622 match err {
623 vibesql_storage::StorageError::TableNotFound(name) => {
624 ExecutorError::TableNotFound(name)
625 }
626 vibesql_storage::StorageError::IndexAlreadyExists(name) => {
627 ExecutorError::IndexAlreadyExists(name)
628 }
629 vibesql_storage::StorageError::IndexNotFound(name) => {
630 ExecutorError::IndexNotFound(name)
631 }
632 vibesql_storage::StorageError::ColumnCountMismatch { expected, actual } => {
633 ExecutorError::ColumnCountMismatch { expected, provided: actual }
634 }
635 vibesql_storage::StorageError::ColumnIndexOutOfBounds { index } => {
636 ExecutorError::ColumnIndexOutOfBounds { index }
637 }
638 vibesql_storage::StorageError::CatalogError(msg) => ExecutorError::StorageError(msg),
639 vibesql_storage::StorageError::TransactionError(msg) => {
640 ExecutorError::StorageError(msg)
641 }
642 vibesql_storage::StorageError::RowNotFound => {
643 ExecutorError::StorageError("Row not found".to_string())
644 }
645 vibesql_storage::StorageError::NullConstraintViolation { column } => {
646 ExecutorError::ConstraintViolation(format!(
647 "NOT NULL constraint violation: column '{}' cannot be NULL",
648 column
649 ))
650 }
651 vibesql_storage::StorageError::TypeMismatch { column, expected, actual } => {
652 ExecutorError::StorageError(format!(
653 "Type mismatch in column '{}': expected {}, got {}",
654 column, expected, actual
655 ))
656 }
657 vibesql_storage::StorageError::ColumnNotFound { column_name, table_name } => {
658 ExecutorError::StorageError(format!(
659 "Column '{}' not found in table '{}'",
660 column_name, table_name
661 ))
662 }
663 vibesql_storage::StorageError::UniqueConstraintViolation(msg) => {
664 ExecutorError::ConstraintViolation(msg)
665 }
666 vibesql_storage::StorageError::InvalidIndexColumn(msg) => {
667 ExecutorError::StorageError(msg)
668 }
669 vibesql_storage::StorageError::NotImplemented(msg) => {
670 ExecutorError::StorageError(format!("Not implemented: {}", msg))
671 }
672 vibesql_storage::StorageError::IoError(msg) => {
673 ExecutorError::StorageError(format!("I/O error: {}", msg))
674 }
675 vibesql_storage::StorageError::InvalidPageSize { expected, actual } => {
676 ExecutorError::StorageError(format!(
677 "Invalid page size: expected {}, got {}",
678 expected, actual
679 ))
680 }
681 vibesql_storage::StorageError::InvalidPageId(page_id) => {
682 ExecutorError::StorageError(format!("Invalid page ID: {}", page_id))
683 }
684 vibesql_storage::StorageError::LockError(msg) => {
685 ExecutorError::StorageError(format!("Lock error: {}", msg))
686 }
687 vibesql_storage::StorageError::MemoryBudgetExceeded { used, budget } => {
688 ExecutorError::StorageError(format!(
689 "Memory budget exceeded: using {} bytes, budget is {} bytes",
690 used, budget
691 ))
692 }
693 vibesql_storage::StorageError::NoIndexToEvict => ExecutorError::StorageError(
694 "No index available to evict (all indexes are already disk-backed)".to_string(),
695 ),
696 vibesql_storage::StorageError::Other(msg) => ExecutorError::StorageError(msg),
697 }
698 }
699}
700
701impl From<vibesql_catalog::CatalogError> for ExecutorError {
702 fn from(err: vibesql_catalog::CatalogError) -> Self {
703 match err {
704 vibesql_catalog::CatalogError::TableAlreadyExists(name) => {
705 ExecutorError::TableAlreadyExists(name)
706 }
707 vibesql_catalog::CatalogError::TableNotFound { table_name } => {
708 ExecutorError::TableNotFound(table_name)
709 }
710 vibesql_catalog::CatalogError::ColumnAlreadyExists(name) => {
711 ExecutorError::ColumnAlreadyExists(name)
712 }
713 vibesql_catalog::CatalogError::ColumnNotFound { column_name, table_name } => {
714 ExecutorError::ColumnNotFound {
715 column_name,
716 table_name,
717 searched_tables: vec![],
718 available_columns: vec![],
719 }
720 }
721 vibesql_catalog::CatalogError::SchemaNotFound(name) => {
722 ExecutorError::SchemaNotFound(name)
723 }
724 vibesql_catalog::CatalogError::SchemaAlreadyExists(name) => {
725 ExecutorError::SchemaAlreadyExists(name)
726 }
727 vibesql_catalog::CatalogError::SchemaNotEmpty(name) => {
728 ExecutorError::SchemaNotEmpty(name)
729 }
730 vibesql_catalog::CatalogError::RoleAlreadyExists(name) => {
731 ExecutorError::StorageError(format!("Role '{}' already exists", name))
732 }
733 vibesql_catalog::CatalogError::RoleNotFound(name) => ExecutorError::RoleNotFound(name),
734 vibesql_catalog::CatalogError::DomainAlreadyExists(name) => {
736 ExecutorError::Other(format!("Domain '{}' already exists", name))
737 }
738 vibesql_catalog::CatalogError::DomainNotFound(name) => {
739 ExecutorError::Other(format!("Domain '{}' not found", name))
740 }
741 vibesql_catalog::CatalogError::DomainInUse { domain_name, dependent_columns } => {
742 ExecutorError::Other(format!(
743 "Domain '{}' is still in use by {} column(s): {}",
744 domain_name,
745 dependent_columns.len(),
746 dependent_columns
747 .iter()
748 .map(|(t, c)| format!("{}.{}", t, c))
749 .collect::<Vec<_>>()
750 .join(", ")
751 ))
752 }
753 vibesql_catalog::CatalogError::SequenceAlreadyExists(name) => {
754 ExecutorError::Other(format!("Sequence '{}' already exists", name))
755 }
756 vibesql_catalog::CatalogError::SequenceNotFound(name) => {
757 ExecutorError::Other(format!("Sequence '{}' not found", name))
758 }
759 vibesql_catalog::CatalogError::SequenceInUse { sequence_name, dependent_columns } => {
760 ExecutorError::Other(format!(
761 "Sequence '{}' is still in use by {} column(s): {}",
762 sequence_name,
763 dependent_columns.len(),
764 dependent_columns
765 .iter()
766 .map(|(t, c)| format!("{}.{}", t, c))
767 .collect::<Vec<_>>()
768 .join(", ")
769 ))
770 }
771 vibesql_catalog::CatalogError::TypeAlreadyExists(name) => {
772 ExecutorError::TypeAlreadyExists(name)
773 }
774 vibesql_catalog::CatalogError::TypeNotFound(name) => ExecutorError::TypeNotFound(name),
775 vibesql_catalog::CatalogError::TypeInUse(name) => ExecutorError::TypeInUse(name),
776 vibesql_catalog::CatalogError::CollationAlreadyExists(name) => {
777 ExecutorError::Other(format!("Collation '{}' already exists", name))
778 }
779 vibesql_catalog::CatalogError::CollationNotFound(name) => {
780 ExecutorError::Other(format!("Collation '{}' not found", name))
781 }
782 vibesql_catalog::CatalogError::CharacterSetAlreadyExists(name) => {
783 ExecutorError::Other(format!("Character set '{}' already exists", name))
784 }
785 vibesql_catalog::CatalogError::CharacterSetNotFound(name) => {
786 ExecutorError::Other(format!("Character set '{}' not found", name))
787 }
788 vibesql_catalog::CatalogError::TranslationAlreadyExists(name) => {
789 ExecutorError::Other(format!("Translation '{}' already exists", name))
790 }
791 vibesql_catalog::CatalogError::TranslationNotFound(name) => {
792 ExecutorError::Other(format!("Translation '{}' not found", name))
793 }
794 vibesql_catalog::CatalogError::ViewAlreadyExists(name) => {
795 ExecutorError::Other(format!("View '{}' already exists", name))
796 }
797 vibesql_catalog::CatalogError::ViewNotFound(name) => {
798 ExecutorError::Other(format!("View '{}' not found", name))
799 }
800 vibesql_catalog::CatalogError::ViewInUse { view_name, dependent_views } => {
801 ExecutorError::Other(format!(
802 "View or table '{}' is still in use by {} view(s): {}",
803 view_name,
804 dependent_views.len(),
805 dependent_views.join(", ")
806 ))
807 }
808 vibesql_catalog::CatalogError::TriggerAlreadyExists(name) => {
809 ExecutorError::TriggerAlreadyExists(name)
810 }
811 vibesql_catalog::CatalogError::TriggerNotFound(name) => {
812 ExecutorError::TriggerNotFound(name)
813 }
814 vibesql_catalog::CatalogError::AssertionAlreadyExists(name) => {
815 ExecutorError::Other(format!("Assertion '{}' already exists", name))
816 }
817 vibesql_catalog::CatalogError::AssertionNotFound(name) => {
818 ExecutorError::Other(format!("Assertion '{}' not found", name))
819 }
820 vibesql_catalog::CatalogError::FunctionAlreadyExists(name) => {
821 ExecutorError::Other(format!("Function '{}' already exists", name))
822 }
823 vibesql_catalog::CatalogError::FunctionNotFound(name) => {
824 ExecutorError::Other(format!("Function '{}' not found", name))
825 }
826 vibesql_catalog::CatalogError::ProcedureAlreadyExists(name) => {
827 ExecutorError::Other(format!("Procedure '{}' already exists", name))
828 }
829 vibesql_catalog::CatalogError::ProcedureNotFound(name) => {
830 ExecutorError::Other(format!("Procedure '{}' not found", name))
831 }
832 vibesql_catalog::CatalogError::ConstraintAlreadyExists(name) => {
833 ExecutorError::ConstraintViolation(format!("Constraint '{}' already exists", name))
834 }
835 vibesql_catalog::CatalogError::ConstraintNotFound(name) => {
836 ExecutorError::ConstraintNotFound {
837 constraint_name: name,
838 table_name: "unknown".to_string(),
839 }
840 }
841 vibesql_catalog::CatalogError::IndexAlreadyExists { index_name, table_name } => {
842 ExecutorError::IndexAlreadyExists(format!("{} on table {}", index_name, table_name))
843 }
844 vibesql_catalog::CatalogError::IndexNotFound { index_name, table_name } => {
845 ExecutorError::IndexNotFound(format!("{} on table {}", index_name, table_name))
846 }
847 vibesql_catalog::CatalogError::CircularForeignKey { table_name, message } => {
848 ExecutorError::ConstraintViolation(format!(
849 "Circular foreign key dependency on table '{}': {}",
850 table_name, message
851 ))
852 }
853 }
854 }
855}