Beispiel #1
0
        // valid for DateTimeOffset
        internal void SetDateTimeOffset(DateTimeOffset value)
        {
            Debug.Assert(
                SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetDateTimeOffset));
            byte scale;
            byte length;

            if (SqlDbType.Variant == _metaData.SqlDbType)
            {
                // VSTFDevDiv #885208 - DateTimeOffset throws ArgumentException for when passing DateTimeOffset value to a sql_variant TVP
                //                      using a SqlDataRecord or SqlDataReader
                MSS.SmiMetaData dateTimeOffsetMetaData = MSS.SmiMetaData.DefaultDateTimeOffset;
                scale  = MetaType.MetaDateTimeOffset.Scale;
                length = (byte)dateTimeOffsetMetaData.MaxLength;
                _stateObj.Parser.WriteSqlVariantHeader(13, TdsEnums.SQLDATETIMEOFFSET, 1, _stateObj);
                _stateObj.WriteByte(scale); //propbytes: scale
            }
            else
            {
                scale  = _metaData.Scale;
                length = (byte)_metaData.MaxLength;
                _stateObj.WriteByte(length);
            }
            DateTime utcDateTime = value.UtcDateTime;
            long     time        = utcDateTime.TimeOfDay.Ticks / TdsEnums.TICKS_FROM_SCALE[scale];
            int      days        = utcDateTime.Subtract(DateTime.MinValue).Days;
            short    offset      = (short)value.Offset.TotalMinutes;

            _stateObj.WriteByteArray(BitConverter.GetBytes(time), length - 5, 0); // time
            _stateObj.WriteByteArray(BitConverter.GetBytes(days), 3, 0);          // date
            _stateObj.WriteByte((byte)(offset & 0xff));                           // offset byte 1
            _stateObj.WriteByte((byte)((offset >> 8) & 0xff));                    // offset byte 2
        }
Beispiel #2
0
        // valid for UniqueIdentifier
        internal void SetGuid(Guid value)
        {
            Debug.Assert(SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetGuid));
#if NETCOREAPP
            Span <byte> bytes = stackalloc byte[16];
            value.TryWriteBytes(bytes);
#else
            byte[] bytes = value.ToByteArray();
#endif
            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.WriteByte((byte)_metaData.MaxLength);
            }
#if NETCOREAPP
            _stateObj.WriteByteSpan(bytes);
#else
            _stateObj.WriteByteArray(bytes, bytes.Length, 0);
#endif
        }
Beispiel #3
0
        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
        }
Beispiel #4
0
        // 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);
        }
Beispiel #5
0
        // valid for DateTime, SmallDateTime, Date, DateTime2
        internal void SetDateTime(DateTime value)
        {
            Debug.Assert(
                SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetDateTime));
            if (SqlDbType.Variant == _metaData.SqlDbType)
            {
                if ((_variantType != null) && (_variantType.SqlDbType == SqlDbType.DateTime2))
                {
                    _stateObj.Parser.WriteSqlVariantDateTime2(value, _stateObj);
                }
                else if ((_variantType != null) && (_variantType.SqlDbType == SqlDbType.Date))
                {
                    _stateObj.Parser.WriteSqlVariantDate(value, _stateObj);
                }
                else
                {
                    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);
                }

                // Clean the variant metadata to prevent sharing it with next row.
                // As a reminder, SetVariantType raises an assert if _variantType is not clean
                _variantType = null;
            }
            else
            {
                _stateObj.WriteByte((byte)_metaData.MaxLength);
                if (SqlDbType.SmallDateTime == _metaData.SqlDbType)
                {
                    TdsDateTime dt = MetaType.FromDateTime(value, (byte)_metaData.MaxLength);
                    Debug.Assert(0 <= dt.days && dt.days <= ushort.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)
                    {
                        long time = value.TimeOfDay.Ticks / TdsEnums.TICKS_FROM_SCALE[_metaData.Scale];
                        _stateObj.WriteByteArray(BitConverter.GetBytes(time), (int)_metaData.MaxLength - 3, 0);
                    }
                    _stateObj.WriteByteArray(BitConverter.GetBytes(days), 3, 0);
                }
            }
        }
