//----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. // //----------------------------------------------------------------------- namespace Microsoft.Isam.Esent.Interop { using System; using System.Collections.Generic; using System.Diagnostics; /// /// Helper methods for the ESENT API. These aren't interop versions /// of the API, but encapsulate very common uses of the functions. /// public static partial class Api { /// /// Position the cursor before the first record in the table. A /// subsequent move next will position the cursor on the first /// record. /// /// The session to use. /// The table to position. public static void MoveBeforeFirst(JET_SESID sesid, JET_TABLEID tableid) { Api.TryMoveFirst(sesid, tableid); Api.TryMovePrevious(sesid, tableid); } /// /// Position the cursor after the last record in the table. A /// subsequent move previous will position the cursor on the /// last record. /// /// The session to use. /// The table to position. public static void MoveAfterLast(JET_SESID sesid, JET_TABLEID tableid) { Api.TryMoveLast(sesid, tableid); Api.TryMoveNext(sesid, tableid); } /// /// Try to navigate through an index. If the navigation succeeds this /// method returns true. If there is no record to navigate to this /// method returns false; an exception will be thrown for other errors. /// /// The session to use. /// The cursor to position. /// The direction to move in. /// Move options. /// True if the move was successful. public static bool TryMove(JET_SESID sesid, JET_TABLEID tableid, JET_Move move, MoveGrbit grbit) { var err = (JET_err)Impl.JetMove(sesid, tableid, (int)move, grbit); if (JET_err.NoCurrentRecord == err) { return false; } Api.Check((int)err); Debug.Assert(err >= JET_err.Success, "Exception should have been thrown in case of error"); return true; } /// /// Try to move to the first record in the table. If the table is empty this /// returns false, if a different error is encountered an exception is thrown. /// /// The session to use. /// The cursor to position. /// True if the move was successful. public static bool TryMoveFirst(JET_SESID sesid, JET_TABLEID tableid) { return TryMove(sesid, tableid, JET_Move.First, MoveGrbit.None); } /// /// Try to move to the last record in the table. If the table is empty this /// returns false, if a different error is encountered an exception is thrown. /// /// The session to use. /// The cursor to position. /// True if the move was successful. public static bool TryMoveLast(JET_SESID sesid, JET_TABLEID tableid) { return TryMove(sesid, tableid, JET_Move.Last, MoveGrbit.None); } /// /// Try to move to the next record in the table. If there is not a next record /// this returns false, if a different error is encountered an exception is thrown. /// /// The session to use. /// The cursor to position. /// True if the move was successful. public static bool TryMoveNext(JET_SESID sesid, JET_TABLEID tableid) { return TryMove(sesid, tableid, JET_Move.Next, MoveGrbit.None); } /// /// Try to move to the previous record in the table. If there is not a previous record /// this returns false, if a different error is encountered an exception is thrown. /// /// The session to use. /// The cursor to position. /// True if the move was successful. public static bool TryMovePrevious(JET_SESID sesid, JET_TABLEID tableid) { return TryMove(sesid, tableid, JET_Move.Previous, MoveGrbit.None); } /// /// Efficiently positions a cursor to an index entry that matches the search /// criteria specified by the search key in that cursor and the specified /// inequality. A search key must have been previously constructed using JetMakeKey. /// /// The session to use. /// The cursor to position. /// Seek option. /// True if a record matching the criteria was found. public static bool TrySeek(JET_SESID sesid, JET_TABLEID tableid, SeekGrbit grbit) { var err = (JET_err)Impl.JetSeek(sesid, tableid, grbit); if (JET_err.RecordNotFound == err) { return false; } Api.Check((int)err); Debug.Assert(err >= JET_err.Success, "Exception should have been thrown in case of error"); return true; } /// /// Temporarily limits the set of index entries that the cursor can walk using /// JetMove to those starting from the current index entry and ending at the index /// entry that matches the search criteria specified by the search key in that cursor /// and the specified bound criteria. A search key must have been previously constructed /// using JetMakeKey. Returns true if the index range is non-empty, false otherwise. /// /// The session to use. /// The cursor to position. /// Seek option. /// True if the seek was successful. public static bool TrySetIndexRange(JET_SESID sesid, JET_TABLEID tableid, SetIndexRangeGrbit grbit) { var err = (JET_err)Impl.JetSetIndexRange(sesid, tableid, grbit); if (JET_err.NoCurrentRecord == err) { return false; } Api.Check((int)err); Debug.Assert(err >= JET_err.Success, "Exception should have been thrown in case of error"); return true; } /// /// Removes an index range created with or /// . If no index range is present this /// method does nothing. /// /// The session to use. /// The cursor to remove the index range on. public static void ResetIndexRange(JET_SESID sesid, JET_TABLEID tableid) { var err = (JET_err)Impl.JetSetIndexRange(sesid, tableid, SetIndexRangeGrbit.RangeRemove); if (JET_err.InvalidOperation == err) { // this error is expected if there isn't currently an index range return; } Api.Check((int)err); return; } /// /// Intersect a group of index ranges and return the bookmarks of the records which are found /// in all the index ranges. /// Also see . /// /// The session to use. /// /// The tableids to use. Each tableid must be from a different index on the same table and /// have an active index range. Use /// to create an index range. /// /// /// The bookmarks of the records which are found in all the index ranges. The bookmarks /// are returned in primary key order. /// public static IEnumerable IntersectIndexes(JET_SESID sesid, params JET_TABLEID[] tableids) { if (null == tableids) { throw new ArgumentNullException("tableids"); } var ranges = new JET_INDEXRANGE[tableids.Length]; for (int i = 0; i < tableids.Length; ++i) { ranges[i] = new JET_INDEXRANGE { tableid = tableids[i] }; } return new GenericEnumerable(() => new IntersectIndexesEnumerator(sesid, ranges)); } /// /// Positions a cursor to an index entry for the record that is associated with /// the specified bookmark. The bookmark can be used with any index defined over /// a table. The bookmark for a record can be retrieved using . /// /// The session to use. /// The cursor to position. /// The bookmark used to position the cursor. /// The size of the bookmark. /// True if a record matching the bookmark was found. public static bool TryGotoBookmark(JET_SESID sesid, JET_TABLEID tableid, byte[] bookmark, int bookmarkSize) { var err = (JET_err)Impl.JetGotoBookmark(sesid, tableid, bookmark, bookmarkSize); // Return false if the record no longer exists. if (JET_err.RecordDeleted == err) { return false; } // Return false if there is no entry for this record on the current (secondary) index. if (JET_err.NoCurrentRecord == err) { return false; } Api.Check((int)err); Debug.Assert(err >= JET_err.Success, "Exception should have been thrown in case of error"); return true; } } }