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 //------------------------------------------------------------------------------ 9 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; 27 28 internal sealed class SqlBuffer { 29 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, 51 } 52 53 internal struct DateTimeInfo { 54 // This is used to store DateTime 55 internal Int32 daypart; 56 internal Int32 timepart; 57 } 58 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; 68 } 69 70 internal struct TimeInfo { 71 internal Int64 ticks; 72 internal byte scale; 73 } 74 75 internal struct DateTime2Info { 76 internal Int32 date; 77 internal TimeInfo timeInfo; 78 } 79 80 internal struct DateTimeOffsetInfo { 81 internal DateTime2Info dateTime2Info; 82 internal Int16 offset; 83 } 84 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; 99 } 100 101 private bool _isNull; 102 private StorageType _type; 103 private Storage _value; 104 private object _object; // String, SqlBinary, SqlCachedBuffer, SqlGuid, SqlString, SqlXml 105 SqlBuffer()106 internal SqlBuffer() { 107 } 108 SqlBuffer(SqlBuffer value)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; 117 } 118 119 internal bool IsEmpty { 120 get { 121 return (StorageType.Empty == _type); 122 } 123 } 124 125 internal bool IsNull { 126 get { 127 return _isNull; 128 } 129 } 130 131 internal StorageType VariantInternalStorageType 132 { 133 get { return _type; } 134 } 135 136 internal Boolean Boolean { 137 get { 138 ThrowIfNull(); 139 140 if (StorageType.Boolean == _type) { 141 return _value._boolean; 142 } 143 return (Boolean)this.Value; // anything else we haven't thought of goes through boxing. 144 } 145 set { 146 Debug.Assert (IsEmpty, "setting value a second time?"); 147 _value._boolean = value; 148 _type = StorageType.Boolean; 149 _isNull = false; 150 } 151 } 152 153 internal Byte Byte { 154 get { 155 ThrowIfNull(); 156 157 if (StorageType.Byte == _type) { 158 return _value._byte; 159 } 160 return (Byte)this.Value; // anything else we haven't thought of goes through boxing. 161 } 162 set { 163 Debug.Assert (IsEmpty, "setting value a second time?"); 164 _value._byte = value; 165 _type = StorageType.Byte; 166 _isNull = false; 167 } 168 } 169 170 internal Byte[] ByteArray { 171 get { 172 ThrowIfNull(); 173 return this.SqlBinary.Value; // 174 } 175 } 176 177 internal DateTime DateTime { 178 get { 179 ThrowIfNull(); 180 181 if (StorageType.Date == _type) { 182 return DateTime.MinValue.AddDays(_value._int32); 183 } 184 if (StorageType.DateTime2 == _type) { 185 return new DateTime(GetTicksFromDateTime2Info(_value._dateTime2Info)); 186 } 187 if (StorageType.DateTime == _type) { 188 return SqlDateTime.ToDateTime(_value._dateTimeInfo.daypart, _value._dateTimeInfo.timepart); 189 } 190 return (DateTime)this.Value; // anything else we haven't thought of goes through boxing. 191 } 192 } 193 194 internal Decimal Decimal { 195 get { 196 ThrowIfNull(); 197 198 if (StorageType.Decimal == _type) { 199 if (_value._numericInfo.data4 != 0 || _value._numericInfo.scale > 28) { 200 throw new OverflowException(SQLResource.ConversionOverflowMessage); 201 } 202 return new Decimal(_value._numericInfo.data1, _value._numericInfo.data2, _value._numericInfo.data3, !_value._numericInfo.positive, _value._numericInfo.scale); 203 } 204 if (StorageType.Money == _type) { 205 long l = _value._int64; 206 bool isNegative = false; 207 if (l < 0) { 208 isNegative = true; 209 l = -l; 210 } 211 return new Decimal((int)(l & 0xffffffff), (int)(l >> 32), 0, isNegative, 4); 212 } 213 return (Decimal)this.Value; // anything else we haven't thought of goes through boxing. 214 } 215 } 216 217 internal Double Double { 218 get { 219 ThrowIfNull(); 220 221 if (StorageType.Double == _type) { 222 return _value._double; 223 } 224 return (Double)this.Value; // anything else we haven't thought of goes through boxing. 225 } 226 set { 227 Debug.Assert (IsEmpty, "setting value a second time?"); 228 _value._double = value; 229 _type = StorageType.Double; 230 _isNull = false; 231 } 232 } 233 234 internal Guid Guid { 235 get { 236 // 237 ThrowIfNull(); 238 return this.SqlGuid.Value; 239 } 240 } 241 242 internal Int16 Int16 { 243 get { 244 ThrowIfNull(); 245 246 if (StorageType.Int16 == _type) { 247 return _value._int16; 248 } 249 return (Int16)this.Value; // anything else we haven't thought of goes through boxing. 250 } 251 set { 252 Debug.Assert (IsEmpty, "setting value a second time?"); 253 _value._int16 = value; 254 _type = StorageType.Int16; 255 _isNull = false; 256 } 257 } 258 259 internal Int32 Int32 { 260 get { 261 ThrowIfNull(); 262 263 if (StorageType.Int32 == _type) { 264 return _value._int32; 265 } 266 return (Int32)this.Value; // anything else we haven't thought of goes through boxing. 267 } 268 set { 269 Debug.Assert (IsEmpty, "setting value a second time?"); 270 _value._int32 = value; 271 _type = StorageType.Int32; 272 _isNull = false; 273 } 274 } 275 276 internal Int64 Int64 { 277 get { 278 ThrowIfNull(); 279 280 if (StorageType.Int64 == _type) { 281 return _value._int64; 282 } 283 return (Int64)this.Value; // anything else we haven't thought of goes through boxing. 284 } 285 set { 286 Debug.Assert (IsEmpty, "setting value a second time?"); 287 _value._int64 = value; 288 _type = StorageType.Int64; 289 _isNull = false; 290 } 291 } 292 293 internal Single Single { 294 get { 295 ThrowIfNull(); 296 297 if (StorageType.Single == _type) { 298 return _value._single; 299 } 300 return (Single)this.Value; // anything else we haven't thought of goes through boxing. 301 } 302 set { 303 Debug.Assert (IsEmpty, "setting value a second time?"); 304 _value._single = value; 305 _type = StorageType.Single; 306 _isNull = false; 307 } 308 } 309 310 internal String String { 311 get { 312 ThrowIfNull(); 313 314 if (StorageType.String == _type) { 315 return (String)_object; 316 } 317 else if (StorageType.SqlCachedBuffer == _type) { 318 return ((SqlCachedBuffer)(_object)).ToString(); 319 } 320 return (String)this.Value; // anything else we haven't thought of goes through boxing. 321 } 322 } 323 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", 334 }; 335 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", 345 }; 346 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", 356 }; 357 358 internal string KatmaiDateTimeString { 359 get { 360 ThrowIfNull(); 361 362 if (StorageType.Date == _type) { 363 return this.DateTime.ToString("yyyy-MM-dd", DateTimeFormatInfo.InvariantInfo); 364 } 365 if (StorageType.Time == _type) { 366 byte scale = _value._timeInfo.scale; 367 return new DateTime(_value._timeInfo.ticks).ToString(__katmaiTimeFormatByScale[scale], DateTimeFormatInfo.InvariantInfo); 368 } 369 if (StorageType.DateTime2 == _type) { 370 byte scale = _value._dateTime2Info.timeInfo.scale; 371 return this.DateTime.ToString(__katmaiDateTime2FormatByScale[scale], DateTimeFormatInfo.InvariantInfo); 372 } 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); 377 } 378 return (String)this.Value; // anything else we haven't thought of goes through boxing. 379 } 380 } 381 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; 390 } 391 return new SqlString(KatmaiDateTimeString); 392 } 393 return (SqlString)this.SqlValue; // anything else we haven't thought of goes through boxing. 394 } 395 } 396 397 internal TimeSpan Time { 398 get { 399 ThrowIfNull(); 400 401 if (StorageType.Time == _type) { 402 return new TimeSpan(_value._timeInfo.ticks); 403 } 404 405 return (TimeSpan)this.Value; // anything else we haven't thought of goes through boxing. 406 } 407 } 408 409 internal DateTimeOffset DateTimeOffset { 410 get { 411 ThrowIfNull(); 412 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); 417 } 418 419 return (DateTimeOffset)this.Value; // anything else we haven't thought of goes through boxing. 420 } 421 } 422 GetTicksFromDateTime2Info(DateTime2Info dateTime2Info)423 private static long GetTicksFromDateTime2Info(DateTime2Info dateTime2Info) { 424 return (dateTime2Info.date * TimeSpan.TicksPerDay + dateTime2Info.timeInfo.ticks); 425 } 426 427 internal SqlBinary SqlBinary { 428 get { 429 if (StorageType.SqlBinary == _type) { 430 return (SqlBinary)_object; 431 } 432 return (SqlBinary)this.SqlValue; // anything else we haven't thought of goes through boxing. 433 } 434 set { 435 Debug.Assert (IsEmpty, "setting value a second time?"); 436 _object = value; 437 _type = StorageType.SqlBinary; 438 _isNull = value.IsNull; 439 } 440 } 441 442 internal SqlBoolean SqlBoolean { 443 get { 444 if (StorageType.Boolean == _type) { 445 if (IsNull) { 446 return SqlBoolean.Null; 447 } 448 return new SqlBoolean(_value._boolean); 449 } 450 return (SqlBoolean)this.SqlValue; // anything else we haven't thought of goes through boxing. 451 } 452 } 453 454 internal SqlByte SqlByte { 455 get { 456 if (StorageType.Byte == _type) { 457 if (IsNull) { 458 return SqlByte.Null; 459 } 460 return new SqlByte(_value._byte); 461 } 462 return (SqlByte)this.SqlValue; // anything else we haven't thought of goes through boxing. 463 } 464 } 465 466 internal SqlCachedBuffer SqlCachedBuffer { 467 get { 468 if (StorageType.SqlCachedBuffer == _type) { 469 if (IsNull) { 470 return SqlCachedBuffer.Null; 471 } 472 return (SqlCachedBuffer)_object; 473 } 474 return (SqlCachedBuffer)this.SqlValue; // anything else we haven't thought of goes through boxing. 475 } 476 set { 477 Debug.Assert (IsEmpty, "setting value a second time?"); 478 _object = value; 479 _type = StorageType.SqlCachedBuffer; 480 _isNull = value.IsNull; 481 } 482 } 483 484 internal SqlXml SqlXml { 485 get { 486 if (StorageType.SqlXml == _type) { 487 if (IsNull) { 488 return SqlXml.Null; 489 } 490 return (SqlXml)_object; 491 } 492 return (SqlXml)this.SqlValue; // anything else we haven't thought of goes through boxing. 493 } 494 set { 495 Debug.Assert (IsEmpty, "setting value a second time?"); 496 _object = value; 497 _type = StorageType.SqlXml; 498 _isNull = value.IsNull; 499 } 500 } 501 502 internal SqlDateTime SqlDateTime { 503 get { 504 if (StorageType.DateTime == _type) { 505 if (IsNull) { 506 return SqlDateTime.Null; 507 } 508 return new SqlDateTime(_value._dateTimeInfo.daypart, _value._dateTimeInfo.timepart); 509 } 510 return (SqlDateTime)SqlValue; // anything else we haven't thought of goes through boxing. 511 } 512 } 513 514 internal SqlDecimal SqlDecimal { 515 get { 516 if (StorageType.Decimal == _type) { 517 if (IsNull) { 518 return SqlDecimal.Null; 519 } 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 527 ); 528 } 529 return (SqlDecimal)this.SqlValue; // anything else we haven't thought of goes through boxing. 530 } 531 } 532 533 internal SqlDouble SqlDouble { 534 get { 535 if (StorageType.Double == _type) { 536 if (IsNull) { 537 return SqlDouble.Null; 538 } 539 return new SqlDouble(_value._double); 540 } 541 return (SqlDouble)this.SqlValue; // anything else we haven't thought of goes through boxing. 542 } 543 } 544 545 internal SqlGuid SqlGuid { 546 get { 547 if (StorageType.SqlGuid == _type) { 548 return (SqlGuid)_object; 549 } 550 return (SqlGuid)this.SqlValue; // anything else we haven't thought of goes through boxing. 551 } 552 set { 553 Debug.Assert (IsEmpty, "setting value a second time?"); 554 _object = value; 555 _type = StorageType.SqlGuid; 556 _isNull = value.IsNull; 557 } 558 } 559 560 internal SqlInt16 SqlInt16 { 561 get { 562 if (StorageType.Int16 == _type) { 563 if (IsNull) { 564 return SqlInt16.Null; 565 } 566 return new SqlInt16(_value._int16); 567 } 568 return (SqlInt16)this.SqlValue; // anything else we haven't thought of goes through boxing. 569 } 570 } 571 572 internal SqlInt32 SqlInt32 { 573 get { 574 if (StorageType.Int32 == _type) { 575 if (IsNull) { 576 return SqlInt32.Null; 577 } 578 return new SqlInt32(_value._int32); 579 } 580 return (SqlInt32)this.SqlValue; // anything else we haven't thought of goes through boxing. 581 } 582 } 583 584 internal SqlInt64 SqlInt64 { 585 get { 586 if (StorageType.Int64 == _type) { 587 if (IsNull) { 588 return SqlInt64.Null; 589 } 590 return new SqlInt64(_value._int64); 591 } 592 return (SqlInt64)this.SqlValue; // anything else we haven't thought of goes through boxing. 593 } 594 } 595 596 internal SqlMoney SqlMoney { 597 get { 598 if (StorageType.Money == _type) { 599 if (IsNull) { 600 return SqlMoney.Null; 601 } 602 return new SqlMoney(_value._int64, 1/*ignored*/); 603 } 604 return (SqlMoney)this.SqlValue; // anything else we haven't thought of goes through boxing. 605 } 606 } 607 608 internal SqlSingle SqlSingle { 609 get { 610 if (StorageType.Single == _type) { 611 if (IsNull) { 612 return SqlSingle.Null; 613 } 614 return new SqlSingle(_value._single); 615 } 616 return (SqlSingle)this.SqlValue; // anything else we haven't thought of goes through boxing. 617 } 618 } 619 620 internal SqlString SqlString { 621 get { 622 if (StorageType.String == _type) { 623 if (IsNull) { 624 return SqlString.Null; 625 } 626 return new SqlString((String)_object); 627 628 } 629 else if (StorageType.SqlCachedBuffer == _type) { 630 SqlCachedBuffer data = (SqlCachedBuffer)(_object); 631 if (data.IsNull) { 632 return SqlString.Null; 633 } 634 return data.ToSqlString(); 635 } 636 return (SqlString)this.SqlValue; // anything else we haven't thought of goes through boxing. 637 } 638 } 639 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: 656 { 657 SqlCachedBuffer data = (SqlCachedBuffer)(_object); 658 if (data.IsNull) { 659 return SqlXml.Null; 660 } 661 return data.ToSqlXml(); 662 } 663 664 case StorageType.SqlBinary: 665 case StorageType.SqlGuid: 666 return _object; 667 668 case StorageType.SqlXml: { 669 if (_isNull) { 670 return SqlXml.Null; 671 } 672 Debug.Assert(null != _object); 673 return (SqlXml) _object; 674 } 675 case StorageType.Date: 676 case StorageType.DateTime2: 677 if (_isNull) { 678 return DBNull.Value; 679 } 680 return DateTime; 681 case StorageType.DateTimeOffset: 682 if (_isNull) { 683 return DBNull.Value; 684 } 685 return DateTimeOffset; 686 case StorageType.Time: 687 if (_isNull) { 688 return DBNull.Value; 689 } 690 return Time; 691 } 692 return null; // need to return the value as an object of some SQL type 693 } 694 } 695 696 internal object Value { 697 get { 698 if (IsNull) { 699 return DBNull.Value; 700 } 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: 716 { 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(); 721 } 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; 728 } 729 case StorageType.Date: return DateTime; 730 case StorageType.DateTime2: return DateTime; 731 case StorageType.DateTimeOffset: return DateTimeOffset; 732 case StorageType.Time: return Time; 733 } 734 return null; // need to return the value as an object of some CLS type 735 } 736 } 737 GetTypeFromStorageType(bool isSqlType)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); 757 } 758 } 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); 777 } 778 } 779 780 return null; // need to return the value as an object of some CLS type 781 } 782 CreateBufferArray(int length)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(); 787 } 788 return buffers; 789 } 790 CloneBufferArray(SqlBuffer[] values)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]); 795 } 796 return copy; 797 } 798 Clear(SqlBuffer[] values)799 internal static void Clear(SqlBuffer[] values) { 800 if (null != values) { 801 for(int i = 0; i < values.Length; ++i) { 802 values[i].Clear(); 803 } 804 } 805 } 806 Clear()807 internal void Clear() { 808 _isNull = false; 809 _type = StorageType.Empty; 810 _object = null; 811 } 812 SetToDateTime(int daypart, int timepart)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; 819 } 820 SetToDecimal(byte precision, byte scale, bool positive, int[] bits)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; 832 } 833 SetToMoney(long value)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; 839 } 840 SetToNullOfType(StorageType storageType)841 internal void SetToNullOfType(StorageType storageType) { 842 Debug.Assert (IsEmpty, "setting value a second time?"); 843 _type = storageType; 844 _isNull = true; 845 _object = null; 846 } 847 SetToString(string value)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; 853 } 854 SetToDate(byte[] bytes)855 internal void SetToDate(byte[] bytes) { 856 Debug.Assert(IsEmpty, "setting value a second time?"); 857 858 _type = StorageType.Date; 859 _value._int32 = GetDateFromByteArray(bytes, 0); 860 _isNull = false; 861 } 862 SetToDate(DateTime date)863 internal void SetToDate(DateTime date) { 864 Debug.Assert(IsEmpty, "setting value a second time?"); 865 866 _type = StorageType.Date; 867 _value._int32 = date.Subtract(DateTime.MinValue).Days; 868 _isNull = false; 869 } 870 SetToTime(byte[] bytes, int length, byte scale, byte denormalizedScale)871 internal void SetToTime(byte[] bytes, int length, byte scale, byte denormalizedScale) { 872 Debug.Assert(IsEmpty, "setting value a second time?"); 873 874 _type = StorageType.Time; 875 FillInTimeInfo(ref _value._timeInfo, bytes, length, scale, denormalizedScale); 876 _isNull = false; 877 } 878 SetToTime(TimeSpan timeSpan, byte scale)879 internal void SetToTime(TimeSpan timeSpan, byte scale) { 880 Debug.Assert(IsEmpty, "setting value a second time?"); 881 882 _type = StorageType.Time; 883 _value._timeInfo.ticks = timeSpan.Ticks; 884 _value._timeInfo.scale = scale; 885 _isNull = false; 886 } 887 SetToDateTime2(byte[] bytes, int length, byte scale, byte denormalizedScale)888 internal void SetToDateTime2(byte[] bytes, int length, byte scale, byte denormalizedScale) { 889 Debug.Assert(IsEmpty, "setting value a second time?"); 890 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; 895 } 896 SetToDateTime2(DateTime dateTime, byte scale)897 internal void SetToDateTime2(DateTime dateTime, byte scale) { 898 Debug.Assert(IsEmpty, "setting value a second time?"); 899 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; 905 } 906 SetToDateTimeOffset(byte[] bytes, int length, byte scale, byte denormalizedScale)907 internal void SetToDateTimeOffset(byte[] bytes, int length, byte scale, byte denormalizedScale) { 908 Debug.Assert(IsEmpty, "setting value a second time?"); 909 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; 915 } 916 SetToDateTimeOffset(DateTimeOffset dateTimeOffset, byte scale)917 internal void SetToDateTimeOffset(DateTimeOffset dateTimeOffset, byte scale) { 918 Debug.Assert(IsEmpty, "setting value a second time?"); 919 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; 927 } 928 FillInTimeInfo(ref TimeInfo timeInfo, byte[] timeBytes, int length, byte scale, byte denormalizedScale)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); 933 934 Int64 tickUnits = (Int64)timeBytes[0] + ((Int64)timeBytes[1] << 8) + ((Int64)timeBytes[2] << 16); 935 if (length > 3) { 936 tickUnits += ((Int64)timeBytes[3] << 24); 937 } 938 if (length > 4) { 939 tickUnits += ((Int64)timeBytes[4] << 32); 940 } 941 timeInfo.ticks = tickUnits * TdsEnums.TICKS_FROM_SCALE[scale]; 942 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; 947 } 948 GetDateFromByteArray(byte[] buf, int offset)949 private static Int32 GetDateFromByteArray(byte[] buf, int offset) { 950 return buf[offset] + (buf[offset + 1] << 8) + (buf[offset + 2] << 16); 951 } 952 ThrowIfNull()953 private void ThrowIfNull() { 954 if (IsNull) { 955 throw new SqlNullValueException(); 956 } 957 } 958 } 959 }// namespace 960