sqlite3_header/
lib.rs

1// https://sqlite.org/fileformat2.html
2
3pub mod error;
4
5use std::convert::TryInto;
6
7/// The C string "SQLite format 3\000"
8const MAGIC_HEADER_BYTES: [u8; 16] = [
9    0x53, 0x51, 0x4c, 0x69,
10    0x74, 0x65, 0x20, 0x66,
11    0x6f, 0x72, 0x6d, 0x61,
12    0x74, 0x20, 0x33, 0x00,
13];
14
15fn two_byte_slice_to_u16(slice: &[u8]) -> u16 {
16    u16::from_be_bytes(slice.try_into().unwrap())
17}
18
19fn four_byte_slice_to_u32(slice: &[u8]) -> u32 {
20    u32::from_be_bytes(slice.try_into().unwrap())
21}
22
23/// The file format write version and file format read version at offsets 18 and 19
24/// are intended to allow for enhancements of the file format in future versions of
25/// SQLite. In current versions of SQLite, both of these values are 1 for rollback
26/// journalling modes and 2 for WAL journalling mode. If a version of SQLite coded
27/// to the current file format specification encounters a database file where the
28/// read version is 1 or 2 but the write version is greater than 2, then the
29/// database file must be treated as read-only. If a database file with a read
30/// version greater than 2 is encountered, then that database cannot be read or
31/// written.
32#[derive(Debug)]
33pub enum FileFormat {
34    Inaccessible,
35    Legacy,
36    WriteAheadLogging,
37}
38
39/// The maximum and minimum embedded payload fractions and the leaf payload
40/// fraction values must be 64, 32, and 32. These values were originally intended
41/// to be tunable parameters that could be used to modify the storage format of the
42/// b-tree algorithm. However, that functionality is not supported and there are no
43/// current plans to add support in the future. Hence, these three bytes are fixed
44/// at the values specified.
45#[derive(Debug)]
46pub struct Payload {
47    pub leaf_fraction: u8,
48    pub maximum_embedded_fraction: u8,
49    pub minimum_embedded_fraction: u8,
50}
51
52/// Unused pages in the database file are stored on a freelist. The 4-byte
53/// big-endian integer at offset 32 stores the page number of the first page of the
54/// freelist, or zero if the freelist is empty. The 4-byte big-endian integer at
55/// offset 36 stores stores the total number of pages on the freelist.
56#[derive(Debug)]
57pub struct Freelist {
58    pub page_index: u32,
59    pub count: u32,
60}
61
62/// The schema format number is a 4-byte big-endian integer at offset 44. The
63/// schema format number is similar to the file format read and write version
64/// numbers at offsets 18 and 19 except that the schema format number refers to the
65/// high-level SQL formatting rather than the low-level b-tree formatting. Four
66/// schema format numbers are currently defined:
67/// 1. Format 1 is understood by all versions of SQLite back to version 3.0.0 (2004-06-18).
68/// 2. Format 2 adds the ability of rows within the same table to have a varying number of columns, in order to support the ALTER TABLE ... ADD COLUMN functionality. Support for reading and writing format 2 was added in SQLite version 3.1.3 on 2005-02-20.
69/// 3. Format 3 adds the ability of extra columns added by ALTER TABLE ... ADD COLUMN to have non-NULL default values. This capability was added in SQLite version 3.1.4 on 2005-03-11.
70/// 4. Format 4 causes SQLite to respect the DESC keyword on index declarations. (The DESC keyword is ignored in indexes for formats 1, 2, and 3.) Format 4 also adds two new boolean record type values (serial types 8 and 9). Support for format 4 was added in SQLite 3.3.0 on 2006-01-10.
71/// New database files created by SQLite use format 4 by default. The
72/// legacy_file_format pragma can be used to cause SQLite to create new database
73/// files using format 1. The format version number can be made to default to 1
74/// instead of 4 by setting SQLITE_DEFAULT_FILE_FORMAT=1 at compile-time.
75#[derive(Debug)]
76pub enum SchemaFormat {
77    Format1,
78    Format2,
79    Format3,
80    Format4,
81}
82
83#[derive(Debug)]
84pub struct Schema {
85    /// The schema cookie is a 4-byte big-endian integer at offset 40 that is
86    /// incremented whenever the database schema changes. A prepared statement is
87    /// compiled against a specific version of the database schema. When the database
88    /// schema changes, the statement must be reprepared. When a prepared statement
89    /// runs, it first checks the schema cookie to ensure the value is the same as when
90    /// the statement was prepared and if the schema cookie has changed, the statement
91    /// either automatically reprepares and reruns or it aborts with an SQLITE_SCHEMA
92    /// error.
93    pub cookie: u32,
94    pub format: SchemaFormat,
95}
96
97/// The 4-byte big-endian integer at offset 56 determines the encoding used for all text strings
98/// stored in the database. A value of 1 means UTF-8. A value of 2 means UTF-16le. A value of 3 means
99/// UTF-16be. No other values are allowed. The sqlite3.h header file defines C-preprocessor macros
100/// SQLITE_UTF8 as 1, SQLITE_UTF16LE as 2, and SQLITE_UTF16BE as 3, to use in place of the numeric
101/// codes for the text encoding.
102#[derive(Debug)]
103pub enum DatabaseTextEncoding {
104    Utf8,
105    Utf16le,
106    Utf16be,
107}
108
109#[derive(Debug)]
110pub enum VacuumMode {
111    Auto,
112    Incremental,
113}
114
115/// The two 4-byte big-endian integers at offsets 52 and 64 are used to manage the
116/// auto_vacuum and incremental_vacuum modes. If the integer at offset 52 is zero
117/// then pointer-map (ptrmap) pages are omitted from the database file and neither
118/// auto_vacuum nor incremental_vacuum are supported. If the integer at offset 52 is
119/// non-zero then it is the page number of the largest root page in the database
120/// file, the database file will contain ptrmap pages, and the mode must be either
121/// auto_vacuum or incremental_vacuum. In this latter case, the integer at offset 64
122/// is true for incremental_vacuum and false for auto_vacuum. If the integer at
123/// offset 52 is zero then the integer at offset 64 must also be zero.
124#[derive(Debug)]
125pub struct Vacuum {
126    pub largest_root_btree_page: u32,
127    pub mode: VacuumMode,
128}
129
130/// The 4-byte big-endian integer at offset 96 stores the SQLITE_VERSION_NUMBER
131/// value for the SQLite library that most recently modified the database file. The
132/// 4-byte big-endian integer at offset 92 is the value of the change counter when
133/// the version number was stored. The integer at offset 92 indicates which
134/// transaction the version number is valid for and is sometimes called the
135/// "version-valid-for number".
136#[derive(Debug)]
137pub struct LastUpdate {
138    pub sqlite_version_number: u32,
139    pub version_valid_for: u32,
140}
141
142#[derive(Debug)]
143pub struct SQLite3Header {
144    page_size: u16,
145
146    file_format_write_version: FileFormat,
147    file_format_read_version: FileFormat,
148
149    reserved_bytes_per_page: u8,
150
151    payload_fraction: Payload,
152
153    file_change_counter: u32,
154
155    in_header_database_size: u32,
156
157    freelist: Freelist,
158
159    schema: Schema,
160
161    default_page_cache_size: u32,
162
163    database_text_encoding: DatabaseTextEncoding,
164
165    user_version: u32,
166
167    vacuum: Option<Vacuum>,
168
169    application_id: u32,
170
171    last_update: LastUpdate,
172}
173
174impl SQLite3Header {
175    /// All other bytes of the database file header are reserved for future expansion
176    /// and must be set to zero.
177    #[allow(non_upper_case_globals)]
178    pub const reserved: [u8; 20] = [0; 20];
179
180    /// Every valid SQLite database file begins with the following 16 bytes (in hex):
181    /// 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00. This byte sequence corresponds
182    /// to the UTF-8 string "SQLite format 3" including the nul terminator character at
183    /// the end.
184    pub fn magic_header_string(&self) -> &str {
185        std::str::from_utf8(&MAGIC_HEADER_BYTES).unwrap()
186    }
187
188    /// The two-byte value beginning at offset 16 determines the page size of the
189    /// database. For SQLite versions 3.7.0.1 (2010-08-04) and earlier, this value is
190    /// interpreted as a big-endian integer and must be a power of two between 512 and
191    /// 32768, inclusive. Beginning with SQLite version 3.7.1 (2010-08-23), a page size
192    /// of 65536 bytes is supported. The value 65536 will not fit in a two-byte
193    /// integer, so to specify a 65536-byte page size, the value at offset 16 is 0x00
194    /// 0x01. This value can be interpreted as a big-endian 1 and thought of as a magic
195    /// number to represent the 65536 page size. Or one can view the two-byte field as
196    /// a little endian number and say that it represents the page size divided by 256.
197    /// These two interpretations of the page-size field are equivalent.
198    pub fn page_size(&self) -> u16 {
199        self.page_size
200    }
201
202    pub fn file_format_read_version(&self) -> &FileFormat {
203        &self.file_format_read_version
204    }
205
206    pub fn file_format_write_version(&self) -> &FileFormat {
207        &self.file_format_write_version
208    }
209
210    /// SQLite has the ability to set aside a small number of extra bytes at the end of
211    /// every page for use by extensions. These extra bytes are used, for example, by
212    /// the SQLite Encryption Extension to store a nonce and/or cryptographic checksum
213    /// associated with each page. The "reserved space" size in the 1-byte integer at
214    /// offset 20 is the number of bytes of space at the end of each page to reserve
215    /// for extensions. This value is usually 0. The value can be odd.
216
217    /// The "usable size" of a database page is the page size specified by the 2-byte
218    /// integer at offset 16 in the header less the "reserved" space size recorded in
219    /// the 1-byte integer at offset 20 in the header. The usable size of a page might
220    /// be an odd number. However, the usable size is not allowed to be less than 480.
221    /// In other words, if the page size is 512, then the reserved space size cannot
222    /// exceed 32.
223    pub fn reserved_bytes_per_page(&self) -> u8 {
224        self.reserved_bytes_per_page
225    }
226
227    pub fn payload_fraction(&self) -> &Payload {
228        &self.payload_fraction
229    }
230
231    /// The file change counter is a 4-byte big-endian integer at offset 24 that is
232    /// incremented whenever the database file is unlocked after having been modified.
233    /// When two or more processes are reading the same database file, each process can
234    /// detect database changes from other processes by monitoring the change counter.
235    /// A process will normally want to flush its database page cache when another
236    /// process modified the database, since the cache has become stale. The file
237    /// change counter facilitates this.
238
239    /// In WAL mode, changes to the database are detected using the wal-index and so
240    /// the change counter is not needed. Hence, the change counter might not be
241    /// incremented on each transaction in WAL mode.
242    pub fn file_change_counter(&self) -> u32 {
243        self.file_change_counter
244    }
245
246    /// The 4-byte big-endian integer at offset 28 into the header stores the size of
247    /// the database file in pages. If this in-header datasize size is not valid (see
248    /// the next paragraph), then the database size is computed by looking at the
249    /// actual size of the database file. Older versions of SQLite ignored the
250    /// in-header database size and used the actual file size exclusively. Newer
251    /// versions of SQLite use the in-header database size if it is available but fall
252    /// back to the actual file size if the in-header database size is not valid.
253
254    /// The in-header database size is only considered to be valid if it is non-zero
255    /// and if the 4-byte change counter at offset 24 exactly matches the 4-byte
256    /// version-valid-for number at offset 92. The in-header database size is always
257    /// valid when the database is only modified using recent versions of SQLite,
258    /// versions 3.7.0 (2010-07-21) and later. If a legacy version of SQLite writes to
259    /// the database, it will not know to update the in-header database size and so the
260    /// in-header database size could be incorrect. But legacy versions of SQLite will
261    /// also leave the version-valid-for number at offset 92 unchanged so it will not
262    /// match the change-counter. Hence, invalid in-header database sizes can be
263    /// detected (and ignored) by observing when the change-counter does not match the
264    /// version-valid-for number.
265    pub fn in_header_database_size(&self) -> u32 {
266        self.in_header_database_size
267    }
268
269    pub fn freelist(&self) -> &Freelist {
270        &self.freelist
271    }
272
273    pub fn schema(&self) -> &Schema {
274        &self.schema
275    }
276
277    /// The 4-byte big-endian signed integer at offset 48 is the suggested cache size
278    /// in pages for the database file. The value is a suggestion only and SQLite is
279    /// under no obligation to honor it. The absolute value of the integer is used as
280    /// the suggested size. The suggested cache size can be set using the
281    /// default_cache_size pragma.
282    pub fn default_page_cache_size(&self) -> u32 {
283        self.default_page_cache_size
284    }
285
286    pub fn database_text_encoding(&self) -> &DatabaseTextEncoding {
287        &self.database_text_encoding
288    }
289
290    /// The 4-byte big-endian integer at offset 60 is the user version which is set and
291    /// queried by the user_version pragma. The user version is not used by SQLite.
292    pub fn user_version(&self) -> u32 {
293        self.user_version
294    }
295
296    pub fn vacuum(&self) -> Option<&Vacuum> {
297        if let Some(vac) = &self.vacuum {
298            Some(vac)
299        } else {
300            None
301        }
302    }
303
304    /// The 4-byte big-endian integer at offset 68 is an "Application ID" that can be
305    /// set by the PRAGMA application_id command in order to identify the database as
306    /// belonging to or associated with a particular application. The application ID is
307    /// intended for database files used as an application file-format. The application
308    /// ID can be used by utilities such as file(1) to determine the specific file type
309    /// rather than just reporting "SQLite3 Database". A list of assigned application
310    /// IDs can be seen by consulting the magic.txt file in the SQLite source repository.
311    pub fn application_id(&self) -> u32 {
312        self.application_id
313    }
314
315    pub fn last_update(&self) -> &LastUpdate {
316        &self.last_update
317    }
318}