/*- * See the file LICENSE for redistribution information. * * Copyright (c) 2009 Oracle. All rights reserved. * */ using System; using System.Collections; using System.Collections.Generic; using System.Text; using BerkeleyDB.Internal; namespace BerkeleyDB { /// /// A class representing database cursors over secondary indexes, which /// allow for traversal of database records. /// public class SecondaryCursor : BaseCursor, IEnumerable>> { private KeyValuePair> cur; /// /// The secondary key and primary key/data pair at which the cursor /// currently points. /// public KeyValuePair> Current { get { return cur; } private set { cur = value; } } internal SecondaryCursor(DBC dbc) : base(dbc) { } /// /// Protected method wrapping DBC->pget() /// /// The secondary key /// The primary key /// The primary data /// Flags to pass to DBC->pget /// Locking parameters /// protected bool PGet( DatabaseEntry key, DatabaseEntry pkey, DatabaseEntry data, uint flags, LockingInfo info) { flags |= (info == null) ? 0 : info.flags; try { dbc.pget(key, pkey, data, flags); Current = new KeyValuePair>(key, new KeyValuePair(pkey, data)); return true; } catch (NotFoundException) { Current = new KeyValuePair>( null, new KeyValuePair()); return false; } } /// /// Delete the key/data pair to which the cursor refers from the primary /// database and all secondary indices. /// /// /// /// The cursor position is unchanged after a delete, and subsequent /// calls to cursor functions expecting the cursor to refer to an /// existing key will fail. /// /// /// /// The element has already been deleted. /// public new void Delete() { base.Delete(); Current = new KeyValuePair>( null, new KeyValuePair()); } /// /// Create a new cursor that uses the same transaction and locker ID as /// the original cursor. /// /// /// This is useful when an application is using locking and requires two /// or more cursors in the same thread of control. /// /// /// If true, the newly created cursor is initialized to refer to the /// same position in the database as the original cursor (if any) and /// hold the same locks (if any). If false, or the original cursor does /// not hold a database position and locks, the created cursor is /// uninitialized and will behave like a cursor newly created by /// . /// A newly created cursor public SecondaryCursor Duplicate(bool keepPosition) { return new SecondaryCursor( dbc.dup(keepPosition ? DbConstants.DB_POSITION : 0)); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } /// /// Returns an enumerator that iterates through the /// . /// /// /// The enumerator will begin at the cursor's current position (or the /// first record if the cursor has not yet been positioned) and iterate /// forwards (i.e. in the direction of ) over the /// remaining records. /// /// An enumerator for the SecondaryCursor. public new IEnumerator>> GetEnumerator() { while (MoveNext()) yield return Current; } /// /// Set the cursor to refer to the first key/data pair of the database, /// and store the secondary key along with the corresponding primary /// key/data pair in . If the first key has /// duplicate values, the first data item in the set of duplicates is /// stored in . /// /// /// If positioning the cursor fails, will contain /// an empty . /// /// /// True if the cursor was positioned successfully, false otherwise. /// public bool MoveFirst() { return MoveFirst(null); } /// /// Set the cursor to refer to the first key/data pair of the database, /// and store the secondary key along with the corresponding primary /// key/data pair in . If the first key has /// duplicate values, the first data item in the set of duplicates is /// stored in . /// /// /// If positioning the cursor fails, will contain /// an empty . /// /// The locking behavior to use. /// /// True if the cursor was positioned successfully, false otherwise. /// public bool MoveFirst(LockingInfo info) { DatabaseEntry key = new DatabaseEntry(); DatabaseEntry pkey = new DatabaseEntry(); DatabaseEntry data = new DatabaseEntry(); return PGet(key, pkey, data, DbConstants.DB_FIRST, info); } /// /// Set the cursor to refer to , and store the /// primary key/data pair associated with the given secondary key in /// . In the presence of duplicate key values, the /// first data item in the set of duplicates is stored in /// . /// /// /// If positioning the cursor fails, will contain /// an empty . /// /// The key at which to position the cursor /// /// If true, require the given key to match the key in the database /// exactly. If false, position the cursor at the smallest key greater /// than or equal to the specified key, permitting partial key matches /// and range searches. /// /// /// True if the cursor was positioned successfully, false otherwise. /// public bool Move(DatabaseEntry key, bool exact) { return Move(key, exact, null); } /// /// Set the cursor to refer to , and store the /// primary key/data pair associated with the given secondary key in /// . In the presence of duplicate key values, the /// first data item in the set of duplicates is stored in /// . /// /// /// If positioning the cursor fails, will contain /// an empty . /// /// The key at which to position the cursor /// /// If true, require the given key to match the key in the database /// exactly. If false, position the cursor at the smallest key greater /// than or equal to the specified key, permitting partial key matches /// and range searches. /// /// The locking behavior to use. /// /// True if the cursor was positioned successfully, false otherwise. /// public bool Move(DatabaseEntry key, bool exact, LockingInfo info) { DatabaseEntry pkey = new DatabaseEntry(); DatabaseEntry data = new DatabaseEntry(); return PGet(key, pkey, data, exact ? DbConstants.DB_SET : DbConstants.DB_SET_RANGE, info); } /// /// Move the cursor to the specified key/data pair of the database. The /// cursor is positioned to a key/data pair if both the key and data /// match the values provided on the key and data parameters. /// /// /// /// If positioning the cursor fails, will contain /// an empty . /// /// /// If this flag is specified on a database configured without sorted /// duplicate support, the value of is ignored. /// /// /// /// The key/data pair at which to position the cursor. /// /// /// If true, require the given key and data to match the key and data /// in the database exactly. If false, position the cursor at the /// smallest data value which is greater than or equal to the value /// provided by (as determined by the /// comparison function). /// /// /// True if the cursor was positioned successfully, false otherwise. /// public bool Move(KeyValuePair> pair, bool exact) { return Move(pair, exact, null); } /// /// Move the cursor to the specified key/data pair of the database. The /// cursor is positioned to a key/data pair if both the key and data /// match the values provided on the key and data parameters. /// /// /// /// If positioning the cursor fails, will contain /// an empty . /// /// /// If this flag is specified on a database configured without sorted /// duplicate support, the value of is ignored. /// /// /// /// The key/data pair at which to position the cursor. /// /// /// If true, require the given key and data to match the key and data /// in the database exactly. If false, position the cursor at the /// smallest data value which is greater than or equal to the value /// provided by (as determined by the /// comparison function). /// /// The locking behavior to use. /// /// True if the cursor was positioned successfully, false otherwise. /// public bool Move(KeyValuePair> pair, bool exact, LockingInfo info) { return PGet(pair.Key, pair.Value.Key, pair.Value.Value, exact ? DbConstants.DB_GET_BOTH : DbConstants.DB_GET_BOTH_RANGE, info); } /// /// Set the cursor to refer to the last key/data pair of the database, /// and store the secondary key and primary key/data pair in /// . If the last key has duplicate values, the /// last data item in the set of duplicates is stored in /// . /// /// /// If positioning the cursor fails, will contain /// an empty . /// /// /// True if the cursor was positioned successfully, false otherwise. /// public bool MoveLast() { return MoveLast(null); } /// /// Set the cursor to refer to the last key/data pair of the database, /// and store the secondary key and primary key/data pair in /// . If the last key has duplicate values, the /// last data item in the set of duplicates is stored in /// . /// /// /// If positioning the cursor fails, will contain /// an empty . /// /// The locking behavior to use. /// /// True if the cursor was positioned successfully, false otherwise. /// public bool MoveLast(LockingInfo info) { DatabaseEntry key = new DatabaseEntry(); DatabaseEntry pkey = new DatabaseEntry(); DatabaseEntry data = new DatabaseEntry(); return PGet(key, pkey, data, DbConstants.DB_LAST, info); } /// /// If the cursor is not yet initialized, MoveNext is identical to /// . Otherwise, move the cursor to the next /// key/data pair of the database, and store the secondary key and /// primary key/data pair in . In the presence of /// duplicate key values, the value of Current.Key /// may not change. /// /// /// If positioning the cursor fails, will contain /// an empty . /// /// /// True if the cursor was positioned successfully, false otherwise. /// public bool MoveNext() { return MoveNext(null); } /// /// If the cursor is not yet initialized, MoveNext is identical to /// . Otherwise, move the cursor to the next /// key/data pair of the database, and store the secondary key and /// primary key/data pair in . In the presence of /// duplicate key values, the value of Current.Key /// may not change. /// /// /// If positioning the cursor fails, will contain /// an empty . /// /// The locking behavior to use. /// /// True if the cursor was positioned successfully, false otherwise. /// public bool MoveNext(LockingInfo info) { DatabaseEntry key = new DatabaseEntry(); DatabaseEntry pkey = new DatabaseEntry(); DatabaseEntry data = new DatabaseEntry(); return PGet(key, pkey, data, DbConstants.DB_NEXT, info); } /// /// If the next key/data pair of the database is a duplicate data record /// for the current key/data pair, move the cursor to the next key/data /// pair in the database, and store the secondary key and primary /// key/data pair in . MoveNextDuplicate will /// return false if the next key/data pair of the database is not a /// duplicate data record for the current key/data pair. /// /// /// If positioning the cursor fails, will contain /// an empty . /// /// /// True if the cursor was positioned successfully, false otherwise. /// public bool MoveNextDuplicate() { return MoveNextDuplicate(null); } /// /// If the next key/data pair of the database is a duplicate data record /// for the current key/data pair, move the cursor to the next key/data /// pair in the database, and store the secondary key and primary /// key/data pair in . MoveNextDuplicate will /// return false if the next key/data pair of the database is not a /// duplicate data record for the current key/data pair. /// /// /// If positioning the cursor fails, will contain /// an empty . /// /// The locking behavior to use. /// /// True if the cursor was positioned successfully, false otherwise. /// public bool MoveNextDuplicate(LockingInfo info) { DatabaseEntry key = new DatabaseEntry(); DatabaseEntry pkey = new DatabaseEntry(); DatabaseEntry data = new DatabaseEntry(); return PGet(key, pkey, data, DbConstants.DB_NEXT_DUP, info); } /// /// If the cursor is not yet initialized, MoveNextUnique is identical to /// . Otherwise, move the cursor to the next /// non-duplicate key in the database, and store the secondary key and /// primary key/data pair in . MoveNextUnique will /// return false if no non-duplicate key/data pairs exist after the /// cursor position in the database. /// /// /// If positioning the cursor fails, will contain /// an empty . /// /// /// True if the cursor was positioned successfully, false otherwise. /// public bool MoveNextUnique() { return MoveNextUnique(null); } /// /// If the cursor is not yet initialized, MoveNextUnique is identical to /// . Otherwise, move the cursor to the next /// non-duplicate key in the database, and store the secondary key and /// primary key/data pair in . MoveNextUnique will /// return false if no non-duplicate key/data pairs exist after the /// cursor position in the database. /// /// /// /// If the database is a Queue or Recno database, MoveNextUnique will /// ignore any keys that exist but were never explicitly created by the /// application, or those that were created and later deleted. /// /// /// If positioning the cursor fails, will contain /// an empty . /// /// /// The locking behavior to use. /// /// True if the cursor was positioned successfully, false otherwise. /// public bool MoveNextUnique(LockingInfo info) { DatabaseEntry key = new DatabaseEntry(); DatabaseEntry pkey = new DatabaseEntry(); DatabaseEntry data = new DatabaseEntry(); return PGet(key, pkey, data, DbConstants.DB_NEXT_NODUP, info); } /// /// If the cursor is not yet initialized, MovePrev is identical to /// . Otherwise, move the cursor to the previous /// key/data pair of the database, and store the secondary key and /// primary key/data pair in . In the presence of /// duplicate key values, the value of Current.Key /// may not change. /// /// /// If positioning the cursor fails, will contain /// an empty . /// /// /// True if the cursor was positioned successfully, false otherwise. /// public bool MovePrev() { return MovePrev(null); } /// /// If the cursor is not yet initialized, MovePrev is identical to /// . Otherwise, move the cursor to /// the previous key/data pair of the database, and store the secondary /// key and primary key/data pair in . In the /// presence of duplicate key values, the value of /// Current.Key may not change. /// /// /// If positioning the cursor fails, will contain /// an empty . /// /// The locking behavior to use. /// /// True if the cursor was positioned successfully, false otherwise. /// public bool MovePrev(LockingInfo info) { DatabaseEntry key = new DatabaseEntry(); DatabaseEntry pkey = new DatabaseEntry(); DatabaseEntry data = new DatabaseEntry(); return PGet(key, pkey, data, DbConstants.DB_PREV, info); } /// /// If the previous key/data pair of the database is a duplicate data /// record for the current key/data pair, the cursor is moved to the /// previous key/data pair of the database, and the secondary key and /// primary key/data pair in . MovePrevDuplicate /// will return false if the previous key/data pair of the database is /// not a duplicate data record for the current key/data pair. /// /// /// If positioning the cursor fails, will contain /// an empty . /// /// /// True if the cursor was positioned successfully, false otherwise. /// public bool MovePrevDuplicate() { return MovePrevDuplicate(null); } /// /// If the previous key/data pair of the database is a duplicate data /// record for the current key/data pair, the cursor is moved to the /// previous key/data pair of the database, and the secondary key and /// primary key/data pair in . MovePrevDuplicate /// will return false if the previous key/data pair of the database is /// not a duplicate data record for the current key/data pair. /// /// /// If positioning the cursor fails, will contain /// an empty . /// /// The locking behavior to use. /// /// True if the cursor was positioned successfully, false otherwise. /// public bool MovePrevDuplicate(LockingInfo info) { DatabaseEntry key = new DatabaseEntry(); DatabaseEntry pkey = new DatabaseEntry(); DatabaseEntry data = new DatabaseEntry(); return PGet(key, pkey, data, DbConstants.DB_PREV_DUP, info); } /// /// If the cursor is not yet initialized, MovePrevUnique is identical to /// . Otherwise, move the cursor to the previous /// non-duplicate key in the database, and store the secondary key and /// primary key/data pair in . MovePrevUnique will /// return false if no non-duplicate key/data pairs exist after the /// cursor position in the database. /// /// /// If positioning the cursor fails, will contain /// an empty . /// /// /// True if the cursor was positioned successfully, false otherwise. /// public bool MovePrevUnique() { return MovePrevUnique(null); } /// /// If the cursor is not yet initialized, MovePrevUnique is identical to /// . Otherwise, move the cursor to /// the previous non-duplicate key in the database, and store the /// secondary key and primary key/data pair in . /// MovePrevUnique will return false if no non-duplicate key/data pairs /// exist after the cursor position in the database. /// /// /// If positioning the cursor fails, will contain /// an empty . /// /// The locking behavior to use. /// /// True if the cursor was positioned successfully, false otherwise. /// public bool MovePrevUnique(LockingInfo info) { DatabaseEntry key = new DatabaseEntry(); DatabaseEntry pkey = new DatabaseEntry(); DatabaseEntry data = new DatabaseEntry(); return PGet(key, pkey, data, DbConstants.DB_PREV_NODUP, info); } /// /// Store the secondary key and primary key/data pair to which the /// cursor refers in . /// /// /// If positioning the cursor fails, will contain /// an empty . /// /// /// True if the cursor was positioned successfully, false otherwise. /// public bool Refresh() { return Refresh(null); } /// /// Store the secondary key and primary key/data pair to which the /// cursor refers in . /// /// /// If positioning the cursor fails, will contain /// an empty . /// /// The locking behavior to use. /// /// True if the cursor was positioned successfully, false otherwise. /// public bool Refresh(LockingInfo info) { DatabaseEntry key = new DatabaseEntry(); DatabaseEntry pkey = new DatabaseEntry(); DatabaseEntry data = new DatabaseEntry(); return PGet(key, pkey, data, DbConstants.DB_CURRENT, info); } } }