lmdb/
cursor.rs

1use std::marker::PhantomData;
2use std::{
3    fmt,
4    mem,
5    ptr,
6    result,
7    slice,
8};
9
10use libc::{
11    c_uint,
12    c_void,
13    size_t,
14    EINVAL,
15};
16
17use database::Database;
18use error::{
19    lmdb_result,
20    Error,
21    Result,
22};
23use ffi;
24use flags::WriteFlags;
25use transaction::Transaction;
26
27/// An LMDB cursor.
28pub trait Cursor<'txn> {
29    /// Returns a raw pointer to the underlying LMDB cursor.
30    ///
31    /// The caller **must** ensure that the pointer is not used after the
32    /// lifetime of the cursor.
33    fn cursor(&self) -> *mut ffi::MDB_cursor;
34
35    /// Retrieves a key/data pair from the cursor. Depending on the cursor op,
36    /// the current key may be returned.
37    fn get(&self, key: Option<&[u8]>, data: Option<&[u8]>, op: c_uint) -> Result<(Option<&'txn [u8]>, &'txn [u8])> {
38        unsafe {
39            let mut key_val = slice_to_val(key);
40            let mut data_val = slice_to_val(data);
41            let key_ptr = key_val.mv_data;
42            lmdb_result(ffi::mdb_cursor_get(self.cursor(), &mut key_val, &mut data_val, op))?;
43            let key_out = if key_ptr != key_val.mv_data {
44                Some(val_to_slice(key_val))
45            } else {
46                None
47            };
48            let data_out = val_to_slice(data_val);
49            Ok((key_out, data_out))
50        }
51    }
52
53    /// Iterate over database items. The iterator will begin with item next
54    /// after the cursor, and continue until the end of the database. For new
55    /// cursors, the iterator will begin with the first item in the database.
56    ///
57    /// For databases with duplicate data items (`DatabaseFlags::DUP_SORT`), the
58    /// duplicate data items of each key will be returned before moving on to
59    /// the next key.
60    fn iter(&mut self) -> Iter<'txn> {
61        Iter::new(self.cursor(), ffi::MDB_NEXT, ffi::MDB_NEXT)
62    }
63
64    /// Iterate over database items starting from the beginning of the database.
65    ///
66    /// For databases with duplicate data items (`DatabaseFlags::DUP_SORT`), the
67    /// duplicate data items of each key will be returned before moving on to
68    /// the next key.
69    fn iter_start(&mut self) -> Iter<'txn> {
70        Iter::new(self.cursor(), ffi::MDB_FIRST, ffi::MDB_NEXT)
71    }
72
73    /// Iterate over database items starting from the given key.
74    ///
75    /// For databases with duplicate data items (`DatabaseFlags::DUP_SORT`), the
76    /// duplicate data items of each key will be returned before moving on to
77    /// the next key.
78    fn iter_from<K>(&mut self, key: K) -> Iter<'txn>
79    where
80        K: AsRef<[u8]>,
81    {
82        match self.get(Some(key.as_ref()), None, ffi::MDB_SET_RANGE) {
83            Ok(_) | Err(Error::NotFound) => (),
84            Err(error) => return Iter::Err(error),
85        };
86        Iter::new(self.cursor(), ffi::MDB_GET_CURRENT, ffi::MDB_NEXT)
87    }
88
89    /// Iterate over duplicate database items. The iterator will begin with the
90    /// item next after the cursor, and continue until the end of the database.
91    /// Each item will be returned as an iterator of its duplicates.
92    fn iter_dup(&mut self) -> IterDup<'txn> {
93        IterDup::new(self.cursor(), ffi::MDB_NEXT)
94    }
95
96    /// Iterate over duplicate database items starting from the beginning of the
97    /// database. Each item will be returned as an iterator of its duplicates.
98    fn iter_dup_start(&mut self) -> IterDup<'txn> {
99        IterDup::new(self.cursor(), ffi::MDB_FIRST)
100    }
101
102    /// Iterate over duplicate items in the database starting from the given
103    /// key. Each item will be returned as an iterator of its duplicates.
104    fn iter_dup_from<K>(&mut self, key: K) -> IterDup<'txn>
105    where
106        K: AsRef<[u8]>,
107    {
108        match self.get(Some(key.as_ref()), None, ffi::MDB_SET_RANGE) {
109            Ok(_) | Err(Error::NotFound) => (),
110            Err(error) => return IterDup::Err(error),
111        };
112        IterDup::new(self.cursor(), ffi::MDB_GET_CURRENT)
113    }
114
115    /// Iterate over the duplicates of the item in the database with the given key.
116    fn iter_dup_of<K>(&mut self, key: K) -> Iter<'txn>
117    where
118        K: AsRef<[u8]>,
119    {
120        match self.get(Some(key.as_ref()), None, ffi::MDB_SET) {
121            Ok(_) | Err(Error::NotFound) => (),
122            Err(error) => return Iter::Err(error),
123        };
124        Iter::new(self.cursor(), ffi::MDB_GET_CURRENT, ffi::MDB_NEXT_DUP)
125    }
126}
127
128/// A read-only cursor for navigating the items within a database.
129pub struct RoCursor<'txn> {
130    cursor: *mut ffi::MDB_cursor,
131    _marker: PhantomData<fn() -> &'txn ()>,
132}
133
134impl<'txn> Cursor<'txn> for RoCursor<'txn> {
135    fn cursor(&self) -> *mut ffi::MDB_cursor {
136        self.cursor
137    }
138}
139
140impl<'txn> fmt::Debug for RoCursor<'txn> {
141    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
142        f.debug_struct("RoCursor").finish()
143    }
144}
145
146impl<'txn> Drop for RoCursor<'txn> {
147    fn drop(&mut self) {
148        unsafe { ffi::mdb_cursor_close(self.cursor) }
149    }
150}
151
152impl<'txn> RoCursor<'txn> {
153    /// Creates a new read-only cursor in the given database and transaction.
154    /// Prefer using `Transaction::open_cursor`.
155    pub(crate) fn new<T>(txn: &'txn T, db: Database) -> Result<RoCursor<'txn>>
156    where
157        T: Transaction,
158    {
159        let mut cursor: *mut ffi::MDB_cursor = ptr::null_mut();
160        unsafe {
161            lmdb_result(ffi::mdb_cursor_open(txn.txn(), db.dbi(), &mut cursor))?;
162        }
163        Ok(RoCursor {
164            cursor,
165            _marker: PhantomData,
166        })
167    }
168}
169
170/// A read-write cursor for navigating items within a database.
171pub struct RwCursor<'txn> {
172    cursor: *mut ffi::MDB_cursor,
173    _marker: PhantomData<fn() -> &'txn ()>,
174}
175
176impl<'txn> Cursor<'txn> for RwCursor<'txn> {
177    fn cursor(&self) -> *mut ffi::MDB_cursor {
178        self.cursor
179    }
180}
181
182impl<'txn> fmt::Debug for RwCursor<'txn> {
183    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
184        f.debug_struct("RwCursor").finish()
185    }
186}
187
188impl<'txn> Drop for RwCursor<'txn> {
189    fn drop(&mut self) {
190        unsafe { ffi::mdb_cursor_close(self.cursor) }
191    }
192}
193
194impl<'txn> RwCursor<'txn> {
195    /// Creates a new read-only cursor in the given database and transaction.
196    /// Prefer using `RwTransaction::open_rw_cursor`.
197    pub(crate) fn new<T>(txn: &'txn T, db: Database) -> Result<RwCursor<'txn>>
198    where
199        T: Transaction,
200    {
201        let mut cursor: *mut ffi::MDB_cursor = ptr::null_mut();
202        unsafe {
203            lmdb_result(ffi::mdb_cursor_open(txn.txn(), db.dbi(), &mut cursor))?;
204        }
205        Ok(RwCursor {
206            cursor,
207            _marker: PhantomData,
208        })
209    }
210
211    /// Puts a key/data pair into the database. The cursor will be positioned at
212    /// the new data item, or on failure usually near it.
213    pub fn put<K, D>(&mut self, key: &K, data: &D, flags: WriteFlags) -> Result<()>
214    where
215        K: AsRef<[u8]>,
216        D: AsRef<[u8]>,
217    {
218        let key = key.as_ref();
219        let data = data.as_ref();
220        let mut key_val: ffi::MDB_val = ffi::MDB_val {
221            mv_size: key.len() as size_t,
222            mv_data: key.as_ptr() as *mut c_void,
223        };
224        let mut data_val: ffi::MDB_val = ffi::MDB_val {
225            mv_size: data.len() as size_t,
226            mv_data: data.as_ptr() as *mut c_void,
227        };
228        unsafe { lmdb_result(ffi::mdb_cursor_put(self.cursor(), &mut key_val, &mut data_val, flags.bits())) }
229    }
230
231    /// Deletes the current key/data pair.
232    ///
233    /// ### Flags
234    ///
235    /// `WriteFlags::NO_DUP_DATA` may be used to delete all data items for the
236    /// current key, if the database was opened with `DatabaseFlags::DUP_SORT`.
237    pub fn del(&mut self, flags: WriteFlags) -> Result<()> {
238        unsafe { lmdb_result(ffi::mdb_cursor_del(self.cursor(), flags.bits())) }
239    }
240}
241
242unsafe fn slice_to_val(slice: Option<&[u8]>) -> ffi::MDB_val {
243    match slice {
244        Some(slice) => ffi::MDB_val {
245            mv_size: slice.len() as size_t,
246            mv_data: slice.as_ptr() as *mut c_void,
247        },
248        None => ffi::MDB_val {
249            mv_size: 0,
250            mv_data: ptr::null_mut(),
251        },
252    }
253}
254
255unsafe fn val_to_slice<'a>(val: ffi::MDB_val) -> &'a [u8] {
256    slice::from_raw_parts(val.mv_data as *const u8, val.mv_size as usize)
257}
258
259/// An iterator over the key/value pairs in an LMDB database.
260pub enum Iter<'txn> {
261    /// An iterator that returns an error on every call to Iter.next().
262    /// Cursor.iter*() creates an Iter of this type when LMDB returns an error
263    /// on retrieval of a cursor.  Using this variant instead of returning
264    /// an error makes Cursor.iter()* methods infallible, so consumers only
265    /// need to check the result of Iter.next().
266    Err(Error),
267
268    /// An iterator that returns an Item on calls to Iter.next().
269    /// The Item is a Result<(&'txn [u8], &'txn [u8])>, so this variant
270    /// might still return an error, if retrieval of the key/value pair
271    /// fails for some reason.
272    Ok {
273        /// The LMDB cursor with which to iterate.
274        cursor: *mut ffi::MDB_cursor,
275
276        /// The first operation to perform when the consumer calls Iter.next().
277        op: c_uint,
278
279        /// The next and subsequent operations to perform.
280        next_op: c_uint,
281
282        /// A marker to ensure the iterator doesn't outlive the transaction.
283        _marker: PhantomData<fn(&'txn ())>,
284    },
285}
286
287impl<'txn> Iter<'txn> {
288    /// Creates a new iterator backed by the given cursor.
289    fn new<'t>(cursor: *mut ffi::MDB_cursor, op: c_uint, next_op: c_uint) -> Iter<'t> {
290        Iter::Ok {
291            cursor,
292            op,
293            next_op,
294            _marker: PhantomData,
295        }
296    }
297}
298
299impl<'txn> fmt::Debug for Iter<'txn> {
300    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
301        f.debug_struct("Iter").finish()
302    }
303}
304
305impl<'txn> Iterator for Iter<'txn> {
306    type Item = Result<(&'txn [u8], &'txn [u8])>;
307
308    fn next(&mut self) -> Option<Result<(&'txn [u8], &'txn [u8])>> {
309        match self {
310            &mut Iter::Ok {
311                cursor,
312                ref mut op,
313                next_op,
314                _marker,
315            } => {
316                let mut key = ffi::MDB_val {
317                    mv_size: 0,
318                    mv_data: ptr::null_mut(),
319                };
320                let mut data = ffi::MDB_val {
321                    mv_size: 0,
322                    mv_data: ptr::null_mut(),
323                };
324                let op = mem::replace(op, next_op);
325                unsafe {
326                    match ffi::mdb_cursor_get(cursor, &mut key, &mut data, op) {
327                        ffi::MDB_SUCCESS => Some(Ok((val_to_slice(key), val_to_slice(data)))),
328                        // EINVAL can occur when the cursor was previously seeked to a non-existent value,
329                        // e.g. iter_from with a key greater than all values in the database.
330                        ffi::MDB_NOTFOUND | EINVAL => None,
331                        error => Some(Err(Error::from_err_code(error))),
332                    }
333                }
334            },
335            &mut Iter::Err(err) => Some(Err(err)),
336        }
337    }
338}
339
340/// An iterator over the keys and duplicate values in an LMDB database.
341///
342/// The yielded items of the iterator are themselves iterators over the duplicate values for a
343/// specific key.
344pub enum IterDup<'txn> {
345    /// An iterator that returns an error on every call to Iter.next().
346    /// Cursor.iter*() creates an Iter of this type when LMDB returns an error
347    /// on retrieval of a cursor.  Using this variant instead of returning
348    /// an error makes Cursor.iter()* methods infallible, so consumers only
349    /// need to check the result of Iter.next().
350    Err(Error),
351
352    /// An iterator that returns an Item on calls to Iter.next().
353    /// The Item is a Result<(&'txn [u8], &'txn [u8])>, so this variant
354    /// might still return an error, if retrieval of the key/value pair
355    /// fails for some reason.
356    Ok {
357        /// The LMDB cursor with which to iterate.
358        cursor: *mut ffi::MDB_cursor,
359
360        /// The first operation to perform when the consumer calls Iter.next().
361        op: c_uint,
362
363        /// A marker to ensure the iterator doesn't outlive the transaction.
364        _marker: PhantomData<fn(&'txn ())>,
365    },
366}
367
368impl<'txn> IterDup<'txn> {
369    /// Creates a new iterator backed by the given cursor.
370    fn new<'t>(cursor: *mut ffi::MDB_cursor, op: c_uint) -> IterDup<'t> {
371        IterDup::Ok {
372            cursor,
373            op,
374            _marker: PhantomData,
375        }
376    }
377}
378
379impl<'txn> fmt::Debug for IterDup<'txn> {
380    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
381        f.debug_struct("IterDup").finish()
382    }
383}
384
385impl<'txn> Iterator for IterDup<'txn> {
386    type Item = Iter<'txn>;
387
388    fn next(&mut self) -> Option<Iter<'txn>> {
389        match self {
390            &mut IterDup::Ok {
391                cursor,
392                ref mut op,
393                _marker,
394            } => {
395                let mut key = ffi::MDB_val {
396                    mv_size: 0,
397                    mv_data: ptr::null_mut(),
398                };
399                let mut data = ffi::MDB_val {
400                    mv_size: 0,
401                    mv_data: ptr::null_mut(),
402                };
403                let op = mem::replace(op, ffi::MDB_NEXT_NODUP);
404                let err_code = unsafe { ffi::mdb_cursor_get(cursor, &mut key, &mut data, op) };
405
406                if err_code == ffi::MDB_SUCCESS {
407                    Some(Iter::new(cursor, ffi::MDB_GET_CURRENT, ffi::MDB_NEXT_DUP))
408                } else {
409                    None
410                }
411            },
412            &mut IterDup::Err(err) => Some(Iter::Err(err)),
413        }
414    }
415}
416
417#[cfg(test)]
418mod test {
419    use tempdir::TempDir;
420
421    use super::*;
422    use environment::*;
423    use ffi::*;
424    use flags::*;
425
426    #[test]
427    fn test_get() {
428        let dir = TempDir::new("test").unwrap();
429        let env = Environment::new().open(dir.path()).unwrap();
430        let db = env.open_db(None).unwrap();
431
432        let mut txn = env.begin_rw_txn().unwrap();
433        txn.put(db, b"key1", b"val1", WriteFlags::empty()).unwrap();
434        txn.put(db, b"key2", b"val2", WriteFlags::empty()).unwrap();
435        txn.put(db, b"key3", b"val3", WriteFlags::empty()).unwrap();
436
437        let cursor = txn.open_ro_cursor(db).unwrap();
438        assert_eq!((Some(&b"key1"[..]), &b"val1"[..]), cursor.get(None, None, MDB_FIRST).unwrap());
439        assert_eq!((Some(&b"key1"[..]), &b"val1"[..]), cursor.get(None, None, MDB_GET_CURRENT).unwrap());
440        assert_eq!((Some(&b"key2"[..]), &b"val2"[..]), cursor.get(None, None, MDB_NEXT).unwrap());
441        assert_eq!((Some(&b"key1"[..]), &b"val1"[..]), cursor.get(None, None, MDB_PREV).unwrap());
442        assert_eq!((Some(&b"key3"[..]), &b"val3"[..]), cursor.get(None, None, MDB_LAST).unwrap());
443        assert_eq!((None, &b"val2"[..]), cursor.get(Some(b"key2"), None, MDB_SET).unwrap());
444        assert_eq!((Some(&b"key3"[..]), &b"val3"[..]), cursor.get(Some(&b"key3"[..]), None, MDB_SET_KEY).unwrap());
445        assert_eq!((Some(&b"key3"[..]), &b"val3"[..]), cursor.get(Some(&b"key2\0"[..]), None, MDB_SET_RANGE).unwrap());
446    }
447
448    #[test]
449    fn test_get_dup() {
450        let dir = TempDir::new("test").unwrap();
451        let env = Environment::new().open(dir.path()).unwrap();
452        let db = env.create_db(None, DatabaseFlags::DUP_SORT).unwrap();
453
454        let mut txn = env.begin_rw_txn().unwrap();
455        txn.put(db, b"key1", b"val1", WriteFlags::empty()).unwrap();
456        txn.put(db, b"key1", b"val2", WriteFlags::empty()).unwrap();
457        txn.put(db, b"key1", b"val3", WriteFlags::empty()).unwrap();
458        txn.put(db, b"key2", b"val1", WriteFlags::empty()).unwrap();
459        txn.put(db, b"key2", b"val2", WriteFlags::empty()).unwrap();
460        txn.put(db, b"key2", b"val3", WriteFlags::empty()).unwrap();
461
462        let cursor = txn.open_ro_cursor(db).unwrap();
463        assert_eq!((Some(&b"key1"[..]), &b"val1"[..]), cursor.get(None, None, MDB_FIRST).unwrap());
464        assert_eq!((None, &b"val1"[..]), cursor.get(None, None, MDB_FIRST_DUP).unwrap());
465        assert_eq!((Some(&b"key1"[..]), &b"val1"[..]), cursor.get(None, None, MDB_GET_CURRENT).unwrap());
466        assert_eq!((Some(&b"key2"[..]), &b"val1"[..]), cursor.get(None, None, MDB_NEXT_NODUP).unwrap());
467        assert_eq!((Some(&b"key2"[..]), &b"val2"[..]), cursor.get(None, None, MDB_NEXT_DUP).unwrap());
468        assert_eq!((Some(&b"key2"[..]), &b"val3"[..]), cursor.get(None, None, MDB_NEXT_DUP).unwrap());
469        assert!(cursor.get(None, None, MDB_NEXT_DUP).is_err());
470        assert_eq!((Some(&b"key2"[..]), &b"val2"[..]), cursor.get(None, None, MDB_PREV_DUP).unwrap());
471        assert_eq!((None, &b"val3"[..]), cursor.get(None, None, MDB_LAST_DUP).unwrap());
472        assert_eq!((Some(&b"key1"[..]), &b"val3"[..]), cursor.get(None, None, MDB_PREV_NODUP).unwrap());
473        assert_eq!((None, &b"val1"[..]), cursor.get(Some(&b"key1"[..]), None, MDB_SET).unwrap());
474        assert_eq!((Some(&b"key2"[..]), &b"val1"[..]), cursor.get(Some(&b"key2"[..]), None, MDB_SET_KEY).unwrap());
475        assert_eq!((Some(&b"key2"[..]), &b"val1"[..]), cursor.get(Some(&b"key1\0"[..]), None, MDB_SET_RANGE).unwrap());
476        assert_eq!((None, &b"val3"[..]), cursor.get(Some(&b"key1"[..]), Some(&b"val3"[..]), MDB_GET_BOTH).unwrap());
477        assert_eq!(
478            (None, &b"val1"[..]),
479            cursor.get(Some(&b"key2"[..]), Some(&b"val"[..]), MDB_GET_BOTH_RANGE).unwrap()
480        );
481    }
482
483    #[test]
484    fn test_get_dupfixed() {
485        let dir = TempDir::new("test").unwrap();
486        let env = Environment::new().open(dir.path()).unwrap();
487        let db = env.create_db(None, DatabaseFlags::DUP_SORT | DatabaseFlags::DUP_FIXED).unwrap();
488
489        let mut txn = env.begin_rw_txn().unwrap();
490        txn.put(db, b"key1", b"val1", WriteFlags::empty()).unwrap();
491        txn.put(db, b"key1", b"val2", WriteFlags::empty()).unwrap();
492        txn.put(db, b"key1", b"val3", WriteFlags::empty()).unwrap();
493        txn.put(db, b"key2", b"val4", WriteFlags::empty()).unwrap();
494        txn.put(db, b"key2", b"val5", WriteFlags::empty()).unwrap();
495        txn.put(db, b"key2", b"val6", WriteFlags::empty()).unwrap();
496
497        let cursor = txn.open_ro_cursor(db).unwrap();
498        assert_eq!((Some(&b"key1"[..]), &b"val1"[..]), cursor.get(None, None, MDB_FIRST).unwrap());
499        assert_eq!((None, &b"val1val2val3"[..]), cursor.get(None, None, MDB_GET_MULTIPLE).unwrap());
500        assert!(cursor.get(None, None, MDB_NEXT_MULTIPLE).is_err());
501    }
502
503    #[test]
504    fn test_iter() {
505        let dir = TempDir::new("test").unwrap();
506        let env = Environment::new().open(dir.path()).unwrap();
507        let db = env.open_db(None).unwrap();
508
509        let items: Vec<(&[u8], &[u8])> =
510            vec![(b"key1", b"val1"), (b"key2", b"val2"), (b"key3", b"val3"), (b"key5", b"val5")];
511
512        {
513            let mut txn = env.begin_rw_txn().unwrap();
514            for &(ref key, ref data) in &items {
515                txn.put(db, key, data, WriteFlags::empty()).unwrap();
516            }
517            txn.commit().unwrap();
518        }
519
520        let txn = env.begin_ro_txn().unwrap();
521        let mut cursor = txn.open_ro_cursor(db).unwrap();
522
523        // Because Result implements FromIterator, we can collect the iterator
524        // of items of type Result<_, E> into a Result<Vec<_, E>> by specifying
525        // the collection type via the turbofish syntax.
526        assert_eq!(items, cursor.iter().collect::<Result<Vec<_>>>().unwrap());
527
528        // Alternately, we can collect it into an appropriately typed variable.
529        let retr: Result<Vec<_>> = cursor.iter_start().collect();
530        assert_eq!(items, retr.unwrap());
531
532        cursor.get(Some(b"key2"), None, MDB_SET).unwrap();
533        assert_eq!(
534            items.clone().into_iter().skip(2).collect::<Vec<_>>(),
535            cursor.iter().collect::<Result<Vec<_>>>().unwrap()
536        );
537
538        assert_eq!(items, cursor.iter_start().collect::<Result<Vec<_>>>().unwrap());
539
540        assert_eq!(
541            items.clone().into_iter().skip(1).collect::<Vec<_>>(),
542            cursor.iter_from(b"key2").collect::<Result<Vec<_>>>().unwrap()
543        );
544
545        assert_eq!(
546            items.clone().into_iter().skip(3).collect::<Vec<_>>(),
547            cursor.iter_from(b"key4").collect::<Result<Vec<_>>>().unwrap()
548        );
549
550        assert_eq!(
551            vec!().into_iter().collect::<Vec<(&[u8], &[u8])>>(),
552            cursor.iter_from(b"key6").collect::<Result<Vec<_>>>().unwrap()
553        );
554    }
555
556    #[test]
557    fn test_iter_empty_database() {
558        let dir = TempDir::new("test").unwrap();
559        let env = Environment::new().open(dir.path()).unwrap();
560        let db = env.open_db(None).unwrap();
561        let txn = env.begin_ro_txn().unwrap();
562        let mut cursor = txn.open_ro_cursor(db).unwrap();
563
564        assert_eq!(0, cursor.iter().count());
565        assert_eq!(0, cursor.iter_start().count());
566        assert_eq!(0, cursor.iter_from(b"foo").count());
567    }
568
569    #[test]
570    fn test_iter_empty_dup_database() {
571        let dir = TempDir::new("test").unwrap();
572        let env = Environment::new().open(dir.path()).unwrap();
573        let db = env.create_db(None, DatabaseFlags::DUP_SORT).unwrap();
574        let txn = env.begin_ro_txn().unwrap();
575        let mut cursor = txn.open_ro_cursor(db).unwrap();
576
577        assert_eq!(0, cursor.iter().count());
578        assert_eq!(0, cursor.iter_start().count());
579        assert_eq!(0, cursor.iter_from(b"foo").count());
580        assert_eq!(0, cursor.iter_dup().count());
581        assert_eq!(0, cursor.iter_dup_start().count());
582        assert_eq!(0, cursor.iter_dup_from(b"foo").count());
583        assert_eq!(0, cursor.iter_dup_of(b"foo").count());
584    }
585
586    #[test]
587    fn test_iter_dup() {
588        let dir = TempDir::new("test").unwrap();
589        let env = Environment::new().open(dir.path()).unwrap();
590        let db = env.create_db(None, DatabaseFlags::DUP_SORT).unwrap();
591
592        let items: Vec<(&[u8], &[u8])> = vec![
593            (b"a", b"1"),
594            (b"a", b"2"),
595            (b"a", b"3"),
596            (b"b", b"1"),
597            (b"b", b"2"),
598            (b"b", b"3"),
599            (b"c", b"1"),
600            (b"c", b"2"),
601            (b"c", b"3"),
602            (b"e", b"1"),
603            (b"e", b"2"),
604            (b"e", b"3"),
605        ];
606
607        {
608            let mut txn = env.begin_rw_txn().unwrap();
609            for &(ref key, ref data) in &items {
610                txn.put(db, key, data, WriteFlags::empty()).unwrap();
611            }
612            txn.commit().unwrap();
613        }
614
615        let txn = env.begin_ro_txn().unwrap();
616        let mut cursor = txn.open_ro_cursor(db).unwrap();
617        assert_eq!(items, cursor.iter_dup().flatten().collect::<Result<Vec<_>>>().unwrap());
618
619        cursor.get(Some(b"b"), None, MDB_SET).unwrap();
620        assert_eq!(
621            items.clone().into_iter().skip(4).collect::<Vec<(&[u8], &[u8])>>(),
622            cursor.iter_dup().flatten().collect::<Result<Vec<_>>>().unwrap()
623        );
624
625        assert_eq!(items, cursor.iter_dup_start().flatten().collect::<Result<Vec<(&[u8], &[u8])>>>().unwrap());
626
627        assert_eq!(
628            items.clone().into_iter().skip(3).collect::<Vec<(&[u8], &[u8])>>(),
629            cursor.iter_dup_from(b"b").flatten().collect::<Result<Vec<_>>>().unwrap()
630        );
631
632        assert_eq!(
633            items.clone().into_iter().skip(3).collect::<Vec<(&[u8], &[u8])>>(),
634            cursor.iter_dup_from(b"ab").flatten().collect::<Result<Vec<_>>>().unwrap()
635        );
636
637        assert_eq!(
638            items.clone().into_iter().skip(9).collect::<Vec<(&[u8], &[u8])>>(),
639            cursor.iter_dup_from(b"d").flatten().collect::<Result<Vec<_>>>().unwrap()
640        );
641
642        assert_eq!(
643            vec!().into_iter().collect::<Vec<(&[u8], &[u8])>>(),
644            cursor.iter_dup_from(b"f").flatten().collect::<Result<Vec<_>>>().unwrap()
645        );
646
647        assert_eq!(
648            items.clone().into_iter().skip(3).take(3).collect::<Vec<(&[u8], &[u8])>>(),
649            cursor.iter_dup_of(b"b").collect::<Result<Vec<_>>>().unwrap()
650        );
651
652        assert_eq!(0, cursor.iter_dup_of(b"foo").count());
653    }
654
655    #[test]
656    fn test_put_del() {
657        let dir = TempDir::new("test").unwrap();
658        let env = Environment::new().open(dir.path()).unwrap();
659        let db = env.open_db(None).unwrap();
660
661        let mut txn = env.begin_rw_txn().unwrap();
662        let mut cursor = txn.open_rw_cursor(db).unwrap();
663
664        cursor.put(b"key1", b"val1", WriteFlags::empty()).unwrap();
665        cursor.put(b"key2", b"val2", WriteFlags::empty()).unwrap();
666        cursor.put(b"key3", b"val3", WriteFlags::empty()).unwrap();
667
668        assert_eq!((Some(&b"key3"[..]), &b"val3"[..]), cursor.get(None, None, MDB_GET_CURRENT).unwrap());
669
670        cursor.del(WriteFlags::empty()).unwrap();
671        assert_eq!((Some(&b"key2"[..]), &b"val2"[..]), cursor.get(None, None, MDB_LAST).unwrap());
672    }
673}