Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / Data / System / Data / SqlClient / TdsValueSetter.cs / 4 / TdsValueSetter.cs
//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// [....]
// [....]
//-----------------------------------------------------------------------------
namespace System.Data.SqlClient {
using Microsoft.SqlServer.Server;
using System;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Diagnostics;
using System.Text;
// TdsValueSetter handles writing a single value out to a TDS stream
// This class can easily be extended to handle multiple versions of TDS by sub-classing and virtualizing
// methods that have different formats or are not supported in one or the other version.
internal class TdsValueSetter {
#region Private fields
private TdsParserStateObject _stateObj; // target to write to
private SmiMetaData _metaData; // metadata describing value
private bool _isPlp; // should this column be sent in PLP format?
private bool _plpUnknownSent;// did we send initial UNKNOWN_LENGTH marker?
private Encoder _encoder; // required for chunking character type data
private SmiMetaData _variantType; // required for sql_variant
#if DEBUG
private int _currentOffset; // for chunking, verify that caller is using correct offsets
#endif
#endregion
#region Exposed Construct/factory methods
internal TdsValueSetter(TdsParserStateObject stateObj, SmiMetaData md) {
_stateObj = stateObj;
_metaData = md;
_isPlp = MetaDataUtilsSmi.IsPlpFormat(md);
_plpUnknownSent = false;
_encoder = null;
#if DEBUG
_currentOffset = 0;
#endif
}
#endregion
#region Setters
// Set value to null
// valid for all types
internal void SetDBNull() {
Debug.Assert(!_plpUnknownSent, "Setting a column to null that we already stated sending!");
if (_isPlp) {
_stateObj.Parser.WriteUnsignedLong(TdsEnums.SQL_PLP_NULL, _stateObj);
}
else {
switch(_metaData.SqlDbType) {
case SqlDbType.BigInt:
case SqlDbType.Bit:
case SqlDbType.DateTime:
case SqlDbType.Decimal:
case SqlDbType.Float:
case SqlDbType.Int:
case SqlDbType.Money:
case SqlDbType.Real:
case SqlDbType.UniqueIdentifier:
case SqlDbType.SmallDateTime:
case SqlDbType.SmallInt:
case SqlDbType.SmallMoney:
case SqlDbType.TinyInt:
case SqlDbType.Date:
case SqlDbType.Time:
case SqlDbType.DateTime2:
case SqlDbType.DateTimeOffset:
_stateObj.Parser.WriteByte(TdsEnums.FIXEDNULL, _stateObj);
break;
case SqlDbType.Binary:
case SqlDbType.Char:
case SqlDbType.Image:
case SqlDbType.NChar:
case SqlDbType.NText:
case SqlDbType.NVarChar:
case SqlDbType.Text:
case SqlDbType.Timestamp:
case SqlDbType.VarBinary:
case SqlDbType.VarChar:
_stateObj.Parser.WriteShort(TdsEnums.VARNULL, _stateObj);
break;
case SqlDbType.Udt:
case SqlDbType.Xml:
Debug.Assert(false, "PLP-only types shouldn't get to this point. Type: " + _metaData.SqlDbType);
break;
case SqlDbType.Variant:
_stateObj.Parser.WriteInt(TdsEnums.FIXEDNULL, _stateObj);
break;
case SqlDbType.Structured:
Debug.Assert(false, "Not yet implemented. Not needed until Structured UDTs");
break;
default:
Debug.Assert(false, "Unexpected SqlDbType: " + _metaData.SqlDbType);
break;
}
}
}
// valid for SqlDbType.Bit
internal void SetBoolean(Boolean value) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetBoolean));
if (SqlDbType.Variant == _metaData.SqlDbType) {
_stateObj.Parser.WriteSqlVariantHeader(3, TdsEnums.SQLBIT, 0, _stateObj);
}
else {
_stateObj.Parser.WriteByte((byte)_metaData.MaxLength, _stateObj);
}
if (value) {
_stateObj.Parser.WriteByte(1, _stateObj);
}
else {
_stateObj.Parser.WriteByte(0, _stateObj);
}
}
// valid for SqlDbType.TinyInt
internal void SetByte(Byte value) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetByte));
if (SqlDbType.Variant == _metaData.SqlDbType) {
_stateObj.Parser.WriteSqlVariantHeader(3, TdsEnums.SQLINT1, 0, _stateObj);
}
else {
_stateObj.Parser.WriteByte((byte)_metaData.MaxLength, _stateObj);
}
_stateObj.Parser.WriteByte(value, _stateObj);
}
// Semantics for SetBytes are to modify existing value, not overwrite
// Use in combination with SetLength to ensure overwriting when necessary
// valid for SqlDbTypes: Binary, VarBinary, Image, Udt, Xml
// (VarBinary assumed for variants)
internal int SetBytes(long fieldOffset, byte[] buffer, int bufferOffset, int length) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetBytes));
CheckSettingOffset(fieldOffset);
SetBytesNoOffsetHandling(fieldOffset, buffer, bufferOffset, length);
#if DEBUG
_currentOffset += length;
#endif
return length;
}
private void SetBytesNoOffsetHandling(long fieldOffset, byte[] buffer, int bufferOffset, int length) {
if (_isPlp) {
if (!_plpUnknownSent) {
_stateObj.Parser.WriteUnsignedLong(TdsEnums.SQL_PLP_UNKNOWNLEN, _stateObj);
_plpUnknownSent = true;
}
// Write chunk length & chunk
_stateObj.Parser.WriteInt(length, _stateObj);
_stateObj.Parser.WriteByteArray(buffer, length, bufferOffset, _stateObj);
}
else {
// Non-plp data must be sent in one chunk for now.
#if DEBUG
Debug.Assert(0 == _currentOffset, "SetBytes doesn't yet support chunking for non-plp data: " + _currentOffset);
#endif
Debug.Assert(!MetaType.GetMetaTypeFromSqlDbType(_metaData.SqlDbType, _metaData.IsMultiValued).IsLong,
"We're assuming long length types are sent as PLP. SqlDbType = " + _metaData.SqlDbType);
if (SqlDbType.Variant == _metaData.SqlDbType) {
_stateObj.Parser.WriteSqlVariantHeader(4 + length, TdsEnums.SQLBIGVARBINARY, 2, _stateObj);
}
_stateObj.Parser.WriteShort(length, _stateObj);
_stateObj.Parser.WriteByteArray(buffer, length, bufferOffset, _stateObj);
}
}
internal void SetBytesLength(long length) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetBytes));
CheckSettingOffset(length);
if (0 == length) {
if (_isPlp) {
Debug.Assert(!_plpUnknownSent, "A plpUnknown has already been sent before setting length to zero.");
_stateObj.Parser.WriteLong(0, _stateObj);
_plpUnknownSent = true;
}
else {
Debug.Assert(!MetaType.GetMetaTypeFromSqlDbType(_metaData.SqlDbType, _metaData.IsMultiValued).IsLong,
"We're assuming long length types are sent as PLP. SqlDbType = " + _metaData.SqlDbType);
if (SqlDbType.Variant == _metaData.SqlDbType) {
_stateObj.Parser.WriteSqlVariantHeader(4, TdsEnums.SQLBIGVARBINARY, 2, _stateObj);
}
_stateObj.Parser.WriteShort(0, _stateObj);
}
}
if (_plpUnknownSent) {
_stateObj.Parser.WriteInt(TdsEnums.SQL_PLP_CHUNK_TERMINATOR, _stateObj);
_plpUnknownSent = false;
}
#if DEBUG
//
_currentOffset = 0;
#endif
}
// Semantics for SetChars are to modify existing value, not overwrite
// Use in combination with SetLength to ensure overwriting when necessary
// valid for character types: Char, VarChar, Text, NChar, NVarChar, NText
// (NVarChar and global clr collation assumed for variants)
internal int SetChars(long fieldOffset, char[] buffer, int bufferOffset, int length) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetChars));
// ANSI types must convert to byte[] because that's the tool we have.
if (MetaDataUtilsSmi.IsAnsiType(_metaData.SqlDbType)) {
if (null == _encoder) {
_encoder = _stateObj.Parser._defaultEncoding.GetEncoder();
}
byte[] bytes = new byte[_encoder.GetByteCount(buffer, bufferOffset, length, false)];
_encoder.GetBytes(buffer, bufferOffset, length, bytes, 0, false);
SetBytesNoOffsetHandling(fieldOffset, bytes, 0, bytes.Length);
}
else {
CheckSettingOffset(fieldOffset);
// Send via PLP format if we can.
if (_isPlp) {
// Handle initial PLP markers
if (!_plpUnknownSent) {
_stateObj.Parser.WriteUnsignedLong(TdsEnums.SQL_PLP_UNKNOWNLEN, _stateObj);
_plpUnknownSent = true;
}
// Write chunk length
_stateObj.Parser.WriteInt(length*ADP.CharSize, _stateObj);
_stateObj.Parser.WriteCharArray(buffer, length, bufferOffset, _stateObj);
}
else {
// Non-plp data must be sent in one chunk for now.
#if DEBUG
Debug.Assert(0 == _currentOffset, "SetChars doesn't yet support chunking for non-plp data: " + _currentOffset);
#endif
if (SqlDbType.Variant == _metaData.SqlDbType) {
_stateObj.Parser.WriteSqlVariantValue(new String(buffer, bufferOffset, length), length, 0, _stateObj);
}
else {
Debug.Assert(!MetaType.GetMetaTypeFromSqlDbType(_metaData.SqlDbType, _metaData.IsMultiValued).IsLong,
"We're assuming long length types are sent as PLP. SqlDbType = " + _metaData.SqlDbType);
_stateObj.Parser.WriteShort(length*ADP.CharSize, _stateObj);
_stateObj.Parser.WriteCharArray(buffer, length, bufferOffset, _stateObj);
}
}
}
#if DEBUG
_currentOffset += length;
#endif
return length;
}
internal void SetCharsLength(long length) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetChars));
CheckSettingOffset(length);
if (0 == length) {
if (_isPlp) {
Debug.Assert(!_plpUnknownSent, "A plpUnknown has already been sent before setting length to zero.");
_stateObj.Parser.WriteLong(0, _stateObj);
_plpUnknownSent = true;
}
else {
Debug.Assert(!MetaType.GetMetaTypeFromSqlDbType(_metaData.SqlDbType, _metaData.IsMultiValued).IsLong,
"We're assuming long length types are sent as PLP. SqlDbType = " + _metaData.SqlDbType);
_stateObj.Parser.WriteShort(0, _stateObj);
}
}
if (_plpUnknownSent) {
_stateObj.Parser.WriteInt(TdsEnums.SQL_PLP_CHUNK_TERMINATOR, _stateObj);
_plpUnknownSent = false;
}
_encoder = null;
#if DEBUG
//
_currentOffset = 0;
#endif
}
// valid for character types: Char, VarChar, Text, NChar, NVarChar, NText
internal void SetString(string value, int offset, int length) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetString));
// ANSI types must convert to byte[] because that's the tool we have.
if (MetaDataUtilsSmi.IsAnsiType(_metaData.SqlDbType)) {
byte[] bytes;
// Optimize for common case of writing entire string
if (offset == 0 && value.Length <= length) {
bytes = _stateObj.Parser._defaultEncoding.GetBytes(value);
}
else {
char[] chars = value.ToCharArray(offset, length);
bytes = _stateObj.Parser._defaultEncoding.GetBytes(chars);
}
SetBytes(0, bytes, 0, bytes.Length);
SetBytesLength(bytes.Length);
}
else if (SqlDbType.Variant == _metaData.SqlDbType) {
Debug.Assert(null != _variantType && SqlDbType.NVarChar == _variantType.SqlDbType, "Invalid variant type");
SqlCollation collation = new SqlCollation();
collation.LCID = checked((int)_variantType.LocaleId);
collation.SqlCompareOptions = _variantType.CompareOptions;
if (length * ADP.CharSize > TdsEnums.TYPE_SIZE_LIMIT) { // send as varchar for length greater than 4000
byte[] bytes;
// Optimize for common case of writing entire string
if (offset == 0 && value.Length <= length) {
bytes = _stateObj.Parser._defaultEncoding.GetBytes(value);
}
else {
bytes = _stateObj.Parser._defaultEncoding.GetBytes(value.ToCharArray(offset, length));
}
_stateObj.Parser.WriteSqlVariantHeader(9 + bytes.Length, TdsEnums.SQLBIGVARCHAR, 7, _stateObj);
_stateObj.Parser.WriteUnsignedInt(collation.info, _stateObj); // propbytes: collation.Info
_stateObj.Parser.WriteByte(collation.sortId, _stateObj); // propbytes: collation.SortId
_stateObj.Parser.WriteShort(bytes.Length, _stateObj); // propbyte: varlen
_stateObj.Parser.WriteByteArray(bytes, bytes.Length, 0, _stateObj);
}
else {
_stateObj.Parser.WriteSqlVariantHeader(9 + length * ADP.CharSize, TdsEnums.SQLNVARCHAR, 7, _stateObj);
_stateObj.Parser.WriteUnsignedInt(collation.info, _stateObj); // propbytes: collation.Info
_stateObj.Parser.WriteByte(collation.sortId, _stateObj); // propbytes: collation.SortId
_stateObj.Parser.WriteShort(length * ADP.CharSize, _stateObj); // propbyte: varlen
_stateObj.Parser.WriteString(value, length, offset, _stateObj);
}
_variantType = null;
}
else if (_isPlp) {
// Send the string as a complete PLP chunk.
_stateObj.Parser.WriteLong(length*ADP.CharSize, _stateObj); // PLP total length
_stateObj.Parser.WriteInt(length*ADP.CharSize, _stateObj); // Chunk length
_stateObj.Parser.WriteString(value, length, offset, _stateObj); // Data
if (length != 0) {
_stateObj.Parser.WriteInt(TdsEnums.SQL_PLP_CHUNK_TERMINATOR, _stateObj); // Terminator
}
}
else {
_stateObj.Parser.WriteShort(length*ADP.CharSize, _stateObj);
_stateObj.Parser.WriteString(value, length, offset, _stateObj);
}
}
// valid for SqlDbType.SmallInt
internal void SetInt16(Int16 value) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetInt16));
if (SqlDbType.Variant == _metaData.SqlDbType) {
_stateObj.Parser.WriteSqlVariantHeader(4, TdsEnums.SQLINT2, 0, _stateObj);
}
else {
_stateObj.Parser.WriteByte((byte)_metaData.MaxLength, _stateObj);
}
_stateObj.Parser.WriteShort(value, _stateObj);
}
// valid for SqlDbType.Int
internal void SetInt32(Int32 value) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetInt32));
if (SqlDbType.Variant == _metaData.SqlDbType) {
_stateObj.Parser.WriteSqlVariantHeader(6, TdsEnums.SQLINT4, 0, _stateObj);
}
else {
_stateObj.Parser.WriteByte((byte)_metaData.MaxLength, _stateObj);
}
_stateObj.Parser.WriteInt(value, _stateObj);
}
// valid for SqlDbType.BigInt, SqlDbType.Money, SqlDbType.SmallMoney
internal void SetInt64(Int64 value) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetInt64));
if (SqlDbType.Variant == _metaData.SqlDbType) {
if (null == _variantType) {
_stateObj.Parser.WriteSqlVariantHeader(10, TdsEnums.SQLINT8, 0, _stateObj);
_stateObj.Parser.WriteLong(value, _stateObj);
}
else {
Debug.Assert(SqlDbType.Money == _variantType.SqlDbType, "Invalid variant type");
_stateObj.Parser.WriteSqlVariantHeader(10, TdsEnums.SQLMONEY, 0, _stateObj);
_stateObj.Parser.WriteInt((int)(value >> 0x20), _stateObj);
_stateObj.Parser.WriteInt((int)value, _stateObj);
_variantType = null;
}
}
else {
_stateObj.Parser.WriteByte((byte)_metaData.MaxLength, _stateObj);
if (SqlDbType.SmallMoney == _metaData.SqlDbType) {
_stateObj.Parser.WriteInt((int)value, _stateObj);
}
else if (SqlDbType.Money == _metaData.SqlDbType) {
_stateObj.Parser.WriteInt((int)(value >> 0x20), _stateObj);
_stateObj.Parser.WriteInt((int)value, _stateObj);
}
else {
_stateObj.Parser.WriteLong(value, _stateObj);
}
}
}
// valid for SqlDbType.Real
internal void SetSingle(Single value) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetSingle));
if (SqlDbType.Variant == _metaData.SqlDbType) {
_stateObj.Parser.WriteSqlVariantHeader(6, TdsEnums.SQLFLT4, 0, _stateObj);
}
else {
_stateObj.Parser.WriteByte((byte)_metaData.MaxLength, _stateObj);
}
_stateObj.Parser.WriteFloat(value, _stateObj);
}
// valid for SqlDbType.Float
internal void SetDouble(Double value) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetDouble));
if (SqlDbType.Variant == _metaData.SqlDbType) {
_stateObj.Parser.WriteSqlVariantHeader(10, TdsEnums.SQLFLT8, 0, _stateObj);
}
else {
_stateObj.Parser.WriteByte((byte)_metaData.MaxLength, _stateObj);
}
_stateObj.Parser.WriteDouble(value, _stateObj);
}
// valid for SqlDbType.Numeric (uses SqlDecimal since Decimal cannot hold full range)
internal void SetSqlDecimal(SqlDecimal value) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetSqlDecimal));
if (SqlDbType.Variant == _metaData.SqlDbType) {
_stateObj.Parser.WriteSqlVariantHeader(21, TdsEnums.SQLNUMERICN, 2, _stateObj);
_stateObj.Parser.WriteByte(value.Precision, _stateObj); // propbytes: precision
_stateObj.Parser.WriteByte(value.Scale, _stateObj); // propbytes: scale
_stateObj.Parser.WriteSqlDecimal(value, _stateObj);
}
else {
_stateObj.Parser.WriteByte(checked((byte)MetaType.MetaDecimal.FixedLength), _stateObj); // SmiMetaData's length and actual wire format's length are different
_stateObj.Parser.WriteSqlDecimal(SqlDecimal.ConvertToPrecScale(value, _metaData.Precision, _metaData.Scale), _stateObj);
}
}
// valid for DateTime, SmallDateTime, Date, DateTime2
internal void SetDateTime(DateTime value) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetDateTime));
if (SqlDbType.Variant == _metaData.SqlDbType) {
TdsDateTime dt = MetaType.FromDateTime(value, 8);
_stateObj.Parser.WriteSqlVariantHeader(10, TdsEnums.SQLDATETIME, 0, _stateObj);
_stateObj.Parser.WriteInt(dt.days, _stateObj);
_stateObj.Parser.WriteInt(dt.time, _stateObj);
}
else {
_stateObj.Parser.WriteByte((byte)_metaData.MaxLength, _stateObj);
if (SqlDbType.SmallDateTime == _metaData.SqlDbType) {
TdsDateTime dt = MetaType.FromDateTime(value, (byte)_metaData.MaxLength);
Debug.Assert (0 <= dt.days && dt.days <= UInt16.MaxValue, "Invalid DateTime '" + value + "' for SmallDateTime");
_stateObj.Parser.WriteShort(dt.days, _stateObj);
_stateObj.Parser.WriteShort(dt.time, _stateObj);
} else if (SqlDbType.DateTime == _metaData.SqlDbType) {
TdsDateTime dt = MetaType.FromDateTime(value, (byte)_metaData.MaxLength);
_stateObj.Parser.WriteInt(dt.days, _stateObj);
_stateObj.Parser.WriteInt(dt.time, _stateObj);
} else { // date and datetime2
int days = value.Subtract(DateTime.MinValue).Days;
if (SqlDbType.DateTime2 == _metaData.SqlDbType) {
Int64 time = value.TimeOfDay.Ticks / TdsEnums.TICKS_FROM_SCALE[_metaData.Scale];
_stateObj.Parser.WriteByteArray(BitConverter.GetBytes(time), (int)_metaData.MaxLength - 3, 0, _stateObj);
}
_stateObj.Parser.WriteByteArray(BitConverter.GetBytes(days), 3, 0, _stateObj);
}
}
}
// valid for UniqueIdentifier
internal void SetGuid(Guid value) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetGuid));
byte[] bytes = value.ToByteArray();
Debug.Assert(SmiMetaData.DefaultUniqueIdentifier.MaxLength == bytes.Length, "Invalid length for guid bytes: " + bytes.Length);
if (SqlDbType.Variant == _metaData.SqlDbType) {
_stateObj.Parser.WriteSqlVariantHeader(18, TdsEnums.SQLUNIQUEID, 0, _stateObj);
}
else {
Debug.Assert(_metaData.MaxLength == bytes.Length, "Unexpected uniqueid metadata length: " + _metaData.MaxLength);
_stateObj.Parser.WriteByte((byte)_metaData.MaxLength, _stateObj);
}
_stateObj.Parser.WriteByteArray(bytes, bytes.Length, 0, _stateObj);
}
// valid for SqlDbType.Time
internal void SetTimeSpan(TimeSpan value) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetTime));
byte scale;
byte length;
if (SqlDbType.Variant == _metaData.SqlDbType) {
scale = MetaType.MetaTime.Scale;
length = (byte)MetaType.MetaTime.FixedLength;
_stateObj.Parser.WriteSqlVariantHeader(8, TdsEnums.SQLTIME, 1, _stateObj);
_stateObj.Parser.WriteByte(scale, _stateObj); //propbytes: scale
} else {
scale = _metaData.Scale;
length = (byte)_metaData.MaxLength;
_stateObj.Parser.WriteByte(length, _stateObj);
}
Int64 time = value.Ticks / TdsEnums.TICKS_FROM_SCALE[scale];
_stateObj.Parser.WriteByteArray(BitConverter.GetBytes(time), length, 0, _stateObj);
}
// valid for DateTimeOffset
internal void SetDateTimeOffset(DateTimeOffset value) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetDateTimeOffset));
byte scale;
byte length;
if (SqlDbType.Variant == _metaData.SqlDbType) {
scale = MetaType.MetaDateTimeOffset.Scale;
length = (byte)MetaType.MetaDateTimeOffset.FixedLength;
_stateObj.Parser.WriteSqlVariantHeader(13, TdsEnums.SQLDATETIMEOFFSET, 1, _stateObj);
_stateObj.Parser.WriteByte(scale, _stateObj); //propbytes: scale
} else {
scale = _metaData.Scale;
length = (byte)_metaData.MaxLength;
_stateObj.Parser.WriteByte(length, _stateObj);
}
DateTime utcDateTime = value.UtcDateTime;
Int64 time = utcDateTime.TimeOfDay.Ticks / TdsEnums.TICKS_FROM_SCALE[scale];
int days = utcDateTime.Subtract(DateTime.MinValue).Days;
Int16 offset = (Int16)value.Offset.TotalMinutes;
_stateObj.Parser.WriteByteArray(BitConverter.GetBytes(time), length - 5, 0, _stateObj); // time
_stateObj.Parser.WriteByteArray(BitConverter.GetBytes(days), 3, 0, _stateObj); // date
_stateObj.Parser.WriteByte((byte)(offset & 0xff), _stateObj); // offset byte 1
_stateObj.Parser.WriteByte((byte)((offset >> 8) & 0xff), _stateObj); // offset byte 2
}
internal void SetVariantType(SmiMetaData value) {
Debug.Assert(null == _variantType, "Variant type can only be set once");
Debug.Assert(value != null && (value.SqlDbType == SqlDbType.Money || value.SqlDbType == SqlDbType.NVarChar), "Invalid variant type");
_variantType = value;
}
#endregion
#region private methods
[Conditional("DEBUG")]
private void CheckSettingOffset(long offset) {
#if DEBUG
Debug.Assert(offset == _currentOffset, "Invalid offset passed. Should be: " + _currentOffset + ", but was: " + offset);
#endif
}
#endregion
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// [....]
// [....]
//-----------------------------------------------------------------------------
namespace System.Data.SqlClient {
using Microsoft.SqlServer.Server;
using System;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Diagnostics;
using System.Text;
// TdsValueSetter handles writing a single value out to a TDS stream
// This class can easily be extended to handle multiple versions of TDS by sub-classing and virtualizing
// methods that have different formats or are not supported in one or the other version.
internal class TdsValueSetter {
#region Private fields
private TdsParserStateObject _stateObj; // target to write to
private SmiMetaData _metaData; // metadata describing value
private bool _isPlp; // should this column be sent in PLP format?
private bool _plpUnknownSent;// did we send initial UNKNOWN_LENGTH marker?
private Encoder _encoder; // required for chunking character type data
private SmiMetaData _variantType; // required for sql_variant
#if DEBUG
private int _currentOffset; // for chunking, verify that caller is using correct offsets
#endif
#endregion
#region Exposed Construct/factory methods
internal TdsValueSetter(TdsParserStateObject stateObj, SmiMetaData md) {
_stateObj = stateObj;
_metaData = md;
_isPlp = MetaDataUtilsSmi.IsPlpFormat(md);
_plpUnknownSent = false;
_encoder = null;
#if DEBUG
_currentOffset = 0;
#endif
}
#endregion
#region Setters
// Set value to null
// valid for all types
internal void SetDBNull() {
Debug.Assert(!_plpUnknownSent, "Setting a column to null that we already stated sending!");
if (_isPlp) {
_stateObj.Parser.WriteUnsignedLong(TdsEnums.SQL_PLP_NULL, _stateObj);
}
else {
switch(_metaData.SqlDbType) {
case SqlDbType.BigInt:
case SqlDbType.Bit:
case SqlDbType.DateTime:
case SqlDbType.Decimal:
case SqlDbType.Float:
case SqlDbType.Int:
case SqlDbType.Money:
case SqlDbType.Real:
case SqlDbType.UniqueIdentifier:
case SqlDbType.SmallDateTime:
case SqlDbType.SmallInt:
case SqlDbType.SmallMoney:
case SqlDbType.TinyInt:
case SqlDbType.Date:
case SqlDbType.Time:
case SqlDbType.DateTime2:
case SqlDbType.DateTimeOffset:
_stateObj.Parser.WriteByte(TdsEnums.FIXEDNULL, _stateObj);
break;
case SqlDbType.Binary:
case SqlDbType.Char:
case SqlDbType.Image:
case SqlDbType.NChar:
case SqlDbType.NText:
case SqlDbType.NVarChar:
case SqlDbType.Text:
case SqlDbType.Timestamp:
case SqlDbType.VarBinary:
case SqlDbType.VarChar:
_stateObj.Parser.WriteShort(TdsEnums.VARNULL, _stateObj);
break;
case SqlDbType.Udt:
case SqlDbType.Xml:
Debug.Assert(false, "PLP-only types shouldn't get to this point. Type: " + _metaData.SqlDbType);
break;
case SqlDbType.Variant:
_stateObj.Parser.WriteInt(TdsEnums.FIXEDNULL, _stateObj);
break;
case SqlDbType.Structured:
Debug.Assert(false, "Not yet implemented. Not needed until Structured UDTs");
break;
default:
Debug.Assert(false, "Unexpected SqlDbType: " + _metaData.SqlDbType);
break;
}
}
}
// valid for SqlDbType.Bit
internal void SetBoolean(Boolean value) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetBoolean));
if (SqlDbType.Variant == _metaData.SqlDbType) {
_stateObj.Parser.WriteSqlVariantHeader(3, TdsEnums.SQLBIT, 0, _stateObj);
}
else {
_stateObj.Parser.WriteByte((byte)_metaData.MaxLength, _stateObj);
}
if (value) {
_stateObj.Parser.WriteByte(1, _stateObj);
}
else {
_stateObj.Parser.WriteByte(0, _stateObj);
}
}
// valid for SqlDbType.TinyInt
internal void SetByte(Byte value) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetByte));
if (SqlDbType.Variant == _metaData.SqlDbType) {
_stateObj.Parser.WriteSqlVariantHeader(3, TdsEnums.SQLINT1, 0, _stateObj);
}
else {
_stateObj.Parser.WriteByte((byte)_metaData.MaxLength, _stateObj);
}
_stateObj.Parser.WriteByte(value, _stateObj);
}
// Semantics for SetBytes are to modify existing value, not overwrite
// Use in combination with SetLength to ensure overwriting when necessary
// valid for SqlDbTypes: Binary, VarBinary, Image, Udt, Xml
// (VarBinary assumed for variants)
internal int SetBytes(long fieldOffset, byte[] buffer, int bufferOffset, int length) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetBytes));
CheckSettingOffset(fieldOffset);
SetBytesNoOffsetHandling(fieldOffset, buffer, bufferOffset, length);
#if DEBUG
_currentOffset += length;
#endif
return length;
}
private void SetBytesNoOffsetHandling(long fieldOffset, byte[] buffer, int bufferOffset, int length) {
if (_isPlp) {
if (!_plpUnknownSent) {
_stateObj.Parser.WriteUnsignedLong(TdsEnums.SQL_PLP_UNKNOWNLEN, _stateObj);
_plpUnknownSent = true;
}
// Write chunk length & chunk
_stateObj.Parser.WriteInt(length, _stateObj);
_stateObj.Parser.WriteByteArray(buffer, length, bufferOffset, _stateObj);
}
else {
// Non-plp data must be sent in one chunk for now.
#if DEBUG
Debug.Assert(0 == _currentOffset, "SetBytes doesn't yet support chunking for non-plp data: " + _currentOffset);
#endif
Debug.Assert(!MetaType.GetMetaTypeFromSqlDbType(_metaData.SqlDbType, _metaData.IsMultiValued).IsLong,
"We're assuming long length types are sent as PLP. SqlDbType = " + _metaData.SqlDbType);
if (SqlDbType.Variant == _metaData.SqlDbType) {
_stateObj.Parser.WriteSqlVariantHeader(4 + length, TdsEnums.SQLBIGVARBINARY, 2, _stateObj);
}
_stateObj.Parser.WriteShort(length, _stateObj);
_stateObj.Parser.WriteByteArray(buffer, length, bufferOffset, _stateObj);
}
}
internal void SetBytesLength(long length) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetBytes));
CheckSettingOffset(length);
if (0 == length) {
if (_isPlp) {
Debug.Assert(!_plpUnknownSent, "A plpUnknown has already been sent before setting length to zero.");
_stateObj.Parser.WriteLong(0, _stateObj);
_plpUnknownSent = true;
}
else {
Debug.Assert(!MetaType.GetMetaTypeFromSqlDbType(_metaData.SqlDbType, _metaData.IsMultiValued).IsLong,
"We're assuming long length types are sent as PLP. SqlDbType = " + _metaData.SqlDbType);
if (SqlDbType.Variant == _metaData.SqlDbType) {
_stateObj.Parser.WriteSqlVariantHeader(4, TdsEnums.SQLBIGVARBINARY, 2, _stateObj);
}
_stateObj.Parser.WriteShort(0, _stateObj);
}
}
if (_plpUnknownSent) {
_stateObj.Parser.WriteInt(TdsEnums.SQL_PLP_CHUNK_TERMINATOR, _stateObj);
_plpUnknownSent = false;
}
#if DEBUG
//
_currentOffset = 0;
#endif
}
// Semantics for SetChars are to modify existing value, not overwrite
// Use in combination with SetLength to ensure overwriting when necessary
// valid for character types: Char, VarChar, Text, NChar, NVarChar, NText
// (NVarChar and global clr collation assumed for variants)
internal int SetChars(long fieldOffset, char[] buffer, int bufferOffset, int length) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetChars));
// ANSI types must convert to byte[] because that's the tool we have.
if (MetaDataUtilsSmi.IsAnsiType(_metaData.SqlDbType)) {
if (null == _encoder) {
_encoder = _stateObj.Parser._defaultEncoding.GetEncoder();
}
byte[] bytes = new byte[_encoder.GetByteCount(buffer, bufferOffset, length, false)];
_encoder.GetBytes(buffer, bufferOffset, length, bytes, 0, false);
SetBytesNoOffsetHandling(fieldOffset, bytes, 0, bytes.Length);
}
else {
CheckSettingOffset(fieldOffset);
// Send via PLP format if we can.
if (_isPlp) {
// Handle initial PLP markers
if (!_plpUnknownSent) {
_stateObj.Parser.WriteUnsignedLong(TdsEnums.SQL_PLP_UNKNOWNLEN, _stateObj);
_plpUnknownSent = true;
}
// Write chunk length
_stateObj.Parser.WriteInt(length*ADP.CharSize, _stateObj);
_stateObj.Parser.WriteCharArray(buffer, length, bufferOffset, _stateObj);
}
else {
// Non-plp data must be sent in one chunk for now.
#if DEBUG
Debug.Assert(0 == _currentOffset, "SetChars doesn't yet support chunking for non-plp data: " + _currentOffset);
#endif
if (SqlDbType.Variant == _metaData.SqlDbType) {
_stateObj.Parser.WriteSqlVariantValue(new String(buffer, bufferOffset, length), length, 0, _stateObj);
}
else {
Debug.Assert(!MetaType.GetMetaTypeFromSqlDbType(_metaData.SqlDbType, _metaData.IsMultiValued).IsLong,
"We're assuming long length types are sent as PLP. SqlDbType = " + _metaData.SqlDbType);
_stateObj.Parser.WriteShort(length*ADP.CharSize, _stateObj);
_stateObj.Parser.WriteCharArray(buffer, length, bufferOffset, _stateObj);
}
}
}
#if DEBUG
_currentOffset += length;
#endif
return length;
}
internal void SetCharsLength(long length) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetChars));
CheckSettingOffset(length);
if (0 == length) {
if (_isPlp) {
Debug.Assert(!_plpUnknownSent, "A plpUnknown has already been sent before setting length to zero.");
_stateObj.Parser.WriteLong(0, _stateObj);
_plpUnknownSent = true;
}
else {
Debug.Assert(!MetaType.GetMetaTypeFromSqlDbType(_metaData.SqlDbType, _metaData.IsMultiValued).IsLong,
"We're assuming long length types are sent as PLP. SqlDbType = " + _metaData.SqlDbType);
_stateObj.Parser.WriteShort(0, _stateObj);
}
}
if (_plpUnknownSent) {
_stateObj.Parser.WriteInt(TdsEnums.SQL_PLP_CHUNK_TERMINATOR, _stateObj);
_plpUnknownSent = false;
}
_encoder = null;
#if DEBUG
//
_currentOffset = 0;
#endif
}
// valid for character types: Char, VarChar, Text, NChar, NVarChar, NText
internal void SetString(string value, int offset, int length) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetString));
// ANSI types must convert to byte[] because that's the tool we have.
if (MetaDataUtilsSmi.IsAnsiType(_metaData.SqlDbType)) {
byte[] bytes;
// Optimize for common case of writing entire string
if (offset == 0 && value.Length <= length) {
bytes = _stateObj.Parser._defaultEncoding.GetBytes(value);
}
else {
char[] chars = value.ToCharArray(offset, length);
bytes = _stateObj.Parser._defaultEncoding.GetBytes(chars);
}
SetBytes(0, bytes, 0, bytes.Length);
SetBytesLength(bytes.Length);
}
else if (SqlDbType.Variant == _metaData.SqlDbType) {
Debug.Assert(null != _variantType && SqlDbType.NVarChar == _variantType.SqlDbType, "Invalid variant type");
SqlCollation collation = new SqlCollation();
collation.LCID = checked((int)_variantType.LocaleId);
collation.SqlCompareOptions = _variantType.CompareOptions;
if (length * ADP.CharSize > TdsEnums.TYPE_SIZE_LIMIT) { // send as varchar for length greater than 4000
byte[] bytes;
// Optimize for common case of writing entire string
if (offset == 0 && value.Length <= length) {
bytes = _stateObj.Parser._defaultEncoding.GetBytes(value);
}
else {
bytes = _stateObj.Parser._defaultEncoding.GetBytes(value.ToCharArray(offset, length));
}
_stateObj.Parser.WriteSqlVariantHeader(9 + bytes.Length, TdsEnums.SQLBIGVARCHAR, 7, _stateObj);
_stateObj.Parser.WriteUnsignedInt(collation.info, _stateObj); // propbytes: collation.Info
_stateObj.Parser.WriteByte(collation.sortId, _stateObj); // propbytes: collation.SortId
_stateObj.Parser.WriteShort(bytes.Length, _stateObj); // propbyte: varlen
_stateObj.Parser.WriteByteArray(bytes, bytes.Length, 0, _stateObj);
}
else {
_stateObj.Parser.WriteSqlVariantHeader(9 + length * ADP.CharSize, TdsEnums.SQLNVARCHAR, 7, _stateObj);
_stateObj.Parser.WriteUnsignedInt(collation.info, _stateObj); // propbytes: collation.Info
_stateObj.Parser.WriteByte(collation.sortId, _stateObj); // propbytes: collation.SortId
_stateObj.Parser.WriteShort(length * ADP.CharSize, _stateObj); // propbyte: varlen
_stateObj.Parser.WriteString(value, length, offset, _stateObj);
}
_variantType = null;
}
else if (_isPlp) {
// Send the string as a complete PLP chunk.
_stateObj.Parser.WriteLong(length*ADP.CharSize, _stateObj); // PLP total length
_stateObj.Parser.WriteInt(length*ADP.CharSize, _stateObj); // Chunk length
_stateObj.Parser.WriteString(value, length, offset, _stateObj); // Data
if (length != 0) {
_stateObj.Parser.WriteInt(TdsEnums.SQL_PLP_CHUNK_TERMINATOR, _stateObj); // Terminator
}
}
else {
_stateObj.Parser.WriteShort(length*ADP.CharSize, _stateObj);
_stateObj.Parser.WriteString(value, length, offset, _stateObj);
}
}
// valid for SqlDbType.SmallInt
internal void SetInt16(Int16 value) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetInt16));
if (SqlDbType.Variant == _metaData.SqlDbType) {
_stateObj.Parser.WriteSqlVariantHeader(4, TdsEnums.SQLINT2, 0, _stateObj);
}
else {
_stateObj.Parser.WriteByte((byte)_metaData.MaxLength, _stateObj);
}
_stateObj.Parser.WriteShort(value, _stateObj);
}
// valid for SqlDbType.Int
internal void SetInt32(Int32 value) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetInt32));
if (SqlDbType.Variant == _metaData.SqlDbType) {
_stateObj.Parser.WriteSqlVariantHeader(6, TdsEnums.SQLINT4, 0, _stateObj);
}
else {
_stateObj.Parser.WriteByte((byte)_metaData.MaxLength, _stateObj);
}
_stateObj.Parser.WriteInt(value, _stateObj);
}
// valid for SqlDbType.BigInt, SqlDbType.Money, SqlDbType.SmallMoney
internal void SetInt64(Int64 value) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetInt64));
if (SqlDbType.Variant == _metaData.SqlDbType) {
if (null == _variantType) {
_stateObj.Parser.WriteSqlVariantHeader(10, TdsEnums.SQLINT8, 0, _stateObj);
_stateObj.Parser.WriteLong(value, _stateObj);
}
else {
Debug.Assert(SqlDbType.Money == _variantType.SqlDbType, "Invalid variant type");
_stateObj.Parser.WriteSqlVariantHeader(10, TdsEnums.SQLMONEY, 0, _stateObj);
_stateObj.Parser.WriteInt((int)(value >> 0x20), _stateObj);
_stateObj.Parser.WriteInt((int)value, _stateObj);
_variantType = null;
}
}
else {
_stateObj.Parser.WriteByte((byte)_metaData.MaxLength, _stateObj);
if (SqlDbType.SmallMoney == _metaData.SqlDbType) {
_stateObj.Parser.WriteInt((int)value, _stateObj);
}
else if (SqlDbType.Money == _metaData.SqlDbType) {
_stateObj.Parser.WriteInt((int)(value >> 0x20), _stateObj);
_stateObj.Parser.WriteInt((int)value, _stateObj);
}
else {
_stateObj.Parser.WriteLong(value, _stateObj);
}
}
}
// valid for SqlDbType.Real
internal void SetSingle(Single value) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetSingle));
if (SqlDbType.Variant == _metaData.SqlDbType) {
_stateObj.Parser.WriteSqlVariantHeader(6, TdsEnums.SQLFLT4, 0, _stateObj);
}
else {
_stateObj.Parser.WriteByte((byte)_metaData.MaxLength, _stateObj);
}
_stateObj.Parser.WriteFloat(value, _stateObj);
}
// valid for SqlDbType.Float
internal void SetDouble(Double value) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetDouble));
if (SqlDbType.Variant == _metaData.SqlDbType) {
_stateObj.Parser.WriteSqlVariantHeader(10, TdsEnums.SQLFLT8, 0, _stateObj);
}
else {
_stateObj.Parser.WriteByte((byte)_metaData.MaxLength, _stateObj);
}
_stateObj.Parser.WriteDouble(value, _stateObj);
}
// valid for SqlDbType.Numeric (uses SqlDecimal since Decimal cannot hold full range)
internal void SetSqlDecimal(SqlDecimal value) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetSqlDecimal));
if (SqlDbType.Variant == _metaData.SqlDbType) {
_stateObj.Parser.WriteSqlVariantHeader(21, TdsEnums.SQLNUMERICN, 2, _stateObj);
_stateObj.Parser.WriteByte(value.Precision, _stateObj); // propbytes: precision
_stateObj.Parser.WriteByte(value.Scale, _stateObj); // propbytes: scale
_stateObj.Parser.WriteSqlDecimal(value, _stateObj);
}
else {
_stateObj.Parser.WriteByte(checked((byte)MetaType.MetaDecimal.FixedLength), _stateObj); // SmiMetaData's length and actual wire format's length are different
_stateObj.Parser.WriteSqlDecimal(SqlDecimal.ConvertToPrecScale(value, _metaData.Precision, _metaData.Scale), _stateObj);
}
}
// valid for DateTime, SmallDateTime, Date, DateTime2
internal void SetDateTime(DateTime value) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetDateTime));
if (SqlDbType.Variant == _metaData.SqlDbType) {
TdsDateTime dt = MetaType.FromDateTime(value, 8);
_stateObj.Parser.WriteSqlVariantHeader(10, TdsEnums.SQLDATETIME, 0, _stateObj);
_stateObj.Parser.WriteInt(dt.days, _stateObj);
_stateObj.Parser.WriteInt(dt.time, _stateObj);
}
else {
_stateObj.Parser.WriteByte((byte)_metaData.MaxLength, _stateObj);
if (SqlDbType.SmallDateTime == _metaData.SqlDbType) {
TdsDateTime dt = MetaType.FromDateTime(value, (byte)_metaData.MaxLength);
Debug.Assert (0 <= dt.days && dt.days <= UInt16.MaxValue, "Invalid DateTime '" + value + "' for SmallDateTime");
_stateObj.Parser.WriteShort(dt.days, _stateObj);
_stateObj.Parser.WriteShort(dt.time, _stateObj);
} else if (SqlDbType.DateTime == _metaData.SqlDbType) {
TdsDateTime dt = MetaType.FromDateTime(value, (byte)_metaData.MaxLength);
_stateObj.Parser.WriteInt(dt.days, _stateObj);
_stateObj.Parser.WriteInt(dt.time, _stateObj);
} else { // date and datetime2
int days = value.Subtract(DateTime.MinValue).Days;
if (SqlDbType.DateTime2 == _metaData.SqlDbType) {
Int64 time = value.TimeOfDay.Ticks / TdsEnums.TICKS_FROM_SCALE[_metaData.Scale];
_stateObj.Parser.WriteByteArray(BitConverter.GetBytes(time), (int)_metaData.MaxLength - 3, 0, _stateObj);
}
_stateObj.Parser.WriteByteArray(BitConverter.GetBytes(days), 3, 0, _stateObj);
}
}
}
// valid for UniqueIdentifier
internal void SetGuid(Guid value) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetGuid));
byte[] bytes = value.ToByteArray();
Debug.Assert(SmiMetaData.DefaultUniqueIdentifier.MaxLength == bytes.Length, "Invalid length for guid bytes: " + bytes.Length);
if (SqlDbType.Variant == _metaData.SqlDbType) {
_stateObj.Parser.WriteSqlVariantHeader(18, TdsEnums.SQLUNIQUEID, 0, _stateObj);
}
else {
Debug.Assert(_metaData.MaxLength == bytes.Length, "Unexpected uniqueid metadata length: " + _metaData.MaxLength);
_stateObj.Parser.WriteByte((byte)_metaData.MaxLength, _stateObj);
}
_stateObj.Parser.WriteByteArray(bytes, bytes.Length, 0, _stateObj);
}
// valid for SqlDbType.Time
internal void SetTimeSpan(TimeSpan value) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetTime));
byte scale;
byte length;
if (SqlDbType.Variant == _metaData.SqlDbType) {
scale = MetaType.MetaTime.Scale;
length = (byte)MetaType.MetaTime.FixedLength;
_stateObj.Parser.WriteSqlVariantHeader(8, TdsEnums.SQLTIME, 1, _stateObj);
_stateObj.Parser.WriteByte(scale, _stateObj); //propbytes: scale
} else {
scale = _metaData.Scale;
length = (byte)_metaData.MaxLength;
_stateObj.Parser.WriteByte(length, _stateObj);
}
Int64 time = value.Ticks / TdsEnums.TICKS_FROM_SCALE[scale];
_stateObj.Parser.WriteByteArray(BitConverter.GetBytes(time), length, 0, _stateObj);
}
// valid for DateTimeOffset
internal void SetDateTimeOffset(DateTimeOffset value) {
Debug.Assert(
SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetDateTimeOffset));
byte scale;
byte length;
if (SqlDbType.Variant == _metaData.SqlDbType) {
scale = MetaType.MetaDateTimeOffset.Scale;
length = (byte)MetaType.MetaDateTimeOffset.FixedLength;
_stateObj.Parser.WriteSqlVariantHeader(13, TdsEnums.SQLDATETIMEOFFSET, 1, _stateObj);
_stateObj.Parser.WriteByte(scale, _stateObj); //propbytes: scale
} else {
scale = _metaData.Scale;
length = (byte)_metaData.MaxLength;
_stateObj.Parser.WriteByte(length, _stateObj);
}
DateTime utcDateTime = value.UtcDateTime;
Int64 time = utcDateTime.TimeOfDay.Ticks / TdsEnums.TICKS_FROM_SCALE[scale];
int days = utcDateTime.Subtract(DateTime.MinValue).Days;
Int16 offset = (Int16)value.Offset.TotalMinutes;
_stateObj.Parser.WriteByteArray(BitConverter.GetBytes(time), length - 5, 0, _stateObj); // time
_stateObj.Parser.WriteByteArray(BitConverter.GetBytes(days), 3, 0, _stateObj); // date
_stateObj.Parser.WriteByte((byte)(offset & 0xff), _stateObj); // offset byte 1
_stateObj.Parser.WriteByte((byte)((offset >> 8) & 0xff), _stateObj); // offset byte 2
}
internal void SetVariantType(SmiMetaData value) {
Debug.Assert(null == _variantType, "Variant type can only be set once");
Debug.Assert(value != null && (value.SqlDbType == SqlDbType.Money || value.SqlDbType == SqlDbType.NVarChar), "Invalid variant type");
_variantType = value;
}
#endregion
#region private methods
[Conditional("DEBUG")]
private void CheckSettingOffset(long offset) {
#if DEBUG
Debug.Assert(offset == _currentOffset, "Invalid offset passed. Should be: " + _currentOffset + ", but was: " + offset);
#endif
}
#endregion
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ConfigurationElement.cs
- ProtocolsConfigurationEntry.cs
- DataBindingList.cs
- AsyncResult.cs
- PeerTransportSecurityElement.cs
- serverconfig.cs
- RemotingSurrogateSelector.cs
- BlurEffect.cs
- HtmlTable.cs
- RectangleF.cs
- TableLayoutSettings.cs
- ActionNotSupportedException.cs
- SecurityPermission.cs
- ReverseInheritProperty.cs
- XMLDiffLoader.cs
- CompilationLock.cs
- ProfileSection.cs
- PolyLineSegment.cs
- DecoderFallbackWithFailureFlag.cs
- ZipIOLocalFileDataDescriptor.cs
- ColorConvertedBitmap.cs
- CapabilitiesAssignment.cs
- HighlightVisual.cs
- TypeSchema.cs
- RegexGroup.cs
- MenuItemCollection.cs
- Point3D.cs
- HwndAppCommandInputProvider.cs
- TypeUtil.cs
- StateManagedCollection.cs
- DispatcherSynchronizationContext.cs
- EncryptedData.cs
- TextServicesCompartmentContext.cs
- SchemaTableOptionalColumn.cs
- PerformanceCountersElement.cs
- AutomationProperties.cs
- TemplatedWizardStep.cs
- AbandonedMutexException.cs
- CurrencyWrapper.cs
- XmlIgnoreAttribute.cs
- BrushProxy.cs
- Utils.cs
- WebPartsPersonalization.cs
- DropTarget.cs
- HierarchicalDataTemplate.cs
- BamlLocalizer.cs
- ObjectNotFoundException.cs
- ImageBrush.cs
- DesignOnlyAttribute.cs
- SID.cs
- OleDbConnection.cs
- SerializationInfoEnumerator.cs
- SqlSelectStatement.cs
- Point.cs
- SingletonInstanceContextProvider.cs
- MethodExpr.cs
- HtmlFormWrapper.cs
- AssemblyNameProxy.cs
- WinCategoryAttribute.cs
- ItemList.cs
- NavigationProperty.cs
- ImageListUtils.cs
- DataBoundControl.cs
- UnsafeNativeMethods.cs
- DataSourceConverter.cs
- ScaleTransform.cs
- MouseOverProperty.cs
- _NTAuthentication.cs
- Assembly.cs
- PolicyStatement.cs
- XhtmlConformanceSection.cs
- CapiSymmetricAlgorithm.cs
- ContextProperty.cs
- AccessedThroughPropertyAttribute.cs
- SiteMap.cs
- _OSSOCK.cs
- StylusCaptureWithinProperty.cs
- CompilationUtil.cs
- InternalBufferManager.cs
- RectValueSerializer.cs
- Identity.cs
- InfoCardRSAOAEPKeyExchangeFormatter.cs
- BaseAsyncResult.cs
- DoWorkEventArgs.cs
- ModelChangedEventArgsImpl.cs
- OleDbFactory.cs
- securitycriticaldata.cs
- HtmlElementCollection.cs
- TransformerConfigurationWizardBase.cs
- OrderedDictionary.cs
- LicFileLicenseProvider.cs
- Message.cs
- UmAlQuraCalendar.cs
- CachedTypeface.cs
- ShaderRenderModeValidation.cs
- ModuleBuilderData.cs
- TimeZone.cs
- HttpPostedFile.cs
- PolyBezierSegment.cs
- MultiPartWriter.cs