diff --git a/src/cursor.rs b/src/cursor.rs index 1f0dc63..0baed51 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -52,8 +52,14 @@ pub trait Cursor<'txn> { /// duplicate data items of each key will be returned before moving on to /// the next key. fn iter_start(&mut self) -> Iter<'txn> { - self.get(None, None, ffi::MDB_FIRST).unwrap(); - Iter::new(self.cursor(), ffi::MDB_GET_CURRENT, ffi::MDB_NEXT) + // When the db is empty, this returns NotFound, which means the iterator should not even + // try to proceed or it too will error with code 22 + let complete = self.get(None, None, ffi::MDB_FIRST) + .map(|_| false) + .unwrap_or(true); + let mut iter = Iter::new(self.cursor(), ffi::MDB_GET_CURRENT, ffi::MDB_NEXT); + iter.complete = complete; + iter } /// Iterate over database items starting from the given key. @@ -225,6 +231,7 @@ pub struct Iter<'txn> { cursor: *mut ffi::MDB_cursor, op: c_uint, next_op: c_uint, + complete: bool, _marker: PhantomData, } @@ -232,7 +239,7 @@ impl <'txn> Iter<'txn> { /// Creates a new iterator backed by the given cursor. fn new<'t>(cursor: *mut ffi::MDB_cursor, op: c_uint, next_op: c_uint) -> Iter<'t> { - Iter { cursor: cursor, op: op, next_op: next_op, _marker: PhantomData } + Iter { cursor: cursor, op: op, next_op: next_op, complete: false, _marker: PhantomData } } } @@ -247,6 +254,9 @@ impl <'txn> Iterator for Iter<'txn> { type Item = (&'txn [u8], &'txn [u8]); fn next(&mut self) -> Option<(&'txn [u8], &'txn [u8])> { + if self.complete { + return None + } let mut key = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() }; let mut data = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() }; @@ -262,6 +272,7 @@ impl <'txn> Iterator for Iter<'txn> { // TODO: validate that these are the only failures possible. debug_assert!(err_code == ffi::MDB_NOTFOUND, "Unexpected LMDB error {:?}.", Error::from_err_code(err_code)); + self.complete = true; None } } @@ -463,6 +474,28 @@ mod test { cursor.iter_from(b"key6").collect::>()); } + #[test] + fn test_iter_start_empty() { + let dir = TempDir::new("test").unwrap(); + let env = Environment::new().open(dir.path()).unwrap(); + let db = env.open_db(None).unwrap(); + let txn = env.begin_ro_txn().unwrap(); + let mut cursor = txn.open_ro_cursor(db).unwrap(); + + assert_eq!(0, cursor.iter_start().count()); + } + + #[test] + fn test_iter_empty() { + let dir = TempDir::new("test").unwrap(); + let env = Environment::new().open(dir.path()).unwrap(); + let db = env.open_db(None).unwrap(); + let txn = env.begin_ro_txn().unwrap(); + let mut cursor = txn.open_ro_cursor(db).unwrap(); + + assert_eq!(0, cursor.iter().count()); + } + #[test] fn test_iter_dup() { let dir = TempDir::new("test").unwrap();