Skip to main content

crabka_pgparser/
error.rs

1//! Parse/lex errors. Most map to SQLSTATE 42601 (`syntax_error`) and carry the
2//! byte offset where the problem was detected. A too-deep query — one whose
3//! nesting would overflow the parser/evaluator stack — instead maps to 54001
4//! (`statement_too_complex` / "stack depth limit exceeded"), matching
5//! `PostgreSQL`.
6
7/// A parse/lex error. `message` is the full, ready-to-display text (the
8/// `#[error]` format is just `"{message}"`), so the `42601` "syntax error at
9/// position N: …" framing is baked in by `new`, while a `54001` depth error
10/// (built by `too_deep`) renders its own PostgreSQL-faithful text verbatim.
11#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
12#[error("{message}")]
13pub struct ParseError {
14    pub message: String,
15    pub position: usize,
16    /// The SQLSTATE this error maps to. Defaults to `"42601"` (`syntax_error`);
17    /// `too_deep` sets it to `"54001"` (`statement_too_complex`).
18    sqlstate: &'static str,
19}
20
21impl ParseError {
22    pub fn new(message: impl Into<String>, position: usize) -> Self {
23        Self {
24            message: format!("syntax error at position {position}: {}", message.into()),
25            position,
26            sqlstate: "42601",
27        }
28    }
29
30    pub(crate) fn new_sqlstate(
31        sqlstate: &'static str,
32        message: impl Into<String>,
33        position: usize,
34    ) -> Self {
35        Self {
36            message: message.into(),
37            position,
38            sqlstate,
39        }
40    }
41
42    /// A recursion-depth-limit error: the statement nests more deeply than the
43    /// parser's `MAX_DEPTH` allows. Maps to SQLSTATE `54001`
44    /// (`statement_too_complex`) with `PostgreSQL`'s "stack depth limit exceeded"
45    /// message, so a maliciously deep query returns a clean error instead of
46    /// overflowing the stack and aborting the server process.
47    #[must_use]
48    pub fn too_deep(position: usize) -> Self {
49        Self {
50            message: "stack depth limit exceeded".to_string(),
51            position,
52            sqlstate: "54001",
53        }
54    }
55
56    #[must_use]
57    pub fn sqlstate(&self) -> &'static str {
58        self.sqlstate
59    }
60}