1pub mod connection;
7pub mod migrate;
8pub mod pragmas;
9pub mod row;
10pub mod statement;
11pub mod transaction;
12pub mod value;
13
14use crate::sqlite_vfs::stable_blob;
15use crate::stable::meta::Superblock;
16use connection::Connection;
17pub use row::{FromColumn, Row};
18pub use stable_blob::ChecksumRefresh;
19use std::ffi::c_int;
20pub use transaction::UpdateConnection;
21pub use value::{Null, ToSql, Value, NULL};
22
23#[derive(Debug, thiserror::Error)]
24pub enum DbError {
25 #[error("sqlite error {0}: {1}")]
26 Sqlite(c_int, String),
27 #[error("sqlite constraint failed: {0}")]
28 Constraint(String),
29 #[error("query returned no rows")]
30 NotFound,
31 #[error("column {index} has type {actual}, expected {expected}")]
32 TypeMismatch {
33 index: usize,
34 expected: &'static str,
35 actual: &'static str,
36 },
37 #[error("column index {index} out of range for {count} columns")]
38 ColumnOutOfRange { index: usize, count: usize },
39 #[error("stable memory error: {0}")]
40 Stable(#[from] crate::stable::memory::StableMemoryError),
41 #[error("migration version exceeds SQLite INTEGER range: {0}")]
42 MigrationVersionOutOfRange(u64),
43 #[error("SQL contains an interior NUL byte")]
44 InteriorNul,
45 #[error("text value too large")]
46 TextTooLarge,
47 #[error("blob value too large")]
48 BlobTooLarge,
49 #[error("too many SQL parameters")]
50 TooManyParameters,
51 #[error("SQL parameter not found: {0}")]
52 ParameterNotFound(String),
53}
54
55pub struct Db;
56
57impl Db {
58 pub fn init() -> Result<(), DbError> {
59 crate::sqlite_vfs::register();
60 Superblock::load()?;
61 Ok(())
62 }
63
64 pub fn update<T, F>(f: F) -> Result<T, DbError>
65 where
66 F: FnOnce(&mut UpdateConnection<'_>) -> Result<T, DbError>,
67 {
68 Self::init()?;
69 stable_blob::begin_update()?;
70 let _overlay_guard = OverlayGuard;
71 let connection = connection::open_read_write()?;
72 transaction::run_immediate(&connection, f)
73 }
74
75 pub fn query<T, F>(f: F) -> Result<T, DbError>
76 where
77 F: FnOnce(&Connection) -> Result<T, DbError>,
78 {
79 Self::init()?;
80 let connection = connection::open_read_only()?;
81 f(&connection)
82 }
83
84 pub fn migrate(migrations: &[migrate::Migration]) -> Result<(), DbError> {
85 Self::update(|connection| migrate::apply(connection, migrations))?;
86 let target_version = migrations
87 .iter()
88 .map(|migration| migration.version)
89 .max()
90 .unwrap_or(0);
91 let mut block = Superblock::load()?;
92 if block.schema_version < target_version {
93 block.schema_version = target_version;
94 block.store()?;
95 }
96 Ok(())
97 }
98
99 pub fn integrity_check() -> Result<String, DbError> {
100 Self::query(|connection| connection.query_string("PRAGMA integrity_check"))
101 }
102
103 pub fn export_chunk(offset: u64, len: u64) -> Result<Vec<u8>, DbError> {
104 Self::init()?;
105 stable_blob::export_chunk(offset, len).map_err(DbError::from)
106 }
107
108 pub fn db_checksum() -> Result<u64, DbError> {
109 Self::init()?;
110 stable_blob::checksum().map_err(DbError::from)
111 }
112
113 pub fn refresh_checksum() -> Result<u64, DbError> {
114 Self::init()?;
115 stable_blob::refresh_checksum().map_err(DbError::from)
116 }
117
118 pub fn refresh_checksum_chunk(max_bytes: u64) -> Result<ChecksumRefresh, DbError> {
119 Self::init()?;
120 stable_blob::refresh_checksum_chunk(max_bytes).map_err(DbError::from)
121 }
122
123 pub fn begin_import(total_size: u64, expected_checksum: u64) -> Result<(), DbError> {
124 Self::init()?;
125 stable_blob::begin_import(total_size, expected_checksum).map_err(DbError::from)
126 }
127
128 pub fn import_chunk(offset: u64, bytes: &[u8]) -> Result<(), DbError> {
129 Self::init()?;
130 stable_blob::import_chunk(offset, bytes).map_err(DbError::from)
131 }
132
133 pub fn finish_import() -> Result<(), DbError> {
134 Self::init()?;
135 stable_blob::finish_import().map_err(DbError::from)
136 }
137}
138
139struct OverlayGuard;
140
141impl Drop for OverlayGuard {
142 fn drop(&mut self) {
143 stable_blob::rollback_update();
144 }
145}