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