lmdb_zero/cursor.rs
1// Copyright 2016 FullContact, Inc
2// Copyright 2017, 2018 Jason Lingle
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10use std::mem;
11use std::ptr;
12use libc::{self, c_void};
13
14use ffi;
15use supercow::{NonSyncSupercow, Supercow, Phantomcow};
16
17use env::Environment;
18use error::Result;
19use mdb_vals::*;
20use traits::*;
21use dbi::Database;
22use tx::{self, put, del, ConstAccessor, ConstTransaction, WriteAccessor};
23use tx::assert_sensible_cursor;
24
25#[derive(Debug)]
26struct CursorHandle(*mut ffi::MDB_cursor);
27impl Drop for CursorHandle {
28 fn drop(&mut self) {
29 unsafe {
30 ffi::mdb_cursor_close(self.0);
31 }
32 }
33}
34
35/// A cursor into an LMDB database.
36///
37/// Depending on the context, a cursor's lifetime may be scoped to a
38/// transaction or to the whole environment. Its lifetime is also naturally
39/// bound to the lifetime of the database it cursors into.
40///
41/// ## Creation and Ownership
42///
43/// Cursors are normally created by calling `.cursor()` on the transaction that
44/// is to own them. Since a `Cursor` is associated with a `Database`, this also
45/// involves passing a reference or other handle to that `Database` to the
46/// call.
47///
48/// For the `Database`, all three ownership models are permitted, though owned
49/// likely is not useful. The transaction can be used with borrowed or shared
50/// ownership, but note that shared ownership requires having the
51/// `CreateCursor` trait imported.
52///
53/// ### Example — Traditional "keep everything on the stack" style
54///
55/// This is the simplest way to use `Cursor`, but not always the easiest. Most
56/// examples in the documentation use this method. Here, the `Cursor` holds
57/// references to the transaction and the database. This makes it somewhat
58/// inflexible; for example, you cannot make a structure which owns both the
59/// transaction and some set of cursors.
60///
61/// ```
62/// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
63/// # fn main() {
64/// # let env = create_env();
65/// # let db = defdb(&env);
66/// # let txn = lmdb::WriteTransaction::new(&env).unwrap();
67/// # run(&txn, &mut txn.access(), &db);
68/// # }
69/// // N.B. Unneeded type and lifetime annotations here for clarity.
70/// fn run<'db, 'txn>(txn: &'txn lmdb::WriteTransaction,
71/// access: &'txn mut lmdb::WriteAccessor,
72/// db: &'db lmdb::Database) {
73/// let mut cursor: lmdb::Cursor<'txn, 'db> = txn.cursor(db).unwrap();
74/// // Do stuff with cursor.
75/// # ::std::mem::drop(cursor);
76/// }
77/// ```
78///
79/// ### Example — Use reference counting for more flexibility
80///
81/// ```
82/// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
83/// use std::sync::Arc;
84///
85/// // We need to import the `CreateCursor` trait to be able to use shared
86/// // mode cursors. `TxExt` also gets us `to_const()` used below.
87/// use lmdb::traits::{CreateCursor, TxExt};
88///
89/// // This approach lets us make this `Context` struct wherein we can pass
90/// // around everything our functions might need in one piece as well as
91/// // having more flexible transaction lifetimes.
92/// struct Context {
93/// txn: Arc<lmdb::ConstTransaction<'static>>,
94/// cursor: Arc<lmdb::Cursor<'static,'static>>,
95/// }
96///
97/// // N.B. Unneeded type and lifetime annotations here for clarity.
98///
99/// # fn main() {
100/// // Everything at higher levels also needs to have `'static` lifetimes.
101/// // Here, we just stuff everything into `Arc`s for simplicity.
102/// let env: Arc<lmdb::Environment> = Arc::new(create_env());
103/// let db: Arc<lmdb::Database<'static>> = Arc::new(lmdb::Database::open(
104/// env.clone(), None, &lmdb::DatabaseOptions::defaults()).unwrap());
105///
106/// // Now we can make our transaction and cursor and pass them around as one.
107/// // Note that you can also use plain `Rc` at this level, too.
108/// let txn: Arc<lmdb::WriteTransaction<'static>> =
109/// Arc::new(lmdb::WriteTransaction::new(env.clone()).unwrap());
110/// let cursor: Arc<lmdb::Cursor<'static, 'static>> = Arc::new(
111/// txn.cursor(db.clone()).unwrap());
112/// let context = Context { txn: txn.clone().to_const(), cursor: cursor };
113/// do_stuff(&context);
114///
115/// // Drop the context so we can get the `WriteTransaction` back
116/// // and commit it.
117/// drop(context);
118/// let txn = Arc::try_unwrap(txn).unwrap();
119/// txn.commit().unwrap();
120/// # }
121///
122/// #[allow(unused_vars)]
123/// fn do_stuff(context: &Context) {
124/// // do stuff
125/// }
126/// ```
127///
128/// ## Lifetime
129///
130/// A cursor must be strictly outlived by both the transaction that created it
131/// and by the database into which it indexes. The two lifetimes are needed to
132/// permit a cursor to be disassociated from its transaction and rebound to a
133/// later transaction.
134///
135/// `Cursor` is covariant on both of its lifetimes. If you have an owned
136/// `Cursor` as a structure member and don't plan on using the `dissoc_cursor`
137/// API, you can use one lifetime parameter to fill both without issue.
138///
139/// ```rust,norun
140/// # #![allow(dead_code)]
141/// # extern crate lmdb_zero as lmdb;
142/// # fn main() { }
143/// #
144/// struct CursorOwner<'a> {
145/// cursor: lmdb::Cursor<'a, 'a>,
146/// }
147/// fn covariance<'a, 'txn: 'a, 'db: 'a>(c: lmdb::Cursor<'txn,'db>)
148/// -> CursorOwner<'a> {
149/// let c: lmdb::Cursor<'a, 'a> = c;
150/// CursorOwner { cursor: c }
151/// }
152/// ```
153///
154/// Note that an `&mut Cursor<'txn,'db>` is naturally _invariant_ on both
155/// lifetimes. This means that structures containing `&mut Cursor` or functions
156/// taking them as references should generally include both.
157///
158/// ```rust,norun
159/// # #![allow(dead_code)]
160/// # extern crate lmdb_zero as lmdb;
161/// # fn main() { }
162/// #
163/// // Write this
164/// fn do_stuff_with_cursor<'txn, 'db>(c: &mut lmdb::Cursor<'txn,'db>) {
165/// // Stuff
166/// }
167/// // Not this
168/// fn do_stuff_with_cursor_2<'a>(c: &mut lmdb::Cursor<'a,'a>) {
169/// // Stuff
170/// }
171/// ```
172///
173/// Attempting to unify the lifetimes on a `&mut Cursor` will often work, but
174/// can also cause the compiler to infer lifetimes in unfavourable ways.
175#[derive(Debug)]
176pub struct Cursor<'txn,'db> {
177 cursor: CursorHandle,
178 txn: NonSyncSupercow<'txn, ConstTransaction<'txn>>,
179 _db: Phantomcow<'db, Database<'db>>,
180}
181
182// Used by transactions to construct/query cursors
183pub unsafe fn create_cursor<'txn, 'db>(
184 raw: *mut ffi::MDB_cursor,
185 txn: NonSyncSupercow<'txn, ConstTransaction<'txn>>,
186 db: Phantomcow<'db, Database<'db>>)
187 -> Cursor<'txn, 'db>
188{
189 Cursor {
190 cursor: CursorHandle(raw),
191 txn: txn,
192 _db: db,
193 }
194}
195pub fn txn_ref<'a,'txn: 'a,'db>(cursor: &'a Cursor<'txn,'db>)
196 -> &'a ConstTransaction<'txn> {
197 &*cursor.txn
198}
199
200/// A read-only cursor which has been dissociated from its original
201/// transaction, so that it can be rebound later.
202///
203/// A `StaleCursor` remains bound to the original database.
204#[derive(Debug)]
205pub struct StaleCursor<'db> {
206 cursor: CursorHandle,
207 env: NonSyncSupercow<'db, Environment>,
208 _db: Phantomcow<'db, Database<'db>>,
209}
210
211// Internal
212pub fn to_stale<'a,'db>(cursor: Cursor<'a,'db>,
213 env: NonSyncSupercow<'db, Environment>)
214 -> StaleCursor<'db> {
215 StaleCursor {
216 cursor: cursor.cursor,
217 env: env,
218 _db: cursor._db,
219 }
220}
221pub fn env_ref<'a,'db>(cursor: &'a StaleCursor<'db>)
222 -> &'a Environment {
223 &*cursor.env
224}
225pub fn stale_cursor_ptr<'db>(cursor: &StaleCursor<'db>)
226 -> *mut ffi::MDB_cursor {
227 cursor.cursor.0
228}
229
230macro_rules! cursor_get_0_kv {
231 ($(#[$doc:meta])* fn $method:ident, $op:path) => {
232 $(#[$doc])*
233 #[inline]
234 pub fn $method<'access, K : FromLmdbBytes + ?Sized,
235 V : FromLmdbBytes + ?Sized>
236 (&mut self, access: &'access ConstAccessor)
237 -> Result<(&'access K, &'access V)>
238 {
239 self.get_0_kv(access, $op)
240 }
241 }
242}
243
244macro_rules! cursor_get_0_v {
245 ($(#[$doc:meta])* fn $method:ident, $op:path) => {
246 $(#[$doc])*
247 #[inline]
248 pub fn $method<'access, V : FromLmdbBytes + ?Sized>
249 (&mut self, access: &'access ConstAccessor)
250 -> Result<(&'access V)>
251 {
252 self.get_0_v(access, $op)
253 }
254 }
255}
256
257impl<'txn,'db> Cursor<'txn,'db> {
258 /// Directly construct a cursor with the given transaction and database
259 /// handles.
260 ///
261 /// This is a low-level function intended only for use by implementations
262 /// of the `CreateCursor` trait. (There is nothing less safe about it being
263 /// low-level; it's simply inconvenient.)
264 pub fn construct(
265 txn: NonSyncSupercow<'txn, ConstTransaction<'txn>>,
266 db: Supercow<'db, Database<'db>>)
267 -> Result<Self>
268 {
269 try!(tx::assert_same_env(&txn, &db));
270
271 let mut raw: *mut ffi::MDB_cursor = ptr::null_mut();
272 unsafe {
273 lmdb_call!(ffi::mdb_cursor_open(tx::txptr(&txn), db.as_raw(),
274 &mut raw));
275 }
276
277 Ok(unsafe { create_cursor(raw, txn,
278 Supercow::phantom(db)) })
279 }
280
281 /// Directly renew a `StaleCursor` into a functional `Cursor` using the
282 /// given database handle.
283 ///
284 /// This is a low-level function intended only for use by implementations
285 /// of the `AssocCursor` trait. (There is nothing less safe about it being
286 /// low-level; it's simply inconvenient.)
287 ///
288 /// It is an error if `txn` is not actually a `ReadTransaction`.
289 pub fn from_stale(
290 stale: StaleCursor<'db>,
291 txn: NonSyncSupercow<'txn, ConstTransaction<'txn>>)
292 -> Result<Self>
293 {
294 try!(tx::assert_in_env(&txn, env_ref(&stale)));
295
296 unsafe {
297 lmdb_call!(ffi::mdb_cursor_renew(
298 tx::txptr(&txn), stale_cursor_ptr(&stale)));
299 }
300
301 Ok(Cursor {
302 cursor: stale.cursor,
303 txn: txn,
304 _db: stale._db,
305 })
306 }
307
308 #[inline]
309 fn get_0_kv<'access, K : FromLmdbBytes + ?Sized,
310 V : FromLmdbBytes + ?Sized>
311 (&mut self, access: &'access ConstAccessor,
312 op: ffi::MDB_cursor_op) -> Result<(&'access K, &'access V)>
313 {
314 try!(assert_sensible_cursor(access, self));
315
316 let mut out_key = EMPTY_VAL;
317 let mut out_val = EMPTY_VAL;
318 unsafe {
319 lmdb_call!(ffi::mdb_cursor_get(
320 self.cursor.0, &mut out_key, &mut out_val, op));
321 }
322
323 Ok((try!(from_val(access, &out_key)),
324 try!(from_val(access, &out_val))))
325 }
326
327 #[inline]
328 fn get_0_v<'access, V : FromLmdbBytes + ?Sized>
329 (&mut self, access: &'access ConstAccessor,
330 op: ffi::MDB_cursor_op) -> Result<&'access V>
331 {
332 try!(assert_sensible_cursor(access, self));
333
334 let mut null_key = EMPTY_VAL;
335 let mut out_val = EMPTY_VAL;
336 unsafe {
337 lmdb_call!(ffi::mdb_cursor_get(
338 self.cursor.0, &mut null_key, &mut out_val, op));
339 }
340
341 from_val(access, &out_val)
342 }
343
344 #[inline]
345 fn get_kv_0<K: AsLmdbBytes + ?Sized, V : AsLmdbBytes + ?Sized>
346 (&mut self, key: &K, val: &V, op: ffi::MDB_cursor_op) -> Result<()>
347 {
348 let mut mv_key = as_val(key);
349 let mut mv_val = as_val(val);
350 unsafe {
351 lmdb_call!(ffi::mdb_cursor_get(
352 self.cursor.0, &mut mv_key, &mut mv_val, op));
353 }
354
355 Ok(())
356 }
357
358 #[inline]
359 fn get_kv_v<'access, K : AsLmdbBytes + ?Sized,
360 V : AsLmdbBytes + FromLmdbBytes + ?Sized>
361 (&mut self, access: &'access ConstAccessor,
362 key: &K, val: &V, op: ffi::MDB_cursor_op) -> Result<&'access V>
363 {
364 try!(assert_sensible_cursor(access, self));
365
366 let mut mv_key = as_val(key);
367 let mut inout_val = as_val(val);
368
369 unsafe {
370 lmdb_call!(ffi::mdb_cursor_get(
371 self.cursor.0, &mut mv_key, &mut inout_val, op));
372 }
373
374 from_val(access, &inout_val)
375 }
376
377 #[inline]
378 fn get_k_v<'access, K : AsLmdbBytes + ?Sized,
379 V : FromLmdbBytes + ?Sized>
380 (&mut self, access: &'access ConstAccessor,
381 key: &K, op: ffi::MDB_cursor_op) -> Result<&'access V>
382 {
383 try!(assert_sensible_cursor(access, self));
384
385 let mut mv_key = as_val(key);
386 let mut out_val = EMPTY_VAL;
387
388 unsafe {
389 lmdb_call!(ffi::mdb_cursor_get(
390 self.cursor.0, &mut mv_key, &mut out_val, op));
391 }
392
393 from_val(access, &out_val)
394 }
395
396 #[inline]
397 fn get_k_kv<'access, K : AsLmdbBytes + FromLmdbBytes + ?Sized,
398 V : FromLmdbBytes + ?Sized>
399 (&mut self, access: &'access ConstAccessor,
400 key: &K, op: ffi::MDB_cursor_op) -> Result<(&'access K, &'access V)>
401 {
402 try!(assert_sensible_cursor(access, self));
403
404 let mut inout_key = as_val(key);
405 let mut out_val = EMPTY_VAL;
406
407 unsafe {
408 lmdb_call!(ffi::mdb_cursor_get(
409 self.cursor.0, &mut inout_key, &mut out_val, op));
410 }
411
412 Ok((try!(from_val(access, &inout_key)),
413 try!(from_val(access, &out_val))))
414 }
415
416 cursor_get_0_kv! {
417 /// Positions the cursor at the first key/value pair in the database
418 /// and returns that pair.
419 ///
420 /// This corresponds to the `mdb_cursor_get` function with the
421 /// `MDB_FIRST` operation.
422 ///
423 /// ## Example
424 ///
425 /// ```
426 /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
427 /// # fn main() {
428 /// # let env = create_env();
429 /// # let db = dupdb(&env);
430 /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
431 /// {
432 /// let mut access = txn.access();
433 /// let f = lmdb::put::Flags::empty();
434 /// access.put(&db, "Germany", "Berlin", f).unwrap();
435 /// access.put(&db, "France", "Paris", f).unwrap();
436 /// access.put(&db, "Latvia", "Rīga", f).unwrap();
437 ///
438 /// let mut cursor = txn.cursor(&db).unwrap();
439 /// assert_eq!(("France", "Paris"), cursor.first(&access).unwrap());
440 /// }
441 /// txn.commit().unwrap();
442 /// # }
443 /// ```
444 fn first, ffi::MDB_cursor_op::MDB_FIRST
445 }
446
447 cursor_get_0_v! {
448 /// Positions the cursor at the first key/value pair whose key is equal
449 /// to the current key, returning the value of that pair.
450 ///
451 /// This only makes sense on `DUPSORT` databases.
452 ///
453 /// This correspnods to the `mdb_cursor_get` function with the
454 /// `MDB_FIRST_DUP` operation.
455 ///
456 /// ## Example
457 ///
458 /// ```
459 /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
460 /// # fn main() {
461 /// # let env = create_env();
462 /// # let db = dupdb(&env);
463 /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
464 /// {
465 /// let mut access = txn.access();
466 /// let f = lmdb::put::Flags::empty();
467 /// access.put(&db, "Fruit", "Apple", f).unwrap();
468 /// access.put(&db, "Fruit", "Orange", f).unwrap();
469 /// access.put(&db, "Fruit", "Durian", f).unwrap();
470 /// access.put(&db, "Animal", "Badger", f).unwrap();
471 ///
472 /// let mut cursor = txn.cursor(&db).unwrap();
473 /// assert_eq!(("Fruit", "Orange"), cursor.last(&access).unwrap());
474 /// assert_eq!("Apple", cursor.first_dup::<str>(&access).unwrap());
475 /// }
476 /// txn.commit().unwrap();
477 /// # }
478 /// ```
479 fn first_dup, ffi::MDB_cursor_op::MDB_FIRST_DUP
480 }
481
482 /// Positions the cursor at the given (key,value) pair.
483 ///
484 /// This only makes sense on `DUPSORT` databases.
485 ///
486 /// This corresponds to the `mdb_cursor_get` function with the
487 /// `MDB_GET_BOTH` operation.
488 ///
489 /// ## Example
490 ///
491 /// ```
492 /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
493 /// # fn main() {
494 /// # let env = create_env();
495 /// # let db = dupdb(&env);
496 /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
497 /// {
498 /// let mut access = txn.access();
499 /// let f = lmdb::put::Flags::empty();
500 /// access.put(&db, "Fruit", "Apple", f).unwrap();
501 /// access.put(&db, "Fruit", "Orange", f).unwrap();
502 /// access.put(&db, "Fruit", "Durian", f).unwrap();
503 /// access.put(&db, "Animal", "Badger", f).unwrap();
504 ///
505 /// let mut cursor = txn.cursor(&db).unwrap();
506 /// cursor.seek_kv("Fruit", "Durian").unwrap();
507 /// assert_eq!(("Fruit", "Orange"), cursor.next(&access).unwrap());
508 /// assert!(cursor.seek_kv("Fruit", "Lychee").is_err());
509 /// }
510 /// txn.commit().unwrap();
511 /// # }
512 /// ```
513 #[inline]
514 pub fn seek_kv<K : AsLmdbBytes + ?Sized, V : AsLmdbBytes + ?Sized>
515 (&mut self, key: &K, val: &V) -> Result<()>
516 {
517 self.get_kv_0(key, val, ffi::MDB_cursor_op::MDB_GET_BOTH)
518 }
519
520 /// Positions the cursor at the given key and the "nearest" value to `val`,
521 /// that is, the first (according to sorting) item whose key equals `key`
522 /// and whose value is greater than or equal to `val`.
523 ///
524 /// The actual value found is returned.
525 ///
526 /// This only makes sense on `DUPSORT` databases.
527 ///
528 /// This corresponds to the `mdb_cursor_get` function with the
529 /// `MDB_GET_BOTH_RANGE` operation.
530 ///
531 /// ## Example
532 ///
533 /// ```
534 /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
535 /// # fn main() {
536 /// # let env = create_env();
537 /// # let db = dupdb(&env);
538 /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
539 /// {
540 /// let mut access = txn.access();
541 /// let f = lmdb::put::Flags::empty();
542 /// access.put(&db, "Animal", "Badger", f).unwrap();
543 /// access.put(&db, "Fruit", "Banana", f).unwrap();
544 /// access.put(&db, "Fruit", "Orange", f).unwrap();
545 /// access.put(&db, "Fruit", "Durian", f).unwrap();
546 /// access.put(&db, "Veggie", "Carrot", f).unwrap();
547 ///
548 /// let mut cursor = txn.cursor(&db).unwrap();
549 /// assert_eq!("Durian", cursor.seek_k_nearest_v::<str,str>(
550 /// &access, "Fruit", "Durian").unwrap());
551 /// assert_eq!("Orange", cursor.seek_k_nearest_v::<str,str>(
552 /// &access, "Fruit", "Lychee").unwrap());
553 /// assert!(cursor.seek_k_nearest_v::<str,str>(
554 /// &access, "Fruit", "Watermelon").is_err());
555 /// assert_eq!("Banana", cursor.seek_k_nearest_v::<str,str>(
556 /// &access, "Fruit", "Apple").unwrap());
557 /// assert!(cursor.seek_k_nearest_v::<str,str>(
558 /// &access, "Plant", "Tree").is_err());
559 /// }
560 /// txn.commit().unwrap();
561 /// # }
562 /// ```
563 #[inline]
564 pub fn seek_k_nearest_v<'access, K : AsLmdbBytes + ?Sized,
565 V : AsLmdbBytes + FromLmdbBytes + ?Sized>
566 (&mut self, access: &'access ConstAccessor,
567 key: &K, val: &V) -> Result<&'access V>
568 {
569 self.get_kv_v(access, key, val, ffi::MDB_cursor_op::MDB_GET_BOTH_RANGE)
570 }
571
572 cursor_get_0_kv! {
573 /// Returns the current key/value pair under this cursor.
574 ///
575 /// This corresponds to the `mdb_cursor_get` function with the
576 /// `MDB_CURRENT` operation.
577 ///
578 /// ## Example
579 ///
580 /// ```
581 /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
582 /// # fn main() {
583 /// # let env = create_env();
584 /// # let db = dupdb(&env);
585 /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
586 /// {
587 /// let mut access = txn.access();
588 /// let f = lmdb::put::Flags::empty();
589 /// access.put(&db, "Germany", "Berlin", f).unwrap();
590 /// access.put(&db, "France", "Paris", f).unwrap();
591 /// access.put(&db, "Latvia", "Rīga", f).unwrap();
592 ///
593 /// let mut cursor = txn.cursor(&db).unwrap();
594 /// cursor.seek_k::<str,str>(&access, "Latvia").unwrap();
595 /// assert_eq!(("Latvia", "Rīga"), cursor.get_current(&access).unwrap());
596 /// }
597 /// txn.commit().unwrap();
598 /// # }
599 /// ```
600 fn get_current, ffi::MDB_cursor_op::MDB_GET_CURRENT
601 }
602
603 /// Returns as many items as possible with the current key from the
604 /// current cursor position.
605 ///
606 /// The cursor is advanced so that `next_multiple()` returns the next
607 /// group of items, if any. Note that this does _not_ return the actual
608 /// key (which LMDB itself does not return, contrary to documentation).
609 ///
610 /// The easiest way to use this is for `V` to be a slice of `LmdbRaw`
611 /// types.
612 ///
613 /// This only makes sense on `DUPSORT` databases with `DUPFIXED` set.
614 ///
615 /// This corresponds to the `mdb_cursor_get` function with the
616 /// `MDB_GET_MULTIPLE` operation, except that it does not have a special
617 /// case if exactly one value is bound to the key.
618 ///
619 /// See `lmdb_zero::db::DUPFIXED` for examples of usage.
620 #[inline]
621 pub fn get_multiple<'access, V : FromLmdbBytes + ?Sized>
622 (&mut self, access: &'access ConstAccessor)
623 -> Result<(&'access V)>
624 {
625 try!(assert_sensible_cursor(access, self));
626
627 let mut null_key = EMPTY_VAL;
628 let mut out_val = EMPTY_VAL;
629 unsafe {
630 lmdb_call!(ffi::mdb_cursor_get(
631 self.cursor.0, &mut null_key, &mut out_val,
632 ffi::MDB_cursor_op::MDB_GET_MULTIPLE));
633 }
634
635 if out_val.mv_data.is_null() {
636 // LMDB seemingly intentionally returns SUCCESS but a NULL data
637 // pointer if there's exactly one element.
638 // https://github.com/LMDB/lmdb/blob/0a2622317f189c7062d03d050be6766586a548b2/libraries/liblmdb/mdb.c#L7228
639 // Presumably it has something to do with the fact that single
640 // values are stored differently than dup values, though it's
641 // unclear why it doesn't do what we do here. If we see this
642 // condition, simply fall back to MDB_GET_CURRENT which doesn't
643 // modify the cursor, so the caller's follow-up call to
644 // next_multiple() will still be sound.
645 unsafe {
646 lmdb_call!(ffi::mdb_cursor_get(
647 self.cursor.0, &mut null_key, &mut out_val,
648 ffi::MDB_cursor_op::MDB_GET_CURRENT));
649 }
650 }
651
652 from_val(access, &out_val)
653
654 }
655
656 cursor_get_0_v! {
657 /// Continues fetching items from a cursor positioned by a call to
658 /// `get_multiple()`.
659 ///
660 /// This corresponds to the `mdb_cursor_get` function with the
661 /// `MDB_NEXT_MULTIPLE` operation.
662 ///
663 /// See `lmdb_zero::db::DUPFIXED` for examples of usage.
664 fn next_multiple, ffi::MDB_cursor_op::MDB_NEXT_MULTIPLE
665 }
666
667 cursor_get_0_kv! {
668 /// Positions the cursor at the last key/value pair in the database,
669 /// and returns that pair.
670 ///
671 /// This corresponds to the `mdb_cursor_get` function with the
672 /// `MDB_LAST` operation.
673 ///
674 /// ## Example
675 ///
676 /// ```
677 /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
678 /// # fn main() {
679 /// # let env = create_env();
680 /// # let db = dupdb(&env);
681 /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
682 /// {
683 /// let mut access = txn.access();
684 /// let f = lmdb::put::Flags::empty();
685 /// access.put(&db, "Germany", "Berlin", f).unwrap();
686 /// access.put(&db, "France", "Paris", f).unwrap();
687 /// access.put(&db, "Latvia", "Rīga", f).unwrap();
688 ///
689 /// let mut cursor = txn.cursor(&db).unwrap();
690 /// assert_eq!(("Latvia", "Rīga"), cursor.last(&access).unwrap());
691 /// }
692 /// txn.commit().unwrap();
693 /// # }
694 /// ```
695 fn last, ffi::MDB_cursor_op::MDB_LAST
696 }
697
698 cursor_get_0_v! {
699 /// Positions the cursor at the last key/value pair whose key is equal
700 /// to the current key.
701 ///
702 /// This only makes sense on `DUPSORT` databases.
703 ///
704 /// This correspnods to the `mdb_cursor_get` function with the
705 /// `MDB_LAST_DUP` operation.
706 ///
707 /// ## Example
708 ///
709 /// ```
710 /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
711 /// # fn main() {
712 /// # let env = create_env();
713 /// # let db = dupdb(&env);
714 /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
715 /// {
716 /// let mut access = txn.access();
717 /// let f = lmdb::put::Flags::empty();
718 /// access.put(&db, "Fruit", "Apple", f).unwrap();
719 /// access.put(&db, "Fruit", "Orange", f).unwrap();
720 /// access.put(&db, "Fruit", "Durian", f).unwrap();
721 /// access.put(&db, "Animal", "Badger", f).unwrap();
722 /// access.put(&db, "Veggie", "Carrot", f).unwrap();
723 ///
724 /// let mut cursor = txn.cursor(&db).unwrap();
725 /// assert_eq!("Apple", cursor.seek_k::<str,str>(&access, "Fruit").unwrap());
726 /// assert_eq!("Orange", cursor.last_dup::<str>(&access).unwrap());
727 /// }
728 /// txn.commit().unwrap();
729 /// # }
730 /// ```
731 fn last_dup, ffi::MDB_cursor_op::MDB_LAST_DUP
732 }
733
734 cursor_get_0_kv! {
735 /// Advances the cursor to the key/value pair following this one.
736 ///
737 /// If the current key has multiple values, this will remain on the
738 /// same key unless it is already on the last value.
739 ///
740 /// This corresponds to the `mdb_cursor_get` function with the
741 /// `MDB_NEXT` operation.
742 ///
743 /// ## Example
744 ///
745 /// ```
746 /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
747 /// # fn main() {
748 /// # let env = create_env();
749 /// # let db = dupdb(&env);
750 /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
751 /// {
752 /// let mut access = txn.access();
753 /// let f = lmdb::put::Flags::empty();
754 /// access.put(&db, "Fruit", "Apple", f).unwrap();
755 /// access.put(&db, "Fruit", "Orange", f).unwrap();
756 /// access.put(&db, "Animal", "Badger", f).unwrap();
757 /// access.put(&db, "Veggie", "Carrot", f).unwrap();
758 ///
759 /// let mut cursor = txn.cursor(&db).unwrap();
760 /// assert_eq!(("Animal", "Badger"), cursor.first(&access).unwrap());
761 /// assert_eq!(("Fruit", "Apple"), cursor.next(&access).unwrap());
762 /// assert_eq!(("Fruit", "Orange"), cursor.next(&access).unwrap());
763 /// assert_eq!(("Veggie", "Carrot"), cursor.next(&access).unwrap());
764 /// assert!(cursor.next::<str,str>(&access).is_err());
765 /// }
766 /// txn.commit().unwrap();
767 /// # }
768 /// ```
769 fn next, ffi::MDB_cursor_op::MDB_NEXT
770 }
771
772 cursor_get_0_kv! {
773 /// Advances the cursor to the next value in the current key.
774 ///
775 /// This only makes sense on `DUPSORT` databases. This call fails if
776 /// there are no more values in the current key.
777 ///
778 /// This corresponds to the `mdb_cursor_get` function with the
779 /// `MDB_NEXT_DUP` operation.
780 ///
781 /// ## Example
782 ///
783 /// ```
784 /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
785 /// # fn main() {
786 /// # let env = create_env();
787 /// # let db = dupdb(&env);
788 /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
789 /// {
790 /// let mut access = txn.access();
791 /// let f = lmdb::put::Flags::empty();
792 /// access.put(&db, "Fruit", "Apple", f).unwrap();
793 /// access.put(&db, "Fruit", "Orange", f).unwrap();
794 /// access.put(&db, "Animal", "Badger", f).unwrap();
795 /// access.put(&db, "Veggie", "Carrot", f).unwrap();
796 ///
797 /// let mut cursor = txn.cursor(&db).unwrap();
798 /// assert_eq!("Apple", cursor.seek_k::<str,str>(&access, "Fruit").unwrap());
799 /// assert_eq!(("Fruit", "Orange"), cursor.next_dup(&access).unwrap());
800 /// assert!(cursor.next_dup::<str,str>(&access).is_err());
801 /// }
802 /// txn.commit().unwrap();
803 /// # }
804 /// ```
805 fn next_dup, ffi::MDB_cursor_op::MDB_NEXT_DUP
806 }
807
808 cursor_get_0_kv! {
809 /// Advances the cursor to the first item of the key following the
810 /// current key.
811 ///
812 /// This is permitted in all databases, but only behaves distinctly
813 /// from `next()` in `DUPSORT` databases.
814 ///
815 /// This corresponds to the `mdb_cursor_get` function with the
816 /// `MDB_NEXT_NODUP` operation.
817 ///
818 /// ## Example
819 ///
820 /// ```
821 /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
822 /// # fn main() {
823 /// # let env = create_env();
824 /// # let db = dupdb(&env);
825 /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
826 /// {
827 /// let mut access = txn.access();
828 /// let f = lmdb::put::Flags::empty();
829 /// access.put(&db, "Fruit", "Apple", f).unwrap();
830 /// access.put(&db, "Fruit", "Orange", f).unwrap();
831 /// access.put(&db, "Animal", "Badger", f).unwrap();
832 /// access.put(&db, "Veggie", "Carrot", f).unwrap();
833 ///
834 /// let mut cursor = txn.cursor(&db).unwrap();
835 /// assert_eq!(("Animal", "Badger"), cursor.first(&access).unwrap());
836 /// assert_eq!(("Fruit", "Apple"), cursor.next_nodup(&access).unwrap());
837 /// assert_eq!(("Veggie", "Carrot"), cursor.next_nodup(&access).unwrap());
838 /// assert!(cursor.next_nodup::<str,str>(&access).is_err());
839 /// }
840 /// txn.commit().unwrap();
841 /// # }
842 /// ```
843 fn next_nodup, ffi::MDB_cursor_op::MDB_NEXT_NODUP
844 }
845
846 cursor_get_0_kv! {
847 /// Retreats the cursor to the previous key/value pair.
848 ///
849 /// If the current key has multiple values, this will remain on the
850 /// same key unless it is already on the first value.
851 ///
852 /// This corresponds to the `mdb_cursor_get` function with the
853 /// `MDB_PREV` operation.
854 ///
855 /// ## Example
856 ///
857 /// ```
858 /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
859 /// # fn main() {
860 /// # let env = create_env();
861 /// # let db = dupdb(&env);
862 /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
863 /// {
864 /// let mut access = txn.access();
865 /// let f = lmdb::put::Flags::empty();
866 /// access.put(&db, "Fruit", "Apple", f).unwrap();
867 /// access.put(&db, "Fruit", "Orange", f).unwrap();
868 /// access.put(&db, "Animal", "Badger", f).unwrap();
869 /// access.put(&db, "Veggie", "Carrot", f).unwrap();
870 ///
871 /// let mut cursor = txn.cursor(&db).unwrap();
872 /// assert_eq!(("Veggie", "Carrot"), cursor.last(&access).unwrap());
873 /// assert_eq!(("Fruit", "Orange"), cursor.prev(&access).unwrap());
874 /// assert_eq!(("Fruit", "Apple"), cursor.prev(&access).unwrap());
875 /// assert_eq!(("Animal", "Badger"), cursor.prev(&access).unwrap());
876 /// assert!(cursor.prev::<str,str>(&access).is_err());
877 /// }
878 /// txn.commit().unwrap();
879 /// # }
880 /// ```
881 fn prev, ffi::MDB_cursor_op::MDB_PREV
882 }
883
884 cursor_get_0_kv! {
885 /// Retreats the cursor to the previous value in the current key.
886 ///
887 /// This only makes sense on `DUPSORT` databases. This call fails if
888 /// there are no prior values in the current key.
889 ///
890 /// This corresponds to the `mdb_cursor_get` function with the
891 /// `MDB_PREV_DUP` operation.
892 ///
893 /// ## Example
894 ///
895 /// ```
896 /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
897 /// # fn main() {
898 /// # let env = create_env();
899 /// # let db = dupdb(&env);
900 /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
901 /// {
902 /// let mut access = txn.access();
903 /// let f = lmdb::put::Flags::empty();
904 /// access.put(&db, "Fruit", "Apple", f).unwrap();
905 /// access.put(&db, "Fruit", "Orange", f).unwrap();
906 /// access.put(&db, "Animal", "Badger", f).unwrap();
907 /// access.put(&db, "Veggie", "Carrot", f).unwrap();
908 ///
909 /// let mut cursor = txn.cursor(&db).unwrap();
910 /// assert_eq!("Apple", cursor.seek_k::<str,str>(&access, "Fruit").unwrap());
911 /// assert_eq!(("Fruit", "Orange"), cursor.next_dup(&access).unwrap());
912 /// assert_eq!(("Fruit", "Apple"), cursor.prev_dup(&access).unwrap());
913 /// assert!(cursor.prev_dup::<str,str>(&access).is_err());
914 /// }
915 /// txn.commit().unwrap();
916 /// # }
917 /// ```
918 fn prev_dup, ffi::MDB_cursor_op::MDB_PREV_DUP
919 }
920
921 cursor_get_0_kv! {
922 /// Retreats the cursor to the final item of the previous key.
923 ///
924 /// This is permitted in all databases, but only behaves distinctly
925 /// from `prev()` in `DUPSORT` databases.
926 ///
927 /// This corresponds to the `mdb_cursor_get` function with the
928 /// `MDB_PREV_NODUP` operation.
929 ///
930 /// ## Example
931 ///
932 /// ```
933 /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
934 /// # fn main() {
935 /// # let env = create_env();
936 /// # let db = dupdb(&env);
937 /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
938 /// {
939 /// let mut access = txn.access();
940 /// let f = lmdb::put::Flags::empty();
941 /// access.put(&db, "Fruit", "Apple", f).unwrap();
942 /// access.put(&db, "Fruit", "Orange", f).unwrap();
943 /// access.put(&db, "Animal", "Badger", f).unwrap();
944 /// access.put(&db, "Veggie", "Carrot", f).unwrap();
945 ///
946 /// let mut cursor = txn.cursor(&db).unwrap();
947 /// assert_eq!(("Veggie", "Carrot"), cursor.last(&access).unwrap());
948 /// assert_eq!(("Fruit", "Orange"), cursor.prev_nodup(&access).unwrap());
949 /// assert_eq!(("Animal", "Badger"), cursor.prev_nodup(&access).unwrap());
950 /// assert!(cursor.prev_nodup::<str,str>(&access).is_err());
951 /// }
952 /// txn.commit().unwrap();
953 /// # }
954 /// ```
955 fn prev_nodup, ffi::MDB_cursor_op::MDB_PREV_NODUP
956 }
957
958 /// Positions the cursor at the first item of the given key.
959 ///
960 /// Returns the value of that item.
961 ///
962 /// This corresponds to the `mdb_cursor_get` function with the `MDB_SET`
963 /// operation.
964 ///
965 /// ## Example
966 ///
967 /// ```
968 /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
969 /// # fn main() {
970 /// # let env = create_env();
971 /// # let db = dupdb(&env);
972 /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
973 /// {
974 /// let mut access = txn.access();
975 /// let f = lmdb::put::Flags::empty();
976 /// access.put(&db, "Fruit", "Apple", f).unwrap();
977 /// access.put(&db, "Fruit", "Orange", f).unwrap();
978 /// access.put(&db, "Animal", "Badger", f).unwrap();
979 /// access.put(&db, "Veggie", "Carrot", f).unwrap();
980 ///
981 /// let mut cursor = txn.cursor(&db).unwrap();
982 /// assert_eq!("Apple", cursor.seek_k::<str,str>(&access, "Fruit").unwrap());
983 /// }
984 /// txn.commit().unwrap();
985 /// # }
986 /// ```
987 #[inline]
988 pub fn seek_k<'access, K : AsLmdbBytes + ?Sized,
989 V : FromLmdbBytes + ?Sized>
990 (&mut self, access: &'access ConstAccessor, key: &K)
991 -> Result<&'access V>
992 {
993 self.get_k_v(access, key, ffi::MDB_cursor_op::MDB_SET)
994 }
995
996 /// Positions the cursor at the first item of the given key.
997 ///
998 /// Returns the key and value of that item.
999 ///
1000 /// This corresponds to the `mdb_cursor_get` function with the
1001 /// `MDB_SET_KEY` operation.
1002 ///
1003 /// ## Example
1004 ///
1005 /// ```
1006 /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
1007 /// # fn main() {
1008 /// # let env = create_env();
1009 /// # let db = dupdb(&env);
1010 /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
1011 /// {
1012 /// let mut access = txn.access();
1013 /// let f = lmdb::put::Flags::empty();
1014 /// access.put(&db, "Fruit", "Apple", f).unwrap();
1015 /// access.put(&db, "Fruit", "Orange", f).unwrap();
1016 /// access.put(&db, "Animal", "Badger", f).unwrap();
1017 /// access.put(&db, "Veggie", "Carrot", f).unwrap();
1018 ///
1019 /// let mut cursor = txn.cursor(&db).unwrap();
1020 /// assert_eq!(("Fruit", "Apple"), cursor.seek_k_both(&access, "Fruit").unwrap());
1021 /// }
1022 /// txn.commit().unwrap();
1023 /// # }
1024 /// ```
1025 #[inline]
1026 pub fn seek_k_both<'access, K : AsLmdbBytes + FromLmdbBytes + ?Sized,
1027 V : FromLmdbBytes + ?Sized>
1028 (&mut self, access: &'access ConstAccessor, key: &K)
1029 -> Result<(&'access K, &'access V)>
1030 {
1031 self.get_k_kv(access, key, ffi::MDB_cursor_op::MDB_SET_KEY)
1032 }
1033
1034 /// Positions the cursor at the first item whose key is greater than or
1035 /// equal to `key`.
1036 ///
1037 /// Return the key and value of that item.
1038 ///
1039 /// This corresponds to the `mdb_cursor_get` function with the
1040 /// `MDB_SET_RANGE` operation.
1041 ///
1042 /// ## Example
1043 ///
1044 /// ```
1045 /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
1046 /// # fn main() {
1047 /// # let env = create_env();
1048 /// # let db = dupdb(&env);
1049 /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
1050 /// {
1051 /// let mut access = txn.access();
1052 /// let f = lmdb::put::Flags::empty();
1053 /// access.put(&db, "Fruit", "Apple", f).unwrap();
1054 /// access.put(&db, "Fruit", "Orange", f).unwrap();
1055 /// access.put(&db, "Animal", "Badger", f).unwrap();
1056 ///
1057 /// let mut cursor = txn.cursor(&db).unwrap();
1058 /// assert_eq!(("Fruit", "Apple"), cursor.seek_range_k(&access, "Fog").unwrap());
1059 /// assert!(cursor.seek_range_k::<str,str>(&access, "Veggie").is_err());
1060 /// }
1061 /// txn.commit().unwrap();
1062 /// # }
1063 /// ```
1064 #[inline]
1065 pub fn seek_range_k<'access, K : AsLmdbBytes + FromLmdbBytes + ?Sized,
1066 V : FromLmdbBytes + ?Sized>
1067 (&mut self, access: &'access ConstAccessor, key: &K)
1068 -> Result<(&'access K, &'access V)>
1069 {
1070 self.get_k_kv(access, key, ffi::MDB_cursor_op::MDB_SET_RANGE)
1071 }
1072
1073 /// Writes a single value through this cursor.
1074 ///
1075 /// By default, any item with the same key (if not `DUPSORT`) or any
1076 /// exactly matching item (if `DUPSORT`) is replaced silently. `flags` can
1077 /// be used to override this.
1078 ///
1079 /// This does not inherently overwrite the current item. See `overwrite()`
1080 /// for that.
1081 ///
1082 /// The cursor is positioned at the new item, or on failure usually near
1083 /// it.
1084 ///
1085 /// ## Example
1086 ///
1087 /// ```
1088 /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
1089 /// # fn main() {
1090 /// # let env = create_env();
1091 /// # let db = dupdb(&env);
1092 /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
1093 /// {
1094 /// let mut access = txn.access();
1095 /// let f = lmdb::put::Flags::empty();
1096 /// let mut cursor = txn.cursor(&db).unwrap();
1097 /// cursor.put(&mut access, "Germany", "Berlin", f).unwrap();
1098 /// assert_eq!(("Germany", "Berlin"), cursor.get_current(&access).unwrap());
1099 /// }
1100 /// txn.commit().unwrap();
1101 /// # }
1102 /// ```
1103 #[inline]
1104 pub fn put<K : AsLmdbBytes + ?Sized, V : AsLmdbBytes + ?Sized>
1105 (&mut self, access: &mut WriteAccessor,
1106 key: &K, val: &V, flags: put::Flags) -> Result<()>
1107 {
1108 try!(assert_sensible_cursor(&*access, self));
1109
1110 let mut mv_key = as_val(key);
1111 let mut mv_val = as_val(val);
1112
1113 unsafe {
1114 lmdb_call!(ffi::mdb_cursor_put(
1115 self.cursor.0, &mut mv_key, &mut mv_val,
1116 flags.bits()));
1117 }
1118
1119 Ok(())
1120 }
1121
1122 /// Overwrites the current item referenced by the cursor.
1123 ///
1124 /// `key` must match the key of the current item. If the database is
1125 /// `DUPSORT`, `val` must still sort into the same position relative to the
1126 /// other items with the same key.
1127 ///
1128 /// This is intended to be used when the new data is the same size as the
1129 /// old. Otherwise it will simply perform a delete of the old record
1130 /// followed by an insert.
1131 ///
1132 /// The cursor is positioned at the new item, or on failure usually near
1133 /// it.
1134 ///
1135 /// ## Example
1136 ///
1137 /// ```
1138 /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
1139 /// # fn main() {
1140 /// # let env = create_env();
1141 /// # let db = defdb(&env);
1142 /// use lmdb::unaligned as u;
1143 ///
1144 /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
1145 /// {
1146 /// let mut access = txn.access();
1147 /// let f = lmdb::put::Flags::empty();
1148 /// let mut cursor = txn.cursor(&db).unwrap();
1149 /// cursor.put(&mut access, "Fourty-two", &42u32, f).unwrap();
1150 /// cursor.overwrite(&mut access, "Fourty-two", &54u32, f).unwrap();
1151 /// assert_eq!(("Fourty-two", u(&54u32)),
1152 /// cursor.get_current(&access).unwrap());
1153 /// }
1154 /// txn.commit().unwrap();
1155 /// # }
1156 /// ```
1157 #[inline]
1158 pub fn overwrite<K : AsLmdbBytes + ?Sized, V : AsLmdbBytes + ?Sized>
1159 (&mut self, access: &mut WriteAccessor,
1160 key: &K, val: &V, flags: put::Flags) -> Result<()>
1161 {
1162 try!(assert_sensible_cursor(&*access, self));
1163
1164 let mut mv_key = as_val(key);
1165 let mut mv_val = as_val(val);
1166
1167 unsafe {
1168 lmdb_call!(ffi::mdb_cursor_put(
1169 self.cursor.0, &mut mv_key, &mut mv_val,
1170 flags.bits() | ffi::MDB_CURRENT));
1171 }
1172
1173 Ok(())
1174 }
1175
1176 /// Reserves space for an entry with the given key and returns a pointer to
1177 /// that entry.
1178 ///
1179 /// The size of the entry is simply the size of `V`.
1180 ///
1181 /// This cannot be used on a `DUPSORT` database.
1182 ///
1183 /// The cursor is positioned at the new item, or on failure usually near
1184 /// it.
1185 ///
1186 /// ## Example
1187 ///
1188 /// ```
1189 /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
1190 /// #[repr(C, packed)]
1191 /// #[derive(Clone,Copy,Debug,PartialEq,Eq)]
1192 /// struct MyStruct {
1193 /// x: i32,
1194 /// y: i32,
1195 /// }
1196 /// unsafe impl lmdb::traits::LmdbRaw for MyStruct { }
1197 ///
1198 /// # fn main() {
1199 /// # let env = create_env();
1200 /// # let db = defdb(&env);
1201 /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
1202 /// {
1203 /// let mut access = txn.access();
1204 /// let f = lmdb::put::Flags::empty();
1205 /// let mut cursor = txn.cursor(&db).unwrap();
1206 /// {
1207 /// let v: &mut MyStruct = cursor.reserve(&mut access, "foo", f).unwrap();
1208 /// // Write directly into the database
1209 /// v.x = 42;
1210 /// v.y = 56;
1211 /// }
1212 ///
1213 /// assert_eq!(("foo", &MyStruct { x: 42, y: 56 }),
1214 /// cursor.get_current(&access).unwrap());
1215 /// }
1216 /// txn.commit().unwrap();
1217 /// # }
1218 /// ```
1219 #[inline]
1220 pub fn reserve<'access, K : AsLmdbBytes + ?Sized,
1221 V : FromReservedLmdbBytes + Sized>
1222 (&mut self, access: &'access mut WriteAccessor,
1223 key: &K, flags: put::Flags) -> Result<&'access mut V>
1224 {
1225 unsafe {
1226 self.reserve_unsized(access, key, mem::size_of::<V>(), flags)
1227 }
1228 }
1229
1230 /// Reserves space for an entry with the given key and returns a pointer to
1231 /// an array of values backing that entry.
1232 ///
1233 /// The size of the entry is simply the size of `V` times the desired
1234 /// number of elements.
1235 ///
1236 /// This cannot be used on a `DUPSORT` database. (Do not confuse with
1237 /// `put_multiple`, which does support `DUPSORT` but is not zero-copy.)
1238 ///
1239 /// The cursor is positioned at the new item, or on failure usually near
1240 /// it.
1241 ///
1242 /// ## Example
1243 ///
1244 /// ```
1245 /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
1246 /// #[repr(C, packed)]
1247 /// #[derive(Clone,Copy,Debug,PartialEq,Eq)]
1248 /// struct MyStruct {
1249 /// x: i32,
1250 /// y: i32,
1251 /// }
1252 /// unsafe impl lmdb::traits::LmdbRaw for MyStruct { }
1253 ///
1254 /// # fn main() {
1255 /// # let env = create_env();
1256 /// # let db = defdb(&env);
1257 /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
1258 /// {
1259 /// let mut access = txn.access();
1260 /// let f = lmdb::put::Flags::empty();
1261 /// let mut cursor = txn.cursor(&db).unwrap();
1262 /// {
1263 /// let v: &mut [u8] = cursor.reserve_array(&mut access, "foo", 4, f).unwrap();
1264 /// // Write directly into the database
1265 /// v[0] = b'b'; v[1] = b'y'; v[2] = b't'; v[3] = b'e';
1266 /// }
1267 ///
1268 /// assert_eq!(("foo", "byte"), cursor.get_current(&access).unwrap());
1269 /// }
1270 /// txn.commit().unwrap();
1271 /// # }
1272 /// ```
1273 #[inline]
1274 pub fn reserve_array<'access, K : AsLmdbBytes + ?Sized,
1275 V : LmdbRaw>
1276 (&mut self, access: &'access mut WriteAccessor,
1277 key: &K, count: usize, flags: put::Flags)
1278 -> Result<&'access mut [V]>
1279 {
1280 unsafe {
1281 self.reserve_unsized(
1282 access, key, count * mem::size_of::<V>(), flags)
1283 }
1284 }
1285
1286 /// Reserves space for an entry with the given key and returns a pointer to
1287 /// that entry.
1288 ///
1289 /// This cannot be used on a `DUPSORT` database.
1290 ///
1291 /// The cursor is positioned at the new item, or on failure usually near
1292 /// it.
1293 ///
1294 /// ## Unsafety
1295 ///
1296 /// The caller must ensure that `size` is a valid size for `V`.
1297 pub unsafe fn reserve_unsized<'access, K : AsLmdbBytes + ?Sized,
1298 V : FromReservedLmdbBytes + ?Sized>
1299 (&mut self, access: &'access mut WriteAccessor,
1300 key: &K, size: usize, flags: put::Flags) -> Result<&'access mut V>
1301 {
1302 try!(assert_sensible_cursor(&*access, self));
1303
1304 let mut mv_key = as_val(key);
1305 let mut out_val = EMPTY_VAL;
1306 out_val.mv_size = size;
1307
1308 lmdb_call!(ffi::mdb_cursor_put(
1309 self.cursor.0, &mut mv_key, &mut out_val,
1310 flags.bits() | ffi::MDB_RESERVE));
1311
1312 Ok(from_reserved(access, &out_val))
1313 }
1314
1315 /// Returns a writable reference to the value belonging to the given key in
1316 /// the database.
1317 ///
1318 /// This has all the caveats of both `overwrite()` and `reserve()`.
1319 ///
1320 /// ## Updating by mutation
1321 ///
1322 /// It is possible to use this call to perform a read-modify-write
1323 /// operation on the data in the database, provided you are certain that
1324 /// the value exists with the exact size of `V`, for example if you just
1325 /// read the value as a `V` using something that requires a particular size
1326 /// (such as `LmdbRaw`).
1327 ///
1328 /// ## Example
1329 ///
1330 /// ```
1331 /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
1332 /// # fn main() {
1333 /// # let env = create_env();
1334 /// # let db = defdb(&env);
1335 /// use lmdb::Unaligned as U;
1336 /// use lmdb::unaligned as u;
1337 ///
1338 /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
1339 /// {
1340 /// let mut access = txn.access();
1341 /// let f = lmdb::put::Flags::empty();
1342 /// let mut cursor = txn.cursor(&db).unwrap();
1343 /// cursor.put(&mut access, "count", &1u32, f).unwrap();
1344 /// {
1345 /// let count: &mut U<u32> = cursor.overwrite_in_place(
1346 /// &mut access, "count", f).unwrap();
1347 /// // Directly edit the value in the database
1348 /// let count2 = count.get() + 1;
1349 /// count.set(count2);
1350 /// }
1351 /// assert_eq!(("count", u(&2u32)), cursor.get_current(&access).unwrap());
1352 /// }
1353 /// txn.commit().unwrap();
1354 /// # }
1355 /// ```
1356 #[inline]
1357 pub fn overwrite_in_place<'access, K : AsLmdbBytes + ?Sized,
1358 V : FromReservedLmdbBytes + Sized>
1359 (&mut self, access: &'access mut WriteAccessor,
1360 key: &K, flags: put::Flags) -> Result<&'access mut V>
1361 {
1362 unsafe {
1363 self.overwrite_in_place_unsized(
1364 access, key, mem::size_of::<V>(), flags)
1365 }
1366 }
1367
1368 /// Returns a writable reference to the array of values belonging to the
1369 /// given key in the database.
1370 ///
1371 /// This has all the caveats of both `overwrite()` and `reserve_array()`.
1372 ///
1373 /// ## Updating by mutation
1374 ///
1375 /// It is possible to use this call to perform a read-modify-write
1376 /// operation on the data in the database, provided you are certain that
1377 /// the value exists with the exact size of `V` times `count`.
1378 ///
1379 /// ## Example
1380 ///
1381 /// ```
1382 /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
1383 /// # fn main() {
1384 /// # let env = create_env();
1385 /// # let db = defdb(&env);
1386 /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
1387 /// {
1388 /// let mut access = txn.access();
1389 /// let f = lmdb::put::Flags::empty();
1390 /// let mut cursor = txn.cursor(&db).unwrap();
1391 /// cursor.put(&mut access, "foo", "bar", f).unwrap();
1392 /// {
1393 /// let data: &mut [u8] = cursor.overwrite_in_place_array(
1394 /// &mut access, "foo", 3, f).unwrap();
1395 /// // Directly edit the value in the database
1396 /// data[2] = b'z';
1397 /// }
1398 /// assert_eq!(("foo", "baz"), cursor.get_current(&access).unwrap());
1399 /// }
1400 /// txn.commit().unwrap();
1401 /// # }
1402 /// ```
1403 #[inline]
1404 pub fn overwrite_in_place_array<'access, K : AsLmdbBytes + ?Sized,
1405 V : LmdbRaw>
1406 (&mut self, access: &'access mut WriteAccessor,
1407 key: &K, count: usize, flags: put::Flags)
1408 -> Result<&'access mut [V]>
1409 {
1410 unsafe {
1411 self.overwrite_in_place_unsized(
1412 access, key, count * mem::size_of::<V>(), flags)
1413 }
1414 }
1415
1416 /// Returns a writable reference to the value belonging to the given key in
1417 /// the database.
1418 ///
1419 /// This has all the caveats of both `overwrite()` and `reserve_unsized()`.
1420 ///
1421 /// ## Unsafety
1422 ///
1423 /// The caller must ensure `size` is a valid size of `V`.
1424 pub unsafe fn overwrite_in_place_unsized
1425 <'access, K : AsLmdbBytes + ?Sized, V : FromReservedLmdbBytes + ?Sized>
1426 (&mut self, access: &'access mut WriteAccessor,
1427 key: &K, size: usize, flags: put::Flags) -> Result<&'access mut V>
1428 {
1429 try!(assert_sensible_cursor(&*access, self));
1430
1431 let mut mv_key = as_val(key);
1432 let mut out_val = EMPTY_VAL;
1433 out_val.mv_size = size;
1434
1435 lmdb_call!(ffi::mdb_cursor_put(
1436 self.cursor.0, &mut mv_key, &mut out_val,
1437 flags.bits() | ffi::MDB_RESERVE | ffi::MDB_CURRENT));
1438
1439 Ok(from_reserved(access, &out_val))
1440 }
1441
1442 /// Stores multiple data elements with the same key in a single request.
1443 ///
1444 /// This is only permitted for `DUPFIXED` databases.
1445 ///
1446 /// Note that `values` must be a slice of `LmdbRaw`, since this function
1447 /// needs to know the exact size of each individual item and must be able
1448 /// to directly reinterpret the slice as a byte array.
1449 ///
1450 /// On success, returns the number of items that were actually written.
1451 ///
1452 /// ## Warning
1453 ///
1454 /// `MDB_MULTIPLE` has historically been rather problematic. Using this
1455 /// function may result in erratic behaviour on many versions of LMDB.
1456 ///
1457 /// ## Example
1458 ///
1459 /// ```
1460 /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
1461 /// # fn main() {
1462 /// # let env = create_env();
1463 /// # let db = dupfixeddb(&env);
1464 /// use lmdb::Unaligned as U;
1465 /// use lmdb::unaligned as u;
1466 ///
1467 /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
1468 /// {
1469 /// let mut access = txn.access();
1470 /// let f = lmdb::put::Flags::empty();
1471 /// let mut cursor = txn.cursor(&db).unwrap();
1472 /// // XXX Whether this is supposed to be 4 or 3 is unclear.
1473 /// assert_eq!(4, cursor.put_multiple(
1474 /// &mut access, "bar", &[U::new(0u32), U::new(1u32),
1475 /// U::new(2u32), U::new(1u32)], f).unwrap());
1476 /// # // XXX I wanted a lot more assertions here, but I kept running into
1477 /// # // issues that I think but am not sure are bugs.
1478 ///
1479 /// assert_eq!(("bar", u(&0u32)), cursor.first(&access).unwrap());
1480 /// assert_eq!(("bar", u(&1u32)), cursor.next(&access).unwrap());
1481 /// assert_eq!(("bar", u(&2u32)), cursor.next(&access).unwrap());
1482 /// assert!(cursor.next::<str,U<u32>>(&access).is_err());
1483 /// }
1484 /// txn.commit().unwrap();
1485 /// # }
1486 /// ```
1487 pub fn put_multiple<K : AsLmdbBytes + ?Sized, V : LmdbRaw>
1488 (&mut self, access: &mut WriteAccessor,
1489 key: &K, values: &[V], flags: put::Flags)
1490 -> Result<usize>
1491 {
1492 try!(assert_sensible_cursor(&*access, self));
1493
1494 // Some LMDB versions didn't (don't?) handle count=0 correctly
1495 if values.is_empty() {
1496 return Ok(0);
1497 }
1498
1499 let mut mv_key = as_val(key);
1500 let mut mv_vals = [ ffi::MDB_val {
1501 mv_size: mem::size_of::<V>() as libc::size_t,
1502 mv_data: values.as_lmdb_bytes().as_ptr() as *mut c_void,
1503 }, ffi::MDB_val {
1504 mv_size: values.len() as libc::size_t,
1505 mv_data: ptr::null_mut(),
1506 }];
1507
1508 unsafe {
1509 lmdb_call!(ffi::mdb_cursor_put(
1510 self.cursor.0, &mut mv_key, mv_vals.as_mut_ptr(),
1511 flags.bits() | ffi::MDB_MULTIPLE));
1512 }
1513
1514 Ok(mv_vals[1].mv_size as usize)
1515 }
1516
1517 /// Delete current key/value pair.
1518 ///
1519 /// By default, this deletes only the current pair. `flags` can be set to
1520 /// `NODUPDATA` for `DUPDATA` databases to delete everything with the
1521 /// current key.
1522 ///
1523 /// See `lmdb_zero::del::NODUPDATA` for examples on how `flags` can be used
1524 /// to control behaviour.
1525 #[inline]
1526 pub fn del(&mut self, access: &mut WriteAccessor,
1527 flags: del::Flags) -> Result<()> {
1528 try!(assert_sensible_cursor(&*access, self));
1529
1530 unsafe {
1531 lmdb_call!(ffi::mdb_cursor_del(self.cursor.0, flags.bits()));
1532 }
1533
1534 Ok(())
1535 }
1536
1537 /// Return count of duplicates for current key.
1538 ///
1539 /// This call is only valid on `DUPSORT` databases.
1540 #[inline]
1541 pub fn count(&mut self) -> Result<usize> {
1542 let mut raw: libc::size_t = 0;
1543 unsafe {
1544 lmdb_call!(ffi::mdb_cursor_count(self.cursor.0, &mut raw));
1545 }
1546 Ok(raw as usize)
1547 }
1548}
1549
1550#[cfg(test)]
1551mod test {
1552 use dbi::{db, Database, DatabaseOptions};
1553 use error::LmdbResultExt;
1554 use tx::{put, WriteTransaction};
1555 use test_helpers::*;
1556 use unaligned::Unaligned as U;
1557 use unaligned::unaligned;
1558
1559 #[test]
1560 fn get_multiple_with_one_item() {
1561 let env = create_env();
1562 let db = Database::open(
1563 &env, None, &DatabaseOptions::new(
1564 db::DUPSORT | db::INTEGERKEY | db::DUPFIXED | db::INTEGERDUP |
1565 db::CREATE)).unwrap();
1566 let txn = WriteTransaction::new(&env).unwrap();
1567 {
1568 let key: i32 = 42;
1569 let val: i32 = 56;
1570
1571 let mut access = txn.access();
1572 access.put(&db, &key, &val, put::Flags::empty()).unwrap();
1573
1574 let mut cursor = txn.cursor(&db).unwrap();
1575 cursor.seek_k::<U<i32>, U<i32>>(&access, unaligned(&key)).unwrap();
1576 let vals = cursor.get_multiple::<[U<i32>]>(&access).unwrap();
1577 assert_eq!(1, vals.len());
1578 assert_eq!(val, vals[0].get());
1579
1580 assert!(cursor.next_multiple::<[U<i32>]>(&access)
1581 .to_opt().unwrap().is_none());
1582 }
1583 }
1584}