// --------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // --------------------------------------------------------------------------- // --------------------------------------------------------------------- // // // --------------------------------------------------------------------- namespace Microsoft.Database.Isam { using System; using System.Collections; using Microsoft.Isam.Esent.Interop; /// /// Enumerates the indices on a given table. /// public class IndexEnumerator : IEnumerator { /// /// The database /// private readonly IsamDatabase database; /// /// The table name /// private readonly string tableName; /// /// The enumerator /// private readonly IDictionaryEnumerator enumerator; /// /// The index list /// private JET_INDEXLIST indexList; /// /// The cleanup /// private bool cleanup = false; /// /// The moved /// private bool moved = false; /// /// The current /// private bool current = false; /// /// The index definition /// private IndexDefinition indexDefinition = null; /// /// The index update identifier /// private long indexUpdateID = 0; /// /// Initializes a new instance of the class. /// /// The database. /// Name of the table. internal IndexEnumerator(IsamDatabase database, string tableName) { this.database = database; this.tableName = tableName; this.enumerator = null; } /// /// Initializes a new instance of the class. /// /// The enumerator. internal IndexEnumerator(IDictionaryEnumerator enumerator) { this.database = null; this.enumerator = enumerator; } /// /// Finalizes an instance of the IndexEnumerator class /// ~IndexEnumerator() { this.Reset(); } /// /// Gets the current element in the collection. /// /// The current element in the collection. /// /// after last index on table /// or /// before first index on table /// /// /// This is the type safe version that may not work in other CLR /// languages. /// public IndexDefinition Current { get { if (this.database != null) { lock (this.database.IsamSession) { if (!this.current) { if (this.moved) { throw new InvalidOperationException("after last index on table"); } else { throw new InvalidOperationException("before first index on table"); } } if (this.indexDefinition == null || this.indexUpdateID != DatabaseCommon.SchemaUpdateID) { this.indexDefinition = IndexDefinition.Load(this.database, this.tableName, this.indexList); this.indexUpdateID = DatabaseCommon.SchemaUpdateID; } return this.indexDefinition; } } else { return (IndexDefinition)this.enumerator.Value; } } } /// /// Gets the current element in the collection. /// /// The current element in the collection. /// /// This is the standard version that will work with other CLR /// languages. /// object IEnumerator.Current { get { return this.Current; } } /// /// Sets the enumerator to its initial position, which is before the first element in the collection. /// public void Reset() { if (this.database != null) { lock (this.database.IsamSession) { if (this.cleanup) { if (!this.database.IsamSession.Disposed) { // BUGBUG: we will try to close an already closed tableid // if it was already closed due to a rollback. this could // cause us to crash in ESENT due to lack of full validation // in small config. we should use cursor LS to detect when // our cursor gets closed and thus avoid closing it again Api.JetCloseTable(this.database.IsamSession.Sesid, this.indexList.tableid); } } this.cleanup = false; this.moved = false; this.current = false; this.indexDefinition = null; } } else { this.enumerator.Reset(); } } /// /// Advances the enumerator to the next element of the collection. /// /// /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection. /// public bool MoveNext() { if (this.database != null) { lock (this.database.IsamSession) { if (!this.moved) { Api.JetGetIndexInfo( this.database.IsamSession.Sesid, this.database.Dbid, this.tableName, null, out this.indexList, JET_IdxInfo.List); this.cleanup = true; this.current = Api.TryMoveFirst(this.database.IsamSession.Sesid, this.indexList.tableid); } else if (this.current) { this.current = Api.TryMoveNext(this.database.IsamSession.Sesid, this.indexList.tableid); if (!this.current) { Api.JetCloseTable(this.database.IsamSession.Sesid, this.indexList.tableid); this.cleanup = false; } } this.moved = true; this.indexDefinition = null; return this.current; } } else { return this.enumerator.MoveNext(); } } } }