diff --git a/src/cursor.rs b/src/cursor.rs index f50eef4..7042524 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -80,7 +80,7 @@ pub trait Cursor<'txn> { /// Iterate over duplicate items in the database starting from the given /// key. Each item will be returned as an iterator of its duplicates. - fn iter_dup_from(&mut self, key: &K) -> IterDup<'txn> where K: AsRef<[u8]> { + fn iter_dup_from(&mut self, key: K) -> IterDup<'txn> where K: AsRef<[u8]> { match self.get(Some(key.as_ref()), None, ffi::MDB_SET_RANGE) { Ok(_) | Err(Error::NotFound) => (), Err(error) => panic!("mdb_cursor_get returned an unexpected error: {}", error), @@ -89,7 +89,7 @@ pub trait Cursor<'txn> { } /// Iterate over the duplicates of the item in the database with the given key. - fn iter_dup_of(&mut self, key: &K) -> Iter<'txn> where K: AsRef<[u8]> { + fn iter_dup_of(&mut self, key: K) -> Iter<'txn> where K: AsRef<[u8]> { match self.get(Some(key.as_ref()), None, ffi::MDB_SET) { Ok(_) | Err(Error::NotFound) => (), Err(error) => panic!("mdb_cursor_get returned an unexpected error: {}", error), diff --git a/src/transaction.rs b/src/transaction.rs index 590fd9f..8dc29b2 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -332,12 +332,22 @@ impl <'env> RwTransaction<'env> { let data_val: Option = data.map(|data| ffi::MDB_val { mv_size: data.len() as size_t, mv_data: data.as_ptr() as *mut c_void }); - unsafe { - lmdb_result(ffi::mdb_del(self.txn(), - database.dbi(), - &mut key_val, - data_val.map(|mut data_val| &mut data_val as *mut _) - .unwrap_or(ptr::null_mut()))) + + if let Some(mut d) = data_val { + unsafe { + lmdb_result(ffi::mdb_del(self.txn(), + database.dbi(), + &mut key_val, + &mut d)) + + } + } else { + unsafe { + lmdb_result(ffi::mdb_del(self.txn(), + database.dbi(), + &mut key_val, + ptr::null_mut())) + } } } @@ -392,6 +402,7 @@ mod test { use flags::*; use super::*; use test_utils::*; + use cursor::Cursor; #[test] fn test_put_get_del() { @@ -414,6 +425,53 @@ mod test { txn.del(db, b"key1", None).unwrap(); assert_eq!(txn.get(db, b"key1"), Err(Error::NotFound)); } + + #[test] + fn test_put_get_del_multi() { + let dir = TempDir::new("test").unwrap(); + let env = Environment::new().open(dir.path()).unwrap(); + let db = env.create_db(None, DatabaseFlags::DUP_SORT).unwrap(); + + let mut txn = env.begin_rw_txn().unwrap(); + txn.put(db, b"key1", b"val1", WriteFlags::empty()).unwrap(); + txn.put(db, b"key1", b"val2", WriteFlags::empty()).unwrap(); + txn.put(db, b"key1", b"val3", WriteFlags::empty()).unwrap(); + txn.put(db, b"key2", b"val1", WriteFlags::empty()).unwrap(); + txn.put(db, b"key2", b"val2", WriteFlags::empty()).unwrap(); + txn.put(db, b"key2", b"val3", WriteFlags::empty()).unwrap(); + txn.put(db, b"key3", b"val1", WriteFlags::empty()).unwrap(); + txn.put(db, b"key3", b"val2", WriteFlags::empty()).unwrap(); + txn.put(db, b"key3", b"val3", WriteFlags::empty()).unwrap(); + txn.commit().unwrap(); + + let txn = env.begin_rw_txn().unwrap(); + { + let mut cur = txn.open_ro_cursor(db).unwrap(); + let iter = cur.iter_dup_of(b"key1"); + let vals = iter.map(|(_,x)| x).collect::>(); + assert_eq!(vals, vec![b"val1", b"val2", b"val3"]); + + } + txn.commit().unwrap(); + + let mut txn = env.begin_rw_txn().unwrap(); + txn.del(db, b"key1", Some(b"val2")).unwrap(); + txn.del(db, b"key2", None).unwrap(); + txn.commit().unwrap(); + + let txn = env.begin_rw_txn().unwrap(); + { + let mut cur = txn.open_ro_cursor(db).unwrap(); + let iter = cur.iter_dup_of(b"key1"); + let vals = iter.map(|(_,x)| x).collect::>(); + assert_eq!(vals, vec![b"val1", b"val3"]); + + let iter = cur.iter_dup_of(b"key2"); + assert_eq!(0, iter.count()); + } + txn.commit().unwrap(); + } + #[test] fn test_reserve() {