// --------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // --------------------------------------------------------------------------- // --------------------------------------------------------------------- // // // --------------------------------------------------------------------- namespace Microsoft.Database.Isam { using System; using System.Collections; using System.Globalization; using Microsoft.Isam.Esent.Interop; /// /// A class containing information about the indices on a particular table. /// It is usually used for metadata discovery. /// public class IndexCollection : DictionaryBase, IEnumerable { /// /// The database /// private readonly IsamDatabase database; /// /// The table name /// private readonly string tableName; /// /// The cached index definition /// private string cachedIndexDefinition = null; /// /// The index definition /// private IndexDefinition indexDefinition = null; /// /// The index update identifier /// private long indexUpdateID = 0; /// /// The read only /// private bool readOnly = false; /// /// Initializes a new instance of the class. /// public IndexCollection() { this.database = null; } /// /// Initializes a new instance of the class. /// /// The database. /// Name of the table. internal IndexCollection(IsamDatabase database, string tableName) { this.database = database; this.tableName = tableName; this.readOnly = true; } /// /// Gets the names. /// /// /// The names. /// /// the names of the indices in this index collection cannot be enumerated in this manner when accessing the table definition of an existing table public ICollection Names { get { if (this.database != null) { // CONSIDER: should we provide an ICollection of our index names to avoid this wart? throw new InvalidOperationException( "the names of the indices in this index collection cannot be enumerated in this manner when accessing the table definition of an existing table"); } else { return this.Dictionary.Keys; } } } /// /// Gets a value indicating whether the object has a fixed size. /// /// true if the object has a fixed size; otherwise, false. public bool IsFixedSize { get { return this.readOnly; } } /// /// Gets a value indicating whether the object is read-only. /// /// true if the object is read-only; otherwise, false. public bool IsReadOnly { get { return this.readOnly; } } /// /// Sets a value indicating whether [read only]. /// /// /// true if [read only]; otherwise, false. /// internal bool ReadOnly { set { this.readOnly = value; } } /// /// Fetches the Index Definition for the specified index name. /// /// /// The corresponding to . /// /// Name of the index. /// An object. public IndexDefinition this[string indexName] { get { if (this.database != null) { lock (this.database.IsamSession) { JET_SESID sesid = this.database.IsamSession.Sesid; if (this.cachedIndexDefinition != indexName.ToLower(CultureInfo.InvariantCulture) || this.indexUpdateID != DatabaseCommon.SchemaUpdateID) { JET_INDEXLIST indexList; Api.JetGetIndexInfo( sesid, this.database.Dbid, this.tableName, indexName, out indexList, JET_IdxInfo.List); try { this.indexDefinition = IndexDefinition.Load(this.database, this.tableName, indexList); } finally { Api.JetCloseTable(sesid, indexList.tableid); } this.cachedIndexDefinition = indexName.ToLower(CultureInfo.InvariantCulture); this.indexUpdateID = DatabaseCommon.SchemaUpdateID; } return this.indexDefinition; } } else { return (IndexDefinition)Dictionary[indexName.ToLower(CultureInfo.InvariantCulture)]; } } set { this.Dictionary[indexName.ToLower(CultureInfo.InvariantCulture)] = value; } } /// /// Fetches an enumerator containing all the indices on this table. /// /// An enumerator containing all the indices on this table. /// /// This is the type safe version that may not work in other CLR /// languages. /// public new IndexEnumerator GetEnumerator() { if (this.database != null) { return new IndexEnumerator(this.database, this.tableName); } else { return new IndexEnumerator(this.Dictionary.GetEnumerator()); } } /// /// Adds the specified index definition. /// /// The index definition. public void Add(IndexDefinition indexDefinition) { this.Dictionary.Add(indexDefinition.Name.ToLower(CultureInfo.InvariantCulture), indexDefinition); } /// /// Determines if the table contains an index with the given name. /// /// Name of the index. /// Whether the collection contains an index of name . public bool Contains(string indexName) { if (this.database != null) { lock (this.database.IsamSession) { bool exists = false; try { int density; Api.JetGetIndexInfo( this.database.IsamSession.Sesid, this.database.Dbid, this.tableName, indexName, out density, JET_IdxInfo.SpaceAlloc); exists = true; } catch (EsentIndexNotFoundException) { } return exists; } } else { return Dictionary.Contains(indexName.ToLower(CultureInfo.InvariantCulture)); } } /// /// Removes the specified index name. /// /// Name of the index. public void Remove(string indexName) { Dictionary.Remove(indexName.ToLower(CultureInfo.InvariantCulture)); } /// /// Fetches an enumerator containing all the indices on this table /// /// /// An object that can be used to iterate through the collection. /// /// /// This is the standard version that will work with other CLR /// languages. /// IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator)this.GetEnumerator(); } /// /// Performs additional custom processes before clearing the contents of the instance. /// protected override void OnClear() { this.CheckReadOnly(); } /// /// Performs additional custom processes before inserting a new element into the instance. /// /// The key of the element to insert. /// The value of the element to insert. protected override void OnInsert(object key, object value) { this.CheckReadOnly(); } /// /// Performs additional custom processes before removing an element from the instance. /// /// The key of the element to remove. /// The value of the element to remove. protected override void OnRemove(object key, object value) { this.CheckReadOnly(); } /// /// Performs additional custom processes before setting a value in the instance. /// /// The key of the element to locate. /// The old value of the element associated with . /// The new value of the element associated with . protected override void OnSet(object key, object oldValue, object newValue) { this.CheckReadOnly(); } /// /// Performs additional custom processes when validating the element with the specified key and value. /// /// The key of the element to validate. /// The value of the element to validate. /// /// key must be of type System.String;key /// or /// value must be of type IndexDefinition;value /// or /// key must match value.Name;key /// protected override void OnValidate(object key, object value) { if (!(key is string)) { throw new ArgumentException("key must be of type System.String", "key"); } if (!(value is IndexDefinition)) { throw new ArgumentException("value must be of type IndexDefinition", "value"); } if (((string)key).ToLower(CultureInfo.InvariantCulture) != ((IndexDefinition)value).Name.ToLower(CultureInfo.InvariantCulture)) { throw new ArgumentException("key must match value.Name", "key"); } } /// /// Checks the read only. /// /// this index collection cannot be changed private void CheckReadOnly() { if (this.readOnly) { throw new NotSupportedException("this index collection cannot be changed"); } } } }