Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / System.Data / System / Data / SqlClient / SqlBuffer.cs
blob9c4084086bba991d00d8aff51ba8c855f45a29ac
1 //------------------------------------------------------------------------------
2 // <copyright file="SqlDataReader.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 // <owner current="true" primary="false">Microsoft</owner>
7 // <owner current="true" primary="false">Microsoft</owner>
8 //------------------------------------------------------------------------------
10 namespace System.Data.SqlClient {
11 using System.Threading;
12 using System.Diagnostics;
13 using System.Reflection;
14 using System;
15 using System.Data;
16 using System.IO;
17 using System.Collections;
18 using System.Collections.Specialized;
19 using System.Data.Sql;
20 using System.Data.SqlTypes;
21 using System.Data.Common;
22 using System.Data.ProviderBase;
23 using System.ComponentModel;
24 using System.Globalization;
25 using System.Xml;
26 using System.Runtime.InteropServices;
28 internal sealed class SqlBuffer {
30 internal enum StorageType {
31 Empty = 0,
32 Boolean,
33 Byte,
34 DateTime,
35 Decimal,
36 Double,
37 Int16,
38 Int32,
39 Int64,
40 Money,
41 Single,
42 String,
43 SqlBinary,
44 SqlCachedBuffer,
45 SqlGuid,
46 SqlXml,
47 Date,
48 DateTime2,
49 DateTimeOffset,
50 Time,
53 internal struct DateTimeInfo {
54 // This is used to store DateTime
55 internal Int32 daypart;
56 internal Int32 timepart;
59 internal struct NumericInfo {
60 // This is used to store Decimal data
61 internal Int32 data1;
62 internal Int32 data2;
63 internal Int32 data3;
64 internal Int32 data4;
65 internal Byte precision;
66 internal Byte scale;
67 internal Boolean positive;
70 internal struct TimeInfo {
71 internal Int64 ticks;
72 internal byte scale;
75 internal struct DateTime2Info {
76 internal Int32 date;
77 internal TimeInfo timeInfo;
80 internal struct DateTimeOffsetInfo {
81 internal DateTime2Info dateTime2Info;
82 internal Int16 offset;
85 [StructLayout(LayoutKind.Explicit)]
86 internal struct Storage {
87 [FieldOffset(0)] internal Boolean _boolean;
88 [FieldOffset(0)] internal Byte _byte;
89 [FieldOffset(0)] internal DateTimeInfo _dateTimeInfo;
90 [FieldOffset(0)] internal Double _double;
91 [FieldOffset(0)] internal NumericInfo _numericInfo;
92 [FieldOffset(0)] internal Int16 _int16;
93 [FieldOffset(0)] internal Int32 _int32;
94 [FieldOffset(0)] internal Int64 _int64; // also used to store Money, UtcDateTime, Date , and Time
95 [FieldOffset(0)] internal Single _single;
96 [FieldOffset(0)] internal TimeInfo _timeInfo;
97 [FieldOffset(0)] internal DateTime2Info _dateTime2Info;
98 [FieldOffset(0)] internal DateTimeOffsetInfo _dateTimeOffsetInfo;
101 private bool _isNull;
102 private StorageType _type;
103 private Storage _value;
104 private object _object; // String, SqlBinary, SqlCachedBuffer, SqlGuid, SqlString, SqlXml
106 internal SqlBuffer() {
109 private SqlBuffer(SqlBuffer value) { // Clone
110 // value types
111 _isNull = value._isNull;
112 _type = value._type;
113 // ref types - should also be read only unless at some point we allow this data
114 // to be mutable, then we will need to copy
115 _value = value._value;
116 _object = value._object;
119 internal bool IsEmpty {
120 get {
121 return (StorageType.Empty == _type);
125 internal bool IsNull {
126 get {
127 return _isNull;
131 internal StorageType VariantInternalStorageType
133 get { return _type; }
136 internal Boolean Boolean {
137 get {
138 ThrowIfNull();
140 if (StorageType.Boolean == _type) {
141 return _value._boolean;
143 return (Boolean)this.Value; // anything else we haven't thought of goes through boxing.
145 set {
146 Debug.Assert (IsEmpty, "setting value a second time?");
147 _value._boolean = value;
148 _type = StorageType.Boolean;
149 _isNull = false;
153 internal Byte Byte {
154 get {
155 ThrowIfNull();
157 if (StorageType.Byte == _type) {
158 return _value._byte;
160 return (Byte)this.Value; // anything else we haven't thought of goes through boxing.
162 set {
163 Debug.Assert (IsEmpty, "setting value a second time?");
164 _value._byte = value;
165 _type = StorageType.Byte;
166 _isNull = false;
170 internal Byte[] ByteArray {
171 get {
172 ThrowIfNull();
173 return this.SqlBinary.Value; //
177 internal DateTime DateTime {
178 get {
179 ThrowIfNull();
181 if (StorageType.Date == _type) {
182 return DateTime.MinValue.AddDays(_value._int32);
184 if (StorageType.DateTime2 == _type) {
185 return new DateTime(GetTicksFromDateTime2Info(_value._dateTime2Info));
187 if (StorageType.DateTime == _type) {
188 return SqlDateTime.ToDateTime(_value._dateTimeInfo.daypart, _value._dateTimeInfo.timepart);
190 return (DateTime)this.Value; // anything else we haven't thought of goes through boxing.
194 internal Decimal Decimal {
195 get {
196 ThrowIfNull();
198 if (StorageType.Decimal == _type) {
199 if (_value._numericInfo.data4 != 0 || _value._numericInfo.scale > 28) {
200 throw new OverflowException(SQLResource.ConversionOverflowMessage);
202 return new Decimal(_value._numericInfo.data1, _value._numericInfo.data2, _value._numericInfo.data3, !_value._numericInfo.positive, _value._numericInfo.scale);
204 if (StorageType.Money == _type) {
205 long l = _value._int64;
206 bool isNegative = false;
207 if (l < 0) {
208 isNegative = true;
209 l = -l;
211 return new Decimal((int)(l & 0xffffffff), (int)(l >> 32), 0, isNegative, 4);
213 return (Decimal)this.Value; // anything else we haven't thought of goes through boxing.
217 internal Double Double {
218 get {
219 ThrowIfNull();
221 if (StorageType.Double == _type) {
222 return _value._double;
224 return (Double)this.Value; // anything else we haven't thought of goes through boxing.
226 set {
227 Debug.Assert (IsEmpty, "setting value a second time?");
228 _value._double = value;
229 _type = StorageType.Double;
230 _isNull = false;
234 internal Guid Guid {
235 get {
237 ThrowIfNull();
238 return this.SqlGuid.Value;
242 internal Int16 Int16 {
243 get {
244 ThrowIfNull();
246 if (StorageType.Int16 == _type) {
247 return _value._int16;
249 return (Int16)this.Value; // anything else we haven't thought of goes through boxing.
251 set {
252 Debug.Assert (IsEmpty, "setting value a second time?");
253 _value._int16 = value;
254 _type = StorageType.Int16;
255 _isNull = false;
259 internal Int32 Int32 {
260 get {
261 ThrowIfNull();
263 if (StorageType.Int32 == _type) {
264 return _value._int32;
266 return (Int32)this.Value; // anything else we haven't thought of goes through boxing.
268 set {
269 Debug.Assert (IsEmpty, "setting value a second time?");
270 _value._int32 = value;
271 _type = StorageType.Int32;
272 _isNull = false;
276 internal Int64 Int64 {
277 get {
278 ThrowIfNull();
280 if (StorageType.Int64 == _type) {
281 return _value._int64;
283 return (Int64)this.Value; // anything else we haven't thought of goes through boxing.
285 set {
286 Debug.Assert (IsEmpty, "setting value a second time?");
287 _value._int64 = value;
288 _type = StorageType.Int64;
289 _isNull = false;
293 internal Single Single {
294 get {
295 ThrowIfNull();
297 if (StorageType.Single == _type) {
298 return _value._single;
300 return (Single)this.Value; // anything else we haven't thought of goes through boxing.
302 set {
303 Debug.Assert (IsEmpty, "setting value a second time?");
304 _value._single = value;
305 _type = StorageType.Single;
306 _isNull = false;
310 internal String String {
311 get {
312 ThrowIfNull();
314 if (StorageType.String == _type) {
315 return (String)_object;
317 else if (StorageType.SqlCachedBuffer == _type) {
318 return ((SqlCachedBuffer)(_object)).ToString();
320 return (String)this.Value; // anything else we haven't thought of goes through boxing.
324 // use static list of format strings indexed by scale for perf!
325 private static string[] __katmaiDateTimeOffsetFormatByScale = new string[] {
326 "yyyy-MM-dd HH:mm:ss zzz",
327 "yyyy-MM-dd HH:mm:ss.f zzz",
328 "yyyy-MM-dd HH:mm:ss.ff zzz",
329 "yyyy-MM-dd HH:mm:ss.fff zzz",
330 "yyyy-MM-dd HH:mm:ss.ffff zzz",
331 "yyyy-MM-dd HH:mm:ss.fffff zzz",
332 "yyyy-MM-dd HH:mm:ss.ffffff zzz",
333 "yyyy-MM-dd HH:mm:ss.fffffff zzz",
336 private static string[] __katmaiDateTime2FormatByScale = new string[] {
337 "yyyy-MM-dd HH:mm:ss",
338 "yyyy-MM-dd HH:mm:ss.f",
339 "yyyy-MM-dd HH:mm:ss.ff",
340 "yyyy-MM-dd HH:mm:ss.fff",
341 "yyyy-MM-dd HH:mm:ss.ffff",
342 "yyyy-MM-dd HH:mm:ss.fffff",
343 "yyyy-MM-dd HH:mm:ss.ffffff",
344 "yyyy-MM-dd HH:mm:ss.fffffff",
347 private static string[] __katmaiTimeFormatByScale = new string[] {
348 "HH:mm:ss",
349 "HH:mm:ss.f",
350 "HH:mm:ss.ff",
351 "HH:mm:ss.fff",
352 "HH:mm:ss.ffff",
353 "HH:mm:ss.fffff",
354 "HH:mm:ss.ffffff",
355 "HH:mm:ss.fffffff",
358 internal string KatmaiDateTimeString {
359 get {
360 ThrowIfNull();
362 if (StorageType.Date == _type) {
363 return this.DateTime.ToString("yyyy-MM-dd", DateTimeFormatInfo.InvariantInfo);
365 if (StorageType.Time == _type) {
366 byte scale = _value._timeInfo.scale;
367 return new DateTime(_value._timeInfo.ticks).ToString(__katmaiTimeFormatByScale[scale], DateTimeFormatInfo.InvariantInfo);
369 if (StorageType.DateTime2 == _type) {
370 byte scale = _value._dateTime2Info.timeInfo.scale;
371 return this.DateTime.ToString(__katmaiDateTime2FormatByScale[scale], DateTimeFormatInfo.InvariantInfo);
373 if (StorageType.DateTimeOffset == _type) {
374 DateTimeOffset dto = this.DateTimeOffset;
375 byte scale = _value._dateTimeOffsetInfo.dateTime2Info.timeInfo.scale;
376 return dto.ToString(__katmaiDateTimeOffsetFormatByScale[scale], DateTimeFormatInfo.InvariantInfo);
378 return (String)this.Value; // anything else we haven't thought of goes through boxing.
382 internal SqlString KatmaiDateTimeSqlString {
383 get {
384 if (StorageType.Date == _type ||
385 StorageType.Time == _type ||
386 StorageType.DateTime2 == _type ||
387 StorageType.DateTimeOffset == _type) {
388 if (IsNull) {
389 return SqlString.Null;
391 return new SqlString(KatmaiDateTimeString);
393 return (SqlString)this.SqlValue; // anything else we haven't thought of goes through boxing.
397 internal TimeSpan Time {
398 get {
399 ThrowIfNull();
401 if (StorageType.Time == _type) {
402 return new TimeSpan(_value._timeInfo.ticks);
405 return (TimeSpan)this.Value; // anything else we haven't thought of goes through boxing.
409 internal DateTimeOffset DateTimeOffset {
410 get {
411 ThrowIfNull();
413 if (StorageType.DateTimeOffset == _type) {
414 TimeSpan offset = new TimeSpan(0, _value._dateTimeOffsetInfo.offset, 0);
415 // datetime part presents time in UTC
416 return new DateTimeOffset(GetTicksFromDateTime2Info(_value._dateTimeOffsetInfo.dateTime2Info) + offset.Ticks, offset);
419 return (DateTimeOffset)this.Value; // anything else we haven't thought of goes through boxing.
423 private static long GetTicksFromDateTime2Info(DateTime2Info dateTime2Info) {
424 return (dateTime2Info.date * TimeSpan.TicksPerDay + dateTime2Info.timeInfo.ticks);
427 internal SqlBinary SqlBinary {
428 get {
429 if (StorageType.SqlBinary == _type) {
430 return (SqlBinary)_object;
432 return (SqlBinary)this.SqlValue; // anything else we haven't thought of goes through boxing.
434 set {
435 Debug.Assert (IsEmpty, "setting value a second time?");
436 _object = value;
437 _type = StorageType.SqlBinary;
438 _isNull = value.IsNull;
442 internal SqlBoolean SqlBoolean {
443 get {
444 if (StorageType.Boolean == _type) {
445 if (IsNull) {
446 return SqlBoolean.Null;
448 return new SqlBoolean(_value._boolean);
450 return (SqlBoolean)this.SqlValue; // anything else we haven't thought of goes through boxing.
454 internal SqlByte SqlByte {
455 get {
456 if (StorageType.Byte == _type) {
457 if (IsNull) {
458 return SqlByte.Null;
460 return new SqlByte(_value._byte);
462 return (SqlByte)this.SqlValue; // anything else we haven't thought of goes through boxing.
466 internal SqlCachedBuffer SqlCachedBuffer {
467 get {
468 if (StorageType.SqlCachedBuffer == _type) {
469 if (IsNull) {
470 return SqlCachedBuffer.Null;
472 return (SqlCachedBuffer)_object;
474 return (SqlCachedBuffer)this.SqlValue; // anything else we haven't thought of goes through boxing.
476 set {
477 Debug.Assert (IsEmpty, "setting value a second time?");
478 _object = value;
479 _type = StorageType.SqlCachedBuffer;
480 _isNull = value.IsNull;
484 internal SqlXml SqlXml {
485 get {
486 if (StorageType.SqlXml == _type) {
487 if (IsNull) {
488 return SqlXml.Null;
490 return (SqlXml)_object;
492 return (SqlXml)this.SqlValue; // anything else we haven't thought of goes through boxing.
494 set {
495 Debug.Assert (IsEmpty, "setting value a second time?");
496 _object = value;
497 _type = StorageType.SqlXml;
498 _isNull = value.IsNull;
502 internal SqlDateTime SqlDateTime {
503 get {
504 if (StorageType.DateTime == _type) {
505 if (IsNull) {
506 return SqlDateTime.Null;
508 return new SqlDateTime(_value._dateTimeInfo.daypart, _value._dateTimeInfo.timepart);
510 return (SqlDateTime)SqlValue; // anything else we haven't thought of goes through boxing.
514 internal SqlDecimal SqlDecimal {
515 get {
516 if (StorageType.Decimal == _type) {
517 if (IsNull) {
518 return SqlDecimal.Null;
520 return new SqlDecimal(_value._numericInfo.precision,
521 _value._numericInfo.scale,
522 _value._numericInfo.positive,
523 _value._numericInfo.data1,
524 _value._numericInfo.data2,
525 _value._numericInfo.data3,
526 _value._numericInfo.data4
529 return (SqlDecimal)this.SqlValue; // anything else we haven't thought of goes through boxing.
533 internal SqlDouble SqlDouble {
534 get {
535 if (StorageType.Double == _type) {
536 if (IsNull) {
537 return SqlDouble.Null;
539 return new SqlDouble(_value._double);
541 return (SqlDouble)this.SqlValue; // anything else we haven't thought of goes through boxing.
545 internal SqlGuid SqlGuid {
546 get {
547 if (StorageType.SqlGuid == _type) {
548 return (SqlGuid)_object;
550 return (SqlGuid)this.SqlValue; // anything else we haven't thought of goes through boxing.
552 set {
553 Debug.Assert (IsEmpty, "setting value a second time?");
554 _object = value;
555 _type = StorageType.SqlGuid;
556 _isNull = value.IsNull;
560 internal SqlInt16 SqlInt16 {
561 get {
562 if (StorageType.Int16 == _type) {
563 if (IsNull) {
564 return SqlInt16.Null;
566 return new SqlInt16(_value._int16);
568 return (SqlInt16)this.SqlValue; // anything else we haven't thought of goes through boxing.
572 internal SqlInt32 SqlInt32 {
573 get {
574 if (StorageType.Int32 == _type) {
575 if (IsNull) {
576 return SqlInt32.Null;
578 return new SqlInt32(_value._int32);
580 return (SqlInt32)this.SqlValue; // anything else we haven't thought of goes through boxing.
584 internal SqlInt64 SqlInt64 {
585 get {
586 if (StorageType.Int64 == _type) {
587 if (IsNull) {
588 return SqlInt64.Null;
590 return new SqlInt64(_value._int64);
592 return (SqlInt64)this.SqlValue; // anything else we haven't thought of goes through boxing.
596 internal SqlMoney SqlMoney {
597 get {
598 if (StorageType.Money == _type) {
599 if (IsNull) {
600 return SqlMoney.Null;
602 return new SqlMoney(_value._int64, 1/*ignored*/);
604 return (SqlMoney)this.SqlValue; // anything else we haven't thought of goes through boxing.
608 internal SqlSingle SqlSingle {
609 get {
610 if (StorageType.Single == _type) {
611 if (IsNull) {
612 return SqlSingle.Null;
614 return new SqlSingle(_value._single);
616 return (SqlSingle)this.SqlValue; // anything else we haven't thought of goes through boxing.
620 internal SqlString SqlString {
621 get {
622 if (StorageType.String == _type) {
623 if (IsNull) {
624 return SqlString.Null;
626 return new SqlString((String)_object);
629 else if (StorageType.SqlCachedBuffer == _type) {
630 SqlCachedBuffer data = (SqlCachedBuffer)(_object);
631 if (data.IsNull) {
632 return SqlString.Null;
634 return data.ToSqlString();
636 return (SqlString)this.SqlValue; // anything else we haven't thought of goes through boxing.
640 internal object SqlValue {
641 get {
642 switch (_type) {
643 case StorageType.Empty: return DBNull.Value;
644 case StorageType.Boolean: return SqlBoolean;
645 case StorageType.Byte: return SqlByte;
646 case StorageType.DateTime: return SqlDateTime;
647 case StorageType.Decimal: return SqlDecimal;
648 case StorageType.Double: return SqlDouble;
649 case StorageType.Int16: return SqlInt16;
650 case StorageType.Int32: return SqlInt32;
651 case StorageType.Int64: return SqlInt64;
652 case StorageType.Money: return SqlMoney;
653 case StorageType.Single: return SqlSingle;
654 case StorageType.String: return SqlString;
655 case StorageType.SqlCachedBuffer:
657 SqlCachedBuffer data = (SqlCachedBuffer)(_object);
658 if (data.IsNull) {
659 return SqlXml.Null;
661 return data.ToSqlXml();
664 case StorageType.SqlBinary:
665 case StorageType.SqlGuid:
666 return _object;
668 case StorageType.SqlXml: {
669 if (_isNull) {
670 return SqlXml.Null;
672 Debug.Assert(null != _object);
673 return (SqlXml) _object;
675 case StorageType.Date:
676 case StorageType.DateTime2:
677 if (_isNull) {
678 return DBNull.Value;
680 return DateTime;
681 case StorageType.DateTimeOffset:
682 if (_isNull) {
683 return DBNull.Value;
685 return DateTimeOffset;
686 case StorageType.Time:
687 if (_isNull) {
688 return DBNull.Value;
690 return Time;
692 return null; // need to return the value as an object of some SQL type
696 internal object Value {
697 get {
698 if (IsNull) {
699 return DBNull.Value;
701 switch (_type) {
702 case StorageType.Empty: return DBNull.Value;
703 case StorageType.Boolean: return Boolean;
704 case StorageType.Byte: return Byte;
705 case StorageType.DateTime: return DateTime;
706 case StorageType.Decimal: return Decimal;
707 case StorageType.Double: return Double;
708 case StorageType.Int16: return Int16;
709 case StorageType.Int32: return Int32;
710 case StorageType.Int64: return Int64;
711 case StorageType.Money: return Decimal;
712 case StorageType.Single: return Single;
713 case StorageType.String: return String;
714 case StorageType.SqlBinary: return ByteArray;
715 case StorageType.SqlCachedBuffer:
717 // If we have a CachedBuffer, it's because it's an XMLTYPE column
718 // and we have to return a string when they're asking for the CLS
719 // value of the column.
720 return ((SqlCachedBuffer)(_object)).ToString();
722 case StorageType.SqlGuid: return Guid;
723 case StorageType.SqlXml: {
724 // XMLTYPE columns must be returned as string when asking for the CLS value
725 SqlXml data = (SqlXml)_object;
726 string s = data.Value;
727 return s;
729 case StorageType.Date: return DateTime;
730 case StorageType.DateTime2: return DateTime;
731 case StorageType.DateTimeOffset: return DateTimeOffset;
732 case StorageType.Time: return Time;
734 return null; // need to return the value as an object of some CLS type
738 internal Type GetTypeFromStorageType (bool isSqlType) {
739 if (isSqlType) {
740 switch (_type) {
741 case SqlBuffer.StorageType.Empty: return null;
742 case SqlBuffer.StorageType.Boolean: return typeof(SqlBoolean);
743 case SqlBuffer.StorageType.Byte: return typeof(SqlByte);
744 case SqlBuffer.StorageType.DateTime: return typeof(SqlDateTime);
745 case SqlBuffer.StorageType.Decimal: return typeof(SqlDecimal);
746 case SqlBuffer.StorageType.Double: return typeof(SqlDouble);
747 case SqlBuffer.StorageType.Int16: return typeof(SqlInt16);
748 case SqlBuffer.StorageType.Int32: return typeof(SqlInt32);
749 case SqlBuffer.StorageType.Int64: return typeof(SqlInt64);
750 case SqlBuffer.StorageType.Money: return typeof(SqlMoney);
751 case SqlBuffer.StorageType.Single: return typeof(SqlSingle);
752 case SqlBuffer.StorageType.String: return typeof(SqlString);
753 case SqlBuffer.StorageType.SqlCachedBuffer: return typeof(SqlString);
754 case SqlBuffer.StorageType.SqlBinary: return typeof(object);
755 case SqlBuffer.StorageType.SqlGuid: return typeof(object);
756 case SqlBuffer.StorageType.SqlXml: return typeof(SqlXml);
759 else { //Is CLR Type
760 switch (_type) {
761 case SqlBuffer.StorageType.Empty: return null;
762 case SqlBuffer.StorageType.Boolean: return typeof(Boolean);
763 case SqlBuffer.StorageType.Byte: return typeof(Byte);
764 case SqlBuffer.StorageType.DateTime: return typeof(DateTime);
765 case SqlBuffer.StorageType.Decimal: return typeof(Decimal);
766 case SqlBuffer.StorageType.Double: return typeof(Double);
767 case SqlBuffer.StorageType.Int16: return typeof(Int16);
768 case SqlBuffer.StorageType.Int32: return typeof(Int32);
769 case SqlBuffer.StorageType.Int64: return typeof(Int64);
770 case SqlBuffer.StorageType.Money: return typeof(Decimal);
771 case SqlBuffer.StorageType.Single: return typeof(Single);
772 case SqlBuffer.StorageType.String: return typeof(String);
773 case SqlBuffer.StorageType.SqlBinary: return typeof(Byte[]);
774 case SqlBuffer.StorageType.SqlCachedBuffer: return typeof(string);
775 case SqlBuffer.StorageType.SqlGuid: return typeof(Guid);
776 case SqlBuffer.StorageType.SqlXml: return typeof(string);
780 return null; // need to return the value as an object of some CLS type
783 internal static SqlBuffer[] CreateBufferArray(int length) {
784 SqlBuffer[] buffers = new SqlBuffer[length];
785 for(int i = 0; i < buffers.Length; ++i) {
786 buffers[i] = new SqlBuffer();
788 return buffers;
791 internal static SqlBuffer[] CloneBufferArray(SqlBuffer[] values) {
792 SqlBuffer[] copy = new SqlBuffer[values.Length];
793 for (int i=0; i<values.Length; i++) {
794 copy[i] = new SqlBuffer(values[i]);
796 return copy;
799 internal static void Clear(SqlBuffer[] values) {
800 if (null != values) {
801 for(int i = 0; i < values.Length; ++i) {
802 values[i].Clear();
807 internal void Clear() {
808 _isNull = false;
809 _type = StorageType.Empty;
810 _object = null;
813 internal void SetToDateTime(int daypart, int timepart) {
814 Debug.Assert (IsEmpty, "setting value a second time?");
815 _value._dateTimeInfo.daypart = daypart;
816 _value._dateTimeInfo.timepart = timepart;
817 _type = StorageType.DateTime;
818 _isNull = false;
821 internal void SetToDecimal(byte precision, byte scale, bool positive, int[] bits) {
822 Debug.Assert (IsEmpty, "setting value a second time?");
823 _value._numericInfo.precision = precision;
824 _value._numericInfo.scale = scale;
825 _value._numericInfo.positive = positive;
826 _value._numericInfo.data1 = bits[0];
827 _value._numericInfo.data2 = bits[1];
828 _value._numericInfo.data3 = bits[2];
829 _value._numericInfo.data4 = bits[3];
830 _type = StorageType.Decimal;
831 _isNull = false;
834 internal void SetToMoney(long value) {
835 Debug.Assert (IsEmpty, "setting value a second time?");
836 _value._int64 = value;
837 _type = StorageType.Money;
838 _isNull = false;
841 internal void SetToNullOfType(StorageType storageType) {
842 Debug.Assert (IsEmpty, "setting value a second time?");
843 _type = storageType;
844 _isNull = true;
845 _object = null;
848 internal void SetToString(string value) {
849 Debug.Assert (IsEmpty, "setting value a second time?");
850 _object = value;
851 _type = StorageType.String;
852 _isNull = false;
855 internal void SetToDate(byte[] bytes) {
856 Debug.Assert(IsEmpty, "setting value a second time?");
858 _type = StorageType.Date;
859 _value._int32 = GetDateFromByteArray(bytes, 0);
860 _isNull = false;
863 internal void SetToDate(DateTime date) {
864 Debug.Assert(IsEmpty, "setting value a second time?");
866 _type = StorageType.Date;
867 _value._int32 = date.Subtract(DateTime.MinValue).Days;
868 _isNull = false;
871 internal void SetToTime(byte[] bytes, int length, byte scale, byte denormalizedScale) {
872 Debug.Assert(IsEmpty, "setting value a second time?");
874 _type = StorageType.Time;
875 FillInTimeInfo(ref _value._timeInfo, bytes, length, scale, denormalizedScale);
876 _isNull = false;
879 internal void SetToTime(TimeSpan timeSpan, byte scale) {
880 Debug.Assert(IsEmpty, "setting value a second time?");
882 _type = StorageType.Time;
883 _value._timeInfo.ticks = timeSpan.Ticks;
884 _value._timeInfo.scale = scale;
885 _isNull = false;
888 internal void SetToDateTime2(byte[] bytes, int length, byte scale, byte denormalizedScale) {
889 Debug.Assert(IsEmpty, "setting value a second time?");
891 _type = StorageType.DateTime2;
892 FillInTimeInfo(ref _value._dateTime2Info.timeInfo, bytes, length - 3, scale, denormalizedScale); // remaining 3 bytes is for date
893 _value._dateTime2Info.date = GetDateFromByteArray(bytes, length - 3); // 3 bytes for date
894 _isNull = false;
897 internal void SetToDateTime2(DateTime dateTime, byte scale) {
898 Debug.Assert(IsEmpty, "setting value a second time?");
900 _type = StorageType.DateTime2;
901 _value._dateTime2Info.timeInfo.ticks = dateTime.TimeOfDay.Ticks;
902 _value._dateTime2Info.timeInfo.scale = scale;
903 _value._dateTime2Info.date = dateTime.Subtract(DateTime.MinValue).Days;
904 _isNull = false;
907 internal void SetToDateTimeOffset(byte[] bytes, int length, byte scale, byte denormalizedScale) {
908 Debug.Assert(IsEmpty, "setting value a second time?");
910 _type = StorageType.DateTimeOffset;
911 FillInTimeInfo(ref _value._dateTimeOffsetInfo.dateTime2Info.timeInfo, bytes, length - 5, scale, denormalizedScale); // remaining 5 bytes are for date and offset
912 _value._dateTimeOffsetInfo.dateTime2Info.date = GetDateFromByteArray(bytes, length - 5); // 3 bytes for date
913 _value._dateTimeOffsetInfo.offset = (Int16)(bytes[length - 2] + (bytes[length - 1] << 8)); // 2 bytes for offset (Int16)
914 _isNull = false;
917 internal void SetToDateTimeOffset(DateTimeOffset dateTimeOffset, byte scale) {
918 Debug.Assert(IsEmpty, "setting value a second time?");
920 _type = StorageType.DateTimeOffset;
921 DateTime utcDateTime = dateTimeOffset.UtcDateTime; // timeInfo stores the utc datetime of a datatimeoffset
922 _value._dateTimeOffsetInfo.dateTime2Info.timeInfo.ticks = utcDateTime.TimeOfDay.Ticks;
923 _value._dateTimeOffsetInfo.dateTime2Info.timeInfo.scale = scale;
924 _value._dateTimeOffsetInfo.dateTime2Info.date = utcDateTime.Subtract(DateTime.MinValue).Days;
925 _value._dateTimeOffsetInfo.offset = (Int16)dateTimeOffset.Offset.TotalMinutes;
926 _isNull = false;
929 private static void FillInTimeInfo(ref TimeInfo timeInfo, byte[] timeBytes, int length, byte scale, byte denormalizedScale) {
930 Debug.Assert(3 <= length && length <= 5, "invalid data length for timeInfo: " + length);
931 Debug.Assert(0 <= scale && scale <= 7, "invalid scale: " + scale);
932 Debug.Assert(0 <= denormalizedScale && denormalizedScale <= 7, "invalid denormalized scale: " + denormalizedScale);
934 Int64 tickUnits = (Int64)timeBytes[0] + ((Int64)timeBytes[1] << 8) + ((Int64)timeBytes[2] << 16);
935 if (length > 3) {
936 tickUnits += ((Int64)timeBytes[3] << 24);
938 if (length > 4) {
939 tickUnits += ((Int64)timeBytes[4] << 32);
941 timeInfo.ticks = tickUnits * TdsEnums.TICKS_FROM_SCALE[scale];
943 // Once the deserialization has been completed using the value scale, we need to set the actual denormalized scale,
944 // coming from the data type, on the original result, so that it has the proper scale setting.
945 // This only applies for values that got serialized/deserialized for encryption. Otherwise, both scales should be equal.
946 timeInfo.scale = denormalizedScale;
949 private static Int32 GetDateFromByteArray(byte[] buf, int offset) {
950 return buf[offset] + (buf[offset + 1] << 8) + (buf[offset + 2] << 16);
953 private void ThrowIfNull() {
954 if (IsNull) {
955 throw new SqlNullValueException();
959 }// namespace