//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // // [....] // [....] //------------------------------------------------------------------------------ namespace System.Data.OleDb { using System; using System.Diagnostics; using System.Data; using System.Data.Common; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; sealed internal class ColumnBinding { // shared with other ColumnBindings private readonly OleDbDataReader _dataReader; // HCHAPTER private readonly RowBinding _rowbinding; // for native buffer interaction private readonly Bindings _bindings; // unique to this ColumnBinding private readonly OleDbParameter _parameter; // output value private readonly int _parameterChangeID; private readonly int _offsetStatus; private readonly int _offsetLength; private readonly int _offsetValue; private readonly int _ordinal; private readonly int _maxLen; private readonly short _wType; private readonly byte _precision; private readonly int _index; private readonly int _indexForAccessor; // HCHAPTER private readonly int _indexWithinAccessor; // HCHAPTER private readonly bool _ifIRowsetElseIRow; // unique per current input value private int _valueBindingOffset; private int _valueBindingSize; internal StringMemHandle _sptr; private GCHandle _pinnedBuffer; // value is cached via property getters so the original may be released // for Value, ValueByteArray, ValueString, ValueVariant private object _value; internal ColumnBinding(OleDbDataReader dataReader, int index, int indexForAccessor, int indexWithinAccessor, OleDbParameter parameter, RowBinding rowbinding, Bindings bindings, tagDBBINDING binding, int offset, bool ifIRowsetElseIRow) { Debug.Assert(null != rowbinding, "null rowbinding"); Debug.Assert(null != bindings, "null bindings"); Debug.Assert(ODB.SizeOf_tagDBBINDING <= offset, "invalid offset" + offset); _dataReader = dataReader; _rowbinding = rowbinding; _bindings = bindings; _index = index; _indexForAccessor = indexForAccessor; _indexWithinAccessor = indexWithinAccessor; if (null != parameter) { _parameter = parameter; _parameterChangeID = parameter.ChangeID; } _offsetStatus = binding.obStatus.ToInt32() + offset; _offsetLength = binding.obLength.ToInt32() + offset; _offsetValue = binding.obValue.ToInt32() + offset; Debug.Assert(0 <= _offsetStatus, "negative _offsetStatus"); Debug.Assert(0 <= _offsetLength, "negative _offsetLength"); Debug.Assert(0 <= _offsetValue, "negative _offsetValue"); _ordinal = binding.iOrdinal.ToInt32(); _maxLen = binding.cbMaxLen.ToInt32(); _wType = binding.wType; _precision = binding.bPrecision; _ifIRowsetElseIRow = ifIRowsetElseIRow; SetSize(Bindings.ParamSize.ToInt32()); } internal Bindings Bindings { get { _bindings.CurrentIndex = IndexWithinAccessor; return _bindings; } } internal RowBinding RowBinding { get { return _rowbinding; } } internal int ColumnBindingOrdinal { get { return _ordinal; } } private int ColumnBindingMaxLen { get { return _maxLen; } } private byte ColumnBindingPrecision { get { return _precision; } } private short DbType { get { return _wType; } } private Type ExpectedType { get { return NativeDBType.FromDBType(DbType, false, false).dataType; } } internal int Index { get { return _index; } } internal int IndexForAccessor { get { return _indexForAccessor; } } internal int IndexWithinAccessor { get { return _indexWithinAccessor; } } private int ValueBindingOffset { // offset within the value of where to start copying get { return _valueBindingOffset; } } private int ValueBindingSize { // maximum size of the value to copy get { return _valueBindingSize; } } internal int ValueOffset { // offset within the native buffer to put the value get { return _offsetValue; } } private OleDbDataReader DataReader() { Debug.Assert(null != _dataReader, "null DataReader"); return _dataReader; } internal bool IsParameterBindingInvalid(OleDbParameter parameter) { Debug.Assert((null != _parameter) && (null != parameter), "null parameter"); return ((_parameter.ChangeID != _parameterChangeID) || (_parameter != parameter)); } internal bool IsValueNull() { return ((DBStatus.S_ISNULL == StatusValue()) || (((NativeDBType.VARIANT == DbType) || (NativeDBType.PROPVARIANT == DbType)) && (Convert.IsDBNull(ValueVariant())))); } private int LengthValue() { int length; if (_ifIRowsetElseIRow) { length = RowBinding.ReadIntPtr(_offsetLength).ToInt32(); } else { // WebData 94427 length = Bindings.DBColumnAccess[IndexWithinAccessor].cbDataLen.ToInt32(); } return Math.Max(length, 0); } private void LengthValue(int value) { Debug.Assert(0 <= value, "negative LengthValue"); RowBinding.WriteIntPtr(_offsetLength, (IntPtr)value); } internal OleDbParameter Parameter() { Debug.Assert(null != _parameter, "null parameter"); return _parameter; } internal void ResetValue() { _value = null; StringMemHandle sptr = _sptr; _sptr = null; if (null != sptr) { sptr.Dispose(); } if (_pinnedBuffer.IsAllocated) { _pinnedBuffer.Free(); } } internal DBStatus StatusValue() { if (_ifIRowsetElseIRow) { return (DBStatus) RowBinding.ReadInt32(_offsetStatus); } else { // WebData 94427 return (DBStatus) Bindings.DBColumnAccess[IndexWithinAccessor].dwStatus; } } internal void StatusValue(DBStatus value) { #if DEBUG switch(value) { case DBStatus.S_OK: case DBStatus.S_ISNULL: case DBStatus.S_DEFAULT: break; default: Debug.Assert(false, "unexpected StatusValue"); break; } #endif RowBinding.WriteInt32(_offsetStatus, (int)value); } internal void SetOffset(int offset) { if (0 > offset) { throw ADP.InvalidOffsetValue(offset); } _valueBindingOffset = Math.Max(offset, 0); } internal void SetSize(int size) { _valueBindingSize = Math.Max(size, 0); } private void SetValueDBNull() { LengthValue(0); StatusValue(DBStatus.S_ISNULL); RowBinding.WriteInt64(ValueOffset, 0); // safe because AlignDataSize forces 8 byte blocks } private void SetValueEmpty() { LengthValue(0); StatusValue(DBStatus.S_DEFAULT); RowBinding.WriteInt64(ValueOffset, 0); // safe because AlignDataSize forces 8 byte blocks } internal Object Value() { object value = _value; if (null == value) { switch(StatusValue()) { case DBStatus.S_OK: switch(DbType) { case NativeDBType.EMPTY: case NativeDBType.NULL: value = DBNull.Value; break; case NativeDBType.I2: value = Value_I2(); // Int16 break; case NativeDBType.I4: value = Value_I4(); // Int32 break; case NativeDBType.R4: value = Value_R4(); // Single break; case NativeDBType.R8: value = Value_R8(); // Double break; case NativeDBType.CY: value = Value_CY(); // Decimal break; case NativeDBType.DATE: value = Value_DATE(); // DateTime break; case NativeDBType.BSTR: value = Value_BSTR(); // String break; case NativeDBType.IDISPATCH: value = Value_IDISPATCH(); // Object break; case NativeDBType.ERROR: value = Value_ERROR(); // Int32 break; case NativeDBType.BOOL: value = Value_BOOL(); // Boolean break; case NativeDBType.VARIANT: value = Value_VARIANT(); // Object break; case NativeDBType.IUNKNOWN: value = Value_IUNKNOWN(); // Object break; case NativeDBType.DECIMAL: value = Value_DECIMAL(); // Decimal break; case NativeDBType.I1: value = (short) Value_I1(); // SByte->Int16 break; case NativeDBType.UI1: value = Value_UI1(); // Byte break; case NativeDBType.UI2: value = (int) Value_UI2(); // UInt16->Int32 break; case NativeDBType.UI4: value = (long) Value_UI4(); // UInt32->Int64 break; case NativeDBType.I8: value = Value_I8(); // Int64 break; case NativeDBType.UI8: value = (Decimal) Value_UI8(); // UInt64->Decimal break; case NativeDBType.FILETIME: value = Value_FILETIME(); // DateTime break; case NativeDBType.GUID: value = Value_GUID(); // Guid break; case NativeDBType.BYTES: value = Value_BYTES(); // Byte[] break; case NativeDBType.WSTR: value = Value_WSTR(); // String break; case NativeDBType.NUMERIC: value = Value_NUMERIC(); // Decimal break; case NativeDBType.DBDATE: value = Value_DBDATE(); // DateTime break; case NativeDBType.DBTIME: value = Value_DBTIME(); // TimeSpan break; case NativeDBType.DBTIMESTAMP: value = Value_DBTIMESTAMP(); // DateTime break; case NativeDBType.PROPVARIANT: value = Value_VARIANT(); // Object break; case NativeDBType.HCHAPTER: value = Value_HCHAPTER(); // OleDbDataReader break; case (NativeDBType.BYREF | NativeDBType.BYTES): value = Value_ByRefBYTES(); break; case (NativeDBType.BYREF | NativeDBType.WSTR): value = Value_ByRefWSTR(); break; default: throw ODB.GVtUnknown(DbType); #if DEBUG case NativeDBType.STR: Debug.Assert(false, "should have bound as WSTR"); goto default; case NativeDBType.VARNUMERIC: Debug.Assert(false, "should have bound as NUMERIC"); goto default; case NativeDBType.UDT: Debug.Assert(false, "UDT binding should not have been encountered"); goto default; case (NativeDBType.BYREF | NativeDBType.STR): Debug.Assert(false, "should have bound as BYREF|WSTR"); goto default; #endif } break; case DBStatus.S_TRUNCATED: switch(DbType) { case NativeDBType.BYTES: value = Value_BYTES(); break; case NativeDBType.WSTR: value = Value_WSTR(); break; case (NativeDBType.BYREF | NativeDBType.BYTES): value = Value_ByRefBYTES(); break; case (NativeDBType.BYREF | NativeDBType.WSTR): value = Value_ByRefWSTR(); break; default: throw ODB.GVtUnknown(DbType); #if DEBUG case NativeDBType.STR: Debug.Assert(false, "should have bound as WSTR"); goto default; case (NativeDBType.BYREF | NativeDBType.STR): Debug.Assert(false, "should have bound as BYREF|WSTR"); goto default; #endif } break; case DBStatus.S_ISNULL: case DBStatus.S_DEFAULT: value = DBNull.Value; break; default: throw CheckTypeValueStatusValue(); // MDAC 71644 } _value = value; } return value; } internal void Value(object value) { if (null == value) { SetValueEmpty(); } else if (Convert.IsDBNull(value)) { SetValueDBNull(); } else switch (DbType) { case NativeDBType.EMPTY: SetValueEmpty(); break; case NativeDBType.NULL: // language null - no representation, use DBNull SetValueDBNull(); break; case NativeDBType.I2: Value_I2((Int16) value); break; case NativeDBType.I4: Value_I4((Int32) value); break; case NativeDBType.R4: Value_R4((Single) value); break; case NativeDBType.R8: Value_R8((Double) value); break; case NativeDBType.CY: Value_CY((Decimal) value); break; case NativeDBType.DATE: Value_DATE((DateTime) value); break; case NativeDBType.BSTR: Value_BSTR((String) value); break; case NativeDBType.IDISPATCH: Value_IDISPATCH(value); break; case NativeDBType.ERROR: Value_ERROR((Int32) value); break; case NativeDBType.BOOL: Value_BOOL((Boolean) value); break; case NativeDBType.VARIANT: Value_VARIANT(value); break; case NativeDBType.IUNKNOWN: Value_IUNKNOWN(value); break; case NativeDBType.DECIMAL: Value_DECIMAL((Decimal) value); break; case NativeDBType.I1: if (value is Int16) { // MDAC 60430 Value_I1(Convert.ToSByte((Int16)value, CultureInfo.InvariantCulture)); } else { Value_I1((SByte) value); } break; case NativeDBType.UI1: Value_UI1((Byte) value); break; case NativeDBType.UI2: if (value is Int32) { Value_UI2(Convert.ToUInt16((Int32)value, CultureInfo.InvariantCulture)); } else { Value_UI2((UInt16) value); } break; case NativeDBType.UI4: if (value is Int64) { Value_UI4(Convert.ToUInt32((Int64)value, CultureInfo.InvariantCulture)); } else { Value_UI4((UInt32) value); } break; case NativeDBType.I8: Value_I8((Int64) value); break; case NativeDBType.UI8: if (value is Decimal) { Value_UI8(Convert.ToUInt64((Decimal)value, CultureInfo.InvariantCulture)); } else { Value_UI8((UInt64) value); } break; case NativeDBType.FILETIME: Value_FILETIME((DateTime) value); break; case NativeDBType.GUID: Value_GUID((Guid) value); break; case NativeDBType.BYTES: Value_BYTES((Byte[]) value); break; case NativeDBType.WSTR: if (value is string) { Value_WSTR((String) value); } else { Value_WSTR((char[]) value); } break; case NativeDBType.NUMERIC: Value_NUMERIC((Decimal) value); break; case NativeDBType.DBDATE: Value_DBDATE((DateTime) value); break; case NativeDBType.DBTIME: Value_DBTIME((TimeSpan) value); break; case NativeDBType.DBTIMESTAMP: Value_DBTIMESTAMP((DateTime) value); break; case NativeDBType.PROPVARIANT: Value_VARIANT(value); break; case (NativeDBType.BYREF | NativeDBType.BYTES): Value_ByRefBYTES((Byte[]) value); break; case (NativeDBType.BYREF | NativeDBType.WSTR): if (value is string) { Value_ByRefWSTR((String) value); } else { Value_ByRefWSTR((char[])value); } break; default: Debug.Assert(false, "unknown DBTYPE"); throw ODB.SVtUnknown(DbType); #if DEBUG case NativeDBType.STR: Debug.Assert(false, "Should have bound as WSTR"); goto default; case NativeDBType.UDT: Debug.Assert(false, "UDT binding should not have been encountered"); goto default; case NativeDBType.HCHAPTER: Debug.Assert(false, "not allowed to set HCHAPTER"); goto default; case NativeDBType.VARNUMERIC: Debug.Assert(false, "should have bound as NUMERIC"); goto default; case (NativeDBType.BYREF | NativeDBType.STR): Debug.Assert(false, "should have bound as BYREF|WSTR"); goto default; #endif } } internal Boolean Value_BOOL() { Debug.Assert((NativeDBType.BOOL == DbType), "Value_BOOL"); Debug.Assert((DBStatus.S_OK == StatusValue()), "Value_BOOL"); Int16 value = RowBinding.ReadInt16(ValueOffset); return (0 != value); } private void Value_BOOL(Boolean value) { Debug.Assert((NativeDBType.BOOL == DbType), "Value_BOOL"); LengthValue(0); StatusValue(DBStatus.S_OK); RowBinding.WriteInt16(ValueOffset, (short)(value ? ODB.VARIANT_TRUE : ODB.VARIANT_FALSE)); } private String Value_BSTR() { Debug.Assert((NativeDBType.BSTR == DbType), "Value_BSTR"); Debug.Assert((DBStatus.S_OK == StatusValue()), "Value_BSTR"); string value = ""; RowBinding bindings = RowBinding; bool mustRelease = false; RuntimeHelpers.PrepareConstrainedRegions(); try { bindings.DangerousAddRef(ref mustRelease); IntPtr ptr = bindings.ReadIntPtr(ValueOffset); if (ADP.PtrZero != ptr) { value = Marshal.PtrToStringBSTR(ptr); } } finally { if (mustRelease) { bindings.DangerousRelease(); } } return value; } private void Value_BSTR(String value) { Debug.Assert((null != value), "Value_BSTR null"); Debug.Assert((NativeDBType.BSTR == DbType), "Value_BSTR"); LengthValue(value.Length * 2); /* bytecount*/ StatusValue(DBStatus.S_OK); RowBinding.SetBstrValue(ValueOffset, value); } private Byte[] Value_ByRefBYTES() { Debug.Assert(((NativeDBType.BYREF | NativeDBType.BYTES) == DbType), "Value_ByRefBYTES"); Debug.Assert((DBStatus.S_OK == StatusValue()), "Value_ByRefBYTES"); byte[] value = null; RowBinding bindings = RowBinding; bool mustRelease = false; RuntimeHelpers.PrepareConstrainedRegions(); try { bindings.DangerousAddRef(ref mustRelease); IntPtr ptr = bindings.ReadIntPtr(ValueOffset); if (ADP.PtrZero != ptr) { value = new byte[LengthValue()]; Marshal.Copy(ptr, value, 0, value.Length); } } finally { if (mustRelease) { bindings.DangerousRelease(); } } return ((null != value) ? value : new byte[0]); } private void Value_ByRefBYTES(Byte[] value) { Debug.Assert(null != value, "Value_ByRefBYTES null"); Debug.Assert((NativeDBType.BYREF | NativeDBType.BYTES) == DbType, "Value_ByRefBYTES"); // we expect the provider/server to apply the silent truncation when binding BY_REF // if (value.Length < ValueBindingOffset) { throw "Offset must refer to a location within the value" } int length = ((ValueBindingOffset < value.Length) ? (value.Length - ValueBindingOffset) : 0); LengthValue(((0 < ValueBindingSize) ? Math.Min(ValueBindingSize, length) : length)); StatusValue(DBStatus.S_OK); IntPtr ptr = ADP.PtrZero; if (0 < length) { // avoid pinning empty byte[] _pinnedBuffer = GCHandle.Alloc(value, GCHandleType.Pinned); ptr = _pinnedBuffer.AddrOfPinnedObject(); ptr = ADP.IntPtrOffset(ptr, ValueBindingOffset); } RowBinding.SetByRefValue(ValueOffset, ptr); } private String Value_ByRefWSTR() { Debug.Assert((NativeDBType.BYREF | NativeDBType.WSTR) == DbType, "Value_ByRefWSTR"); Debug.Assert((DBStatus.S_OK == StatusValue()) || (DBStatus.S_TRUNCATED == StatusValue()), "Value_ByRefWSTR"); string value = ""; RowBinding bindings = RowBinding; bool mustRelease = false; RuntimeHelpers.PrepareConstrainedRegions(); try { bindings.DangerousAddRef(ref mustRelease); IntPtr ptr = bindings.ReadIntPtr(ValueOffset); if (ADP.PtrZero != ptr) { int charCount = LengthValue() / 2; value = Marshal.PtrToStringUni(ptr, charCount); } } finally { if (mustRelease) { bindings.DangerousRelease(); } } return value; } private void Value_ByRefWSTR(String value) { Debug.Assert(null != value, "Value_ByRefWSTR null"); Debug.Assert((NativeDBType.BYREF | NativeDBType.WSTR) == DbType, "Value_ByRefWSTR"); // we expect the provider/server to apply the silent truncation when binding BY_REF // if (value.Length < ValueBindingOffset) { throw "Offset must refer to a location within the value" } int length = ((ValueBindingOffset < value.Length) ? (value.Length - ValueBindingOffset) : 0); LengthValue(((0 < ValueBindingSize) ? Math.Min(ValueBindingSize, length) : length) * 2); /* charcount->bytecount*/ StatusValue(DBStatus.S_OK); IntPtr ptr = ADP.PtrZero; if (0 < length) { // avoid pinning empty string, i.e String.Empty _pinnedBuffer = GCHandle.Alloc(value, GCHandleType.Pinned); ptr = _pinnedBuffer.AddrOfPinnedObject(); ptr = ADP.IntPtrOffset(ptr, ValueBindingOffset); } RowBinding.SetByRefValue(ValueOffset, ptr); } private void Value_ByRefWSTR(char[] value) { Debug.Assert(null != value, "Value_ByRefWSTR null"); Debug.Assert((NativeDBType.BYREF | NativeDBType.WSTR) == DbType, "Value_ByRefWSTR"); // we expect the provider/server to apply the silent truncation when binding BY_REF // if (value.Length < ValueBindingOffset) { throw "Offset must refer to a location within the value" } int length = ((ValueBindingOffset < value.Length) ? (value.Length - ValueBindingOffset) : 0); LengthValue(((0 < ValueBindingSize) ? Math.Min(ValueBindingSize, length) : length) * 2); /* charcount->bytecount*/ StatusValue(DBStatus.S_OK); IntPtr ptr = ADP.PtrZero; if (0 < length) { // avoid pinning empty char[] _pinnedBuffer = GCHandle.Alloc(value, GCHandleType.Pinned); ptr = _pinnedBuffer.AddrOfPinnedObject(); ptr = ADP.IntPtrOffset(ptr, ValueBindingOffset); } RowBinding.SetByRefValue(ValueOffset, ptr); } private Byte[] Value_BYTES() { Debug.Assert(NativeDBType.BYTES == DbType, "Value_BYTES"); Debug.Assert((DBStatus.S_OK == StatusValue()) || (DBStatus.S_TRUNCATED == StatusValue()), "Value_BYTES"); int byteCount = Math.Min(LengthValue(), ColumnBindingMaxLen); byte[] value = new byte[byteCount]; RowBinding.ReadBytes(ValueOffset, value, 0, byteCount); return value; } private void Value_BYTES(Byte[] value) { Debug.Assert(null != value, "Value_BYTES null"); // we silently truncate when the user has specified a given Size int bytecount = ((ValueBindingOffset < value.Length) ? Math.Min(value.Length - ValueBindingOffset, ColumnBindingMaxLen) : 0); // 70232 LengthValue(bytecount); StatusValue(DBStatus.S_OK); if (0 < bytecount) { RowBinding.WriteBytes(ValueOffset, value, ValueBindingOffset, bytecount); } } private Decimal Value_CY() { Debug.Assert(NativeDBType.CY == DbType, "Value_CY"); Debug.Assert(DBStatus.S_OK == StatusValue(), "Value_CY"); return Decimal.FromOACurrency(RowBinding.ReadInt64(ValueOffset)); } private void Value_CY(Decimal value) { Debug.Assert(NativeDBType.CY == DbType, "Value_CY"); LengthValue(0); StatusValue(DBStatus.S_OK); RowBinding.WriteInt64(ValueOffset, Decimal.ToOACurrency(value)); } private DateTime Value_DATE() { Debug.Assert(NativeDBType.DATE == DbType, "Value_DATE"); Debug.Assert(DBStatus.S_OK == StatusValue(), "Value_DATE"); return DateTime.FromOADate(RowBinding.ReadDouble(ValueOffset)); } private void Value_DATE(DateTime value) { Debug.Assert(NativeDBType.DATE == DbType, "Value_DATE"); LengthValue(0); StatusValue(DBStatus.S_OK); RowBinding.WriteDouble(ValueOffset, value.ToOADate()); } private DateTime Value_DBDATE() { Debug.Assert(NativeDBType.DBDATE == DbType, "Value_DBDATE"); Debug.Assert(DBStatus.S_OK == StatusValue(), "Value_DBDATE"); return RowBinding.ReadDate(ValueOffset); } private void Value_DBDATE(DateTime value) { Debug.Assert(NativeDBType.DBDATE == DbType, "Value_DATE"); LengthValue(0); StatusValue(DBStatus.S_OK); RowBinding.WriteDate(ValueOffset, value); } private TimeSpan Value_DBTIME() { Debug.Assert(NativeDBType.DBTIME == DbType, "Value_DBTIME"); Debug.Assert(DBStatus.S_OK == StatusValue(), "Value_DBTIME"); return RowBinding.ReadTime(ValueOffset); } private void Value_DBTIME(TimeSpan value) { Debug.Assert(NativeDBType.DBTIME == DbType, "Value_DBTIME"); LengthValue(0); StatusValue(DBStatus.S_OK); RowBinding.WriteTime(ValueOffset, value); } private DateTime Value_DBTIMESTAMP() { Debug.Assert(NativeDBType.DBTIMESTAMP == DbType, "Value_DBTIMESTAMP"); Debug.Assert(DBStatus.S_OK == StatusValue(), "Value_DBTIMESTAMP"); return RowBinding.ReadDateTime(ValueOffset); } private void Value_DBTIMESTAMP(DateTime value) { Debug.Assert(NativeDBType.DBTIMESTAMP == DbType, "Value_DBTIMESTAMP"); LengthValue(0); StatusValue(DBStatus.S_OK); RowBinding.WriteDateTime(ValueOffset, value); } private Decimal Value_DECIMAL() { Debug.Assert(NativeDBType.DECIMAL == DbType, "Value_DECIMAL"); Debug.Assert(DBStatus.S_OK == StatusValue(), "Value_DECIMAL"); int[] buffer = new int[4]; RowBinding.ReadInt32Array(ValueOffset, buffer, 0, 4); return new Decimal( buffer[2], // low buffer[3], // mid buffer[1], // high (0 != (buffer[0] & unchecked((int)0x80000000))), // sign unchecked((byte)((buffer[0] & unchecked((int)0x00FF0000)) >> 16))); // scale, MDAC 95080 } private void Value_DECIMAL(Decimal value) { Debug.Assert(NativeDBType.DECIMAL == DbType, "Value_DECIMAL"); /* pending breaking change approval if (_precision < ((System.Data.SqlTypes.SqlDecimal) value).Precision) { // WebData 87236 throw ADP.ParameterValueOutOfRange(value); } */ LengthValue(0); StatusValue(DBStatus.S_OK); int[] tmp = Decimal.GetBits(value); int[] buffer = new int[4] { tmp[3], tmp[2], tmp[0], tmp[1] }; RowBinding.WriteInt32Array(ValueOffset, buffer, 0, 4); } private Int32 Value_ERROR() { Debug.Assert(NativeDBType.ERROR == DbType, "Value_ERROR"); Debug.Assert(DBStatus.S_OK == StatusValue(), "Value_ERROR"); return RowBinding.ReadInt32(ValueOffset); } private void Value_ERROR(Int32 value) { Debug.Assert(NativeDBType.ERROR == DbType, "Value_ERROR"); LengthValue(0); StatusValue(DBStatus.S_OK); RowBinding.WriteInt32(ValueOffset, value); } private DateTime Value_FILETIME() { Debug.Assert(NativeDBType.FILETIME == DbType, "Value_FILETIME"); Debug.Assert(DBStatus.S_OK == StatusValue(), "Value_FILETIME"); Int64 tmp = RowBinding.ReadInt64(ValueOffset); return DateTime.FromFileTime(tmp); } private void Value_FILETIME(DateTime value) { Debug.Assert(NativeDBType.FILETIME == DbType, "Value_FILETIME"); LengthValue(0); StatusValue(DBStatus.S_OK); Int64 tmp = value.ToFileTime(); RowBinding.WriteInt64(ValueOffset, tmp); } internal Guid Value_GUID() { Debug.Assert(NativeDBType.GUID == DbType, "Value_GUID"); Debug.Assert(DBStatus.S_OK == StatusValue(), "Value_GUID"); return RowBinding.ReadGuid(ValueOffset); } private void Value_GUID(Guid value) { Debug.Assert(NativeDBType.GUID == DbType, "Value_GUID"); LengthValue(0); StatusValue(DBStatus.S_OK); RowBinding.WriteGuid(ValueOffset, value); } internal OleDbDataReader Value_HCHAPTER() { Debug.Assert(NativeDBType.HCHAPTER == DbType, "Value_HCHAPTER"); Debug.Assert(DBStatus.S_OK == StatusValue(), "Value_HCHAPTER"); return DataReader().ResetChapter(IndexForAccessor, IndexWithinAccessor, RowBinding, ValueOffset); } private SByte Value_I1() { Debug.Assert(NativeDBType.I1 == DbType, "Value_I1"); Debug.Assert(DBStatus.S_OK == StatusValue(), "Value_I1"); byte value = RowBinding.ReadByte(ValueOffset); return unchecked((SByte)value); } private void Value_I1(SByte value) { Debug.Assert(NativeDBType.I1 == DbType, "Value_I1"); LengthValue(0); StatusValue(DBStatus.S_OK); RowBinding.WriteByte(ValueOffset, unchecked((Byte) value)); } internal Int16 Value_I2() { Debug.Assert(NativeDBType.I2 == DbType, "Value_I2"); Debug.Assert(DBStatus.S_OK == StatusValue(), "Value_I2"); return RowBinding.ReadInt16(ValueOffset); } private void Value_I2(Int16 value) { Debug.Assert(NativeDBType.I2 == DbType, "Value_I2"); LengthValue(0); StatusValue(DBStatus.S_OK); RowBinding.WriteInt16(ValueOffset, value); } private Int32 Value_I4() { Debug.Assert(NativeDBType.I4 == DbType, "Value_I4"); Debug.Assert(DBStatus.S_OK == StatusValue(), "Value_I4"); return RowBinding.ReadInt32(ValueOffset); } private void Value_I4(Int32 value) { Debug.Assert(NativeDBType.I4 == DbType, "Value_I4"); LengthValue(0); StatusValue(DBStatus.S_OK); RowBinding.WriteInt32(ValueOffset, value); } private Int64 Value_I8() { Debug.Assert(NativeDBType.I8 == DbType, "Value_I8"); Debug.Assert(DBStatus.S_OK == StatusValue(), "Value_I8"); return RowBinding.ReadInt64(ValueOffset); } private void Value_I8(Int64 value) { Debug.Assert(NativeDBType.I8 == DbType, "Value_I8"); LengthValue(0); StatusValue(DBStatus.S_OK); RowBinding.WriteInt64(ValueOffset, value); } private object Value_IDISPATCH() { Debug.Assert(NativeDBType.IDISPATCH == DbType, "Value_IDISPATCH"); Debug.Assert(DBStatus.S_OK == StatusValue(), "Value_IDISPATCH"); object value; RowBinding bindings = RowBinding; bool mustRelease = false; RuntimeHelpers.PrepareConstrainedRegions(); try { bindings.DangerousAddRef(ref mustRelease); IntPtr ptr = bindings.ReadIntPtr(ValueOffset); value = Marshal.GetObjectForIUnknown(ptr); } finally { if (mustRelease) { bindings.DangerousRelease(); } } return value; } private void Value_IDISPATCH(object value) { // (new System.Security.NamedPermissionSet("FullTrust")).Demand(); // MDAC 80727 Debug.Assert(NativeDBType.IDISPATCH == DbType, "Value_IDISPATCH"); LengthValue(0); StatusValue(DBStatus.S_OK); IntPtr ptr = Marshal.GetIDispatchForObject(value); // MDAC 80727 RowBinding.WriteIntPtr(ValueOffset, ptr); } private object Value_IUNKNOWN() { Debug.Assert(NativeDBType.IUNKNOWN == DbType, "Value_IUNKNOWN"); Debug.Assert(DBStatus.S_OK == StatusValue(), "Value_IUNKNOWN"); object value; RowBinding bindings = RowBinding; bool mustRelease = false; RuntimeHelpers.PrepareConstrainedRegions(); try { bindings.DangerousAddRef(ref mustRelease); IntPtr ptr = bindings.ReadIntPtr(ValueOffset); value = Marshal.GetObjectForIUnknown(ptr); } finally { if (mustRelease) { bindings.DangerousRelease(); } } return value; } private void Value_IUNKNOWN(object value) { // (new System.Security.NamedPermissionSet("FullTrust")).Demand(); // MDAC 80727 Debug.Assert(NativeDBType.IUNKNOWN == DbType, "Value_IUNKNOWN"); LengthValue(0); StatusValue(DBStatus.S_OK); IntPtr ptr = Marshal.GetIUnknownForObject(value); // MDAC 80727 RowBinding.WriteIntPtr(ValueOffset, ptr); } private Decimal Value_NUMERIC() { Debug.Assert(NativeDBType.NUMERIC == DbType, "Value_NUMERIC"); Debug.Assert(DBStatus.S_OK == StatusValue(), "Value_NUMERIC"); return RowBinding.ReadNumeric(ValueOffset); } private void Value_NUMERIC(Decimal value) { Debug.Assert(NativeDBType.NUMERIC == DbType, "Value_NUMERIC"); /* pending breaking change approval if (_precision < ((System.Data.SqlTypes.SqlDecimal) value).Precision) { // WebData 87236 throw ADP.ParameterValueOutOfRange(value); } */ LengthValue(0); StatusValue(DBStatus.S_OK); RowBinding.WriteNumeric(ValueOffset, value, ColumnBindingPrecision); } private Single Value_R4() { Debug.Assert(NativeDBType.R4 == DbType, "Value_R4"); Debug.Assert(DBStatus.S_OK == StatusValue(), "Value_R4"); return RowBinding.ReadSingle(ValueOffset); } private void Value_R4(Single value) { Debug.Assert(NativeDBType.R4 == DbType, "Value_R4"); LengthValue(0); StatusValue(DBStatus.S_OK); RowBinding.WriteSingle(ValueOffset,value); } private Double Value_R8() { Debug.Assert(NativeDBType.R8 == DbType, "Value_R8"); Debug.Assert(DBStatus.S_OK == StatusValue(), "Value_R8"); return RowBinding.ReadDouble(ValueOffset); } private void Value_R8(Double value) { Debug.Assert(NativeDBType.R8 == DbType, "Value_I4"); LengthValue(0); StatusValue(DBStatus.S_OK); RowBinding.WriteDouble(ValueOffset, value); } private Byte Value_UI1() { Debug.Assert(NativeDBType.UI1 == DbType, "Value_UI1"); Debug.Assert(DBStatus.S_OK == StatusValue(), "Value_UI1"); return RowBinding.ReadByte(ValueOffset); } private void Value_UI1(Byte value) { Debug.Assert(NativeDBType.UI1 == DbType, "Value_UI1"); LengthValue(0); StatusValue(DBStatus.S_OK); RowBinding.WriteByte(ValueOffset, value); } internal UInt16 Value_UI2() { Debug.Assert(NativeDBType.UI2 == DbType, "Value_UI2"); Debug.Assert(DBStatus.S_OK == StatusValue(), "Value_UI2"); return unchecked((UInt16) RowBinding.ReadInt16(ValueOffset)); } private void Value_UI2(UInt16 value) { Debug.Assert(NativeDBType.UI2 == DbType, "Value_UI2"); LengthValue(0); StatusValue(DBStatus.S_OK); RowBinding.WriteInt16(ValueOffset, unchecked((Int16) value)); } internal UInt32 Value_UI4() { Debug.Assert(NativeDBType.UI4 == DbType, "Value_UI4"); Debug.Assert(DBStatus.S_OK == StatusValue(), "Value_UI4"); return unchecked((UInt32) RowBinding.ReadInt32(ValueOffset)); } private void Value_UI4(UInt32 value) { Debug.Assert(NativeDBType.UI4 == DbType, "Value_UI4"); LengthValue(0); StatusValue(DBStatus.S_OK); RowBinding.WriteInt32(ValueOffset, unchecked((Int32) value)); } internal UInt64 Value_UI8() { Debug.Assert(NativeDBType.UI8 == DbType, "Value_UI8"); Debug.Assert(DBStatus.S_OK == StatusValue(), "Value_UI8"); return unchecked((UInt64) RowBinding.ReadInt64(ValueOffset)); } private void Value_UI8(UInt64 value) { Debug.Assert(NativeDBType.UI8 == DbType, "Value_UI8"); LengthValue(0); StatusValue(DBStatus.S_OK); RowBinding.WriteInt64(ValueOffset, unchecked((Int64) value)); } private String Value_WSTR() { Debug.Assert(NativeDBType.WSTR == DbType, "Value_WSTR"); Debug.Assert((DBStatus.S_OK == StatusValue()) || (DBStatus.S_TRUNCATED == StatusValue()), "Value_WSTR"); Debug.Assert(2 < ColumnBindingMaxLen, "Value_WSTR"); int byteCount = Math.Min(LengthValue(), ColumnBindingMaxLen-2); return RowBinding.PtrToStringUni(ValueOffset, byteCount / 2); } private void Value_WSTR(String value) { Debug.Assert(null != value, "Value_BYTES null"); Debug.Assert(NativeDBType.WSTR == DbType, "Value_WSTR"); // we silently truncate when the user has specified a given Size int charCount = ((ValueBindingOffset < value.Length) ? Math.Min(value.Length - ValueBindingOffset, (ColumnBindingMaxLen-2)/2) : 0); // 70232 LengthValue(charCount*2); StatusValue(DBStatus.S_OK); if (0 < charCount) { char[] chars = value.ToCharArray(ValueBindingOffset, charCount); RowBinding.WriteCharArray(ValueOffset, chars, ValueBindingOffset, charCount); } } private void Value_WSTR(char[] value) { Debug.Assert(null != value, "Value_BYTES null"); Debug.Assert(NativeDBType.WSTR == DbType, "Value_WSTR"); // we silently truncate when the user has specified a given Size int charCount = ((ValueBindingOffset < value.Length) ? Math.Min(value.Length - ValueBindingOffset, (ColumnBindingMaxLen-2)/2) : 0); // 70232 LengthValue(charCount*2); StatusValue(DBStatus.S_OK); if (0 < charCount) { RowBinding.WriteCharArray(ValueOffset, value, ValueBindingOffset, charCount); } } private object Value_VARIANT() { Debug.Assert((NativeDBType.VARIANT == DbType) || (NativeDBType.PROPVARIANT == DbType), "Value_VARIANT"); Debug.Assert(DBStatus.S_OK == StatusValue(), "Value_VARIANT"); return RowBinding.GetVariantValue(ValueOffset); } private void Value_VARIANT(object value) { Debug.Assert((NativeDBType.VARIANT == DbType) || (NativeDBType.PROPVARIANT == DbType), "Value_VARIANT"); LengthValue(0); StatusValue(DBStatus.S_OK); RowBinding.SetVariantValue(ValueOffset, value); } internal Boolean ValueBoolean() { Boolean value; switch(StatusValue()) { case DBStatus.S_OK: switch(DbType) { case NativeDBType.BOOL: value = Value_BOOL(); break; case NativeDBType.VARIANT: value = (Boolean) ValueVariant(); break; default: throw ODB.ConversionRequired(); } break; default: throw CheckTypeValueStatusValue(typeof(Boolean)); } return value; } internal byte[] ValueByteArray() { byte[] value = (byte[]) _value; if (null == value) { switch(StatusValue()) { case DBStatus.S_OK: switch(DbType) { case NativeDBType.BYTES: value = Value_BYTES(); // String break; case NativeDBType.VARIANT: value = (byte[])ValueVariant(); // Object break; case (NativeDBType.BYREF | NativeDBType.BYTES): value = Value_ByRefBYTES(); break; default: throw ODB.ConversionRequired(); } break; case DBStatus.S_TRUNCATED: switch(DbType) { case NativeDBType.BYTES: value = Value_BYTES(); break; case (NativeDBType.BYREF | NativeDBType.BYTES): value = Value_ByRefBYTES(); break; default: throw ODB.ConversionRequired(); } break; default: throw CheckTypeValueStatusValue(typeof(byte[])); } _value = value; } return value; } internal Byte ValueByte() { Byte value; switch(StatusValue()) { case DBStatus.S_OK: switch(DbType) { case NativeDBType.UI1: value = Value_UI1(); break; case NativeDBType.VARIANT: value = (Byte) ValueVariant(); break; default: throw ODB.ConversionRequired(); } break; default: throw CheckTypeValueStatusValue(typeof(Byte)); } return value; } internal OleDbDataReader ValueChapter() { OleDbDataReader value = (OleDbDataReader) _value; if (null == value) { switch(StatusValue()) { case DBStatus.S_OK: switch(DbType) { case NativeDBType.HCHAPTER: value = Value_HCHAPTER(); // OleDbDataReader break; default: throw ODB.ConversionRequired(); } break; default: throw CheckTypeValueStatusValue(typeof(String)); } _value = value; } return value; } internal DateTime ValueDateTime() { DateTime value; switch(StatusValue()) { case DBStatus.S_OK: switch(DbType) { case NativeDBType.DATE: value = Value_DATE(); break; case NativeDBType.DBDATE: value = Value_DBDATE(); break; case NativeDBType.DBTIMESTAMP: value = Value_DBTIMESTAMP(); break; case NativeDBType.FILETIME: value = Value_FILETIME(); break; case NativeDBType.VARIANT: value = (DateTime) ValueVariant(); break; default: throw ODB.ConversionRequired(); } break; default: throw CheckTypeValueStatusValue(typeof(Int16)); } return value; } internal Decimal ValueDecimal() { Decimal value; switch(StatusValue()) { case DBStatus.S_OK: switch(DbType) { case NativeDBType.CY: value = Value_CY(); break; case NativeDBType.DECIMAL: value = Value_DECIMAL(); break; case NativeDBType.NUMERIC: value = Value_NUMERIC(); break; case NativeDBType.UI8: value = (Decimal)Value_UI8(); break; case NativeDBType.VARIANT: value = (Decimal) ValueVariant(); break; default: throw ODB.ConversionRequired(); } break; default: throw CheckTypeValueStatusValue(typeof(Int16)); } return value; } internal Guid ValueGuid() { Guid value; switch(StatusValue()) { case DBStatus.S_OK: switch(DbType) { case NativeDBType.GUID: value = Value_GUID(); break; default: throw ODB.ConversionRequired(); } break; default: throw CheckTypeValueStatusValue(typeof(Int16)); } return value; } internal Int16 ValueInt16() { Int16 value; switch(StatusValue()) { case DBStatus.S_OK: switch(DbType) { case NativeDBType.I2: value = Value_I2(); break; case NativeDBType.I1: value = (Int16) Value_I1(); break; case NativeDBType.VARIANT: object variant = ValueVariant(); if (variant is SByte) { value = (Int16)(SByte) variant; } else { value = (Int16) variant; } break; default: throw ODB.ConversionRequired(); } break; default: throw CheckTypeValueStatusValue(typeof(Int16)); } return value; } internal Int32 ValueInt32() { Int32 value; switch(StatusValue()) { case DBStatus.S_OK: switch(DbType) { case NativeDBType.I4: value = Value_I4(); break; case NativeDBType.UI2: value = (Int32) Value_UI2(); break; case NativeDBType.VARIANT: object variant = ValueVariant(); if (variant is UInt16) { value = (Int32)(UInt16) variant; } else { value = (Int32) variant; } break; default: throw ODB.ConversionRequired(); } break; default: throw CheckTypeValueStatusValue(typeof(Int32)); } return value; } internal Int64 ValueInt64() { Int64 value; switch(StatusValue()) { case DBStatus.S_OK: switch(DbType) { case NativeDBType.I8: value = Value_I8(); break; case NativeDBType.UI4: value = (Int64) Value_UI4(); break; case NativeDBType.VARIANT: object variant = ValueVariant(); if (variant is UInt32) { value = (Int64)(UInt32) variant; } else { value = (Int64) variant; } break; default: throw ODB.ConversionRequired(); } break; default: throw CheckTypeValueStatusValue(typeof(Int64)); } return value; } internal Single ValueSingle() { Single value; switch(StatusValue()) { case DBStatus.S_OK: switch(DbType) { case NativeDBType.R4: value = Value_R4(); break; case NativeDBType.VARIANT: value = (Single) ValueVariant(); break; default: throw ODB.ConversionRequired(); } break; default: throw CheckTypeValueStatusValue(typeof(Single)); } return value; } internal Double ValueDouble() { Double value; switch(StatusValue()) { case DBStatus.S_OK: switch(DbType) { case NativeDBType.R8: value = Value_R8(); break; case NativeDBType.VARIANT: value = (Double) ValueVariant(); break; default: throw ODB.ConversionRequired(); } break; default: throw CheckTypeValueStatusValue(typeof(Double)); } return value; } internal string ValueString() { string value = (String) _value; if (null == value) { switch(StatusValue()) { case DBStatus.S_OK: switch(DbType) { case NativeDBType.BSTR: value = Value_BSTR(); // String break; case NativeDBType.VARIANT: value = (String) ValueVariant(); // Object break; case NativeDBType.WSTR: value = Value_WSTR(); // String break; case (NativeDBType.BYREF | NativeDBType.WSTR): value = Value_ByRefWSTR(); break; default: throw ODB.ConversionRequired(); } break; case DBStatus.S_TRUNCATED: switch(DbType) { case NativeDBType.WSTR: value = Value_WSTR(); break; case (NativeDBType.BYREF | NativeDBType.WSTR): value = Value_ByRefWSTR(); break; default: throw ODB.ConversionRequired(); } break; default: throw CheckTypeValueStatusValue(typeof(String)); } _value = value; } return value; } private object ValueVariant() { object value = _value; if (null == value) { value = Value_VARIANT(); _value = value; } return value; } private Exception CheckTypeValueStatusValue() { // MDAC 71644 return CheckTypeValueStatusValue(ExpectedType); } private Exception CheckTypeValueStatusValue(Type expectedType) { // MDAC 71644 switch (StatusValue()) { case DBStatus.S_OK: Debug.Assert(false, "CheckStatusValue: unhandled data with ok status"); goto case DBStatus.E_CANTCONVERTVALUE; case DBStatus.S_TRUNCATED: Debug.Assert(false, "CheckStatusValue: unhandled data with truncated status"); goto case DBStatus.E_CANTCONVERTVALUE; case DBStatus.E_BADACCESSOR: return ODB.BadAccessor(); case DBStatus.E_CANTCONVERTVALUE: return ODB.CantConvertValue(); // case DBStatus.S_ISNULL: // database null return ADP.InvalidCast(); // case DBStatus.E_SIGNMISMATCH: return ODB.SignMismatch(expectedType); case DBStatus.E_DATAOVERFLOW: return ODB.DataOverflow(expectedType); case DBStatus.E_CANTCREATE: return ODB.CantCreate(expectedType); case DBStatus.E_UNAVAILABLE: return ODB.Unavailable(expectedType); default: return ODB.UnexpectedStatusValue(StatusValue()); } } } }