1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2009 Oracle.  All rights reserved.
5 *
6 */
7using System;
8using System.Collections;
9using System.Collections.Generic;
10using System.Text;
11using BerkeleyDB.Internal;
12
13namespace BerkeleyDB {
14    /// <summary>
15    /// A class representing database cursors, which allow for traversal of
16    /// database records.
17    /// </summary>
18    public class Cursor
19        : BaseCursor,
20        IDisposable, IEnumerable<KeyValuePair<DatabaseEntry, DatabaseEntry>> {
21        private KeyValuePair<DatabaseEntry, DatabaseEntry> cur;
22        private KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> curMult;
23        private MultipleKeyDatabaseEntry curMultKey;
24        private DatabaseType dbtype;
25
26        /// <summary>
27        /// Protected member, storing the pagesize of the underlying database.
28        /// Used during bulk get (i.e. Move*Multiple).
29        /// </summary>
30        protected uint pgsz;
31
32        /// <summary>
33        /// Specifies where to place duplicate data elements of the key to which
34        /// the cursor refers.
35        /// </summary>
36        public enum InsertLocation {
37            /// <summary>
38            /// The new element appears immediately after the current cursor
39            /// position.
40            /// </summary>
41            AFTER,
42            /// <summary>
43            /// The new element appears immediately before the current cursor
44            /// position.
45            /// </summary>
46            BEFORE,
47            /// <summary>
48            /// The new element appears as the first of the data items for the
49            /// given key
50            /// </summary>
51            FIRST,
52            /// <summary>
53            /// The new element appears as the last of the data items for the
54            /// given key
55            /// </summary>
56            LAST
57        };
58
59        /// <summary>
60        /// The key/data pair at which the cursor currently points.
61        /// </summary>
62        /// <remarks>
63        /// Only one of <see cref="Current"/>, <see cref="CurrentMultiple"/> and
64        /// <see cref="CurrentMultipleKey"/> will ever be non-empty.
65        /// </remarks>
66        public KeyValuePair<DatabaseEntry, DatabaseEntry> Current {
67            private set {
68                cur = value;
69                curMult =
70                    new KeyValuePair<DatabaseEntry, MultipleDatabaseEntry>();
71                curMultKey = null;
72            }
73            get { return cur; }
74        }
75        /// <summary>
76        /// The key and multiple data items at which the cursor currently
77        /// points.
78        /// </summary>
79        /// <remarks>
80        /// Only one of <see cref="Current"/>, <see cref="CurrentMultiple"/> and
81        /// <see cref="CurrentMultipleKey"/> will ever be non-empty.
82        /// </remarks>
83        public
84            KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> CurrentMultiple {
85            private set {
86                cur = new KeyValuePair<DatabaseEntry, DatabaseEntry>();
87                curMult = value;
88                curMultKey = null;
89            }
90            get { return curMult; }
91        }
92        /// <summary>
93        /// The multiple key and data items at which the cursor currently
94        /// points.
95        /// </summary>
96        /// <remarks>
97        /// Only one of <see cref="Current"/>, <see cref="CurrentMultiple"/> and
98        /// <see cref="CurrentMultipleKey"/> will ever be non-empty.
99        /// </remarks>
100        public MultipleKeyDatabaseEntry CurrentMultipleKey {
101            private set {
102                cur = new KeyValuePair<DatabaseEntry, DatabaseEntry>();
103                curMult =
104                    new KeyValuePair<DatabaseEntry, MultipleDatabaseEntry>();
105                curMultKey = value;
106            }
107            get { return curMultKey; }
108        }
109        private CachePriority _priority;
110        /// <summary>
111        /// The cache priority for pages referenced by the cursor.
112        /// </summary>
113        /// <remarks>
114        /// The priority of a page biases the replacement algorithm to be more
115        /// or less likely to discard a page when space is needed in the buffer
116        /// pool. The bias is temporary, and pages will eventually be discarded
117        /// if they are not referenced again. The setting is only advisory, and
118        /// does not guarantee pages will be treated in a specific way.
119        /// </remarks>
120        public CachePriority Priority {
121            get { return _priority; }
122            set {
123                dbc.set_priority(value.priority);
124                _priority = value;
125            }
126        }
127
128        internal Cursor(DBC dbc, DatabaseType DbType, uint pagesize)
129            : base(dbc) {
130            pgsz = pagesize;
131            dbtype = DbType;
132        }
133        internal Cursor(
134            DBC dbc, DatabaseType DbType, uint pagesize, CachePriority pri)
135            : base(dbc) {
136            Priority = pri;
137            pgsz = pagesize;
138            dbtype = DbType;
139        }
140
141        #region Internal API
142        /* These protected methods do the heavy lifting.  The API methods for
143         * Cursor and its subclasses call into them, which allows the API
144         * methods to expose subsets of the arg lists, because some args are
145         * optional. */
146
147        /* Only BTree and Hash can call this version of Add(). */
148        /// <summary>
149        /// Protected method for BTree and Hash to insert with KEYFIRST and
150        /// KEYLAST.
151        /// </summary>
152        /// <param name="pair">The key/data pair to add</param>
153        /// <param name="loc">Where to add, if adding duplicate data</param>
154        protected void Add(KeyValuePair<DatabaseEntry, DatabaseEntry> pair, InsertLocation loc) {
155            if (loc == InsertLocation.AFTER)
156                throw new ArgumentException("AFTER may only be specified on Insert().");
157            if (loc == InsertLocation.BEFORE)
158                throw new ArgumentException("BEFORE may only be specified on Insert().");
159            Put(pair.Key, pair.Value, (loc == InsertLocation.FIRST) ? DbConstants.DB_KEYFIRST : DbConstants.DB_KEYLAST);
160        }
161        /* Only BTree and Hash can call AddUnique(). */
162        /// <summary>
163        /// Protected method for BTree and Hash to insert with NODUPDATA.
164        /// </summary>
165        /// <param name="pair">The key/data pair to add</param>
166        protected void AddUnique(KeyValuePair<DatabaseEntry, DatabaseEntry> pair) {
167            Put(pair.Key, pair.Value, DbConstants.DB_NODUPDATA);
168        }
169        /* Only BTree, Hash and Recno can call Insert(). */
170        /// <summary>
171        /// Protected method for BTree, Hash and Recno to insert with AFTER and
172        /// BEFORE.
173        /// </summary>
174        /// <param name="data">The duplicate data item to add</param>
175        /// <param name="loc">
176        /// Whether to add the dup data before or after the current cursor
177        /// position
178        /// </param>
179        protected void Insert(DatabaseEntry data, InsertLocation loc) {
180            if (loc == InsertLocation.FIRST)
181                throw new ArgumentException("FIRST may only be specified on Add().");
182            if (loc == InsertLocation.LAST)
183                throw new ArgumentException("LAST may only be specified on Add().");
184            DatabaseEntry key = new DatabaseEntry();
185            Put(key, data, (loc == InsertLocation.AFTER) ? DbConstants.DB_AFTER : DbConstants.DB_BEFORE);
186        }
187
188        /*
189         * All flavors of get and put boil down to a call to one of these two
190         * methods, just with different flags.
191         */
192        /// <summary>
193        /// Protected method wrapping DBC->get.
194        /// </summary>
195        /// <param name="key">The key to retrieve</param>
196        /// <param name="data">The data to retrieve</param>
197        /// <param name="flags">Modify the behavior of get</param>
198        /// <param name="info">The locking configuration to use</param>
199        /// <returns>
200        /// True if the cursor was positioned successfully, false otherwise.
201        /// </returns>
202        protected bool Get(DatabaseEntry key, DatabaseEntry data, uint flags, LockingInfo info) {
203            flags |= (info == null) ? 0 : info.flags;
204
205            try {
206                dbc.get(key, data, flags);
207                Current = new KeyValuePair<DatabaseEntry, DatabaseEntry>(key, data);
208                return true;
209            } catch (NotFoundException) {
210                Current = new KeyValuePair<DatabaseEntry, DatabaseEntry>();
211                return false;
212            }
213        }
214        /// <summary>
215        /// Protected method wrapping DBC->get for bulk get.
216        /// </summary>
217        /// <param name="key">The key to retrieve</param>
218        /// <param name="data">The data to retrieve</param>
219        /// <param name="BufferSize">Size of the bulk buffer</param>
220        /// <param name="flags">Modify the behavior of get</param>
221        /// <param name="info">The locking configuration to use</param>
222        /// <param name="isMultKey">
223        /// If true, use DB_MULTIPLE_KEY instead of DB_MULTIPLE
224        /// </param>
225        /// <returns>
226        /// True if the cursor was positioned successfully, false otherwise.
227        /// </returns>
228        protected bool GetMultiple(DatabaseEntry key, DatabaseEntry data,
229            int BufferSize, uint flags, LockingInfo info, bool isMultKey) {
230            int datasz = 0;
231            bool getboth = false;
232
233            if (flags == DbConstants.DB_GET_BOTH ||
234                flags == DbConstants.DB_GET_BOTH_RANGE) {
235                datasz = (int)data.Data.Length;
236                getboth = true;
237            }
238            flags |= (info == null) ? 0 : info.flags;
239            flags |= (isMultKey) ?
240                DbConstants.DB_MULTIPLE_KEY : DbConstants.DB_MULTIPLE;
241
242            for (; ; ) {
243                if (getboth) {
244                    byte[] udata = new byte[BufferSize];
245                    Array.Copy(data.Data, udata, datasz);
246                    data.UserData = udata;
247                    data.size = (uint)datasz;
248                } else {
249                    data.UserData = new byte[BufferSize];
250                }
251
252                try {
253                    dbc.get(key, data, flags);
254                    if (isMultKey)
255                        CurrentMultipleKey =
256                            new MultipleKeyDatabaseEntry(dbtype, data);
257                    else {
258                        MultipleDatabaseEntry mult =
259                            new MultipleDatabaseEntry(data);
260                        CurrentMultiple = new
261                            KeyValuePair<DatabaseEntry, MultipleDatabaseEntry>(
262                            key, mult);
263                    }
264                    return true;
265                } catch (NotFoundException) {
266                    if (isMultKey)
267                        CurrentMultipleKey = null;
268                    else
269                        CurrentMultiple = new
270                           KeyValuePair<DatabaseEntry, MultipleDatabaseEntry>();
271                    return false;
272                } catch (MemoryException) {
273                    int sz = (int)data.size;
274                    if (sz > BufferSize)
275                        BufferSize = sz;
276                    else
277                        BufferSize *= 2;
278                }
279            }
280        }
281
282        /// <summary>
283        /// Protected method wrapping DBC->put.
284        /// </summary>
285        /// <param name="key">The key to store</param>
286        /// <param name="data">The data to store</param>
287        /// <param name="flags">Modify the behavior of put</param>
288        protected void Put(DatabaseEntry key, DatabaseEntry data, uint flags) {
289            int ret;
290            ret = dbc.put(key, data, flags);
291        }
292        #endregion Internal API
293
294        /*
295         * User facing API below.  These methods just set the flags as needed
296         * before calling Get or Put.
297         */
298
299        /// <summary>
300        /// Stores the key/data pair in the database.
301        /// </summary>
302        /// <remarks>
303        /// If the underlying database supports duplicate data items, and if the
304        /// key already exists in the database and a duplicate sort function has
305        /// been specified, the inserted data item is added in its sorted
306        /// location. If the key already exists in the database and no duplicate
307        /// sort function has been specified, the inserted data item is added as
308        /// the first of the data items for that key.
309        /// </remarks>
310        /// <param name="pair">
311        /// The key/data pair to be stored in the database.
312        /// </param>
313        public void Add(KeyValuePair<DatabaseEntry, DatabaseEntry> pair) {
314            Put(pair.Key, pair.Value, DbConstants.DB_KEYFIRST);
315        }
316
317        /// <summary>
318        /// Delete the key/data pair to which the cursor refers.
319        /// </summary>
320        /// <remarks>
321        /// <para>
322        /// The cursor position is unchanged after a delete, and subsequent
323        /// calls to cursor functions expecting the cursor to refer to an
324        /// existing key will fail.
325        /// </para>
326        /// </remarks>
327        /// <exception cref="KeyEmptyException">
328        /// The element has already been deleted.
329        /// </exception>
330        public new void Delete() {
331            base.Delete();
332            Current = new KeyValuePair<DatabaseEntry, DatabaseEntry>();
333        }
334
335        /// <summary>
336        /// Create a new cursor that uses the same transaction and locker ID as
337        /// the original cursor.
338        /// </summary>
339        /// <remarks>
340        /// This is useful when an application is using locking and requires two
341        /// or more cursors in the same thread of control.
342        /// </remarks>
343        /// <param name="keepPosition">
344        /// If true, the newly created cursor is initialized to refer to the
345        /// same position in the database as the original cursor (if any) and
346        /// hold the same locks (if any). If false, or the original cursor does
347        /// not hold a database position and locks, the created cursor is
348        /// uninitialized and will behave like a cursor newly created by
349        /// <see cref="BaseDatabase.Cursor"/>.</param>
350        /// <returns>A newly created cursor</returns>
351        public Cursor Duplicate(bool keepPosition) {
352            return new Cursor(dbc.dup(
353                keepPosition ? DbConstants.DB_POSITION : 0), dbtype, pgsz);
354        }
355
356        IEnumerator IEnumerable.GetEnumerator() {
357            return GetEnumerator();
358        }
359
360        /// <summary>
361        /// Returns an enumerator that iterates through the
362        /// <see cref="Cursor"/>.
363        /// </summary>
364        /// <remarks>
365        /// The enumerator will begin at the cursor's current position (or the
366        /// first record if the cursor has not yet been positioned) and iterate
367        /// forwards (i.e. in the direction of <see cref="MoveNext"/>) over the
368        /// remaining records.
369        /// </remarks>
370        /// <returns>An enumerator for the Cursor.</returns>
371        public new IEnumerator<KeyValuePair<DatabaseEntry, DatabaseEntry>>
372            GetEnumerator() {
373            while (MoveNext())
374                yield return Current;
375        }
376
377        /// <summary>
378        /// Set the cursor to refer to the first key/data pair of the database,
379        /// and store that pair in <see cref="Current"/>. If the first key has
380        /// duplicate values, the first data item in the set of duplicates is
381        /// stored in <see cref="Current"/>.
382        /// </summary>
383        /// <remarks>
384        /// If positioning the cursor fails, <see cref="Current"/> will contain
385        /// an empty <see cref="KeyValuePair{T,T}"/>.
386        /// </remarks>
387        /// <returns>
388        /// True if the cursor was positioned successfully, false otherwise.
389        /// </returns>
390        public bool MoveFirst() { return MoveFirst(null); }
391        /// <summary>
392        /// Set the cursor to refer to the first key/data pair of the database,
393        /// and store that pair in <see cref="Current"/>. If the first key has
394        /// duplicate values, the first data item in the set of duplicates is
395        /// stored in <see cref="Current"/>.
396        /// </summary>
397        /// <remarks>
398        /// If positioning the cursor fails, <see cref="Current"/> will contain
399        /// an empty <see cref="KeyValuePair{T,T}"/>.
400        /// </remarks>
401        /// <param name="info">The locking behavior to use.</param>
402        /// <returns>
403        /// True if the cursor was positioned successfully, false otherwise.
404        /// </returns>
405        public bool MoveFirst(LockingInfo info) {
406            DatabaseEntry key = new DatabaseEntry();
407            DatabaseEntry data = new DatabaseEntry();
408
409            return Get(key, data, DbConstants.DB_FIRST, info);
410        }
411
412        /// <summary>
413        /// Set the cursor to refer to the first key/data pair of the database,
414        /// and store that key and as many duplicate data items that can fit in
415        /// a buffer the size of one database page in
416        /// <see cref="CurrentMultiple"/>.
417        /// </summary>
418        /// <overloads>
419        /// If positioning the cursor fails, <see cref="CurrentMultiple"/> will
420        /// contain an empty
421        /// <see cref="KeyValuePair{T,T}"/>.
422        /// </overloads>
423        /// <returns>
424        /// True if the cursor was positioned successfully, false otherwise.
425        /// </returns>
426        public bool MoveFirstMultiple() {
427            return MoveFirstMultiple((int)pgsz, null);
428        }
429        /// <summary>
430        /// Set the cursor to refer to the first key/data pair of the database,
431        /// and store that key and as many duplicate data items that can fit in
432        /// a buffer the size of <paramref name="BufferSize"/> in
433        /// <see cref="CurrentMultiple"/>.
434        /// </summary>
435        /// <param name="BufferSize">
436        /// The size of a buffer to fill with duplicate data items.  Must be at
437        /// least the page size of the underlying database and be a multiple of
438        /// 1024.
439        /// </param>
440        /// <returns>
441        /// True if the cursor was positioned successfully, false otherwise.
442        /// </returns>
443        public bool MoveFirstMultiple(int BufferSize) {
444            return MoveFirstMultiple(BufferSize, null);
445        }
446        /// <summary>
447        /// Set the cursor to refer to the first key/data pair of the database,
448        /// and store that key and as many duplicate data items that can fit in
449        /// a buffer the size of one database page in
450        /// <see cref="CurrentMultiple"/>.
451        /// </summary>
452        /// <param name="info">The locking behavior to use.</param>
453        /// <returns>
454        /// True if the cursor was positioned successfully, false otherwise.
455        /// </returns>
456        public bool MoveFirstMultiple(LockingInfo info) {
457            return MoveFirstMultiple((int)pgsz, info);
458        }
459        /// <summary>
460        /// Set the cursor to refer to the first key/data pair of the database,
461        /// and store that key and as many duplicate data items that can fit in
462        /// a buffer the size of <paramref name="BufferSize"/> in
463        /// <see cref="CurrentMultiple"/>.
464        /// </summary>
465        /// <param name="BufferSize">
466        /// The size of a buffer to fill with duplicate data items.  Must be at
467        /// least the page size of the underlying database and be a multiple of
468        /// 1024.
469        /// </param>
470        /// <param name="info">The locking behavior to use.</param>
471        /// <returns>
472        /// True if the cursor was positioned successfully, false otherwise.
473        /// </returns>
474        public bool MoveFirstMultiple(int BufferSize, LockingInfo info) {
475            DatabaseEntry key = new DatabaseEntry();
476            DatabaseEntry data = new DatabaseEntry();
477
478            return GetMultiple(
479                key, data, BufferSize, DbConstants.DB_FIRST, info, false);
480        }
481
482        /// <summary>
483        /// Set the cursor to refer to the first key/data pair of the database,
484        /// and store that pair and as many ensuing key/data pairs that can fit
485        /// in a buffer the size of one database page in
486        /// <see cref="CurrentMultipleKey"/>.
487        /// </summary>
488        /// <returns>
489        /// True if the cursor was positioned successfully, false otherwise.
490        /// </returns>
491        public bool MoveFirstMultipleKey() {
492            return MoveFirstMultipleKey((int)pgsz, null);
493        }
494        /// <summary>
495        /// Set the cursor to refer to the first key/data pair of the database,
496        /// and store that pair and as many ensuing key/data pairs that can fit
497        /// in a buffer the size of <paramref name="BufferSize"/> in
498        /// <see cref="CurrentMultipleKey"/>.
499        /// </summary>
500        /// <param name="BufferSize">
501        /// The size of a buffer to fill with key/data pairs.  Must be at least
502        /// the page size of the underlying database and be a multiple of 1024.
503        /// </param>
504        /// <returns>
505        /// True if the cursor was positioned successfully, false otherwise.
506        /// </returns>
507        public bool MoveFirstMultipleKey(int BufferSize) {
508            return MoveFirstMultipleKey(BufferSize, null);
509        }
510        /// <summary>
511        /// Set the cursor to refer to the first key/data pair of the database,
512        /// and store that pair and as many ensuing key/data pairs that can fit
513        /// in a buffer the size of one database page in
514        /// <see cref="CurrentMultipleKey"/>.
515        /// </summary>
516        /// <param name="info">The locking behavior to use.</param>
517        /// <returns>
518        /// True if the cursor was positioned successfully, false otherwise.
519        /// </returns>
520        public bool MoveFirstMultipleKey(LockingInfo info) {
521            return MoveFirstMultipleKey((int)pgsz, info);
522        }
523        /// <summary>
524        /// Set the cursor to refer to the first key/data pair of the database,
525        /// and store that pair and as many ensuing key/data pairs that can fit
526        /// in a buffer the size of <paramref name="BufferSize"/> in
527        /// <see cref="CurrentMultipleKey"/>.
528        /// </summary>
529        /// <param name="BufferSize">
530        /// The size of a buffer to fill with key/data pairs.  Must be at least
531        /// the page size of the underlying database and be a multiple of 1024.
532        /// </param>
533        /// <param name="info">The locking behavior to use.</param>
534        /// <returns>
535        /// True if the cursor was positioned successfully, false otherwise.
536        /// </returns>
537        public bool MoveFirstMultipleKey(int BufferSize, LockingInfo info) {
538            DatabaseEntry key = new DatabaseEntry();
539            DatabaseEntry data = new DatabaseEntry();
540
541            return GetMultiple(
542                key, data, BufferSize, DbConstants.DB_FIRST, info, true);
543        }
544
545        /// <summary>
546        /// Set the cursor to refer to <paramref name="key"/>, and store the
547        /// datum associated with the given key in <see cref="Current"/>. In the
548        /// presence of duplicate key values, the first data item in the set of
549        /// duplicates is stored in <see cref="Current"/>.
550        /// </summary>
551        /// <remarks>
552        /// If positioning the cursor fails, <see cref="Current"/> will contain
553        /// an empty <see cref="KeyValuePair{T,T}"/>.
554        /// </remarks>
555        /// <param name="key">The key at which to position the cursor</param>
556        /// <param name="exact">
557        /// If true, require the given key to match the key in the database
558        /// exactly.  If false, position the cursor at the smallest key greater
559        /// than or equal to the specified key, permitting partial key matches
560        /// and range searches.
561        /// </param>
562        /// <returns>
563        /// True if the cursor was positioned successfully, false otherwise.
564        /// </returns>
565        public bool Move(DatabaseEntry key, bool exact) {
566            return Move(key, exact, null);
567        }
568        /// <summary>
569        /// Set the cursor to refer to <paramref name="key"/>, and store the
570        /// datum associated with the given key in <see cref="Current"/>. In the
571        /// presence of duplicate key values, the first data item in the set of
572        /// duplicates is stored in <see cref="Current"/>.
573        /// </summary>
574        /// <remarks>
575        /// If positioning the cursor fails, <see cref="Current"/> will contain
576        /// an empty <see cref="KeyValuePair{T,T}"/>.
577        /// </remarks>
578        /// <param name="key">The key at which to position the cursor</param>
579        /// <param name="exact">
580        /// If true, require the given key to match the key in the database
581        /// exactly.  If false, position the cursor at the smallest key greater
582        /// than or equal to the specified key, permitting partial key matches
583        /// and range searches.
584        /// </param>
585        /// <param name="info">The locking behavior to use.</param>
586        /// <returns>
587        /// True if the cursor was positioned successfully, false otherwise.
588        /// </returns>
589        public bool Move(DatabaseEntry key, bool exact, LockingInfo info) {
590            DatabaseEntry data = new DatabaseEntry();
591
592            return Get(key, data,
593                exact ? DbConstants.DB_SET : DbConstants.DB_SET_RANGE, info);
594        }
595
596        /// <summary>
597        /// Move the cursor to the specified key/data pair of the database. The
598        /// cursor is positioned to a key/data pair if both the key and data
599        /// match the values provided on the key and data parameters.
600        /// </summary>
601        /// <remarks>
602        /// <para>
603        /// If positioning the cursor fails, <see cref="Current"/> will contain
604        /// an empty <see cref="KeyValuePair{T,T}"/>.
605        /// </para>
606        /// <para>
607        /// If this flag is specified on a database configured without sorted
608        /// duplicate support, the value of <paramref name="exact"/> is ignored.
609        /// </para>
610        /// </remarks>
611        /// <param name="pair">
612        /// The key/data pair at which to position the cursor.
613        /// </param>
614        /// <param name="exact">
615        /// If true, require the given key and data to match the key and data
616        /// in the database exactly.  If false, position the cursor at the
617        /// smallest data value which is greater than or equal to the value
618        /// provided by <paramref name="pair.Value"/> (as determined by the
619        /// comparison function).
620        /// </param>
621        /// <returns>
622        /// True if the cursor was positioned successfully, false otherwise.
623        /// </returns>
624        public bool Move(
625            KeyValuePair<DatabaseEntry, DatabaseEntry> pair, bool exact) {
626            return Move(pair, exact, null);
627        }
628        /// <summary>
629        /// Move the cursor to the specified key/data pair of the database. The
630        /// cursor is positioned to a key/data pair if both the key and data
631        /// match the values provided on the key and data parameters.
632        /// </summary>
633        /// <remarks>
634        /// <para>
635        /// If positioning the cursor fails, <see cref="Current"/> will contain
636        /// an empty <see cref="KeyValuePair{T,T}"/>.
637        /// </para>
638        /// <para>
639        /// If this flag is specified on a database configured without sorted
640        /// duplicate support, the value of <paramref name="exact"/> is ignored.
641        /// </para>
642        /// </remarks>
643        /// <param name="pair">
644        /// The key/data pair at which to position the cursor.
645        /// </param>
646        /// <param name="exact">
647        /// If true, require the given key and data to match the key and data
648        /// in the database exactly.  If false, position the cursor at the
649        /// smallest data value which is greater than or equal to the value
650        /// provided by <paramref name="pair.Value"/> (as determined by the
651        /// comparison function).
652        /// </param>
653        /// <param name="info">The locking behavior to use.</param>
654        /// <returns>
655        /// True if the cursor was positioned successfully, false otherwise.
656        /// </returns>
657        public bool Move(KeyValuePair<DatabaseEntry, DatabaseEntry> pair,
658            bool exact, LockingInfo info) {
659            return Get(pair.Key, pair.Value, exact ?
660                DbConstants.DB_GET_BOTH : DbConstants.DB_GET_BOTH_RANGE, info);
661        }
662
663        /// <summary>
664        /// Set the cursor to refer to the last key/data pair of the database,
665        /// and store that pair in <see cref="Current"/>. If the last key has
666        /// duplicate values, the last data item in the set of duplicates is
667        /// stored in <see cref="Current"/>.
668        /// </summary>
669        /// <remarks>
670        /// If positioning the cursor fails, <see cref="Current"/> will contain
671        /// an empty <see cref="KeyValuePair{T,T}"/>.
672        /// </remarks>
673        /// <returns>
674        /// True if the cursor was positioned successfully, false otherwise.
675        /// </returns>
676        public bool MoveLast() { return MoveLast(null); }
677        /// <summary>
678        /// Set the cursor to refer to the last key/data pair of the database,
679        /// and store that pair in <see cref="Current"/>. If the last key has
680        /// duplicate values, the last data item in the set of duplicates is
681        /// stored in <see cref="Current"/>.
682        /// </summary>
683        /// <remarks>
684        /// If positioning the cursor fails, <see cref="Current"/> will contain
685        /// an empty <see cref="KeyValuePair{T,T}"/>.
686        /// </remarks>
687        /// <param name="info">The locking behavior to use.</param>
688        /// <returns>
689        /// True if the cursor was positioned successfully, false otherwise.
690        /// </returns>
691        public bool MoveLast(LockingInfo info) {
692            DatabaseEntry key = new DatabaseEntry();
693            DatabaseEntry data = new DatabaseEntry();
694
695            return Get(key, data, DbConstants.DB_LAST, info);
696        }
697
698        /// <summary>
699        /// Set the cursor to refer to <paramref name="key"/>, and store that
700        /// key and as many duplicate data items associated with the given key that
701        /// can fit in a buffer the size of one database page in
702        /// <see cref="CurrentMultiple"/>.
703        /// </summary>
704        /// <param name="key">The key at which to position the cursor</param>
705        /// <param name="exact">
706        /// If true, require the given key to match the key in the database
707        /// exactly.  If false, position the cursor at the smallest key greater
708        /// than or equal to the specified key, permitting partial key matches
709        /// and range searches.
710        /// </param>
711        /// <returns>
712        /// True if the cursor was positioned successfully, false otherwise.
713        /// </returns>
714        public bool MoveMultiple(DatabaseEntry key, bool exact) {
715            return MoveMultiple(key, exact, (int)pgsz, null);
716        }
717        /// <summary>
718        /// Set the cursor to refer to <paramref name="key"/>, and store that
719        /// key and as many duplicate data items associated with the given key that
720        /// can fit in a buffer the size of <paramref name="BufferSize"/> in
721        /// <see cref="CurrentMultiple"/>.
722        /// </summary>
723        /// <param name="key">The key at which to position the cursor</param>
724        /// <param name="exact">
725        /// If true, require the given key to match the key in the database
726        /// exactly.  If false, position the cursor at the smallest key greater
727        /// than or equal to the specified key, permitting partial key matches
728        /// and range searches.
729        /// </param>
730        /// <param name="BufferSize">
731        /// The size of a buffer to fill with duplicate data items.  Must be at
732        /// least the page size of the underlying database and be a multiple of
733        /// 1024.
734        /// </param>
735        /// <returns>
736        /// True if the cursor was positioned successfully, false otherwise.
737        /// </returns>
738        public bool MoveMultiple(
739            DatabaseEntry key, bool exact, int BufferSize) {
740            return MoveMultiple(key, exact, BufferSize, null);
741        }
742        /// <summary>
743        /// Set the cursor to refer to <paramref name="key"/>, and store that
744        /// key and as many duplicate data items associated with the given key that
745        /// can fit in a buffer the size of one database page in
746        /// <see cref="CurrentMultiple"/>.
747        /// </summary>
748        /// <param name="key">The key at which to position the cursor</param>
749        /// <param name="exact">
750        /// If true, require the given key to match the key in the database
751        /// exactly.  If false, position the cursor at the smallest key greater
752        /// than or equal to the specified key, permitting partial key matches
753        /// and range searches.
754        /// </param>
755        /// <param name="info">The locking behavior to use.</param>
756        /// <returns>
757        /// True if the cursor was positioned successfully, false otherwise.
758        /// </returns>
759        public bool MoveMultiple(
760            DatabaseEntry key, bool exact, LockingInfo info) {
761            return MoveMultiple(key, exact, (int)pgsz, info);
762        }
763        /// <summary>
764        /// Set the cursor to refer to <paramref name="key"/>, and store that
765        /// key and as many duplicate data items associated with the given key that
766        /// can fit in a buffer the size of <paramref name="BufferSize"/> in
767        /// <see cref="CurrentMultiple"/>.
768        /// </summary>
769        /// <param name="key">The key at which to position the cursor</param>
770        /// <param name="exact">
771        /// If true, require the given key to match the key in the database
772        /// exactly.  If false, position the cursor at the smallest key greater
773        /// than or equal to the specified key, permitting partial key matches
774        /// and range searches.
775        /// </param>
776        /// <param name="BufferSize">
777        /// The size of a buffer to fill with duplicate data items.  Must be at
778        /// least the page size of the underlying database and be a multiple of
779        /// 1024.
780        /// </param>
781        /// <param name="info">The locking behavior to use.</param>
782        /// <returns>
783        /// True if the cursor was positioned successfully, false otherwise.
784        /// </returns>
785        public bool MoveMultiple(
786            DatabaseEntry key, bool exact, int BufferSize, LockingInfo info) {
787            DatabaseEntry data = new DatabaseEntry();
788
789            return GetMultiple(key, data, BufferSize, (exact ?
790                DbConstants.DB_SET : DbConstants.DB_SET_RANGE), info, false);
791        }
792
793        /// <summary>
794        /// Move the cursor to the specified key/data pair of the database, and
795        /// store that key/data pair and as many duplicate data items associated
796        /// with the given key that can fit in a buffer the size of one database
797        /// page in <see cref="CurrentMultiple"/>. The cursor is positioned to a
798        /// key/data pair if both the key and data match the values provided on
799        /// the key and data parameters.
800        /// </summary>
801        /// <param name="pair">
802        /// The key/data pair at which to position the cursor.
803        /// </param>
804        /// <param name="exact">
805        /// If true, require the given key and data to match the key and data
806        /// in the database exactly.  If false, position the cursor at the
807        /// smallest data value which is greater than or equal to the value
808        /// provided by <paramref name="pair.Value"/> (as determined by the
809        /// comparison function).
810        /// </param>
811        /// <returns>
812        /// True if the cursor was positioned successfully, false otherwise.
813        /// </returns>
814        public bool MoveMultiple(
815            KeyValuePair<DatabaseEntry, DatabaseEntry> pair, bool exact) {
816            return MoveMultiple(pair, exact, (int)pgsz, null);
817        }
818        /// <summary>
819        /// Move the cursor to the specified key/data pair of the database, and
820        /// store that key/data pair and as many duplicate data items associated
821        /// with the given key that can fit in a buffer the size of
822        /// <paramref name="BufferSize"/> in <see cref="CurrentMultiple"/>. The
823        /// cursor is positioned to a key/data pair if both the key and data
824        /// match the values provided on the key and data parameters.
825        /// </summary>
826        /// <param name="pair">
827        /// The key/data pair at which to position the cursor.
828        /// </param>
829        /// <param name="exact">
830        /// If true, require the given key and data to match the key and data
831        /// in the database exactly.  If false, position the cursor at the
832        /// smallest data value which is greater than or equal to the value
833        /// provided by <paramref name="pair.Value"/> (as determined by the
834        /// comparison function).
835        /// </param>
836        /// <param name="BufferSize">
837        /// The size of a buffer to fill with duplicate data items.  Must be at
838        /// least the page size of the underlying database and be a multiple of
839        /// 1024.
840        /// </param>
841        /// <returns>
842        /// True if the cursor was positioned successfully, false otherwise.
843        /// </returns>
844        public bool MoveMultiple(
845            KeyValuePair<DatabaseEntry, DatabaseEntry> pair,
846            bool exact, int BufferSize) {
847            return MoveMultiple(pair, exact, BufferSize, null);
848        }
849        /// <summary>
850        /// Move the cursor to the specified key/data pair of the database, and
851        /// store that key/data pair and as many duplicate data items associated
852        /// with the given key that can fit in a buffer the size of one database
853        /// page in <see cref="CurrentMultiple"/>. The cursor is positioned to a
854        /// key/data pair if both the key and data match the values provided on
855        /// the key and data parameters.
856        /// </summary>
857        /// <param name="pair">
858        /// The key/data pair at which to position the cursor.
859        /// </param>
860        /// <param name="exact">
861        /// If true, require the given key and data to match the key and data
862        /// in the database exactly.  If false, position the cursor at the
863        /// smallest data value which is greater than or equal to the value
864        /// provided by <paramref name="pair.Value"/> (as determined by the
865        /// comparison function).
866        /// </param>
867        /// <param name="info">The locking behavior to use.</param>
868        /// <returns>
869        /// True if the cursor was positioned successfully, false otherwise.
870        /// </returns>
871        public bool MoveMultiple(
872            KeyValuePair<DatabaseEntry, DatabaseEntry> pair,
873            bool exact, LockingInfo info) {
874            return MoveMultiple(pair, exact, (int)pgsz, info);
875        }
876        /// <summary>
877        /// Move the cursor to the specified key/data pair of the database, and
878        /// store that key/data pair and as many duplicate data items associated
879        /// with the given key that can fit in a buffer the size of
880        /// <paramref name="BufferSize"/> in <see cref="CurrentMultiple"/>. The
881        /// cursor is positioned to a key/data pair if both the key and data
882        /// match the values provided on the key and data parameters.
883        /// </summary>
884        /// <param name="pair">
885        /// The key/data pair at which to position the cursor.
886        /// </param>
887        /// <param name="exact">
888        /// If true, require the given key and data to match the key and data
889        /// in the database exactly.  If false, position the cursor at the
890        /// smallest data value which is greater than or equal to the value
891        /// provided by <paramref name="pair.Value"/> (as determined by the
892        /// comparison function).
893        /// </param>
894        /// <param name="BufferSize">
895        /// The size of a buffer to fill with duplicate data items.  Must be at
896        /// least the page size of the underlying database and be a multiple of
897        /// 1024.
898        /// </param>
899        /// <param name="info">The locking behavior to use.</param>
900        /// <returns>
901        /// True if the cursor was positioned successfully, false otherwise.
902        /// </returns>
903        public bool MoveMultiple(
904            KeyValuePair<DatabaseEntry, DatabaseEntry> pair,
905            bool exact, int BufferSize, LockingInfo info) {
906            return GetMultiple(pair.Key, pair.Value, BufferSize, (exact ?
907                DbConstants.DB_GET_BOTH : DbConstants.DB_GET_BOTH_RANGE),
908                info, false);
909        }
910
911        /// <summary>
912        /// Set the cursor to refer to <paramref name="key"/>, and store that
913        /// key and as many ensuing key/data pairs that can fit in a buffer the
914        /// size of one database page in <see cref="CurrentMultipleKey"/>.
915        /// </summary>
916        /// <param name="key">The key at which to position the cursor</param>
917        /// <param name="exact">
918        /// If true, require the given key to match the key in the database
919        /// exactly.  If false, position the cursor at the smallest key greater
920        /// than or equal to the specified key, permitting partial key matches
921        /// and range searches.
922        /// </param>
923        /// <returns>
924        /// True if the cursor was positioned successfully, false otherwise.
925        /// </returns>
926        public bool MoveMultipleKey(DatabaseEntry key, bool exact) {
927            return MoveMultipleKey(key, exact, (int)pgsz, null);
928        }
929        /// <summary>
930        /// Set the cursor to refer to <paramref name="key"/>, and store that
931        /// key and as many ensuing key/data pairs that can fit in a buffer the
932        /// size of <paramref name="BufferSize"/> in
933        /// <see cref="CurrentMultipleKey"/>.
934        /// </summary>
935        /// <param name="key">The key at which to position the cursor</param>
936        /// <param name="exact">
937        /// If true, require the given key to match the key in the database
938        /// exactly.  If false, position the cursor at the smallest key greater
939        /// than or equal to the specified key, permitting partial key matches
940        /// and range searches.
941        /// </param>
942        /// <param name="BufferSize">
943        /// The size of a buffer to fill with key/data pairs.  Must be at least
944        /// the page size of the underlying database and be a multiple of 1024.
945        /// </param>
946        /// <returns>
947        /// True if the cursor was positioned successfully, false otherwise.
948        /// </returns>
949        public bool MoveMultipleKey(
950            DatabaseEntry key, bool exact, int BufferSize) {
951            return MoveMultipleKey(key, exact, BufferSize, null);
952        }
953        /// <summary>
954        /// Set the cursor to refer to <paramref name="key"/>, and store that
955        /// key and as many ensuing key/data pairs that can fit in a buffer the
956        /// size of one database page in <see cref="CurrentMultipleKey"/>.
957        /// </summary>
958        /// <param name="key">The key at which to position the cursor</param>
959        /// <param name="exact">
960        /// If true, require the given key to match the key in the database
961        /// exactly.  If false, position the cursor at the smallest key greater
962        /// than or equal to the specified key, permitting partial key matches
963        /// and range searches.
964        /// </param>
965        /// <param name="info">The locking behavior to use.</param>
966        /// <returns>
967        /// True if the cursor was positioned successfully, false otherwise.
968        /// </returns>
969        public bool MoveMultipleKey(
970            DatabaseEntry key, bool exact, LockingInfo info) {
971            return MoveMultipleKey(key, exact, (int)pgsz, info);
972        }
973        /// <summary>
974        /// Set the cursor to refer to <paramref name="key"/>, and store that
975        /// key and as many ensuing key/data pairs that can fit in a buffer the
976        /// size of <paramref name="BufferSize"/> in
977        /// <see cref="CurrentMultipleKey"/>.
978        /// </summary>
979        /// <param name="key">The key at which to position the cursor</param>
980        /// <param name="exact">
981        /// If true, require the given key to match the key in the database
982        /// exactly.  If false, position the cursor at the smallest key greater
983        /// than or equal to the specified key, permitting partial key matches
984        /// and range searches.
985        /// </param>
986        /// <param name="BufferSize">
987        /// The size of a buffer to fill with key/data pairs.  Must be at least
988        /// the page size of the underlying database and be a multiple of 1024.
989        /// </param>
990        /// <param name="info">The locking behavior to use.</param>
991        /// <returns>
992        /// True if the cursor was positioned successfully, false otherwise.
993        /// </returns>
994        public bool MoveMultipleKey(
995            DatabaseEntry key, bool exact, int BufferSize, LockingInfo info) {
996            DatabaseEntry data = new DatabaseEntry();
997
998            return GetMultiple(key, data, BufferSize,
999                (exact ?
1000                DbConstants.DB_SET : DbConstants.DB_SET_RANGE), info, true);
1001        }
1002
1003        /// <summary>
1004        /// Move the cursor to the specified key/data pair of the database, and
1005        /// store that key/data pair and as many ensuing key/data pairs that can
1006        /// fit in a buffer the size of one database page in
1007        /// <see cref="CurrentMultipleKey"/>. The cursor is positioned to a
1008        /// key/data pair if both the key and data match the values provided on
1009        /// the key and data parameters.
1010        /// </summary>
1011        /// <param name="pair">
1012        /// The key/data pair at which to position the cursor.
1013        /// </param>
1014        /// <param name="exact">
1015        /// If true, require the given key and data to match the key and data
1016        /// in the database exactly.  If false, position the cursor at the
1017        /// smallest data value which is greater than or equal to the value
1018        /// provided by <paramref name="pair.Value"/> (as determined by the
1019        /// comparison function).
1020        /// </param>
1021        /// <returns>
1022        /// True if the cursor was positioned successfully, false otherwise.
1023        /// </returns>
1024        public bool MoveMultipleKey(
1025            KeyValuePair<DatabaseEntry, DatabaseEntry> pair, bool exact) {
1026            return MoveMultipleKey(pair, exact, (int)pgsz, null);
1027        }
1028        /// <summary>
1029        /// Move the cursor to the specified key/data pair of the database, and
1030        /// store that key/data pair and as many ensuing key/data pairs that can
1031        /// fit in a buffer the size of <paramref name="BufferSize"/> in
1032        /// <see cref="CurrentMultipleKey"/>. The cursor is positioned to a
1033        /// key/data pair if both the key and data match the values provided on
1034        /// the key and data parameters.
1035        /// </summary>
1036        /// <param name="pair">
1037        /// The key/data pair at which to position the cursor.
1038        /// </param>
1039        /// <param name="exact">
1040        /// If true, require the given key and data to match the key and data
1041        /// in the database exactly.  If false, position the cursor at the
1042        /// smallest data value which is greater than or equal to the value
1043        /// provided by <paramref name="pair.Value"/> (as determined by the
1044        /// comparison function).
1045        /// </param>
1046        /// <param name="BufferSize">
1047        /// The size of a buffer to fill with key/data pairs.  Must be at least
1048        /// the page size of the underlying database and be a multiple of 1024.
1049        /// </param>
1050        /// <returns>
1051        /// True if the cursor was positioned successfully, false otherwise.
1052        /// </returns>
1053        public bool MoveMultipleKey(
1054            KeyValuePair<DatabaseEntry, DatabaseEntry> pair,
1055            bool exact, int BufferSize) {
1056            return MoveMultipleKey(pair, exact, BufferSize, null);
1057        }
1058        /// <summary>
1059        /// Move the cursor to the specified key/data pair of the database, and
1060        /// store that key/data pair and as many ensuing key/data pairs that can
1061        /// fit in a buffer the size of one database page in
1062        /// <see cref="CurrentMultipleKey"/>. The cursor is positioned to a
1063        /// key/data pair if both the key and data match the values provided on
1064        /// the key and data parameters.
1065        /// </summary>
1066        /// <param name="pair">
1067        /// The key/data pair at which to position the cursor.
1068        /// </param>
1069        /// <param name="exact">
1070        /// If true, require the given key and data to match the key and data
1071        /// in the database exactly.  If false, position the cursor at the
1072        /// smallest data value which is greater than or equal to the value
1073        /// provided by <paramref name="pair.Value"/> (as determined by the
1074        /// comparison function).
1075        /// </param>
1076        /// <param name="info">The locking behavior to use.</param>
1077        /// <returns>
1078        /// True if the cursor was positioned successfully, false otherwise.
1079        /// </returns>
1080        public bool MoveMultipleKey(
1081            KeyValuePair<DatabaseEntry, DatabaseEntry> pair,
1082            bool exact, LockingInfo info) {
1083            return MoveMultipleKey(pair, exact, (int)pgsz, info);
1084        }
1085        /// <summary>
1086        /// Move the cursor to the specified key/data pair of the database, and
1087        /// store that key/data pair and as many ensuing key/data pairs that can
1088        /// fit in a buffer the size of <paramref name="BufferSize"/> in
1089        /// <see cref="CurrentMultipleKey"/>. The cursor is positioned to a
1090        /// key/data pair if both the key and data match the values provided on
1091        /// the key and data parameters.
1092        /// </summary>
1093        /// <param name="pair">
1094        /// The key/data pair at which to position the cursor.
1095        /// </param>
1096        /// <param name="exact">
1097        /// If true, require the given key and data to match the key and data
1098        /// in the database exactly.  If false, position the cursor at the
1099        /// smallest data value which is greater than or equal to the value
1100        /// provided by <paramref name="pair.Value"/> (as determined by the
1101        /// comparison function).
1102        /// </param>
1103        /// <param name="BufferSize">
1104        /// The size of a buffer to fill with key/data pairs.  Must be at least
1105        /// the page size of the underlying database and be a multiple of 1024.
1106        /// </param>
1107        /// <param name="info">The locking behavior to use.</param>
1108        /// <returns>
1109        /// True if the cursor was positioned successfully, false otherwise.
1110        /// </returns>
1111        public bool MoveMultipleKey(
1112            KeyValuePair<DatabaseEntry, DatabaseEntry> pair,
1113            bool exact, int BufferSize, LockingInfo info) {
1114            return GetMultiple(pair.Key, pair.Value, BufferSize, (exact ?
1115                DbConstants.DB_GET_BOTH : DbConstants.DB_GET_BOTH_RANGE),
1116                info, true);
1117        }
1118
1119        /// <summary>
1120        /// If the cursor is not yet initialized, MoveNext is identical to
1121        /// <see cref="MoveFirst()"/>. Otherwise, move the cursor to the next
1122        /// key/data pair of the database, and store that pair in
1123        /// <see cref="Current"/>. In the presence of duplicate key values, the
1124        /// value of <see cref="Current">Current.Key</see> may not change.
1125        /// </summary>
1126        /// <remarks>
1127        /// If positioning the cursor fails, <see cref="Current"/> will contain
1128        /// an empty <see cref="KeyValuePair{T,T}"/>.
1129        /// </remarks>
1130        /// <returns>
1131        /// True if the cursor was positioned successfully, false otherwise.
1132        /// </returns>
1133        public bool MoveNext() { return MoveNext(null); }
1134        /// <summary>
1135        /// If the cursor is not yet initialized, MoveNext is identical to
1136        /// <see cref="MoveFirst(LockingInfo)"/>. Otherwise, move the cursor to
1137        /// the next key/data pair of the database, and store that pair in
1138        /// <see cref="Current"/>. In the presence of duplicate key values, the
1139        /// value of <see cref="Current">Current.Key</see> may not change.
1140        /// </summary>
1141        /// <remarks>
1142        /// If positioning the cursor fails, <see cref="Current"/> will contain
1143        /// an empty <see cref="KeyValuePair{T,T}"/>.
1144        /// </remarks>
1145        /// <param name="info">The locking behavior to use.</param>
1146        /// <returns>
1147        /// True if the cursor was positioned successfully, false otherwise.
1148        /// </returns>
1149        public bool MoveNext(LockingInfo info) {
1150            DatabaseEntry key = new DatabaseEntry();
1151            DatabaseEntry data = new DatabaseEntry();
1152
1153            return Get(key, data, DbConstants.DB_NEXT, info);
1154        }
1155
1156        /// <summary>
1157        /// If the cursor is not yet initialized, MoveNextMultiple is identical
1158        /// to <see cref="MoveFirstMultiple()"/>. Otherwise, move the cursor to
1159        /// the next key/data pair of the database, and store that pair and as
1160        /// many duplicate data items that can fit in a buffer the size of one
1161        /// database page in <see cref="CurrentMultiple"/>. In the presence of
1162        /// duplicate key values, the value of
1163        /// <see cref="CurrentMultiple">CurrentMultiple.Key</see> may not
1164        /// change.
1165        /// </summary>
1166        /// <returns>
1167        /// True if the cursor was positioned successfully, false otherwise.
1168        /// </returns>
1169        public bool MoveNextMultiple() {
1170            return MoveNextMultiple((int)pgsz, null);
1171        }
1172        /// <summary>
1173        /// If the cursor is not yet initialized, MoveNextMultiple is identical
1174        /// to <see cref="MoveFirstMultiple(int)"/>. Otherwise, move the cursor
1175        /// to the next key/data pair of the database, and store that pair and
1176        /// as many duplicate data items that can fit in a buffer the size of
1177        /// <paramref name="BufferSize"/> in <see cref="CurrentMultiple"/>. In
1178        /// the presence of duplicate key values, the value of
1179        /// <see cref="CurrentMultiple">CurrentMultiple.Key</see> may not
1180        /// change.
1181        /// </summary>
1182        /// <param name="BufferSize">
1183        /// The size of a buffer to fill with duplicate data items.  Must be at
1184        /// least the page size of the underlying database and be a multiple of
1185        /// 1024.
1186        /// </param>
1187        /// <returns>
1188        /// True if the cursor was positioned successfully, false otherwise.
1189        /// </returns>
1190        public bool MoveNextMultiple(int BufferSize) {
1191            return MoveNextMultiple(BufferSize, null);
1192        }
1193        /// <summary>
1194        /// If the cursor is not yet initialized, MoveNextMultiple is identical
1195        /// to <see cref="MoveFirstMultiple(LockingInfo)"/>. Otherwise, move the
1196        /// cursor to the next key/data pair of the database, and store that
1197        /// pair and as many duplicate data items that can fit in a buffer the
1198        /// size of one database page in <see cref="CurrentMultiple"/>. In the
1199        /// presence of duplicate key values, the value of
1200        /// <see cref="CurrentMultiple">CurrentMultiple.Key</see> may not
1201        /// change.
1202        /// </summary>
1203        /// <param name="info">The locking behavior to use.</param>
1204        /// <returns>
1205        /// True if the cursor was positioned successfully, false otherwise.
1206        /// </returns>
1207        public bool MoveNextMultiple(LockingInfo info) {
1208            return MoveNextMultiple((int)pgsz, null);
1209        }
1210        /// <summary>
1211        /// If the cursor is not yet initialized, MoveNextMultiple is identical
1212        /// to <see cref="MoveFirstMultiple(int, LockingInfo)"/>. Otherwise,
1213        /// move the cursor to the next key/data pair of the database, and store
1214        /// that pair and as many duplicate data items that can fit in a buffer
1215        /// the size of <paramref name="BufferSize"/> in
1216        /// <see cref="CurrentMultiple"/>. In the presence of duplicate key
1217        /// values, the value of
1218        /// <see cref="CurrentMultiple">CurrentMultiple.Key</see> may not
1219        /// change.
1220        /// </summary>
1221        /// <param name="BufferSize">
1222        /// The size of a buffer to fill with duplicate data items.  Must be at
1223        /// least the page size of the underlying database and be a multiple of
1224        /// 1024.
1225        /// </param>
1226        /// <param name="info">The locking behavior to use.</param>
1227        /// <returns>
1228        /// True if the cursor was positioned successfully, false otherwise.
1229        /// </returns>
1230        public bool MoveNextMultiple(int BufferSize, LockingInfo info) {
1231            DatabaseEntry key = new DatabaseEntry();
1232            DatabaseEntry data = new DatabaseEntry();
1233
1234            return GetMultiple(
1235                key, data, BufferSize, DbConstants.DB_NEXT, info, false);
1236        }
1237
1238        /// <summary>
1239        /// If the cursor is not yet initialized, MoveNextMultipleKey is
1240        /// identical to <see cref="MoveFirstMultipleKey()"/>. Otherwise, move
1241        /// the cursor to the next key/data pair of the database, and store that
1242        /// pair and as many ensuing key/data pairs that can fit in a buffer the
1243        /// size of one database page in <see cref="CurrentMultipleKey"/>. In
1244        /// the presence of duplicate key values, the keys of
1245        /// <see cref="CurrentMultipleKey"/> may not change.
1246        /// </summary>
1247        /// <returns>
1248        /// True if the cursor was positioned successfully, false otherwise.
1249        /// </returns>
1250        public bool MoveNextMultipleKey() {
1251            return MoveNextMultipleKey((int)pgsz, null);
1252        }
1253        /// <summary>
1254        /// If the cursor is not yet initialized, MoveNextMultipleKey is
1255        /// identical to <see cref="MoveFirstMultipleKey(int)"/>. Otherwise,
1256        /// move the cursor to the next key/data pair of the database, and store
1257        /// that pair and as many ensuing key/data pairs that can fit in a
1258        /// buffer the size of <paramref name="BufferSize"/> in
1259        /// <see cref="CurrentMultipleKey"/>. In the presence of duplicate key
1260        /// values, the keys of <see cref="CurrentMultipleKey"/> may not change.
1261        /// </summary>
1262        /// <param name="BufferSize">
1263        /// The size of a buffer to fill with key/data pairs.  Must be at least
1264        /// the page size of the underlying database and be a multiple of 1024.
1265        /// </param>
1266        /// <returns>
1267        /// True if the cursor was positioned successfully, false otherwise.
1268        /// </returns>
1269        public bool MoveNextMultipleKey(int BufferSize) {
1270            return MoveNextMultipleKey(BufferSize, null);
1271        }
1272        /// <summary>
1273        /// If the cursor is not yet initialized, MoveNextMultipleKey is
1274        /// identical to <see cref="MoveFirstMultipleKey(LockingInfo)"/>.
1275        /// Otherwise, move the cursor to the next key/data pair of the
1276        /// database, and store that pair and as many ensuing key/data pairs
1277        /// that can fit in a buffer the size of one database page in
1278        /// <see cref="CurrentMultipleKey"/>. In the presence of duplicate key
1279        /// values, the keys of <see cref="CurrentMultipleKey"/> may not change.
1280        /// </summary>
1281        /// <param name="info">The locking behavior to use.</param>
1282        /// <returns>
1283        /// True if the cursor was positioned successfully, false otherwise.
1284        /// </returns>
1285        public bool MoveNextMultipleKey(LockingInfo info) {
1286            return MoveNextMultipleKey((int)pgsz, null);
1287        }
1288        /// <summary>
1289        /// If the cursor is not yet initialized, MoveNextMultipleKey is
1290        /// identical to <see cref="MoveFirstMultipleKey(int, LockingInfo)"/>.
1291        /// Otherwise, move the cursor to the next key/data pair of the
1292        /// database, and store that pair and as many ensuing key/data pairs
1293        /// that can fit in a buffer the size of <paramref name="BufferSize"/>
1294        /// in <see cref="CurrentMultipleKey"/>. In the presence of duplicate
1295        /// key values, the keys of <see cref="CurrentMultipleKey"/> may not
1296        /// change.
1297        /// </summary>
1298        /// <param name="BufferSize">
1299        /// The size of a buffer to fill with key/data pairs.  Must be at least
1300        /// the page size of the underlying database and be a multiple of 1024.
1301        /// </param>
1302        /// <param name="info">The locking behavior to use.</param>
1303        /// <returns>
1304        /// True if the cursor was positioned successfully, false otherwise.
1305        /// </returns>
1306        public bool MoveNextMultipleKey(int BufferSize, LockingInfo info) {
1307            DatabaseEntry key = new DatabaseEntry();
1308            DatabaseEntry data = new DatabaseEntry();
1309
1310            return GetMultiple(
1311                key, data, BufferSize, DbConstants.DB_NEXT, info, true);
1312        }
1313
1314        /// <summary>
1315        /// If the next key/data pair of the database is a duplicate data record
1316        /// for the current key/data pair, move the cursor to the next key/data
1317        /// pair in the database, and store that pair in <see cref="Current"/>.
1318        /// MoveNextDuplicate will return false if the next key/data pair of the
1319        /// database is not a duplicate data record for the current key/data
1320        /// pair.
1321        /// </summary>
1322        /// <remarks>
1323        /// If positioning the cursor fails, <see cref="Current"/> will contain
1324        /// an empty <see cref="KeyValuePair{T,T}"/>.
1325        /// </remarks>
1326        /// <returns>
1327        /// True if the cursor was positioned successfully, false otherwise.
1328        /// </returns>
1329        public bool MoveNextDuplicate() { return MoveNextDuplicate(null); }
1330        /// <summary>
1331        /// If the next key/data pair of the database is a duplicate data record
1332        /// for the current key/data pair, move the cursor to the next key/data
1333        /// pair in the database, and store that pair in <see cref="Current"/>.
1334        /// MoveNextDuplicate will return false if the next key/data pair of the
1335        /// database is not a duplicate data record for the current key/data
1336        /// pair.
1337        /// </summary>
1338        /// <remarks>
1339        /// If positioning the cursor fails, <see cref="Current"/> will contain
1340        /// an empty <see cref="KeyValuePair{T,T}"/>.
1341        /// </remarks>
1342        /// <param name="info">The locking behavior to use.</param>
1343        /// <returns>
1344        /// True if the cursor was positioned successfully, false otherwise.
1345        /// </returns>
1346        public bool MoveNextDuplicate(LockingInfo info) {
1347            DatabaseEntry key = new DatabaseEntry();
1348            DatabaseEntry data = new DatabaseEntry();
1349
1350            return Get(key, data, DbConstants.DB_NEXT_DUP, info);
1351        }
1352
1353        /// <summary>
1354        /// If the next key/data pair of the database is a duplicate data record
1355        /// for the current key/data pair, move the cursor to the next key/data
1356        /// pair in the database, and store that pair and as many duplicate data
1357        /// items that can fit in a buffer the size of one database page in
1358        /// <see cref="CurrentMultiple"/>. MoveNextDuplicateMultiple will return
1359        /// false if the next key/data pair of the database is not a duplicate
1360        /// data record for the current key/data pair.
1361        /// </summary>
1362        /// <returns>
1363        /// True if the cursor was positioned successfully, false otherwise.
1364        /// </returns>
1365        public bool MoveNextDuplicateMultiple() {
1366            return MoveNextDuplicateMultiple((int)pgsz, null);
1367        }
1368        /// <summary>
1369        /// If the next key/data pair of the database is a duplicate data record
1370        /// for the current key/data pair, then move cursor to the next key/data
1371        /// pair in the database, and store that pair and as many duplicate data
1372        /// items that can fit in a buffer the size of
1373        /// <paramref name="BufferSize"/> in <see cref="CurrentMultiple"/>.
1374        /// MoveNextDuplicateMultiple will return false if the next key/data
1375        /// pair of the database is not a duplicate data record for the current
1376        /// key/data pair.
1377        /// </summary>
1378        /// <param name="BufferSize">
1379        /// The size of a buffer to fill with duplicate data items.  Must be at
1380        /// least the page size of the underlying database and be a multiple of
1381        /// 1024.
1382        /// </param>
1383        /// <returns>
1384        /// True if the cursor was positioned successfully, false otherwise.
1385        /// </returns>
1386        public bool MoveNextDuplicateMultiple(int BufferSize) {
1387            return MoveNextDuplicateMultiple(BufferSize, null);
1388        }
1389        /// <summary>
1390        /// If the next key/data pair of the database is a duplicate data record
1391        /// for the current key/data pair, move the cursor to the next key/data
1392        /// pair in the database, and store that pair and as many duplicate data
1393        /// items that can fit in a buffer the size of one database page in
1394        /// <see cref="CurrentMultiple"/>. MoveNextDuplicateMultiple will return
1395        /// false if the next key/data pair of the database is not a duplicate
1396        /// data record for the current key/data pair.
1397        /// </summary>
1398        /// <param name="info">The locking behavior to use.</param>
1399        /// <returns>
1400        /// True if the cursor was positioned successfully, false otherwise.
1401        /// </returns>
1402        public bool MoveNextDuplicateMultiple(LockingInfo info) {
1403            return MoveNextDuplicateMultiple((int)pgsz, info);
1404        }
1405        /// <summary>
1406        /// If the next key/data pair of the database is a duplicate data record
1407        /// for the current key/data pair, move the cursor to the next key/data
1408        /// pair in the database, and store that pair and as many duplicate data
1409        /// items that can fit in a buffer the size of
1410        /// <paramref name="BufferSize"/> in <see cref="CurrentMultiple"/>.
1411        /// MoveNextDuplicateMultiple will return false if the next key/data
1412        /// pair of the database is not a duplicate data record for the current
1413        /// key/data pair.
1414        /// </summary>
1415        /// <param name="BufferSize">
1416        /// The size of a buffer to fill with duplicate data items.  Must be at
1417        /// least the page size of the underlying database and be a multiple of
1418        /// 1024.
1419        /// </param>
1420        /// <param name="info">The locking behavior to use.</param>
1421        /// <returns>
1422        /// True if the cursor was positioned successfully, false otherwise.
1423        /// </returns>
1424        public bool MoveNextDuplicateMultiple(
1425            int BufferSize, LockingInfo info) {
1426            DatabaseEntry key = new DatabaseEntry();
1427            DatabaseEntry data = new DatabaseEntry();
1428
1429            return GetMultiple(
1430                key, data, BufferSize, DbConstants.DB_NEXT_DUP, info, false);
1431        }
1432
1433        /// <summary>
1434        /// If the next key/data pair of the database is a duplicate data record
1435        /// for the current key/data pair, move the cursor to the next key/data
1436        /// pair in the database, and store that pair and as many duplicate data
1437        /// items that can fit in a buffer the size of one database page in
1438        /// <see cref="CurrentMultipleKey"/>. MoveNextDuplicateMultipleKey will
1439        /// return false if the next key/data pair of the database is not a
1440        /// duplicate data record for the current key/data pair.
1441        /// </summary>
1442        /// <returns>
1443        /// True if the cursor was positioned successfully, false otherwise.
1444        /// </returns>
1445        public bool MoveNextDuplicateMultipleKey() {
1446            return MoveNextDuplicateMultipleKey((int)pgsz, null);
1447        }
1448        /// <summary>
1449        /// If the next key/data pair of the database is a duplicate data record
1450        /// for the current key/data pair, move the cursor to the next key/data
1451        /// pair in the database, and store that pair and as many duplicate data
1452        /// items that can fit in a buffer the size of
1453        /// <paramref name="BufferSize"/> in <see cref="CurrentMultipleKey"/>.
1454        /// MoveNextDuplicateMultipleKey will return false if the next key/data
1455        /// pair of the database is not a duplicate data record for the current
1456        /// key/data pair.
1457        /// </summary>
1458        /// <param name="BufferSize">
1459        /// The size of a buffer to fill with key/data pairs.  Must be at least
1460        /// the page size of the underlying database and be a multiple of 1024.
1461        /// </param>
1462        /// <returns>
1463        /// True if the cursor was positioned successfully, false otherwise.
1464        /// </returns>
1465        public bool MoveNextDuplicateMultipleKey(int BufferSize) {
1466            return MoveNextDuplicateMultipleKey(BufferSize, null);
1467        }
1468        /// <summary>
1469        /// If the next key/data pair of the database is a duplicate data record
1470        /// for the current key/data pair, move the cursor to the next key/data
1471        /// pair in the database, and store that pair and as many duplicate data
1472        /// items that can fit in a buffer the size of one database page in
1473        /// <see cref="CurrentMultipleKey"/>. MoveNextDuplicateMultipleKey will
1474        /// return false if the next key/data pair of the database is not a
1475        /// duplicate data record for the current key/data pair.
1476        /// </summary>
1477        /// <param name="info">The locking behavior to use.</param>
1478        /// <returns>
1479        /// True if the cursor was positioned successfully, false otherwise.
1480        /// </returns>
1481        public bool MoveNextDuplicateMultipleKey(LockingInfo info) {
1482            return MoveNextDuplicateMultipleKey((int)pgsz, info);
1483        }
1484        /// <summary>
1485        /// If the next key/data pair of the database is a duplicate data record
1486        /// for the current key/data pair, move the cursor to the next key/data
1487        /// pair in the database, and store that pair and as many duplicate data
1488        /// items that can fit in a buffer the size of
1489        /// <paramref name="BufferSize"/> in <see cref="CurrentMultipleKey"/>.
1490        /// MoveNextDuplicateMultipleKey will return false if the next key/data
1491        /// pair of the database is not a duplicate data record for the current
1492        /// key/data pair.
1493        /// </summary>
1494        /// <param name="BufferSize">
1495        /// The size of a buffer to fill with key/data pairs.  Must be at least
1496        /// the page size of the underlying database and be a multiple of 1024.
1497        /// </param>
1498        /// <param name="info">The locking behavior to use.</param>
1499        /// <returns>
1500        /// True if the cursor was positioned successfully, false otherwise.
1501        /// </returns>
1502        public bool MoveNextDuplicateMultipleKey(
1503            int BufferSize, LockingInfo info) {
1504            DatabaseEntry key = new DatabaseEntry();
1505            DatabaseEntry data = new DatabaseEntry();
1506
1507            return GetMultiple(
1508                key, data, BufferSize, DbConstants.DB_NEXT_DUP, info, true);
1509        }
1510
1511        /// <summary>
1512        /// If the cursor is not yet initialized, MoveNextUnique is identical to
1513        /// <see cref="MoveFirst()"/>. Otherwise, move the cursor to the next
1514        /// non-duplicate key in the database, and store that key and associated
1515        /// datum in <see cref="Current"/>. MoveNextUnique will return false if
1516        /// no non-duplicate key/data pairs exist after the cursor position in
1517        /// the database.
1518        /// </summary>
1519        /// <remarks>
1520        /// If positioning the cursor fails, <see cref="Current"/> will contain
1521        /// an empty <see cref="KeyValuePair{T,T}"/>.
1522        /// </remarks>
1523        /// <returns>
1524        /// True if the cursor was positioned successfully, false otherwise.
1525        /// </returns>
1526        public bool MoveNextUnique() { return MoveNextUnique(null); }
1527        /// <summary>
1528        /// If the cursor is not yet initialized, MoveNextUnique is identical to
1529        /// <see cref="MoveFirst(LockingInfo)"/>. Otherwise, move the cursor to
1530        /// the next non-duplicate key in the database, and store that key and
1531        /// associated datum in <see cref="Current"/>. MoveNextUnique will
1532        /// return false if no non-duplicate key/data pairs exist after the
1533        /// cursor position in the database.
1534        /// </summary>
1535        /// <remarks>
1536        /// <para>
1537        /// If the database is a Queue or Recno database, MoveNextUnique will
1538        /// ignore any keys that exist but were never explicitly created by the
1539        /// application, or those that were created and later deleted.
1540        /// </para>
1541        /// <para>
1542        /// If positioning the cursor fails, <see cref="Current"/> will contain
1543        /// an empty <see cref="KeyValuePair{T,T}"/>.
1544        /// </para>
1545        /// </remarks>
1546        /// <param name="info">The locking behavior to use.</param>
1547        /// <returns>
1548        /// True if the cursor was positioned successfully, false otherwise.
1549        /// </returns>
1550        public bool MoveNextUnique(LockingInfo info) {
1551            DatabaseEntry key = new DatabaseEntry();
1552            DatabaseEntry data = new DatabaseEntry();
1553
1554            return Get(key, data, DbConstants.DB_NEXT_NODUP, info);
1555        }
1556
1557        /// <summary>
1558        /// If the cursor is not yet initialized, MoveNextUniqueMultiple is
1559        /// identical to <see cref="MoveFirstMultiple()"/>. Otherwise, move the
1560        /// cursor to the next non-duplicate key in the database, and store that
1561        /// key and associated datum and as many duplicate data items that can
1562        /// fit in a buffer the size of one database page in
1563        /// <see cref="CurrentMultiple"/>. MoveNextUniqueMultiple will return
1564        /// false if no non-duplicate key/data pairs exist after the cursor
1565        /// position in the database.
1566        /// </summary>
1567        /// <returns>
1568        /// True if the cursor was positioned successfully, false otherwise.
1569        /// </returns>
1570        public bool MoveNextUniqueMultiple() {
1571            return MoveNextUniqueMultiple((int)pgsz, null);
1572        }
1573        /// <summary>
1574        /// If the cursor is not yet initialized, MoveNextUniqueMultiple is
1575        /// identical to <see cref="MoveFirstMultiple(int)"/>. Otherwise, move
1576        /// the cursor to the next non-duplicate key in the database, and store
1577        /// that key and associated datum and as many duplicate data items that
1578        /// can fit in a buffer the size of <paramref name="BufferSize"/> in
1579        /// <see cref="CurrentMultiple"/>. MoveNextUniqueMultiple will return
1580        /// false if no non-duplicate key/data pairs exist after the cursor
1581        /// position in the database.
1582        /// </summary>
1583        /// <param name="BufferSize">
1584        /// The size of a buffer to fill with duplicate data items.  Must be at
1585        /// least the page size of the underlying database and be a multiple of
1586        /// 1024.
1587        /// </param>
1588        /// <returns>
1589        /// True if the cursor was positioned successfully, false otherwise.
1590        /// </returns>
1591        public bool MoveNextUniqueMultiple(int BufferSize) {
1592            return MoveNextUniqueMultiple(BufferSize, null);
1593        }
1594        /// <summary>
1595        /// If the cursor is not yet initialized, MoveNextUniqueMultiple is
1596        /// identical to <see cref="MoveFirstMultiple(LockingInfo)"/>.
1597        /// Otherwise, move the cursor to the next non-duplicate key in the
1598        /// database, and store that key and associated datum and as many
1599        /// duplicate data items that can fit in a buffer the size of one
1600        /// database page in <see cref="CurrentMultiple"/>.
1601        /// MoveNextUniqueMultiple will return false if no non-duplicate
1602        /// key/data pairs exist after the cursor position in the database.
1603        /// </summary>
1604        /// <param name="info">The locking behavior to use.</param>
1605        /// <returns>
1606        /// True if the cursor was positioned successfully, false otherwise.
1607        /// </returns>
1608        public bool MoveNextUniqueMultiple(LockingInfo info) {
1609            return MoveNextUniqueMultiple((int)pgsz, info);
1610        }
1611        /// <summary>
1612        /// If the cursor is not yet initialized, MoveNextUniqueMultiple is
1613        /// identical to <see cref="MoveFirstMultiple(int, LockingInfo)"/>.
1614        /// Otherwise, move the cursor to the next non-duplicate key in the
1615        /// database, and store that key and associated datum and as many
1616        /// duplicate data items that can fit in a buffer the size of
1617        /// <paramref name="BufferSize"/> in <see cref="CurrentMultiple"/>.
1618        /// MoveNextUniqueMultiple will return false if no non-duplicate
1619        /// key/data pairs exist after the cursor position in the database.
1620        /// </summary>
1621        /// <param name="BufferSize">
1622        /// The size of a buffer to fill with duplicate data items.  Must be at
1623        /// least the page size of the underlying database and be a multiple of
1624        /// 1024.
1625        /// </param>
1626        /// <param name="info">The locking behavior to use.</param>
1627        /// <returns>
1628        /// True if the cursor was positioned successfully, false otherwise.
1629        /// </returns>
1630        public bool MoveNextUniqueMultiple(int BufferSize, LockingInfo info) {
1631            DatabaseEntry key = new DatabaseEntry();
1632            DatabaseEntry data = new DatabaseEntry();
1633
1634            return GetMultiple(
1635                key, data, BufferSize, DbConstants.DB_NEXT_NODUP, info, false);
1636        }
1637
1638        /// <summary>
1639        /// If the cursor is not yet initialized, MoveNextUniqueMultipleKey is
1640        /// identical to <see cref="MoveFirstMultipleKey()"/>. Otherwise, move
1641        /// the cursor to the next non-duplicate key in the database, and store
1642        /// that key and associated datum and as many ensuing key/data pairs
1643        /// that can fit in a buffer the size of one database page in
1644        /// <see cref="CurrentMultipleKey"/>. MoveNextUniqueMultipleKey will
1645        /// return false if no non-duplicate key/data pairs exist after the
1646        /// cursor position in the database.
1647        /// </summary>
1648        /// <returns>
1649        /// True if the cursor was positioned successfully, false otherwise.
1650        /// </returns>
1651        public bool MoveNextUniqueMultipleKey() {
1652            return MoveNextUniqueMultipleKey((int)pgsz, null);
1653        }
1654        /// <summary>
1655        /// If the cursor is not yet initialized, MoveNextUniqueMultipleKey is
1656        /// identical to <see cref="MoveFirstMultipleKey(int)"/>. Otherwise,
1657        /// move the cursor to the next non-duplicate key in the database, and
1658        /// store that key and associated datum and as many ensuing key/data
1659        /// pairs that can fit in a buffer the size of
1660        /// <paramref name="BufferSize"/> in <see cref="CurrentMultipleKey"/>.
1661        /// MoveNextUniqueMultipleKey will return false if no non-duplicate
1662        /// key/data pairs exist after the cursor position in the database.
1663        /// </summary>
1664        /// <param name="BufferSize">
1665        /// The size of a buffer to fill with key/data pairs.  Must be at least
1666        /// the page size of the underlying database and be a multiple of 1024.
1667        /// </param>
1668        /// <returns>
1669        /// True if the cursor was positioned successfully, false otherwise.
1670        /// </returns>
1671        public bool MoveNextUniqueMultipleKey(int BufferSize) {
1672            return MoveNextUniqueMultipleKey(BufferSize, null);
1673        }
1674        /// <summary>
1675        /// If the cursor is not yet initialized, MoveNextUniqueMultipleKey is
1676        /// identical to <see cref="MoveFirstMultipleKey(LockingInfo)"/>.
1677        /// Otherwise, move the cursor to the next non-duplicate key in the
1678        /// database, and store that key and associated datum and as many
1679        /// ensuing key/data pairs that can fit in a buffer the size of one
1680        /// database page in <see cref="CurrentMultipleKey"/>.
1681        /// MoveNextUniqueMultipleKey will return false if no non-duplicate
1682        /// key/data pairs exist after the cursor position in the database.
1683        /// </summary>
1684        /// <param name="info">The locking behavior to use.</param>
1685        /// <returns>
1686        /// True if the cursor was positioned successfully, false otherwise.
1687        /// </returns>
1688        public bool MoveNextUniqueMultipleKey(LockingInfo info) {
1689            return MoveNextUniqueMultipleKey((int)pgsz, info);
1690        }
1691        /// <summary>
1692        /// If the cursor is not yet initialized, MoveNextUniqueMultipleKey is
1693        /// identical to <see cref="MoveFirstMultipleKey(int, LockingInfo)"/>.
1694        /// Otherwise, move the cursor to the next non-duplicate key in the
1695        /// database, and store that key and associated datum and as many
1696        /// ensuing key/data pairs that can fit in a buffer the size of
1697        /// <paramref name="BufferSize"/> in <see cref="CurrentMultipleKey"/>.
1698        /// MoveNextUniqueMultipleKey will return false if no non-duplicate
1699        /// key/data pairs exist after the cursor position in the database.
1700        /// </summary>
1701        /// <param name="BufferSize">
1702        /// The size of a buffer to fill with key/data pairs.  Must be at least
1703        /// the page size of the underlying database and be a multiple of 1024.
1704        /// </param>
1705        /// <param name="info">The locking behavior to use.</param>
1706        /// <returns>
1707        /// True if the cursor was positioned successfully, false otherwise.
1708        /// </returns>
1709        public bool MoveNextUniqueMultipleKey(
1710            int BufferSize, LockingInfo info) {
1711            DatabaseEntry key = new DatabaseEntry();
1712            DatabaseEntry data = new DatabaseEntry();
1713
1714            return GetMultiple(
1715                key, data, BufferSize, DbConstants.DB_NEXT_NODUP, info, true);
1716        }
1717
1718        /// <summary>
1719        /// If the cursor is not yet initialized, MovePrev is identical to
1720        /// <see cref="MoveLast()"/>. Otherwise, move the cursor to the previous
1721        /// key/data pair of the database, and store that pair in
1722        /// <see cref="Current"/>. In the presence of duplicate key values, the
1723        /// value of <see cref="Current">Current.Key</see> may not change.
1724        /// </summary>
1725        /// <remarks>
1726        /// If positioning the cursor fails, <see cref="Current"/> will contain
1727        /// an empty <see cref="KeyValuePair{T,T}"/>.
1728        /// </remarks>
1729        /// <returns>
1730        /// True if the cursor was positioned successfully, false otherwise.
1731        /// </returns>
1732        public bool MovePrev() { return MovePrev(null); }
1733        /// <summary>
1734        /// If the cursor is not yet initialized, MovePrev is identical to
1735        /// <see cref="MoveLast(LockingInfo)"/>. Otherwise, move the cursor to
1736        /// the previous key/data pair of the database, and store that pair in
1737        /// <see cref="Current"/>. In the presence of duplicate key values, the
1738        /// value of <see cref="Current">Current.Key</see> may not change.
1739        /// </summary>
1740        /// <remarks>
1741        /// If positioning the cursor fails, <see cref="Current"/> will contain
1742        /// an empty <see cref="KeyValuePair{T,T}"/>.
1743        /// </remarks>
1744        /// <param name="info">The locking behavior to use.</param>
1745        /// <returns>
1746        /// True if the cursor was positioned successfully, false otherwise.
1747        /// </returns>
1748        public bool MovePrev(LockingInfo info) {
1749            DatabaseEntry key = new DatabaseEntry();
1750            DatabaseEntry data = new DatabaseEntry();
1751
1752            return Get(key, data, DbConstants.DB_PREV, info);
1753        }
1754
1755        /// <summary>
1756        /// If the previous key/data pair of the database is a duplicate data
1757        /// record for the current key/data pair, the cursor is moved to the
1758        /// previous key/data pair of the database, and that pair is stored in
1759        /// <see cref="Current"/>. MovePrevDuplicate will return false if the
1760        /// previous key/data pair of the database is not a duplicate data
1761        /// record for the current key/data pair.
1762        /// </summary>
1763        /// <remarks>
1764        /// If positioning the cursor fails, <see cref="Current"/> will contain
1765        /// an empty <see cref="KeyValuePair{T,T}"/>.
1766        /// </remarks>
1767        /// <returns>
1768        /// True if the cursor was positioned successfully, false otherwise.
1769        /// </returns>
1770        public bool MovePrevDuplicate() { return MovePrevDuplicate(null); }
1771        /// <summary>
1772        /// If the previous key/data pair of the database is a duplicate data
1773        /// record for the current key/data pair, the cursor is moved to the
1774        /// previous key/data pair of the database, and that pair is stored in
1775        /// <see cref="Current"/>. MovePrevDuplicate will return false if the
1776        /// previous key/data pair of the database is not a duplicate data
1777        /// record for the current key/data pair.
1778        /// </summary>
1779        /// <remarks>
1780        /// If positioning the cursor fails, <see cref="Current"/> will contain
1781        /// an empty <see cref="KeyValuePair{T,T}"/>.
1782        /// </remarks>
1783        /// <param name="info">The locking behavior to use.</param>
1784        /// <returns>
1785        /// True if the cursor was positioned successfully, false otherwise.
1786        /// </returns>
1787        public bool MovePrevDuplicate(LockingInfo info) {
1788            DatabaseEntry key = new DatabaseEntry();
1789            DatabaseEntry data = new DatabaseEntry();
1790
1791            return Get(key, data, DbConstants.DB_PREV_DUP, info);
1792        }
1793
1794        /// <summary>
1795        /// If the cursor is not yet initialized, MovePrevUnique is identical to
1796        /// <see cref="MoveLast()"/>. Otherwise, move the cursor to the previous
1797        /// non-duplicate key in the database, and store that key and associated
1798        /// datum in <see cref="Current"/>. MovePrevUnique will return false if
1799        /// no non-duplicate key/data pairs exist after the cursor position in
1800        /// the database.
1801        /// </summary>
1802        /// <remarks>
1803        /// If positioning the cursor fails, <see cref="Current"/> will contain
1804        /// an empty <see cref="KeyValuePair{T,T}"/>.
1805        /// </remarks>
1806        /// <returns>
1807        /// True if the cursor was positioned successfully, false otherwise.
1808        /// </returns>
1809        public bool MovePrevUnique() { return MovePrevUnique(null); }
1810        /// <summary>
1811        /// If the cursor is not yet initialized, MovePrevUnique is identical to
1812        /// <see cref="MoveLast(LockingInfo)"/>. Otherwise, move the cursor to
1813        /// the previous non-duplicate key in the database, and store that key
1814        /// and associated datum in <see cref="Current"/>. MovePrevUnique will
1815        /// return false if no non-duplicate key/data pairs exist after the
1816        /// cursor position in the database.
1817        /// </summary>
1818        /// <remarks>
1819        /// If positioning the cursor fails, <see cref="Current"/> will contain
1820        /// an empty <see cref="KeyValuePair{T,T}"/>.
1821        /// </remarks>
1822        /// <param name="info">The locking behavior to use.</param>
1823        /// <returns>
1824        /// True if the cursor was positioned successfully, false otherwise.
1825        /// </returns>
1826        public bool MovePrevUnique(LockingInfo info) {
1827            DatabaseEntry key = new DatabaseEntry();
1828            DatabaseEntry data = new DatabaseEntry();
1829
1830            return Get(key, data, DbConstants.DB_PREV_NODUP, info);
1831        }
1832
1833        /// <summary>
1834        /// Overwrite the data of the key/data pair to which the cursor refers
1835        /// with the specified data item.
1836        /// </summary>
1837        /// <param name="data"></param>
1838        public void Overwrite(DatabaseEntry data) {
1839            DatabaseEntry key = new DatabaseEntry();
1840
1841            Put(key, data, DbConstants.DB_CURRENT);
1842        }
1843
1844        /// <summary>
1845        /// Store the key/data pair to which the cursor refers in
1846        /// <see cref="Current"/>.
1847        /// </summary>
1848        /// <remarks>
1849        /// If positioning the cursor fails, <see cref="Current"/> will contain
1850        /// an empty <see cref="KeyValuePair{T,T}"/>.
1851        /// </remarks>
1852        /// <returns>
1853        /// True if the cursor was positioned successfully, false otherwise.
1854        /// </returns>
1855        public bool Refresh() { return Refresh(null); }
1856        /// <summary>
1857        /// Store the key/data pair to which the cursor refers in
1858        /// <see cref="Current"/>.
1859        /// </summary>
1860        /// <remarks>
1861        /// If positioning the cursor fails, <see cref="Current"/> will contain
1862        /// an empty <see cref="KeyValuePair{T,T}"/>.
1863        /// </remarks>
1864        /// <param name="info">The locking behavior to use.</param>
1865        /// <returns>
1866        /// True if the cursor was positioned successfully, false otherwise.
1867        /// </returns>
1868        public bool Refresh(LockingInfo info) {
1869            DatabaseEntry key = new DatabaseEntry();
1870            DatabaseEntry data = new DatabaseEntry();
1871
1872            return Get(key, data, DbConstants.DB_CURRENT, info);
1873        }
1874
1875        /// <summary>
1876        /// Store the key/data pair to which the cursor refers and as many
1877        /// duplicate data items that can fit in a buffer the size of one
1878        /// database page in <see cref="CurrentMultiple"/>.
1879        /// </summary>
1880        /// <returns>
1881        /// True if the cursor was positioned successfully, false otherwise.
1882        /// </returns>
1883        public bool RefreshMultiple() {
1884            return RefreshMultiple((int)pgsz, null);
1885        }
1886        /// <summary>
1887        /// Store the key/data pair to which the cursor refers and as many
1888        /// duplicate data items that can fit in a buffer the size of
1889        /// <paramref name="BufferSize"/> in <see cref="CurrentMultiple"/>.
1890        /// </summary>
1891        /// <param name="BufferSize">
1892        /// The size of a buffer to fill with duplicate data items.  Must be at
1893        /// least the page size of the underlying database and be a multiple of
1894        /// 1024.
1895        /// </param>
1896        /// <returns>
1897        /// True if the cursor was positioned successfully, false otherwise.
1898        /// </returns>
1899        public bool RefreshMultiple(int BufferSize) {
1900            return RefreshMultiple(BufferSize, null);
1901        }
1902        /// <summary>
1903        /// Store the key/data pair to which the cursor refers and as many
1904        /// duplicate data items that can fit in a buffer the size of one
1905        /// database page in <see cref="CurrentMultiple"/>.
1906        /// </summary>
1907        /// <param name="info">The locking behavior to use.</param>
1908        /// <returns>
1909        /// True if the cursor was positioned successfully, false otherwise.
1910        /// </returns>
1911        public bool RefreshMultiple(LockingInfo info) {
1912            return RefreshMultiple((int)pgsz, info);
1913        }
1914        /// <summary>
1915        /// Store the key/data pair to which the cursor refers and as many
1916        /// duplicate data items that can fit in a buffer the size of
1917        /// <paramref name="BufferSize"/> in <see cref="CurrentMultiple"/>.
1918        /// </summary>
1919        /// <param name="BufferSize">
1920        /// The size of a buffer to fill with duplicate data items.  Must be at
1921        /// least the page size of the underlying database and be a multiple of
1922        /// 1024.
1923        /// </param>
1924        /// <param name="info">The locking behavior to use.</param>
1925        /// <returns>
1926        /// True if the cursor was positioned successfully, false otherwise.
1927        /// </returns>
1928        public bool RefreshMultiple(int BufferSize, LockingInfo info) {
1929            DatabaseEntry key = new DatabaseEntry();
1930            DatabaseEntry data = new DatabaseEntry();
1931
1932            return GetMultiple(
1933                key, data, BufferSize, DbConstants.DB_CURRENT, info, false);
1934        }
1935
1936        /// <summary>
1937        /// Store the key/data pair to which the cursor refers and as many
1938        /// ensuing key/data pairs that can fit in a buffer the size of one
1939        /// database page in <see cref="CurrentMultipleKey"/>.
1940        /// </summary>
1941        /// <returns>
1942        /// True if the cursor was positioned successfully, false otherwise.
1943        /// </returns>
1944        public bool RefreshMultipleKey() {
1945            return RefreshMultipleKey((int)pgsz, null);
1946        }
1947        /// <summary>
1948        /// Store the key/data pair to which the cursor refers and as many
1949        /// ensuing key/data pairs that can fit in a buffer the size of
1950        /// <paramref name="BufferSize"/> in <see cref="CurrentMultipleKey"/>.
1951        /// </summary>
1952        /// <param name="BufferSize">
1953        /// The size of a buffer to fill with key/data pairs.  Must be at least
1954        /// the page size of the underlying database and be a multiple of 1024.
1955        /// </param>
1956        /// <returns>
1957        /// True if the cursor was positioned successfully, false otherwise.
1958        /// </returns>
1959        public bool RefreshMultipleKey(int BufferSize) {
1960            return RefreshMultipleKey(BufferSize, null);
1961        }
1962        /// <summary>
1963        /// Store the key/data pair to which the cursor refers and as many
1964        /// ensuing key/data pairs that can fit in a buffer the size of one
1965        /// database page in <see cref="CurrentMultipleKey"/>.
1966        /// </summary>
1967        /// <param name="info">The locking behavior to use.</param>
1968        /// <returns>
1969        /// True if the cursor was positioned successfully, false otherwise.
1970        /// </returns>
1971        public bool RefreshMultipleKey(LockingInfo info) {
1972            return RefreshMultipleKey((int)pgsz, info);
1973        }
1974        /// <summary>
1975        /// Store the key/data pair to which the cursor refers and as many
1976        /// ensuing key/data pairs that can fit in a buffer the size of
1977        /// <paramref name="BufferSize"/> in <see cref="CurrentMultipleKey"/>.
1978        /// </summary>
1979        /// <param name="BufferSize">
1980        /// The size of a buffer to fill with key/data pairs.  Must be at least
1981        /// the page size of the underlying database and be a multiple of 1024.
1982        /// </param>
1983        /// <param name="info">The locking behavior to use.</param>
1984        /// <returns>
1985        /// True if the cursor was positioned successfully, false otherwise.
1986        /// </returns>
1987        public bool RefreshMultipleKey(int BufferSize, LockingInfo info) {
1988            DatabaseEntry key = new DatabaseEntry();
1989            DatabaseEntry data = new DatabaseEntry();
1990
1991            return GetMultiple(
1992                key, data, BufferSize, DbConstants.DB_CURRENT, info, true);
1993        }
1994    }
1995}
1996