Skip to main content

sql_engine/
sql_engine.rs

1use duck_diagnostic::*;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
4enum SqlError {
5  SyntaxError,
6  UnknownTable,
7  UnknownColumn,
8  AmbiguousColumn,
9  TypeMismatch,
10  DivisionByZero,
11  FullTableScan,
12  DeprecatedSyntax,
13}
14
15impl DiagnosticCode for SqlError {
16  fn code(&self) -> &str {
17    match self {
18      Self::SyntaxError => "SQL0001",
19      Self::UnknownTable => "SQL0002",
20      Self::UnknownColumn => "SQL0003",
21      Self::AmbiguousColumn => "SQL0004",
22      Self::TypeMismatch => "SQL0005",
23      Self::DivisionByZero => "SQL0006",
24      Self::FullTableScan => "SQL-W001",
25      Self::DeprecatedSyntax => "SQL-W002",
26    }
27  }
28
29  fn severity(&self) -> Severity {
30    match self {
31      Self::FullTableScan | Self::DeprecatedSyntax => Severity::Warning,
32      _ => Severity::Error,
33    }
34  }
35}
36
37fn main() {
38  let query = r#"SELECT u.name, o.total
39FROM users u
40JOIN orders o ON u.id = o.user_id
41WHERE u.age / 0 > 10
42  AND o.status = active"#;
43
44  let mut engine = DiagnosticEngine::<SqlError>::new();
45
46  engine.emit(
47    Diagnostic::new(SqlError::DivisionByZero, "division by zero in expression")
48      .with_label(Label::primary(
49        Span::new("query.sql", 4, 6, 11),
50        Some("this will always fail at runtime".into()),
51      ))
52      .with_note("division by a literal zero is never valid"),
53  );
54
55  engine.emit(
56    Diagnostic::new(SqlError::UnknownColumn, "unknown column `active`")
57      .with_label(Label::primary(
58        Span::new("query.sql", 5, 18, 6),
59        Some("not a known column".into()),
60      ))
61      .with_help("did you mean the string `'active'`?"),
62  );
63
64  engine.emit(
65    Diagnostic::new(SqlError::FullTableScan, "query requires a full table scan on `users`")
66      .with_label(Label::primary(
67        Span::new("query.sql", 2, 5, 7),
68        Some("no index on `users.age`".into()),
69      ))
70      .with_help("consider adding an index: CREATE INDEX idx_users_age ON users(age)"),
71  );
72
73  engine.print_all(query);
74}