/// <summary> /// Retrieves a single column value from the current record. The record is that /// record associated with the index entry at the current position of the cursor. /// Alternatively, this function can retrieve a column from a record being created /// in the cursor copy buffer. This function can also retrieve column data from an /// index entry that references the current record. In addition to retrieving the /// actual column value, JetRetrieveColumn can also be used to retrieve the size /// of a column, before retrieving the column data itself so that application /// buffers can be sized appropriately. /// </summary> /// <remarks> /// This is an internal method that takes a buffer offset as well as size. /// </remarks> /// <param name="sesid">The session to use.</param> /// <param name="tableid">The cursor to retrieve the column from.</param> /// <param name="columnid">The columnid to retrieve.</param> /// <param name="data">The data buffer to be retrieved into.</param> /// <param name="dataSize">The size of the data buffer.</param> /// <param name="dataOffset">Offset into the data buffer to read data into.</param> /// <param name="actualDataSize">Returns the actual size of the data buffer.</param> /// <param name="grbit">Retrieve column options.</param> /// <param name="retinfo"> /// If pretinfo is give as NULL then the function behaves as though an itagSequence /// of 1 and an ibLongValue of 0 (zero) were given. This causes column retrieval to /// retrieve the first value of a multi-valued column, and to retrieve long data at /// offset 0 (zero). /// </param> /// <returns>An ESENT warning code.</returns> public static JET_wrn JetRetrieveColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, byte[] data, int dataSize, int dataOffset, out int actualDataSize, RetrieveColumnGrbit grbit, JET_RETINFO retinfo) { if (dataOffset < 0 || (null != data && 0 != dataSize && dataOffset >= data.Length) || (null == data && dataOffset != 0)) { throw new ArgumentOutOfRangeException( "dataOffset", dataOffset, "must be inside the data buffer"); } if ((null == data && dataSize > 0) || (null != data && dataSize > data.Length)) { throw new ArgumentOutOfRangeException( "dataSize", dataSize, "cannot be greater than the length of the data"); } unsafe { fixed (byte* pointer = data) { return Api.JetRetrieveColumn( sesid, tableid, columnid, new IntPtr(pointer + dataOffset), dataSize, out actualDataSize, grbit, retinfo); } } }
/// <summary> /// Initializes a new instance of the <see cref="ColumnAccessor" /> class. /// </summary> /// <param name="cursor">The cursor.</param> /// <param name="isamSession">The session.</param> /// <param name="tableid">The tableid.</param> /// <param name="grbit">The grbit.</param> internal ColumnAccessor(Cursor cursor, IsamSession isamSession, JET_TABLEID tableid, RetrieveColumnGrbit grbit) { this.cursor = cursor; this.isamSession = isamSession; this.tableid = tableid; this.grbit = grbit; }
/// <summary> /// Validation for the requested retrieve options for the column. /// </summary> /// <param name="grbit">The retrieve options to validate.</param> protected virtual void ValidateRetrieveGrbit(RetrieveColumnGrbit grbit) { // We cannot support this request when there is no way to indicate that a column reference is returned. if ((grbit & (RetrieveColumnGrbit)0x00020000) != 0) // UnpublishedGrbits.RetrieveAsRefIfNotInRecord { throw new EsentInvalidGrbitException(); } }
/// <summary> /// Retrieve a column from the current record as a DateTime /// </summary> /// <param name="columnid">The columnid to retrieve.</param> /// <param name="grbit">Retrieve options.</param> /// <returns>The data from the column.</returns> public virtual DateTime?RetrieveColumnAsDateTime(JET_COLUMNID columnid, RetrieveColumnGrbit grbit) { this.Tracer.TraceVerbose("RetrieveColumn"); this.CheckNotDisposed(); if (0 == (RetrieveColumnGrbit.RetrieveCopy & grbit)) { this.CheckHasCurrency(); } return(Api.RetrieveColumnAsDateTime(this.session, this.table, columnid, grbit)); }
// retrieves all the columns from the record with JetRetrieveColumn private byte[][] GetColumnsWithJetRetrieveColumn( JET_SESID sesid, JET_TABLEID tableid, RetrieveColumnGrbit grbit) { var data = new byte[this.columnInfos.Length][]; for (int i = 0; i < this.columnInfos.Length; ++i) { data[i] = Api.RetrieveColumn(sesid, tableid, this.columnInfos[i].Columnid, grbit, null); } return(data); }
/// <summary> /// Retrieves a boolean column value from the current record. The record is that /// record associated with the index entry at the current position of the cursor. /// </summary> /// <param name="sesid">The session to use.</param> /// <param name="tableid">The cursor to retrieve the column from.</param> /// <param name="columnid">The columnid to retrieve.</param> /// <param name="grbit">Retrieval options.</param> /// <returns>The data retrieved from the column as a boolean. Null if the column is null.</returns> public static bool?RetrieveColumnAsBoolean( JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, RetrieveColumnGrbit grbit) { byte?b = RetrieveColumnAsByte(sesid, tableid, columnid, grbit); if (b.HasValue) { return(0 != b.Value); } return(new bool?()); }
/// <summary> /// Retrieve a column from the record. /// </summary> /// <param name="column">The column to retrieve.</param> /// <returns>The value of the column.</returns> private object RetrieveColumn(string column) { RetrieveColumnGrbit grbit = this.CurrentlyInUpdate ? RetrieveColumnGrbit.RetrieveCopy : RetrieveColumnGrbit.None; try { return(this.Table.Columns[column].RetrieveColumn(this.Cursor, grbit)); } catch (KeyNotFoundException ex) { throw new EsentColumnNotFoundException(this.Table.TableName, column, ex); } }
/// <summary> /// Retrieves a datetime column value from the current record. The record is that /// record associated with the index entry at the current position of the cursor. /// </summary> /// <param name="sesid">The session to use.</param> /// <param name="tableid">The cursor to retrieve the column from.</param> /// <param name="columnid">The columnid to retrieve.</param> /// <param name="grbit">Retrieval options.</param> /// <returns>The data retrieved from the column as a datetime. Null if the column is null.</returns> public static DateTime?RetrieveColumnAsDateTime( JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, RetrieveColumnGrbit grbit) { // Internally DateTime is stored in OLE Automation format double?oadate = RetrieveColumnAsDouble(sesid, tableid, columnid, grbit); if (oadate.HasValue) { return(Conversions.ConvertDoubleToDateTime(oadate.Value)); } return(new DateTime?()); }
/// <summary> /// A retrieve column function which always claims that the data in the column /// is larger than the passed in buffer. /// </summary> /// <param name="sesid">The session to use.</param> /// <param name="tableid">The cursor to retrieve the column from.</param> /// <param name="columnid">The columnid to retrieve.</param> /// <param name="data">The data buffer to be retrieved into.</param> /// <param name="dataSize">The size of the data buffer.</param> /// <param name="actualDataSize">Returns the actual size of the data buffer.</param> /// <param name="grbit">Retrieve column options.</param> /// <param name="retinfo"> /// Retrieve options. /// </param> /// <returns>Always returns <see cref="JET_wrn.BufferTruncated"/>.</returns> private static int BadRetrieveColumn( JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, IntPtr data, int dataSize, out int actualDataSize, RetrieveColumnGrbit grbit, JET_RETINFO retinfo) { actualDataSize = (dataSize * 2) + (1024 * 1024); return((int)JET_wrn.BufferTruncated); }
public static ulong?RetrieveColumnAsUInt64( JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, RetrieveColumnGrbit grbit) { unsafe { const int DataSize = sizeof(ulong); ulong data; var pointer = new IntPtr(&data); int actualDataSize; JET_wrn wrn = JetRetrieveColumn( sesid, tableid, columnid, pointer, DataSize, out actualDataSize, grbit, null); return(CreateReturnValue(data, DataSize, wrn, actualDataSize)); } }
/// <summary> /// Retrieves a single column value from the current record. The record is that /// record associated with the index entry at the current position of the cursor. /// Alternatively, this function can retrieve a column from a record being created /// in the cursor copy buffer. This function can also retrieve column data from an /// index entry that references the current record. In addition to retrieving the /// actual column value, JetRetrieveColumn can also be used to retrieve the size /// of a column, before retrieving the column data itself so that application /// buffers can be sized appropriately. /// </summary> /// <param name="sesid">The session to use.</param> /// <param name="tableid">The cursor to retrieve the column from.</param> /// <param name="columnid">The columnid to retrieve.</param> /// <param name="grbit">Retrieve column options.</param> /// <param name="retinfo"> /// If pretinfo is give as NULL then the function behaves as though an itagSequence /// of 1 and an ibLongValue of 0 (zero) were given. This causes column retrieval to /// retrieve the first value of a multi-valued column, and to retrieve long data at /// offset 0 (zero). /// </param> /// <returns>The data retrieved from the column. Null if the column is null.</returns> public static byte[] RetrieveColumn( JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, RetrieveColumnGrbit grbit, JET_RETINFO retinfo) { // We expect most column values retrieved this way to be small (retrieving a 1GB LV as one // chunk is a bit extreme!). Allocate a cached buffer and use that, allocating a larger one // if needed. byte[] cache = Caches.ColumnCache.Allocate(); byte[] data = cache; int dataSize; JET_wrn wrn = JetRetrieveColumn( sesid, tableid, columnid, data, data.Length, out dataSize, grbit, retinfo); if (JET_wrn.ColumnNull == wrn) { // null column data = null; } else if (JET_wrn.Success == wrn) { data = MemoryCache.Duplicate(data, dataSize); } else { // there is more data to retrieve Debug.Assert(JET_wrn.BufferTruncated == wrn, "Unexpected warning", wrn.ToString()); data = new byte[dataSize]; wrn = JetRetrieveColumn( sesid, tableid, columnid, data, data.Length, out dataSize, grbit, retinfo); if (JET_wrn.Success != wrn) { string error = String.Format( CultureInfo.CurrentCulture, "Column size changed from {0} to {1}. The record was probably updated by another thread.", data.Length, dataSize); Trace.TraceError(error); throw new InvalidOperationException(error); } } Caches.ColumnCache.Free(ref cache); return(data); }
/// <summary> /// Retrieves a single column value from the current record. The record is that /// record associated with the index entry at the current position of the cursor. /// Alternatively, this function can retrieve a column from a record being created /// in the cursor copy buffer. This function can also retrieve column data from an /// index entry that references the current record. In addition to retrieving the /// actual column value, JetRetrieveColumn can also be used to retrieve the size /// of a column, before retrieving the column data itself so that application /// buffers can be sized appropriately. /// </summary> /// <param name="sesid">The session to use.</param> /// <param name="tableid">The cursor to retrieve the column from.</param> /// <param name="columnid">The columnid to retrieve.</param> /// <param name="grbit">Retrieve column options.</param> /// <param name="retinfo"> /// If pretinfo is give as NULL then the function behaves as though an itagSequence /// of 1 and an ibLongValue of 0 (zero) were given. This causes column retrieval to /// retrieve the first value of a multi-valued column, and to retrieve long data at /// offset 0 (zero). /// </param> /// <returns>The data retrieved from the column. Null if the column is null.</returns> public static byte[] RetrieveColumn( JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, RetrieveColumnGrbit grbit, JET_RETINFO retinfo) { // We expect most column values retrieved this way to be small (retrieving a 1GB LV as one // chunk is a bit extreme!). Allocate a small buffer and use that, allocating a larger one // if needed. var data = new byte[256]; int dataSize; JET_wrn wrn = JetRetrieveColumn( sesid, tableid, columnid, data, data.Length, out dataSize, grbit, retinfo); if (JET_wrn.ColumnNull == wrn) { // null column data = null; } else { Array.Resize(ref data, dataSize); if (JET_wrn.BufferTruncated == wrn) { // there is more data to retrieve wrn = JetRetrieveColumn( sesid, tableid, columnid, data, data.Length, out dataSize, grbit, retinfo); if (JET_wrn.Success != wrn) { string error = String.Format( CultureInfo.CurrentCulture, "Column size changed from {0} to {1}. The record was probably updated by another thread.", data.Length, dataSize); Trace.TraceError(error); throw new InvalidOperationException(error); } } } return(data); }
/// <summary> /// Deserialize an object from a column. /// </summary> /// <param name="sesid">The session to use.</param> /// <param name="tableid">The table to read from.</param> /// <param name="columnid">The column to read from.</param> /// <param name="grbit">The retrieval options to use.</param> /// <returns>The deserialized object. Null if the column was null.</returns> public static object DeserializeObjectFromColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, RetrieveColumnGrbit grbit) { int actualSize; if (JET_wrn.ColumnNull == Api.JetRetrieveColumn(sesid, tableid, columnid, null, 0, out actualSize, grbit, null)) { return(null); } using (var stream = new ColumnStream(sesid, tableid, columnid)) { var deseriaizer = new BinaryFormatter(); return(deseriaizer.Deserialize(stream)); } }
/// <summary> /// Retrieves a single column value from the current record. The record is that /// record associated with the index entry at the current position of the cursor. /// Alternatively, this function can retrieve a column from a record being created /// in the cursor copy buffer. This function can also retrieve column data from an /// index entry that references the current record. In addition to retrieving the /// actual column value, JetRetrieveColumn can also be used to retrieve the size /// of a column, before retrieving the column data itself so that application /// buffers can be sized appropriately. /// </summary> /// <remarks> /// This is an internal method that takes a buffer offset as well as size. /// </remarks> /// <param name="sesid">The session to use.</param> /// <param name="tableid">The cursor to retrieve the column from.</param> /// <param name="columnid">The columnid to retrieve.</param> /// <param name="data">The data buffer to be retrieved into.</param> /// <param name="dataSize">The size of the data buffer.</param> /// <param name="dataOffset">Offset into the data buffer to read data into.</param> /// <param name="actualDataSize">Returns the actual size of the data buffer.</param> /// <param name="grbit">Retrieve column options.</param> /// <param name="retinfo"> /// If pretinfo is give as NULL then the function behaves as though an itagSequence /// of 1 and an ibLongValue of 0 (zero) were given. This causes column retrieval to /// retrieve the first value of a multi-valued column, and to retrieve long data at /// offset 0 (zero). /// </param> /// <returns>An ESENT warning code.</returns> public static JET_wrn JetRetrieveColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, byte[] data, int dataSize, int dataOffset, out int actualDataSize, RetrieveColumnGrbit grbit, JET_RETINFO retinfo) { if (dataOffset < 0 || (null != data && 0 != dataSize && dataOffset >= data.Length) || (null == data && dataOffset != 0)) { throw new ArgumentOutOfRangeException( "dataOffset", dataOffset, "must be inside the data buffer"); } if ((null == data && dataSize > 0) || (null != data && dataSize > data.Length)) { throw new ArgumentOutOfRangeException( "dataSize", dataSize, "cannot be greater than the length of the data"); } unsafe { fixed(byte *pointer = data) { return(Api.JetRetrieveColumn( sesid, tableid, columnid, new IntPtr(pointer + dataOffset), dataSize, out actualDataSize, grbit, retinfo)); } } }
/// <summary> /// Retrieves a single column value from the current record. The record is that /// record associated with the index entry at the current position of the cursor. /// Alternatively, this function can retrieve a column from a record being created /// in the cursor copy buffer. This function can also retrieve column data from an /// index entry that references the current record. In addition to retrieving the /// actual column value, JetRetrieveColumn can also be used to retrieve the size /// of a column, before retrieving the column data itself so that application /// buffers can be sized appropriately. /// </summary> /// <remarks> /// This is an internal-use version that takes an IntPtr. /// </remarks> /// <param name="sesid">The session to use.</param> /// <param name="tableid">The cursor to retrieve the column from.</param> /// <param name="columnid">The columnid to retrieve.</param> /// <param name="data">The data buffer to be retrieved into.</param> /// <param name="dataSize">The size of the data buffer.</param> /// <param name="actualDataSize">Returns the actual size of the data buffer.</param> /// <param name="grbit">Retrieve column options.</param> /// <param name="retinfo"> /// If pretinfo is give as NULL then the function behaves as though an itagSequence /// of 1 and an ibLongValue of 0 (zero) were given. This causes column retrieval to /// retrieve the first value of a multi-valued column, and to retrieve long data at /// offset 0 (zero). /// </param> /// <returns>An ESENT warning code.</returns> internal static JET_wrn JetRetrieveColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, IntPtr data, int dataSize, out int actualDataSize, RetrieveColumnGrbit grbit, JET_RETINFO retinfo) { return(Api.Check(Impl.JetRetrieveColumn(sesid, tableid, columnid, data, dataSize, out actualDataSize, grbit, retinfo))); }
/// <summary> /// A retrieve column function which always claims that the data in the column /// is larger than the passed in buffer. /// </summary> /// <param name="sesid">The session to use.</param> /// <param name="tableid">The cursor to retrieve the column from.</param> /// <param name="columnid">The columnid to retrieve.</param> /// <param name="data">The data buffer to be retrieved into.</param> /// <param name="dataSize">The size of the data buffer.</param> /// <param name="actualDataSize">Returns the actual size of the data buffer.</param> /// <param name="grbit">Retrieve column options.</param> /// <param name="retinfo"> /// Retrieve options. /// </param> /// <returns><see cref="JET_wrn.BufferTruncated"/>.</returns> private static int BadRetrieveColumn( JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, IntPtr data, int dataSize, out int actualDataSize, RetrieveColumnGrbit grbit, JET_RETINFO retinfo) { actualDataSize = (dataSize * 2) + (1024 * 1024); return (int)JET_wrn.BufferTruncated; }
/// <summary> /// Retrieves a string column value from the current record. The record is that /// record associated with the index entry at the current position of the cursor. /// </summary> /// <param name="sesid">The session to use.</param> /// <param name="tableid">The cursor to retrieve the column from.</param> /// <param name="columnid">The columnid to retrieve.</param> /// <param name="encoding">The string encoding to use when converting data.</param> /// <param name="grbit">Retrieval options.</param> /// <returns>The data retrieved from the column as a string. Null if the column is null.</returns> public static string RetrieveColumnAsString( JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, Encoding encoding, RetrieveColumnGrbit grbit) { JET_wrn wrn; // This is an optimization for retrieving small Unicode strings // We use a stack-allocated buffer to retrieve the data and then create // a string from the data if (Encoding.Unicode == encoding) { unsafe { // 512 bytes give 256 Unicode characters. const int BufferSize = 512; char * buffer = stackalloc char[BufferSize]; int actualDataSize; wrn = JetRetrieveColumn( sesid, tableid, columnid, new IntPtr(buffer), BufferSize, out actualDataSize, grbit, null); if (JET_wrn.ColumnNull == wrn) { return(null); } if (JET_wrn.Success == wrn) { return(new string(buffer, 0, actualDataSize / sizeof(char))); } Debug.Assert(JET_wrn.BufferTruncated == wrn, "Unexpected warning code"); // Fallthrough to normal case below } } // Retrieving a string happens in two stages: first the data is retrieved into a data // buffer and then the buffer is converted to a string. The buffer isn't needed for // very long so we try to use a cached buffer. byte[] cachedBuffer = memoryCache.Allocate(); byte[] data = cachedBuffer; int dataSize; wrn = JetRetrieveColumn(sesid, tableid, columnid, data, data.Length, out dataSize, grbit, null); if (JET_wrn.ColumnNull == wrn) { return(null); } if (JET_wrn.BufferTruncated == wrn) { Debug.Assert(dataSize > data.Length, "Expected column to be bigger than buffer"); data = new byte[dataSize]; wrn = JetRetrieveColumn(sesid, tableid, columnid, data, data.Length, out dataSize, grbit, null); if (JET_wrn.BufferTruncated == wrn) { string error = String.Format( CultureInfo.CurrentCulture, "Column size changed from {0} to {1}. The record was probably updated by another thread.", data.Length, dataSize); Trace.TraceError(error); throw new InvalidOperationException(error); } } // TODO: for Unicode strings pin the buffer and use the String(char*) constructor. string s = encoding.GetString(data, 0, dataSize); // Now we have extracted the string from the buffer we can free (cache) the buffer. memoryCache.Free(cachedBuffer); return(s); }
/// <summary> /// Retrieves a single column value from the current record. The record is that /// record associated with the index entry at the current position of the cursor. /// Alternatively, this function can retrieve a column from a record being created /// in the cursor copy buffer. This function can also retrieve column data from an /// index entry that references the current record. In addition to retrieving the /// actual column value, JetRetrieveColumn can also be used to retrieve the size /// of a column, before retrieving the column data itself so that application /// buffers can be sized appropriately. /// </summary> /// <remarks> /// This is an internal-use version that takes an IntPtr. /// </remarks> /// <param name="sesid">The session to use.</param> /// <param name="tableid">The cursor to retrieve the column from.</param> /// <param name="columnid">The columnid to retrieve.</param> /// <param name="data">The data buffer to be retrieved into.</param> /// <param name="dataSize">The size of the data buffer.</param> /// <param name="actualDataSize">Returns the actual size of the data buffer.</param> /// <param name="grbit">Retrieve column options.</param> /// <param name="retinfo"> /// If pretinfo is give as NULL then the function behaves as though an itagSequence /// of 1 and an ibLongValue of 0 (zero) were given. This causes column retrieval to /// retrieve the first value of a multi-valued column, and to retrieve long data at /// offset 0 (zero). /// </param> /// <returns>An ESENT warning code.</returns> internal static JET_wrn JetRetrieveColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, IntPtr data, int dataSize, out int actualDataSize, RetrieveColumnGrbit grbit, JET_RETINFO retinfo) { return Api.Check(Impl.JetRetrieveColumn(sesid, tableid, columnid, data, dataSize, out actualDataSize, grbit, retinfo)); }
// retrieves all the columns from the record with JetRetrieveColumn private byte[][] GetColumnsWithJetRetrieveColumn( JET_SESID sesid, JET_TABLEID tableid, RetrieveColumnGrbit grbit) { var data = new byte[this.columnInfos.Length][]; for (int i = 0; i < this.columnInfos.Length; ++i) { data[i] = Api.RetrieveColumn(sesid, tableid, this.columnInfos[i].Columnid, grbit, null); } return data; }
/// <summary> /// Retrieve a column from the current record as a String /// </summary> /// <param name="columnid">The columnid to retrieve.</param> /// <param name="encoding">The string encoding format.</param> /// <param name="grbit">Retrieve options.</param> /// <returns>The data from the column.</returns> public virtual string RetrieveColumnAsString(JET_COLUMNID columnid, Encoding encoding, RetrieveColumnGrbit grbit) { this.Tracer.TraceVerbose("RetrieveColumn"); this.CheckNotDisposed(); if (0 == (RetrieveColumnGrbit.RetrieveCopy & grbit)) { this.CheckHasCurrency(); } return Api.RetrieveColumnAsString(this.session, this.table, columnid, encoding, grbit); }
/// <summary> /// Retrieves a single column value from the current record. The record is that /// record associated with the index entry at the current position of the cursor. /// Alternatively, this function can retrieve a column from a record being created /// in the cursor copy buffer. This function can also retrieve column data from an /// index entry that references the current record. In addition to retrieving the /// actual column value, JetRetrieveColumn can also be used to retrieve the size /// of a column, before retrieving the column data itself so that application /// buffers can be sized appropriately. /// </summary> /// <remarks> /// The RetrieveColumnAs functions provide datatype-specific retrieval functions. /// </remarks> /// <param name="sesid">The session to use.</param> /// <param name="tableid">The cursor to retrieve the column from.</param> /// <param name="columnid">The columnid to retrieve.</param> /// <param name="data">The data buffer to be retrieved into.</param> /// <param name="dataSize">The size of the data buffer.</param> /// <param name="actualDataSize">Returns the actual size of the data buffer.</param> /// <param name="grbit">Retrieve column options.</param> /// <param name="retinfo"> /// If pretinfo is give as NULL then the function behaves as though an itagSequence /// of 1 and an ibLongValue of 0 (zero) were given. This causes column retrieval to /// retrieve the first value of a multi-valued column, and to retrieve long data at /// offset 0 (zero). /// </param> /// <returns>An ESENT warning code.</returns> public static JET_wrn JetRetrieveColumn(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, byte[] data, int dataSize, out int actualDataSize, RetrieveColumnGrbit grbit, JET_RETINFO retinfo) { return Api.JetRetrieveColumn(sesid, tableid, columnid, data, dataSize, 0, out actualDataSize, grbit, retinfo); }
/// <summary> /// Перечислить значения в столбце со многоими значениями. /// </summary> /// <param name="table">Таблица.</param> /// <param name="columnid">Идентификатор столбца.</param> /// <param name="grbit">Флаг получения.</param> /// <returns>Результат.</returns> protected IEnumerable <T> EnumMultivalueColumn <T>(EsentTable table, JET_COLUMNID columnid, RetrieveColumnGrbit grbit = RetrieveColumnGrbit.None) where T : ColumnValue, new() { var count = GetMultiValueCount(table, columnid); if (count == 0) { yield break; } var a = new ColumnValue[1]; for (var i = 1; i <= count; i++) { var col = new T { ItagSequence = i, Columnid = columnid, RetrieveGrbit = grbit }; a[0] = col; Api.RetrieveColumns(table.Session, table.Table, a); yield return(col); } }
/// <summary> /// Retrieves a string column value from the current record. The record is that /// record associated with the index entry at the current position of the cursor. /// </summary> /// <param name="sesid">The session to use.</param> /// <param name="tableid">The cursor to retrieve the column from.</param> /// <param name="columnid">The columnid to retrieve.</param> /// <param name="encoding">The string encoding to use when converting data.</param> /// <param name="grbit">Retrieval options.</param> /// <returns>The data retrieved from the column as a string. Null if the column is null.</returns> public static string RetrieveColumnAsString( JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, Encoding encoding, RetrieveColumnGrbit grbit) { // This is an optimization for retrieving Unicode strings if (Encoding.Unicode == encoding) { return(RetrieveUnicodeString(sesid, tableid, columnid, grbit)); } // Retrieving a string happens in two stages: first the data is retrieved into a data // buffer and then the buffer is converted to a string. The buffer isn't needed for // very long so we try to use a cached buffer. byte[] cachedBuffer = Caches.ColumnCache.Allocate(); byte[] data = cachedBuffer; int dataSize; JET_wrn wrn = JetRetrieveColumn(sesid, tableid, columnid, data, data.Length, out dataSize, grbit, null); if (JET_wrn.ColumnNull == wrn) { return(null); } if (JET_wrn.BufferTruncated == wrn) { Debug.Assert(dataSize > data.Length, "Expected column to be bigger than buffer"); data = new byte[dataSize]; wrn = JetRetrieveColumn(sesid, tableid, columnid, data, data.Length, out dataSize, grbit, null); if (JET_wrn.BufferTruncated == wrn) { string error = String.Format( CultureInfo.CurrentCulture, "Column size changed from {0} to {1}. The record was probably updated by another thread.", data.Length, dataSize); Trace.TraceError(error); throw new InvalidOperationException(error); } } // If we are about to decode ASCII data then use the UTF8 decoder instead. This // is done because the UTF8 decoder is faster and will produce the same results // on ASCII data. Different results will be produced on invalid data, but that // behaviour can be considered undefined. Encoding decoder = (encoding is ASCIIEncoding) ? asciiDecoder : encoding; string s = decoder.GetString(data, 0, dataSize); // Now we have extracted the string from the buffer we can free (cache) the buffer. Caches.ColumnCache.Free(ref cachedBuffer); return(s); }
/// <summary> /// Retrieves the size of a single column value from the current record. /// The record is that record associated with the index entry at the /// current position of the cursor. Alternatively, this function can /// retrieve a column from a record being created in the cursor copy /// buffer. This function can also retrieve column data from an index /// entry that references the current record. /// </summary> /// <param name="sesid">The session to use.</param> /// <param name="tableid">The cursor to retrieve the column from.</param> /// <param name="columnid">The columnid to retrieve.</param> /// <param name="itagSequence"> /// The sequence number of value in a multi-valued column. /// The array of values is one-based. The first value is /// sequence 1, not 0. If the record column has only one value then /// 1 should be passed as the itagSequence. /// </param> /// <param name="grbit">Retrieve column options.</param> /// <returns>The size of the column. 0 if the column is null.</returns> public static int?RetrieveColumnSize( JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, int itagSequence, RetrieveColumnGrbit grbit) { var retinfo = new JET_RETINFO { itagSequence = itagSequence }; int dataSize; JET_wrn wrn = JetRetrieveColumn( sesid, tableid, columnid, null, 0, out dataSize, grbit, retinfo); if (JET_wrn.ColumnNull == wrn) { return(null); } return(dataSize); }
/// <summary> /// Retrieve a column from the current record as a String /// </summary> /// <param name="columnid">The columnid to retrieve.</param> /// <param name="encoding">The string encoding format.</param> /// <param name="grbit">Retrieve options.</param> /// <returns>The data from the column.</returns> public virtual string RetrieveColumnAsString(JET_COLUMNID columnid, Encoding encoding, RetrieveColumnGrbit grbit) { this.Tracer.TraceVerbose("RetrieveColumn"); this.CheckNotDisposed(); if (0 == (RetrieveColumnGrbit.RetrieveCopy & grbit)) { this.CheckHasCurrency(); } return(Api.RetrieveColumnAsString(this.session, this.table, columnid, encoding, grbit)); }
/// <summary> /// Retrieve a Unicode (UTF16) string. This is optimized to take advantage of the fact /// that no conversion is needed. /// </summary> /// <param name="sesid">The session to use.</param> /// <param name="tableid">The table to retrieve from.</param> /// <param name="columnid">The column to retrieve.</param> /// <param name="grbit">Retrieve options.</param> /// <returns>The string retrieved from the column.</returns> private static unsafe string RetrieveUnicodeString(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, RetrieveColumnGrbit grbit) { // 512 Unicode characters (1kb on stack) const int BufferSize = 512; char * buffer = stackalloc char[BufferSize]; int actualDataSize; JET_wrn wrn = JetRetrieveColumn(sesid, tableid, columnid, new IntPtr(buffer), BufferSize * sizeof(char), out actualDataSize, grbit, null); if (JET_wrn.ColumnNull == wrn) { return(null); } if (JET_wrn.Success == wrn) { ////return StringCache.GetString(buffer, 0, actualDataSize); return(new string(buffer, 0, actualDataSize / sizeof(char))); } Debug.Assert(JET_wrn.BufferTruncated == wrn, "Unexpected warning code"); // Create a fake string of the appropriate size and then fill it in. var s = new string('\0', actualDataSize / sizeof(char)); fixed(char *p = s) { int newDataSize; wrn = JetRetrieveColumn(sesid, tableid, columnid, new IntPtr(p), actualDataSize, out newDataSize, grbit, null); if (JET_wrn.BufferTruncated == wrn) { string error = String.Format( CultureInfo.CurrentCulture, "Column size changed from {0} to {1}. The record was probably updated by another thread.", actualDataSize, newDataSize); Trace.TraceError(error); throw new InvalidOperationException(error); } } return(s); }
/// <summary> /// Retrieve a column from the current record as a UInt64 /// </summary> /// <param name="columnid">The columnid to retrieve.</param> /// <param name="grbit">Retrieve options.</param> /// <returns>The data from the column.</returns> public virtual ulong? RetrieveColumnAsUInt64(JET_COLUMNID columnid, RetrieveColumnGrbit grbit) { this.Tracer.TraceVerbose("RetrieveColumn"); this.CheckNotDisposed(); if (0 == (RetrieveColumnGrbit.RetrieveCopy & grbit)) { this.CheckHasCurrency(); } return Api.RetrieveColumnAsUInt64(this.session, this.table, columnid, grbit); }
/// <summary> /// Gets the fields of the current row. /// </summary> /// <param name="grbit">The grbit.</param> /// <returns>A <see cref="FieldCollection"/> object to allow retrieval of all fields of the current row.</returns> internal FieldCollection GetFields(RetrieveColumnGrbit grbit) { JET_PFNREALLOC allocator = (context, pv, cb) => IntPtr.Zero == pv ? Marshal.AllocHGlobal(new IntPtr(cb)) : Marshal.ReAllocHGlobal(pv, new IntPtr(cb)); lock (this.isamSession) { this.CheckDisposed(); this.CheckRecord(); EnumerateColumnsGrbit enumerateGrbit = ((grbit & RetrieveColumnGrbit.RetrieveCopy) != 0) ? EnumerateColumnsGrbit.EnumerateCopy : EnumerateColumnsGrbit.None; using (IsamTransaction trx = new IsamTransaction(this.isamSession, true)) { // enumerate all field values in the current record or copy // buffer JET_ENUMCOLUMN[] jecs; int numColumnValues; Api.JetEnumerateColumns( this.isamSession.Sesid, this.tableid, 0, // numColumnids null, // columnids out numColumnValues, out jecs, allocator, IntPtr.Zero, // allocatorContext, int.MaxValue, enumerateGrbit); // create a field collection to contain our field values FieldCollection fields = new FieldCollection(); // save the location of the source record for these field values fields.Location = this.Location; // fill the field collection with our field values if (jecs != null && jecs.Length > 0) { foreach (JET_ENUMCOLUMN jec in jecs) { if (jec.rgEnumColumnValue != null && jec.rgEnumColumnValue.Length > 0) { JET_COLUMNBASE columnbase; VistaApi.JetGetTableColumnInfo( this.isamSession.Sesid, this.tableid, jec.columnid, out columnbase); Columnid columnid = new Columnid(columnbase); bool isAscii = columnbase.cp == JET_CP.ASCII; FieldValueCollection values = new FieldValueCollection(columnid); foreach (JET_ENUMCOLUMNVALUE jecv in jec.rgEnumColumnValue) { // FUTURE-2013/11/15-martinc: Drat, this is an IntPtr, and ObjectFromBytes() really // wants a byte[] array. Copying the data to a byte array just to simply // re-interpret it as an object is inefficient. // We should write Converter.ObjectFromIntPtr... byte[] bytesData = new byte[jecv.cbData]; Marshal.Copy(jecv.pvData, bytesData, 0, bytesData.Length); values.Add(Converter.ObjectFromBytes(columnbase.coltyp, isAscii, bytesData)); } values.ReadOnly = true; fields.Add(values); } } } fields.ReadOnly = true; // Return the field collection. return fields; } } }