/*-
* 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);
}
}
}