sqlite_parser_nom/
model.rs

1use crate::error::SQLiteError;
2
3pub struct Database<'a> {
4    pub header: DbHeader,
5    pub pages: Vec<Page<'a>>,
6}
7
8pub struct DbHeader {
9    pub page_size: PageSize,
10    pub write_version: u8,
11    pub read_version: u8,
12    pub max_payload_fraction: u8,
13    pub min_payload_fraction: u8,
14    pub leaf_payload_fraction: u8,
15    pub file_change_counter: u32,
16    pub db_size: u32,
17    pub first_freelist_page_no: u32,
18    pub total_freelist_pages: u32,
19    pub schema_cookie: u32,
20    pub schema_format_no: u32,
21    pub default_page_cache_size: u32,
22    pub no_largest_root_b_tree: u32,
23    pub db_text_encoding: TextEncoding,
24    pub user_version: u32,
25    pub incremental_vacuum_mode: u32,
26    pub application_id: u32,
27    pub version_valid_for_no: u32,
28    pub sqlite_version_number: u32,
29}
30
31pub struct PageSize(pub u16);
32
33impl PageSize {
34    pub fn real_size(&self) -> usize {
35        match self.0 {
36            1 => 0x1_00_00,
37            _ => self.0.into(),
38        }
39    }
40}
41
42#[derive(Copy, Clone)]
43pub enum TextEncoding {
44    Utf8,
45    Utf16Le,
46    Utf16Be,
47}
48
49impl TryFrom<u32> for TextEncoding {
50    type Error = SQLiteError;
51
52    fn try_from(value: u32) -> Result<Self, Self::Error> {
53        use TextEncoding::*;
54
55        match value {
56            1 => Ok(Utf8),
57            2 => Ok(Utf16Le),
58            3 => Ok(Utf16Be),
59            _ => Err(SQLiteError::UnknownTextEncodingError(value)),
60        }
61    }
62}
63
64pub enum Page<'a> {
65    InteriorIndex(InteriorIndexPage<'a>),
66    LeafIndex(LeafIndexPage<'a>),
67    InteriorTable(InteriorTablePage),
68    LeafTable(LeafTablePage<'a>),
69}
70
71pub struct InteriorPageHeader {
72    pub first_freeblock_offset: Option<u16>,
73    pub no_cells: u16,
74    pub cell_content_offset: CellOffset,
75    pub no_fragmented_bytes: u8,
76    pub rightmost_pointer: u32,
77}
78
79pub struct InteriorIndexPage<'a> {
80    pub header: InteriorPageHeader,
81    pub cell_pointers: Vec<u16>,
82    pub cells: Vec<InteriorIndexCell<'a>>,
83}
84
85pub struct InteriorTablePage {
86    pub header: InteriorPageHeader,
87    pub cell_pointers: Vec<u16>,
88    pub cells: Vec<InteriorTableCell>,
89}
90
91pub struct IndexCellPayload<'a> {
92    pub header_size: u64,
93    pub column_types: Vec<SerialType>,
94    pub column_values: Vec<Option<Payload<'a>>>,
95    pub rowid: u64,
96}
97
98pub struct InteriorIndexCell<'a> {
99    pub left_child_page_no: u32,
100    pub payload_size: u64,
101    pub payload: IndexCellPayload<'a>,
102    pub overflow_page_no: Option<u32>,
103}
104
105pub struct InteriorTableCell {
106    pub left_child_page_no: u32,
107    pub integer_key: u64,
108}
109
110pub struct CellOffset(pub u16);
111
112impl CellOffset {
113    pub fn real_offset(&self) -> u32 {
114        match self.0 {
115            0 => 0x1_00_00,
116            _ => self.0.into(),
117        }
118    }
119}
120
121pub struct LeafPageHeader {
122    pub first_freeblock_offset: Option<u16>,
123    pub no_cells: u16,
124    pub cell_content_offset: CellOffset,
125    pub no_fragmented_bytes: u8,
126}
127
128pub struct LeafIndexPage<'a> {
129    pub header: LeafPageHeader,
130    pub cell_pointers: Vec<u16>,
131    pub cells: Vec<LeafIndexCell<'a>>,
132}
133
134pub struct LeafIndexCell<'a> {
135    pub payload_size: u64,
136    pub payload: IndexCellPayload<'a>,
137    pub overflow_page_no: Option<u32>,
138}
139
140pub struct LeafTablePage<'a> {
141    pub header: LeafPageHeader,
142    pub cell_pointers: Vec<u16>,
143    pub cells: Vec<LeafTableCell<'a>>,
144}
145
146pub struct TableCellPayload<'a> {
147    pub header_size: u64,
148    pub column_types: Vec<SerialType>,
149    pub column_values: Vec<Option<Payload<'a>>>,
150}
151
152pub struct LeafTableCell<'a> {
153    pub payload_size: u64,
154    pub rowid: u64,
155    pub payload: TableCellPayload<'a>,
156    pub overflow_page_no: Option<u32>,
157}
158
159#[derive(Debug, Eq, PartialEq)]
160pub enum SerialType {
161    Null,
162    I8,
163    I16,
164    I24,
165    I32,
166    I48,
167    I64,
168    F64,
169    Const0,
170    Const1,
171    Reserved,
172    Blob(u64),
173    Text(u64),
174}
175
176impl From<u64> for SerialType {
177    fn from(value: u64) -> Self {
178        use SerialType::*;
179        match value {
180            0 => Null,
181            1 => I8,
182            2 => I16,
183            3 => I24,
184            4 => I32,
185            5 => I48,
186            6 => I64,
187            7 => F64,
188            8 => Const0,
189            9 => Const1,
190            10 | 11 => Reserved,
191            n if n >= 12 && n % 2 == 0 => Blob(n),
192            n if n >= 13 && n % 2 == 1 => Text(n),
193            _ => unreachable!(),
194        }
195    }
196}
197
198impl SerialType {
199    pub fn size(&self) -> usize {
200        match self {
201            SerialType::Null => 0,
202            SerialType::I8 => 1,
203            SerialType::I16 => 2,
204            SerialType::I24 => 3,
205            SerialType::I32 => 4,
206            SerialType::I48 => 6,
207            SerialType::I64 => 8,
208            SerialType::F64 => 8,
209            SerialType::Const0 => 0,
210            SerialType::Const1 => 0,
211            SerialType::Reserved => unimplemented!("reserved"),
212            SerialType::Blob(n) => ((n - 12) / 2).try_into().unwrap(),
213            SerialType::Text(n) => ((n - 13) / 2).try_into().unwrap(),
214        }
215    }
216}
217
218#[derive(Debug, Clone, PartialEq)]
219pub struct RawText<'a>(&'a [u8]);
220
221impl<'a> RawText<'a> {
222    pub fn new(v: &'a [u8]) -> Self {
223        RawText(v)
224    }
225
226    pub fn decode(&self, text_encoding: TextEncoding) -> String {
227        match text_encoding {
228            TextEncoding::Utf8 => String::from_utf8_lossy(self.0).to_string(),
229            TextEncoding::Utf16Le => unimplemented!("utf16 not supported yet"),
230            TextEncoding::Utf16Be => unimplemented!("utf16 not supported yet"),
231        }
232    }
233}
234
235impl<'a> From<&'a str> for RawText<'a> {
236    fn from(value: &'a str) -> Self {
237        RawText(value.as_bytes())
238    }
239}
240
241#[derive(Debug, Clone, PartialEq)]
242pub enum Payload<'a> {
243    I8(i8),
244    I16(i16),
245    I32(i32),
246    I64(i64),
247    F64(f64),
248    Blob(&'a [u8]),
249    Text(RawText<'a>),
250}
251
252impl<'a> From<&'a str> for Payload<'a> {
253    fn from(value: &'a str) -> Self {
254        Payload::Text(value.into())
255    }
256}
257
258impl<'a> From<&'a [u8]> for Payload<'a> {
259    fn from(value: &'a [u8]) -> Self {
260        Payload::Blob(value)
261    }
262}
263
264impl<'a> From<i8> for Payload<'a> {
265    fn from(value: i8) -> Self {
266        Payload::I8(value)
267    }
268}
269
270impl<'a> From<i16> for Payload<'a> {
271    fn from(value: i16) -> Self {
272        Payload::I16(value)
273    }
274}
275
276impl<'a> From<i32> for Payload<'a> {
277    fn from(value: i32) -> Self {
278        Payload::I32(value)
279    }
280}
281
282impl<'a> From<i64> for Payload<'a> {
283    fn from(value: i64) -> Self {
284        Payload::I64(value)
285    }
286}
287
288impl<'a> From<f64> for Payload<'a> {
289    fn from(value: f64) -> Self {
290        Payload::F64(value)
291    }
292}
293
294#[cfg(test)]
295impl<'a> Eq for Payload<'a> {}