// --------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // --------------------------------------------------------------------------- // --------------------------------------------------------------------- // // // --------------------------------------------------------------------- namespace Microsoft.Database.Isam { using System; using System.Collections; using Microsoft.Isam.Esent.Interop; /// /// Enumerates the tables in a given database. /// public class TableEnumerator : IEnumerator { /// /// The database /// private readonly IsamDatabase database; /// /// The enumerator /// private readonly IDictionaryEnumerator enumerator; /// /// The object list /// private JET_OBJECTLIST objectList; /// /// The cleanup /// private bool cleanup = false; /// /// The moved /// private bool moved = false; /// /// The current /// private bool current = false; /// /// The table definition /// private TableDefinition tableDefinition = null; /// /// The table update identifier /// private long tableUpdateID = 0; /// /// Initializes a new instance of the class. /// /// The database. internal TableEnumerator(IsamDatabase database) { this.database = database; this.enumerator = null; } /// /// Initializes a new instance of the class. /// /// The enumerator. internal TableEnumerator(IDictionaryEnumerator enumerator) { this.database = null; this.enumerator = enumerator; } /// /// Finalizes an instance of the TableEnumerator class /// ~TableEnumerator() { this.Reset(); } /// /// Gets the current element in the collection. /// /// The current element in the collection. /// /// after last table in database /// or /// before first table in database /// /// /// This is the type safe version that may not work in other CLR /// languages. /// public TableDefinition Current { get { if (this.database != null) { lock (this.database.IsamSession) { if (!this.current) { if (this.moved) { throw new InvalidOperationException("after last table in database"); } else { throw new InvalidOperationException("before first table in database"); } } if (this.tableDefinition == null || this.tableUpdateID != DatabaseCommon.SchemaUpdateID) { this.tableDefinition = TableDefinition.Load(this.database, this.objectList); this.tableUpdateID = DatabaseCommon.SchemaUpdateID; } return this.tableDefinition; } } else { return (TableDefinition)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.objectList.tableid); } } this.cleanup = false; this.moved = false; this.current = false; this.tableDefinition = 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) { // filter out anything that is not a normal table ObjectInfoFlags flags = 0; do { this.MoveNext_(); if (this.current) { flags = (ObjectInfoFlags)Api.RetrieveColumnAsUInt32( this.database.IsamSession.Sesid, this.objectList.tableid, this.objectList.columnidflags); } } while (this.current && (flags & (ObjectInfoFlags.System | ObjectInfoFlags.TableTemplate)) != 0); return this.current; } } else { return this.enumerator.MoveNext(); } } /// /// Moves the next_. /// internal void MoveNext_() { if (!this.moved) { Api.JetGetObjectInfo(this.database.IsamSession.Sesid, this.database.Dbid, out this.objectList); this.cleanup = true; this.current = Api.TryMoveFirst(this.database.IsamSession.Sesid, this.objectList.tableid); } else if (this.current) { this.current = Api.TryMoveNext(this.database.IsamSession.Sesid, this.objectList.tableid); if (!this.current) { Api.JetCloseTable(this.database.IsamSession.Sesid, this.objectList.tableid); this.cleanup = false; } } this.moved = true; this.tableDefinition = null; } } }