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