1use std::fmt;
6
7use rupg_common::SqlState;
8
9#[derive(Clone, Debug, PartialEq, Eq)]
11pub struct Error {
12 pub code: SqlState,
14 pub message: String,
16 pub detail: Option<&'static str>,
18 pub hint: Option<&'static str>,
20 pub location: Option<usize>,
22}
23
24impl Error {
25 pub(crate) fn syntax(text: &[u8], message: &str, start: usize, end: usize) -> Error {
27 let message = if start >= text.len() {
28 format!("{message} at end of input")
29 } else {
30 let near = String::from_utf8_lossy(&text[start..end.clamp(start, text.len())]);
31 format!("{message} at or near \"{near}\"")
32 };
33 Error {
34 code: SqlState::SYNTAX_ERROR,
35 message,
36 detail: None,
37 hint: None,
38 location: Some(start),
39 }
40 }
41
42 pub(crate) fn at(code: SqlState, message: &str, location: usize) -> Error {
44 Error {
45 code,
46 message: message.to_owned(),
47 detail: None,
48 hint: None,
49 location: Some(location),
50 }
51 }
52
53 pub(crate) fn not_ported(rule: &str) -> Error {
55 Error {
56 code: SqlState::FEATURE_NOT_SUPPORTED,
57 message: format!("the action of the rule {rule} of gram.y is not ported"),
58 detail: None,
59 hint: None,
60 location: None,
61 }
62 }
63
64 pub(crate) fn internal(message: &str) -> Error {
66 Error {
67 code: SqlState::INTERNAL_ERROR,
68 message: message.to_owned(),
69 detail: None,
70 hint: None,
71 location: None,
72 }
73 }
74
75 pub(crate) fn encoding(bad: &[u8]) -> Error {
77 let first = bad.first().copied().unwrap_or(0);
78 let length = match first {
79 b if b & 0x80 == 0 => 1,
80 b if b & 0xe0 == 0xc0 => 2,
81 b if b & 0xf0 == 0xe0 => 3,
82 b if b & 0xf8 == 0xf0 => 4,
83 _ => 1,
84 };
85 let bytes: Vec<String> = bad.iter().take(length).map(|b| format!("0x{b:02x}")).collect();
86 Error {
87 code: SqlState::CHARACTER_NOT_IN_REPERTOIRE,
88 message: format!("invalid byte sequence for encoding \"UTF8\": {}", bytes.join(" ")),
89 detail: None,
90 hint: None,
91 location: None,
92 }
93 }
94
95 pub fn position(&self, text: &str) -> Option<usize> {
97 let location = self.location?.min(text.len());
98 let characters = text.as_bytes()[..location].iter().filter(|&&b| b & 0xc0 != 0x80).count();
99 Some(characters + 1)
100 }
101}
102
103impl fmt::Display for Error {
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 f.write_str(&self.message)
106 }
107}
108
109impl std::error::Error for Error {}
110
111impl From<Error> for rupg_common::Error {
112 fn from(error: Error) -> Self {
114 let mut common = rupg_common::Error::new(error.code, error.message);
115 if let Some(detail) = error.detail {
116 common = common.with_detail(detail);
117 }
118 if let Some(hint) = error.hint {
119 common = common.with_hint(hint);
120 }
121 common
122 }
123}
124
125#[derive(Clone, Debug, PartialEq, Eq)]
127pub struct Notice {
128 pub severity: Severity,
130 pub code: SqlState,
132 pub message: String,
134 pub location: Option<usize>,
136}
137
138#[derive(Clone, Copy, Debug, PartialEq, Eq)]
140pub enum Severity {
141 Notice,
143 Warning,
145}