aboutsummaryrefslogtreecommitdiff
path: root/src/db/sqlite_adapter.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/db/sqlite_adapter.rs')
-rw-r--r--src/db/sqlite_adapter.rs184
1 files changed, 142 insertions, 42 deletions
diff --git a/src/db/sqlite_adapter.rs b/src/db/sqlite_adapter.rs
index 3eccfdde..a91b9011 100644
--- a/src/db/sqlite_adapter.rs
+++ b/src/db/sqlite_adapter.rs
@@ -169,10 +169,6 @@ impl IDb for SqliteDb {
}
}
- fn fast_len(&self, tree: usize) -> Result<Option<usize>> {
- Ok(Some(self.len(tree)?))
- }
-
fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<Option<Value>> {
let tree = self.get_tree(tree)?;
let db = self.db.get()?;
@@ -371,33 +367,64 @@ impl<'a> ITx for SqliteTx<'a> {
Ok(old_val)
}
+ fn clear(&mut self, tree: usize) -> TxOpResult<()> {
+ let tree = self.get_tree(tree)?;
+ self.tx.execute(&format!("DELETE FROM {}", tree), [])?;
+ Ok(())
+ }
- fn iter(&self, _tree: usize) -> TxOpResult<TxValueIter<'_>> {
- unimplemented!();
+ fn iter(&self, tree: usize) -> TxOpResult<TxValueIter<'_>> {
+ let tree = self.get_tree(tree)?;
+ let sql = format!("SELECT k, v FROM {} ORDER BY k ASC", tree);
+ TxValueIterator::make(self, &sql, [])
}
- fn iter_rev(&self, _tree: usize) -> TxOpResult<TxValueIter<'_>> {
- unimplemented!();
+ fn iter_rev(&self, tree: usize) -> TxOpResult<TxValueIter<'_>> {
+ let tree = self.get_tree(tree)?;
+ let sql = format!("SELECT k, v FROM {} ORDER BY k DESC", tree);
+ TxValueIterator::make(self, &sql, [])
}
fn range<'r>(
&self,
- _tree: usize,
- _low: Bound<&'r [u8]>,
- _high: Bound<&'r [u8]>,
+ tree: usize,
+ low: Bound<&'r [u8]>,
+ high: Bound<&'r [u8]>,
) -> TxOpResult<TxValueIter<'_>> {
- unimplemented!();
+ let tree = self.get_tree(tree)?;
+
+ let (bounds_sql, params) = bounds_sql(low, high);
+ let sql = format!("SELECT k, v FROM {} {} ORDER BY k ASC", tree, bounds_sql);
+
+ let params = params
+ .iter()
+ .map(|x| x as &dyn rusqlite::ToSql)
+ .collect::<Vec<_>>();
+
+ TxValueIterator::make::<&[&dyn rusqlite::ToSql]>(self, &sql, params.as_ref())
}
fn range_rev<'r>(
&self,
- _tree: usize,
- _low: Bound<&'r [u8]>,
- _high: Bound<&'r [u8]>,
+ tree: usize,
+ low: Bound<&'r [u8]>,
+ high: Bound<&'r [u8]>,
) -> TxOpResult<TxValueIter<'_>> {
- unimplemented!();
+ let tree = self.get_tree(tree)?;
+
+ let (bounds_sql, params) = bounds_sql(low, high);
+ let sql = format!("SELECT k, v FROM {} {} ORDER BY k DESC", tree, bounds_sql);
+
+ let params = params
+ .iter()
+ .map(|x| x as &dyn rusqlite::ToSql)
+ .collect::<Vec<_>>();
+
+ TxValueIterator::make::<&[&dyn rusqlite::ToSql]>(self, &sql, params.as_ref())
}
}
-// ----
+// ---- iterators outside transactions ----
+// complicated, they must hold the Statement and Row objects
+// therefore quite some unsafe code (it is a self-referential struct)
struct DbValueIterator<'a> {
db: Connection,
@@ -417,17 +444,23 @@ impl<'a> DbValueIterator<'a> {
let mut boxed = Box::pin(res);
trace!("make iterator with sql: {}", sql);
- unsafe {
- let db = NonNull::from(&boxed.db);
- let stmt = db.as_ref().prepare(sql)?;
+ // This unsafe allows us to bypass lifetime checks
+ let db = unsafe { NonNull::from(&boxed.db).as_ref() };
+ let stmt = db.prepare(sql)?;
- let mut_ref: Pin<&mut DbValueIterator<'a>> = Pin::as_mut(&mut boxed);
+ let mut_ref = Pin::as_mut(&mut boxed);
+ // This unsafe allows us to write in a field of the pinned struct
+ unsafe {
Pin::get_unchecked_mut(mut_ref).stmt = Some(stmt);
+ }
- let mut stmt = NonNull::from(&boxed.stmt);
- let iter = stmt.as_mut().as_mut().unwrap().query(args)?;
+ // This unsafe allows us to bypass lifetime checks
+ let stmt = unsafe { NonNull::from(&boxed.stmt).as_mut() };
+ let iter = stmt.as_mut().unwrap().query(args)?;
- let mut_ref: Pin<&mut DbValueIterator<'a>> = Pin::as_mut(&mut boxed);
+ let mut_ref = Pin::as_mut(&mut boxed);
+ // This unsafe allows us to write in a field of the pinned struct
+ unsafe {
Pin::get_unchecked_mut(mut_ref).iter = Some(iter);
}
@@ -449,28 +482,73 @@ impl<'a> Iterator for DbValueIteratorPin<'a> {
type Item = Result<(Value, Value)>;
fn next(&mut self) -> Option<Self::Item> {
- let next = unsafe {
- let mut_ref: Pin<&mut DbValueIterator<'a>> = Pin::as_mut(&mut self.0);
- Pin::get_unchecked_mut(mut_ref).iter.as_mut()?.next()
- };
- let row = match next {
- Err(e) => return Some(Err(e.into())),
- Ok(None) => return None,
- Ok(Some(r)) => r,
- };
- let k = match row.get::<_, Vec<u8>>(0) {
- Err(e) => return Some(Err(e.into())),
- Ok(x) => x,
- };
- let v = match row.get::<_, Vec<u8>>(1) {
- Err(e) => return Some(Err(e.into())),
- Ok(y) => y,
+ let mut_ref = Pin::as_mut(&mut self.0);
+ // This unsafe allows us to mutably access the iterator field
+ let next = unsafe { Pin::get_unchecked_mut(mut_ref).iter.as_mut()?.next() };
+ iter_next_row(next)
+ }
+}
+
+// ---- iterators within transactions ----
+// it's the same except we don't hold a mutex guard,
+// only a Statement and a Rows object
+
+struct TxValueIterator<'a> {
+ stmt: Statement<'a>,
+ iter: Option<Rows<'a>>,
+ _pin: PhantomPinned,
+}
+
+impl<'a> TxValueIterator<'a> {
+ fn make<P: rusqlite::Params>(
+ tx: &'a SqliteTx<'a>,
+ sql: &str,
+ args: P,
+ ) -> TxOpResult<TxValueIter<'a>> {
+ let stmt = tx.tx.prepare(sql)?;
+ let res = TxValueIterator {
+ stmt,
+ iter: None,
+ _pin: PhantomPinned,
};
- Some(Ok((k, v)))
+ let mut boxed = Box::pin(res);
+ trace!("make iterator with sql: {}", sql);
+
+ // This unsafe allows us to bypass lifetime checks
+ let stmt = unsafe { NonNull::from(&boxed.stmt).as_mut() };
+ let iter = stmt.query(args)?;
+
+ let mut_ref = Pin::as_mut(&mut boxed);
+ // This unsafe allows us to write in a field of the pinned struct
+ unsafe {
+ Pin::get_unchecked_mut(mut_ref).iter = Some(iter);
+ }
+
+ Ok(Box::new(TxValueIteratorPin(boxed)))
}
}
-// ----
+impl<'a> Drop for TxValueIterator<'a> {
+ fn drop(&mut self) {
+ trace!("drop iter");
+ drop(self.iter.take());
+ }
+}
+
+struct TxValueIteratorPin<'a>(Pin<Box<TxValueIterator<'a>>>);
+
+impl<'a> Iterator for TxValueIteratorPin<'a> {
+ type Item = TxOpResult<(Value, Value)>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let mut_ref = Pin::as_mut(&mut self.0);
+ // This unsafe allows us to mutably access the iterator field
+ let next = unsafe { Pin::get_unchecked_mut(mut_ref).iter.as_mut()?.next() };
+ iter_next_row(next)
+ }
+}
+
+// ---- utility ----
fn bounds_sql<'r>(low: Bound<&'r [u8]>, high: Bound<&'r [u8]>) -> (String, Vec<Vec<u8>>) {
let mut sql = String::new();
@@ -510,3 +588,25 @@ fn bounds_sql<'r>(low: Bound<&'r [u8]>, high: Bound<&'r [u8]>) -> (String, Vec<V
(sql, params)
}
+
+fn iter_next_row<E>(
+ next_row: rusqlite::Result<Option<&rusqlite::Row>>,
+) -> Option<std::result::Result<(Value, Value), E>>
+where
+ E: From<rusqlite::Error>,
+{
+ let row = match next_row {
+ Err(e) => return Some(Err(e.into())),
+ Ok(None) => return None,
+ Ok(Some(r)) => r,
+ };
+ let k = match row.get::<_, Vec<u8>>(0) {
+ Err(e) => return Some(Err(e.into())),
+ Ok(x) => x,
+ };
+ let v = match row.get::<_, Vec<u8>>(1) {
+ Err(e) => return Some(Err(e.into())),
+ Ok(y) => y,
+ };
+ Some(Ok((k, v)))
+}