Beispiel #6
0
        // 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);
        }
Beispiel #7
0
 // 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.WriteByte((byte)_metaData.MaxLength);
     }
     _stateObj.Parser.WriteDouble(value, _stateObj);
 }
Beispiel #8
0
 // valid for SqlDbType.Int
 internal void SetInt32(int value)
 {
     Debug.Assert(
         SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetInt32));
     if (SqlDbType.Variant == _metaData.SqlDbType)
     {
         _stateObj.Parser.WriteSqlVariantHeader(6, TdsEnums.SQLINT4, 0, _stateObj);
     }
     else
     {
         _stateObj.WriteByte((byte)_metaData.MaxLength);
     }
     _stateObj.Parser.WriteInt(value, _stateObj);
 }
Beispiel #9
0
 // 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.WriteByte(value.Precision); // propbytes: precision
         _stateObj.WriteByte(value.Scale);     // propbytes: scale
         _stateObj.Parser.WriteSqlDecimal(value, _stateObj);
     }
     else
     {
         _stateObj.WriteByte(checked ((byte)MetaType.MetaDecimal.FixedLength)); // SmiMetaData's length and actual wire format's length are different
         _stateObj.Parser.WriteSqlDecimal(SqlDecimal.ConvertToPrecScale(value, _metaData.Precision, _metaData.Scale), _stateObj);
     }
 }
Beispiel #10
0
 //  valid for SqlDbType.Bit
 internal void SetBoolean(bool value)
 {
     Debug.Assert(
         SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetBoolean));
     if (SqlDbType.Variant == _metaData.SqlDbType)
     {
         _stateObj.Parser.WriteSqlVariantHeader(3, TdsEnums.SQLBIT, 0, _stateObj);
     }
     else
     {
         _stateObj.WriteByte((byte)_metaData.MaxLength);
     }
     if (value)
     {
         _stateObj.WriteByte(1);
     }
     else
     {
         _stateObj.WriteByte(0);
     }
 }
Beispiel #11
0
        // valid for SqlDbType.BigInt, SqlDbType.Money, SqlDbType.SmallMoney
        internal void SetInt64(long 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.WriteByte((byte)_metaData.MaxLength);
                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);
                }
            }
        }
Beispiel #12
0
        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
            //UNDONE: assumes SetBytesLength is done at end.  But we could optimize deciding when we send PLP's!
            _currentOffset = 0;
#endif
        }
Beispiel #13
0
        // 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  = SmiMetaData.DefaultTime.Scale;
                length = (byte)SmiMetaData.DefaultTime.MaxLength;
                _stateObj.Parser.WriteSqlVariantHeader(8, TdsEnums.SQLTIME, 1, _stateObj);
                _stateObj.WriteByte(scale); //propbytes: scale
            }
            else
            {
                scale  = _metaData.Scale;
                length = (byte)_metaData.MaxLength;
                _stateObj.WriteByte(length);
            }
            long time = value.Ticks / TdsEnums.TICKS_FROM_SCALE[scale];

            _stateObj.WriteByteArray(BitConverter.GetBytes(time), length, 0);
        }
Beispiel #14
0
        // 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.WriteByte(collation.sortId);                        // propbytes: collation.SortId
                    _stateObj.Parser.WriteShort(bytes.Length, _stateObj);         // propbyte: varlen
                    _stateObj.WriteByteArray(bytes, bytes.Length, 0);
                }
                else
                {
                    _stateObj.Parser.WriteSqlVariantHeader(9 + length * ADP.CharSize, TdsEnums.SQLNVARCHAR, 7, _stateObj);
                    _stateObj.Parser.WriteUnsignedInt(collation.info, _stateObj);  // propbytes: collation.Info
                    _stateObj.WriteByte(collation.sortId);                         // 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);
            }
        }