// --------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // --------------------------------------------------------------------------- // --------------------------------------------------------------------- // // // --------------------------------------------------------------------- namespace Microsoft.Database.Isam { using System; using System.Collections; using Microsoft.Isam.Esent.Interop; /// /// Wraps a JET_TABLEID with indexed accessors /// public class ColumnAccessor : IEnumerable { /// /// The underlying session. /// private readonly IsamSession isamSession; /// /// The underlying tableid. /// private readonly JET_TABLEID tableid; /// /// The grbits to use for retrieving the column. /// private readonly RetrieveColumnGrbit grbit; /// /// The underlying cursor. /// private Cursor cursor; /// /// The Update Identifier. /// private long updateID = 0; /// /// Initializes a new instance of the class. /// /// The cursor. /// The session. /// The tableid. /// The grbit. internal ColumnAccessor(Cursor cursor, IsamSession isamSession, JET_TABLEID tableid, RetrieveColumnGrbit grbit) { this.cursor = cursor; this.isamSession = isamSession; this.tableid = tableid; this.grbit = grbit; } /// /// Gets the update identifier. /// internal long UpdateID { get { return this.updateID; } } /// /// Accessor for itag 1 of a column, converted to/from an object /// /// /// The . /// /// Name of the column. /// The value stored within. public object this[string columnName] { get { return this.RetrieveColumn(columnName, 0); } set { this.SetColumn(columnName, 0, value); } } /// /// Accessor for any itag of a column, converted to/from an object /// /// /// The . /// /// Name of the column. /// The index. /// The value stored within. /// /// The index argument is 0-based, we add 1 to get the itag /// public object this[string columnName, int index] { get { return this.RetrieveColumn(columnName, index); } set { this.SetColumn(columnName, index, value); } } /// /// Accessor for itag 1 of a column, converted to/from an object /// /// /// The . /// /// The columnid. /// The value stored within. public object this[Columnid columnid] { get { return this.RetrieveColumn(columnid.InteropColumnid, columnid.Coltyp, columnid.IsAscii, 0); } set { this.SetColumn(columnid.InteropColumnid, columnid.Coltyp, columnid.IsAscii, 0, value); } } /// /// Accessor for any itag of a column, converted to/from an object /// /// /// The . /// /// The columnid. /// The index. /// The value stored within. /// /// The index argument is 0-based, we add 1 to get the itag /// public object this[Columnid columnid, int index] { get { return this.RetrieveColumn(columnid.InteropColumnid, columnid.Coltyp, columnid.IsAscii, index); } set { this.SetColumn(columnid.InteropColumnid, columnid.Coltyp, columnid.IsAscii, index, value); } } /// /// Calculates the size of the specified multivalue stored in the specified column. /// /// Name of the column. /// The index. /// Returns the size of the specified multivalue stored in the specified column. public long SizeOf(string columnName, int index) { lock (this.isamSession) { this.cursor.CheckDisposed(); using (IsamTransaction trx = new IsamTransaction(this.isamSession, true)) { return this.SizeOf(this.cursor.TableDefinition.Columns[columnName].Columnid, index); } } } /// /// Calculates the size of the specified column. /// /// Name of the column. /// Returns the size of the specified column. public long SizeOf(string columnName) { return this.SizeOf(columnName, 0); } /// /// Calculates the size of the specified multivalue stored in the specified column. /// /// The columnid. /// The index. /// Returns the size of the specified multivalue stored in the specified column. public long SizeOf(Columnid columnid, int index) { lock (this.isamSession) { this.cursor.CheckDisposed(); if ((this.grbit & RetrieveColumnGrbit.RetrieveCopy) == 0) { this.cursor.CheckRecord(); } int itagSequence = index + 1; int? size = Api.RetrieveColumnSize( this.isamSession.Sesid, this.tableid, columnid.InteropColumnid, itagSequence, RetrieveColumnGrbit.None); return size.GetValueOrDefault(); } } /// /// Calculates the size of the specified column. /// /// The columnid. /// Returns the size of the specified column. public long SizeOf(Columnid columnid) { return this.SizeOf(columnid, 0); } /// /// Fetches an enumerator containing all the field values in the record. /// /// /// Returns an enumerator containing all the field values in the record. /// /// /// This is the type safe version that may not work in other CLR /// languages. /// public RecordEnumerator GetEnumerator() { // return the enumerator for the field collection return this.cursor.GetFields(this.grbit).GetEnumerator(); } /// /// Fetches an enumerator containing all the field values in the record /// /// /// 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(); } /// /// Retrieves the column. /// /// Name of the column. /// The index. /// The value stored within. private object RetrieveColumn(string columnName, int index) { lock (this.isamSession) { this.cursor.CheckDisposed(); ColumnDefinition columnDefinition = this.cursor.TableDefinition.Columns[columnName]; return this.RetrieveColumn(columnDefinition, index); } } /// /// Retrieves the column. /// /// The column definition. /// The index. /// The value stored within. private object RetrieveColumn(ColumnDefinition columnDefinition, int index) { lock (this.isamSession) { this.cursor.CheckDisposed(); using (IsamTransaction trx = new IsamTransaction(this.isamSession, true)) { Columnid columnid = columnDefinition.Columnid; return this.RetrieveColumn(columnid.InteropColumnid, columnid.Coltyp, columnid.IsAscii, index); } } } /// /// Sets the column. /// /// Name of the column. /// The index. /// The object. private void SetColumn(string columnName, int index, object obj) { lock (this.isamSession) { this.cursor.CheckDisposed(); // Note that this overload doesn't start a transaction, but assumes the // implementation does the transaction. ColumnDefinition columnDefinition = this.cursor.TableDefinition.Columns[columnName]; this.SetColumn(columnDefinition, index, obj); } } /// /// Sets the column. /// /// The column definition. /// The index. /// The object. private void SetColumn(ColumnDefinition columnDefinition, int index, object obj) { lock (this.isamSession) { this.cursor.CheckDisposed(); using (IsamTransaction trx = new IsamTransaction(this.isamSession, true)) { Columnid columnid = columnDefinition.Columnid; this.SetColumn(columnid.InteropColumnid, columnid.Coltyp, columnid.IsAscii, index, obj); trx.Commit(); } } } /// /// Retrieves the column. /// /// The columnid. /// The coltyp. /// Whether a textual column is Ascii. /// The index. /// The value stored within. /// /// Itags start at 1, so we add 1 to the index /// private object RetrieveColumn(JET_COLUMNID columnid, JET_coltyp coltyp, bool isAscii, int index) { lock (this.isamSession) { this.cursor.CheckDisposed(); if ((this.grbit & RetrieveColumnGrbit.RetrieveCopy) == 0) { this.cursor.CheckRecord(); } JET_RETINFO retinfo = new JET_RETINFO(); retinfo.ibLongValue = 0; retinfo.itagSequence = index + 1; byte[] bytes = Api.RetrieveColumn(this.isamSession.Sesid, this.tableid, columnid, this.grbit, retinfo); object obj = Converter.ObjectFromBytes(coltyp, isAscii, bytes); return obj; } } /// /// Sets the column. /// /// The columnid. /// The coltyp. /// Whether a textual column is Ascii. /// The index. /// The object. /// You may only update fields through Cursor.EditRecord. /// /// Itags start at 1, so we add 1 to the index /// private void SetColumn(JET_COLUMNID columnid, JET_coltyp coltyp, bool isAscii, int index, object obj) { lock (this.isamSession) { this.cursor.CheckDisposed(); if ((this.grbit & RetrieveColumnGrbit.RetrieveCopy) == 0) { this.cursor.CheckRecord(); throw new InvalidOperationException("You may only update fields through Cursor.EditRecord."); } // if this is a Sort or PreSortTemporary TT and we are setting // an LV column then always attempt to use intrinsic LVs SetColumnGrbit grbitSet = SetColumnGrbit.None; if ((this.cursor.TableDefinition.Type == TableType.Sort || this.cursor.TableDefinition.Type == TableType.PreSortTemporary) && (coltyp == JET_coltyp.LongText || coltyp == JET_coltyp.LongBinary)) { grbitSet = grbitSet | SetColumnGrbit.IntrinsicLV; } JET_SETINFO setinfo = new JET_SETINFO(); setinfo.ibLongValue = 0; setinfo.itagSequence = index + 1; byte[] bytes = Converter.BytesFromObject(coltyp, isAscii, obj); int bytesLength = bytes == null ? 0 : bytes.Length; Api.JetSetColumn(this.isamSession.Sesid, this.tableid, columnid, bytes, bytesLength, grbitSet, setinfo); this.updateID++; } } } }