SqlBuffer.cs 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959
  1. //------------------------------------------------------------------------------
  2. // <copyright file="SqlDataReader.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. // <owner current="true" primary="true">[....]</owner>
  6. // <owner current="true" primary="false">[....]</owner>
  7. // <owner current="true" primary="false">[....]</owner>
  8. //------------------------------------------------------------------------------
  9. namespace System.Data.SqlClient {
  10. using System.Threading;
  11. using System.Diagnostics;
  12. using System.Reflection;
  13. using System;
  14. using System.Data;
  15. using System.IO;
  16. using System.Collections;
  17. using System.Collections.Specialized;
  18. using System.Data.Sql;
  19. using System.Data.SqlTypes;
  20. using System.Data.Common;
  21. using System.Data.ProviderBase;
  22. using System.ComponentModel;
  23. using System.Globalization;
  24. using System.Xml;
  25. using System.Runtime.InteropServices;
  26. internal sealed class SqlBuffer {
  27. internal enum StorageType {
  28. Empty = 0,
  29. Boolean,
  30. Byte,
  31. DateTime,
  32. Decimal,
  33. Double,
  34. Int16,
  35. Int32,
  36. Int64,
  37. Money,
  38. Single,
  39. String,
  40. SqlBinary,
  41. SqlCachedBuffer,
  42. SqlGuid,
  43. SqlXml,
  44. Date,
  45. DateTime2,
  46. DateTimeOffset,
  47. Time,
  48. }
  49. internal struct DateTimeInfo {
  50. // This is used to store DateTime
  51. internal Int32 daypart;
  52. internal Int32 timepart;
  53. }
  54. internal struct NumericInfo {
  55. // This is used to store Decimal data
  56. internal Int32 data1;
  57. internal Int32 data2;
  58. internal Int32 data3;
  59. internal Int32 data4;
  60. internal Byte precision;
  61. internal Byte scale;
  62. internal Boolean positive;
  63. }
  64. internal struct TimeInfo {
  65. internal Int64 ticks;
  66. internal byte scale;
  67. }
  68. internal struct DateTime2Info {
  69. internal Int32 date;
  70. internal TimeInfo timeInfo;
  71. }
  72. internal struct DateTimeOffsetInfo {
  73. internal DateTime2Info dateTime2Info;
  74. internal Int16 offset;
  75. }
  76. [StructLayout(LayoutKind.Explicit)]
  77. internal struct Storage {
  78. [FieldOffset(0)] internal Boolean _boolean;
  79. [FieldOffset(0)] internal Byte _byte;
  80. [FieldOffset(0)] internal DateTimeInfo _dateTimeInfo;
  81. [FieldOffset(0)] internal Double _double;
  82. [FieldOffset(0)] internal NumericInfo _numericInfo;
  83. [FieldOffset(0)] internal Int16 _int16;
  84. [FieldOffset(0)] internal Int32 _int32;
  85. [FieldOffset(0)] internal Int64 _int64; // also used to store Money, UtcDateTime, Date , and Time
  86. [FieldOffset(0)] internal Single _single;
  87. [FieldOffset(0)] internal TimeInfo _timeInfo;
  88. [FieldOffset(0)] internal DateTime2Info _dateTime2Info;
  89. [FieldOffset(0)] internal DateTimeOffsetInfo _dateTimeOffsetInfo;
  90. }
  91. private bool _isNull;
  92. private StorageType _type;
  93. private Storage _value;
  94. private object _object; // String, SqlBinary, SqlCachedBuffer, SqlGuid, SqlString, SqlXml
  95. internal SqlBuffer() {
  96. }
  97. private SqlBuffer(SqlBuffer value) { // Clone
  98. // value types
  99. _isNull = value._isNull;
  100. _type = value._type;
  101. // ref types - should also be read only unless at some point we allow this data
  102. // to be mutable, then we will need to copy
  103. _value = value._value;
  104. _object = value._object;
  105. }
  106. internal bool IsEmpty {
  107. get {
  108. return (StorageType.Empty == _type);
  109. }
  110. }
  111. internal bool IsNull {
  112. get {
  113. return _isNull;
  114. }
  115. }
  116. internal StorageType VariantInternalStorageType
  117. {
  118. get { return _type; }
  119. }
  120. internal Boolean Boolean {
  121. get {
  122. ThrowIfNull();
  123. if (StorageType.Boolean == _type) {
  124. return _value._boolean;
  125. }
  126. return (Boolean)this.Value; // anything else we haven't thought of goes through boxing.
  127. }
  128. set {
  129. Debug.Assert (IsEmpty, "setting value a second time?");
  130. _value._boolean = value;
  131. _type = StorageType.Boolean;
  132. _isNull = false;
  133. }
  134. }
  135. internal Byte Byte {
  136. get {
  137. ThrowIfNull();
  138. if (StorageType.Byte == _type) {
  139. return _value._byte;
  140. }
  141. return (Byte)this.Value; // anything else we haven't thought of goes through boxing.
  142. }
  143. set {
  144. Debug.Assert (IsEmpty, "setting value a second time?");
  145. _value._byte = value;
  146. _type = StorageType.Byte;
  147. _isNull = false;
  148. }
  149. }
  150. internal Byte[] ByteArray {
  151. get {
  152. ThrowIfNull();
  153. return this.SqlBinary.Value; //
  154. }
  155. }
  156. internal DateTime DateTime {
  157. get {
  158. ThrowIfNull();
  159. if (StorageType.Date == _type) {
  160. return DateTime.MinValue.AddDays(_value._int32);
  161. }
  162. if (StorageType.DateTime2 == _type) {
  163. return new DateTime(GetTicksFromDateTime2Info(_value._dateTime2Info));
  164. }
  165. if (StorageType.DateTime == _type) {
  166. return SqlDateTime.ToDateTime(_value._dateTimeInfo.daypart, _value._dateTimeInfo.timepart);
  167. }
  168. return (DateTime)this.Value; // anything else we haven't thought of goes through boxing.
  169. }
  170. }
  171. internal Decimal Decimal {
  172. get {
  173. ThrowIfNull();
  174. if (StorageType.Decimal == _type) {
  175. if (_value._numericInfo.data4 != 0 || _value._numericInfo.scale > 28) {
  176. throw new OverflowException(SQLResource.ConversionOverflowMessage);
  177. }
  178. return new Decimal(_value._numericInfo.data1, _value._numericInfo.data2, _value._numericInfo.data3, !_value._numericInfo.positive, _value._numericInfo.scale);
  179. }
  180. if (StorageType.Money == _type) {
  181. long l = _value._int64;
  182. bool isNegative = false;
  183. if (l < 0) {
  184. isNegative = true;
  185. l = -l;
  186. }
  187. return new Decimal((int)(l & 0xffffffff), (int)(l >> 32), 0, isNegative, 4);
  188. }
  189. return (Decimal)this.Value; // anything else we haven't thought of goes through boxing.
  190. }
  191. }
  192. internal Double Double {
  193. get {
  194. ThrowIfNull();
  195. if (StorageType.Double == _type) {
  196. return _value._double;
  197. }
  198. return (Double)this.Value; // anything else we haven't thought of goes through boxing.
  199. }
  200. set {
  201. Debug.Assert (IsEmpty, "setting value a second time?");
  202. _value._double = value;
  203. _type = StorageType.Double;
  204. _isNull = false;
  205. }
  206. }
  207. internal Guid Guid {
  208. get {
  209. //
  210. ThrowIfNull();
  211. return this.SqlGuid.Value;
  212. }
  213. }
  214. internal Int16 Int16 {
  215. get {
  216. ThrowIfNull();
  217. if (StorageType.Int16 == _type) {
  218. return _value._int16;
  219. }
  220. return (Int16)this.Value; // anything else we haven't thought of goes through boxing.
  221. }
  222. set {
  223. Debug.Assert (IsEmpty, "setting value a second time?");
  224. _value._int16 = value;
  225. _type = StorageType.Int16;
  226. _isNull = false;
  227. }
  228. }
  229. internal Int32 Int32 {
  230. get {
  231. ThrowIfNull();
  232. if (StorageType.Int32 == _type) {
  233. return _value._int32;
  234. }
  235. return (Int32)this.Value; // anything else we haven't thought of goes through boxing.
  236. }
  237. set {
  238. Debug.Assert (IsEmpty, "setting value a second time?");
  239. _value._int32 = value;
  240. _type = StorageType.Int32;
  241. _isNull = false;
  242. }
  243. }
  244. internal Int64 Int64 {
  245. get {
  246. ThrowIfNull();
  247. if (StorageType.Int64 == _type) {
  248. return _value._int64;
  249. }
  250. return (Int64)this.Value; // anything else we haven't thought of goes through boxing.
  251. }
  252. set {
  253. Debug.Assert (IsEmpty, "setting value a second time?");
  254. _value._int64 = value;
  255. _type = StorageType.Int64;
  256. _isNull = false;
  257. }
  258. }
  259. internal Single Single {
  260. get {
  261. ThrowIfNull();
  262. if (StorageType.Single == _type) {
  263. return _value._single;
  264. }
  265. return (Single)this.Value; // anything else we haven't thought of goes through boxing.
  266. }
  267. set {
  268. Debug.Assert (IsEmpty, "setting value a second time?");
  269. _value._single = value;
  270. _type = StorageType.Single;
  271. _isNull = false;
  272. }
  273. }
  274. internal String String {
  275. get {
  276. ThrowIfNull();
  277. if (StorageType.String == _type) {
  278. return (String)_object;
  279. }
  280. else if (StorageType.SqlCachedBuffer == _type) {
  281. return ((SqlCachedBuffer)(_object)).ToString();
  282. }
  283. return (String)this.Value; // anything else we haven't thought of goes through boxing.
  284. }
  285. }
  286. // use static list of format strings indexed by scale for perf!
  287. private static string[] __katmaiDateTimeOffsetFormatByScale = new string[] {
  288. "yyyy-MM-dd HH:mm:ss zzz",
  289. "yyyy-MM-dd HH:mm:ss.f zzz",
  290. "yyyy-MM-dd HH:mm:ss.ff zzz",
  291. "yyyy-MM-dd HH:mm:ss.fff zzz",
  292. "yyyy-MM-dd HH:mm:ss.ffff zzz",
  293. "yyyy-MM-dd HH:mm:ss.fffff zzz",
  294. "yyyy-MM-dd HH:mm:ss.ffffff zzz",
  295. "yyyy-MM-dd HH:mm:ss.fffffff zzz",
  296. };
  297. private static string[] __katmaiDateTime2FormatByScale = new string[] {
  298. "yyyy-MM-dd HH:mm:ss",
  299. "yyyy-MM-dd HH:mm:ss.f",
  300. "yyyy-MM-dd HH:mm:ss.ff",
  301. "yyyy-MM-dd HH:mm:ss.fff",
  302. "yyyy-MM-dd HH:mm:ss.ffff",
  303. "yyyy-MM-dd HH:mm:ss.fffff",
  304. "yyyy-MM-dd HH:mm:ss.ffffff",
  305. "yyyy-MM-dd HH:mm:ss.fffffff",
  306. };
  307. private static string[] __katmaiTimeFormatByScale = new string[] {
  308. "HH:mm:ss",
  309. "HH:mm:ss.f",
  310. "HH:mm:ss.ff",
  311. "HH:mm:ss.fff",
  312. "HH:mm:ss.ffff",
  313. "HH:mm:ss.fffff",
  314. "HH:mm:ss.ffffff",
  315. "HH:mm:ss.fffffff",
  316. };
  317. internal string KatmaiDateTimeString {
  318. get {
  319. ThrowIfNull();
  320. if (StorageType.Date == _type) {
  321. return this.DateTime.ToString("yyyy-MM-dd", DateTimeFormatInfo.InvariantInfo);
  322. }
  323. if (StorageType.Time == _type) {
  324. byte scale = _value._timeInfo.scale;
  325. return new DateTime(_value._timeInfo.ticks).ToString(__katmaiTimeFormatByScale[scale], DateTimeFormatInfo.InvariantInfo);
  326. }
  327. if (StorageType.DateTime2 == _type) {
  328. byte scale = _value._dateTime2Info.timeInfo.scale;
  329. return this.DateTime.ToString(__katmaiDateTime2FormatByScale[scale], DateTimeFormatInfo.InvariantInfo);
  330. }
  331. if (StorageType.DateTimeOffset == _type) {
  332. DateTimeOffset dto = this.DateTimeOffset;
  333. byte scale = _value._dateTimeOffsetInfo.dateTime2Info.timeInfo.scale;
  334. return dto.ToString(__katmaiDateTimeOffsetFormatByScale[scale], DateTimeFormatInfo.InvariantInfo);
  335. }
  336. return (String)this.Value; // anything else we haven't thought of goes through boxing.
  337. }
  338. }
  339. internal SqlString KatmaiDateTimeSqlString {
  340. get {
  341. if (StorageType.Date == _type ||
  342. StorageType.Time == _type ||
  343. StorageType.DateTime2 == _type ||
  344. StorageType.DateTimeOffset == _type) {
  345. if (IsNull) {
  346. return SqlString.Null;
  347. }
  348. return new SqlString(KatmaiDateTimeString);
  349. }
  350. return (SqlString)this.SqlValue; // anything else we haven't thought of goes through boxing.
  351. }
  352. }
  353. internal TimeSpan Time {
  354. get {
  355. ThrowIfNull();
  356. if (StorageType.Time == _type) {
  357. return new TimeSpan(_value._timeInfo.ticks);
  358. }
  359. return (TimeSpan)this.Value; // anything else we haven't thought of goes through boxing.
  360. }
  361. }
  362. internal DateTimeOffset DateTimeOffset {
  363. get {
  364. ThrowIfNull();
  365. if (StorageType.DateTimeOffset == _type) {
  366. TimeSpan offset = new TimeSpan(0, _value._dateTimeOffsetInfo.offset, 0);
  367. // datetime part presents time in UTC
  368. return new DateTimeOffset(GetTicksFromDateTime2Info(_value._dateTimeOffsetInfo.dateTime2Info) + offset.Ticks, offset);
  369. }
  370. return (DateTimeOffset)this.Value; // anything else we haven't thought of goes through boxing.
  371. }
  372. }
  373. private static long GetTicksFromDateTime2Info(DateTime2Info dateTime2Info) {
  374. return (dateTime2Info.date * TimeSpan.TicksPerDay + dateTime2Info.timeInfo.ticks);
  375. }
  376. internal SqlBinary SqlBinary {
  377. get {
  378. if (StorageType.SqlBinary == _type) {
  379. return (SqlBinary)_object;
  380. }
  381. return (SqlBinary)this.SqlValue; // anything else we haven't thought of goes through boxing.
  382. }
  383. set {
  384. Debug.Assert (IsEmpty, "setting value a second time?");
  385. _object = value;
  386. _type = StorageType.SqlBinary;
  387. _isNull = value.IsNull;
  388. }
  389. }
  390. internal SqlBoolean SqlBoolean {
  391. get {
  392. if (StorageType.Boolean == _type) {
  393. if (IsNull) {
  394. return SqlBoolean.Null;
  395. }
  396. return new SqlBoolean(_value._boolean);
  397. }
  398. return (SqlBoolean)this.SqlValue; // anything else we haven't thought of goes through boxing.
  399. }
  400. }
  401. internal SqlByte SqlByte {
  402. get {
  403. if (StorageType.Byte == _type) {
  404. if (IsNull) {
  405. return SqlByte.Null;
  406. }
  407. return new SqlByte(_value._byte);
  408. }
  409. return (SqlByte)this.SqlValue; // anything else we haven't thought of goes through boxing.
  410. }
  411. }
  412. internal SqlCachedBuffer SqlCachedBuffer {
  413. get {
  414. if (StorageType.SqlCachedBuffer == _type) {
  415. if (IsNull) {
  416. return SqlCachedBuffer.Null;
  417. }
  418. return (SqlCachedBuffer)_object;
  419. }
  420. return (SqlCachedBuffer)this.SqlValue; // anything else we haven't thought of goes through boxing.
  421. }
  422. set {
  423. Debug.Assert (IsEmpty, "setting value a second time?");
  424. _object = value;
  425. _type = StorageType.SqlCachedBuffer;
  426. _isNull = value.IsNull;
  427. }
  428. }
  429. internal SqlXml SqlXml {
  430. get {
  431. if (StorageType.SqlXml == _type) {
  432. if (IsNull) {
  433. return SqlXml.Null;
  434. }
  435. return (SqlXml)_object;
  436. }
  437. return (SqlXml)this.SqlValue; // anything else we haven't thought of goes through boxing.
  438. }
  439. set {
  440. Debug.Assert (IsEmpty, "setting value a second time?");
  441. _object = value;
  442. _type = StorageType.SqlXml;
  443. _isNull = value.IsNull;
  444. }
  445. }
  446. internal SqlDateTime SqlDateTime {
  447. get {
  448. if (StorageType.DateTime == _type) {
  449. if (IsNull) {
  450. return SqlDateTime.Null;
  451. }
  452. return new SqlDateTime(_value._dateTimeInfo.daypart, _value._dateTimeInfo.timepart);
  453. }
  454. return (SqlDateTime)SqlValue; // anything else we haven't thought of goes through boxing.
  455. }
  456. }
  457. internal SqlDecimal SqlDecimal {
  458. get {
  459. if (StorageType.Decimal == _type) {
  460. if (IsNull) {
  461. return SqlDecimal.Null;
  462. }
  463. return new SqlDecimal(_value._numericInfo.precision,
  464. _value._numericInfo.scale,
  465. _value._numericInfo.positive,
  466. _value._numericInfo.data1,
  467. _value._numericInfo.data2,
  468. _value._numericInfo.data3,
  469. _value._numericInfo.data4
  470. );
  471. }
  472. return (SqlDecimal)this.SqlValue; // anything else we haven't thought of goes through boxing.
  473. }
  474. }
  475. internal SqlDouble SqlDouble {
  476. get {
  477. if (StorageType.Double == _type) {
  478. if (IsNull) {
  479. return SqlDouble.Null;
  480. }
  481. return new SqlDouble(_value._double);
  482. }
  483. return (SqlDouble)this.SqlValue; // anything else we haven't thought of goes through boxing.
  484. }
  485. }
  486. internal SqlGuid SqlGuid {
  487. get {
  488. if (StorageType.SqlGuid == _type) {
  489. return (SqlGuid)_object;
  490. }
  491. return (SqlGuid)this.SqlValue; // anything else we haven't thought of goes through boxing.
  492. }
  493. set {
  494. Debug.Assert (IsEmpty, "setting value a second time?");
  495. _object = value;
  496. _type = StorageType.SqlGuid;
  497. _isNull = value.IsNull;
  498. }
  499. }
  500. internal SqlInt16 SqlInt16 {
  501. get {
  502. if (StorageType.Int16 == _type) {
  503. if (IsNull) {
  504. return SqlInt16.Null;
  505. }
  506. return new SqlInt16(_value._int16);
  507. }
  508. return (SqlInt16)this.SqlValue; // anything else we haven't thought of goes through boxing.
  509. }
  510. }
  511. internal SqlInt32 SqlInt32 {
  512. get {
  513. if (StorageType.Int32 == _type) {
  514. if (IsNull) {
  515. return SqlInt32.Null;
  516. }
  517. return new SqlInt32(_value._int32);
  518. }
  519. return (SqlInt32)this.SqlValue; // anything else we haven't thought of goes through boxing.
  520. }
  521. }
  522. internal SqlInt64 SqlInt64 {
  523. get {
  524. if (StorageType.Int64 == _type) {
  525. if (IsNull) {
  526. return SqlInt64.Null;
  527. }
  528. return new SqlInt64(_value._int64);
  529. }
  530. return (SqlInt64)this.SqlValue; // anything else we haven't thought of goes through boxing.
  531. }
  532. }
  533. internal SqlMoney SqlMoney {
  534. get {
  535. if (StorageType.Money == _type) {
  536. if (IsNull) {
  537. return SqlMoney.Null;
  538. }
  539. return new SqlMoney(_value._int64, 1/*ignored*/);
  540. }
  541. return (SqlMoney)this.SqlValue; // anything else we haven't thought of goes through boxing.
  542. }
  543. }
  544. internal SqlSingle SqlSingle {
  545. get {
  546. if (StorageType.Single == _type) {
  547. if (IsNull) {
  548. return SqlSingle.Null;
  549. }
  550. return new SqlSingle(_value._single);
  551. }
  552. return (SqlSingle)this.SqlValue; // anything else we haven't thought of goes through boxing.
  553. }
  554. }
  555. internal SqlString SqlString {
  556. get {
  557. if (StorageType.String == _type) {
  558. if (IsNull) {
  559. return SqlString.Null;
  560. }
  561. return new SqlString((String)_object);
  562. }
  563. else if (StorageType.SqlCachedBuffer == _type) {
  564. SqlCachedBuffer data = (SqlCachedBuffer)(_object);
  565. if (data.IsNull) {
  566. return SqlString.Null;
  567. }
  568. return data.ToSqlString();
  569. }
  570. return (SqlString)this.SqlValue; // anything else we haven't thought of goes through boxing.
  571. }
  572. }
  573. internal object SqlValue {
  574. get {
  575. switch (_type) {
  576. case StorageType.Empty: return DBNull.Value;
  577. case StorageType.Boolean: return SqlBoolean;
  578. case StorageType.Byte: return SqlByte;
  579. case StorageType.DateTime: return SqlDateTime;
  580. case StorageType.Decimal: return SqlDecimal;
  581. case StorageType.Double: return SqlDouble;
  582. case StorageType.Int16: return SqlInt16;
  583. case StorageType.Int32: return SqlInt32;
  584. case StorageType.Int64: return SqlInt64;
  585. case StorageType.Money: return SqlMoney;
  586. case StorageType.Single: return SqlSingle;
  587. case StorageType.String: return SqlString;
  588. case StorageType.SqlCachedBuffer:
  589. {
  590. SqlCachedBuffer data = (SqlCachedBuffer)(_object);
  591. if (data.IsNull) {
  592. return SqlXml.Null;
  593. }
  594. return data.ToSqlXml();
  595. }
  596. case StorageType.SqlBinary:
  597. case StorageType.SqlGuid:
  598. return _object;
  599. case StorageType.SqlXml: {
  600. if (_isNull) {
  601. return SqlXml.Null;
  602. }
  603. Debug.Assert(null != _object);
  604. return (SqlXml) _object;
  605. }
  606. case StorageType.Date:
  607. case StorageType.DateTime2:
  608. if (_isNull) {
  609. return DBNull.Value;
  610. }
  611. return DateTime;
  612. case StorageType.DateTimeOffset:
  613. if (_isNull) {
  614. return DBNull.Value;
  615. }
  616. return DateTimeOffset;
  617. case StorageType.Time:
  618. if (_isNull) {
  619. return DBNull.Value;
  620. }
  621. return Time;
  622. }
  623. return null; // need to return the value as an object of some SQL type
  624. }
  625. }
  626. internal object Value {
  627. get {
  628. if (IsNull) {
  629. return DBNull.Value;
  630. }
  631. switch (_type) {
  632. case StorageType.Empty: return DBNull.Value;
  633. case StorageType.Boolean: return Boolean;
  634. case StorageType.Byte: return Byte;
  635. case StorageType.DateTime: return DateTime;
  636. case StorageType.Decimal: return Decimal;
  637. case StorageType.Double: return Double;
  638. case StorageType.Int16: return Int16;
  639. case StorageType.Int32: return Int32;
  640. case StorageType.Int64: return Int64;
  641. case StorageType.Money: return Decimal;
  642. case StorageType.Single: return Single;
  643. case StorageType.String: return String;
  644. case StorageType.SqlBinary: return ByteArray;
  645. case StorageType.SqlCachedBuffer:
  646. {
  647. // If we have a CachedBuffer, it's because it's an XMLTYPE column
  648. // and we have to return a string when they're asking for the CLS
  649. // value of the column.
  650. return ((SqlCachedBuffer)(_object)).ToString();
  651. }
  652. case StorageType.SqlGuid: return Guid;
  653. case StorageType.SqlXml: {
  654. // XMLTYPE columns must be returned as string when asking for the CLS value
  655. SqlXml data = (SqlXml)_object;
  656. string s = data.Value;
  657. return s;
  658. }
  659. case StorageType.Date: return DateTime;
  660. case StorageType.DateTime2: return DateTime;
  661. case StorageType.DateTimeOffset: return DateTimeOffset;
  662. case StorageType.Time: return Time;
  663. }
  664. return null; // need to return the value as an object of some CLS type
  665. }
  666. }
  667. internal Type GetTypeFromStorageType (bool isSqlType) {
  668. if (isSqlType) {
  669. switch (_type) {
  670. case SqlBuffer.StorageType.Empty: return null;
  671. case SqlBuffer.StorageType.Boolean: return typeof(SqlBoolean);
  672. case SqlBuffer.StorageType.Byte: return typeof(SqlByte);
  673. case SqlBuffer.StorageType.DateTime: return typeof(SqlDateTime);
  674. case SqlBuffer.StorageType.Decimal: return typeof(SqlDecimal);
  675. case SqlBuffer.StorageType.Double: return typeof(SqlDouble);
  676. case SqlBuffer.StorageType.Int16: return typeof(SqlInt16);
  677. case SqlBuffer.StorageType.Int32: return typeof(SqlInt32);
  678. case SqlBuffer.StorageType.Int64: return typeof(SqlInt64);
  679. case SqlBuffer.StorageType.Money: return typeof(SqlMoney);
  680. case SqlBuffer.StorageType.Single: return typeof(SqlSingle);
  681. case SqlBuffer.StorageType.String: return typeof(SqlString);
  682. case SqlBuffer.StorageType.SqlCachedBuffer: return typeof(SqlString);
  683. case SqlBuffer.StorageType.SqlBinary: return typeof(object);
  684. case SqlBuffer.StorageType.SqlGuid: return typeof(object);
  685. case SqlBuffer.StorageType.SqlXml: return typeof(SqlXml);
  686. }
  687. }
  688. else { //Is CLR Type
  689. switch (_type) {
  690. case SqlBuffer.StorageType.Empty: return null;
  691. case SqlBuffer.StorageType.Boolean: return typeof(Boolean);
  692. case SqlBuffer.StorageType.Byte: return typeof(Byte);
  693. case SqlBuffer.StorageType.DateTime: return typeof(DateTime);
  694. case SqlBuffer.StorageType.Decimal: return typeof(Decimal);
  695. case SqlBuffer.StorageType.Double: return typeof(Double);
  696. case SqlBuffer.StorageType.Int16: return typeof(Int16);
  697. case SqlBuffer.StorageType.Int32: return typeof(Int32);
  698. case SqlBuffer.StorageType.Int64: return typeof(Int64);
  699. case SqlBuffer.StorageType.Money: return typeof(Decimal);
  700. case SqlBuffer.StorageType.Single: return typeof(Single);
  701. case SqlBuffer.StorageType.String: return typeof(String);
  702. case SqlBuffer.StorageType.SqlBinary: return typeof(Byte[]);
  703. case SqlBuffer.StorageType.SqlCachedBuffer: return typeof(string);
  704. case SqlBuffer.StorageType.SqlGuid: return typeof(Guid);
  705. case SqlBuffer.StorageType.SqlXml: return typeof(string);
  706. }
  707. }
  708. return null; // need to return the value as an object of some CLS type
  709. }
  710. internal static SqlBuffer[] CreateBufferArray(int length) {
  711. SqlBuffer[] buffers = new SqlBuffer[length];
  712. for(int i = 0; i < buffers.Length; ++i) {
  713. buffers[i] = new SqlBuffer();
  714. }
  715. return buffers;
  716. }
  717. internal static SqlBuffer[] CloneBufferArray(SqlBuffer[] values) {
  718. SqlBuffer[] copy = new SqlBuffer[values.Length];
  719. for (int i=0; i<values.Length; i++) {
  720. copy[i] = new SqlBuffer(values[i]);
  721. }
  722. return copy;
  723. }
  724. internal static void Clear(SqlBuffer[] values) {
  725. if (null != values) {
  726. for(int i = 0; i < values.Length; ++i) {
  727. values[i].Clear();
  728. }
  729. }
  730. }
  731. internal void Clear() {
  732. _isNull = false;
  733. _type = StorageType.Empty;
  734. _object = null;
  735. }
  736. internal void SetToDateTime(int daypart, int timepart) {
  737. Debug.Assert (IsEmpty, "setting value a second time?");
  738. _value._dateTimeInfo.daypart = daypart;
  739. _value._dateTimeInfo.timepart = timepart;
  740. _type = StorageType.DateTime;
  741. _isNull = false;
  742. }
  743. internal void SetToDecimal(byte precision, byte scale, bool positive, int[] bits) {
  744. Debug.Assert (IsEmpty, "setting value a second time?");
  745. _value._numericInfo.precision = precision;
  746. _value._numericInfo.scale = scale;
  747. _value._numericInfo.positive = positive;
  748. _value._numericInfo.data1 = bits[0];
  749. _value._numericInfo.data2 = bits[1];
  750. _value._numericInfo.data3 = bits[2];
  751. _value._numericInfo.data4 = bits[3];
  752. _type = StorageType.Decimal;
  753. _isNull = false;
  754. }
  755. internal void SetToMoney(long value) {
  756. Debug.Assert (IsEmpty, "setting value a second time?");
  757. _value._int64 = value;
  758. _type = StorageType.Money;
  759. _isNull = false;
  760. }
  761. internal void SetToNullOfType(StorageType storageType) {
  762. Debug.Assert (IsEmpty, "setting value a second time?");
  763. _type = storageType;
  764. _isNull = true;
  765. _object = null;
  766. }
  767. internal void SetToString(string value) {
  768. Debug.Assert (IsEmpty, "setting value a second time?");
  769. _object = value;
  770. _type = StorageType.String;
  771. _isNull = false;
  772. }
  773. internal void SetToDate(byte[] bytes) {
  774. Debug.Assert(IsEmpty, "setting value a second time?");
  775. _type = StorageType.Date;
  776. _value._int32 = GetDateFromByteArray(bytes, 0);
  777. _isNull = false;
  778. }
  779. internal void SetToDate(DateTime date) {
  780. Debug.Assert(IsEmpty, "setting value a second time?");
  781. _type = StorageType.Date;
  782. _value._int32 = date.Subtract(DateTime.MinValue).Days;
  783. _isNull = false;
  784. }
  785. internal void SetToTime(byte[] bytes, int length, byte scale, byte denormalizedScale) {
  786. Debug.Assert(IsEmpty, "setting value a second time?");
  787. _type = StorageType.Time;
  788. FillInTimeInfo(ref _value._timeInfo, bytes, length, scale, denormalizedScale);
  789. _isNull = false;
  790. }
  791. internal void SetToTime(TimeSpan timeSpan, byte scale) {
  792. Debug.Assert(IsEmpty, "setting value a second time?");
  793. _type = StorageType.Time;
  794. _value._timeInfo.ticks = timeSpan.Ticks;
  795. _value._timeInfo.scale = scale;
  796. _isNull = false;
  797. }
  798. internal void SetToDateTime2(byte[] bytes, int length, byte scale, byte denormalizedScale) {
  799. Debug.Assert(IsEmpty, "setting value a second time?");
  800. _type = StorageType.DateTime2;
  801. FillInTimeInfo(ref _value._dateTime2Info.timeInfo, bytes, length - 3, scale, denormalizedScale); // remaining 3 bytes is for date
  802. _value._dateTime2Info.date = GetDateFromByteArray(bytes, length - 3); // 3 bytes for date
  803. _isNull = false;
  804. }
  805. internal void SetToDateTime2(DateTime dateTime, byte scale) {
  806. Debug.Assert(IsEmpty, "setting value a second time?");
  807. _type = StorageType.DateTime2;
  808. _value._dateTime2Info.timeInfo.ticks = dateTime.TimeOfDay.Ticks;
  809. _value._dateTime2Info.timeInfo.scale = scale;
  810. _value._dateTime2Info.date = dateTime.Subtract(DateTime.MinValue).Days;
  811. _isNull = false;
  812. }
  813. internal void SetToDateTimeOffset(byte[] bytes, int length, byte scale, byte denormalizedScale) {
  814. Debug.Assert(IsEmpty, "setting value a second time?");
  815. _type = StorageType.DateTimeOffset;
  816. FillInTimeInfo(ref _value._dateTimeOffsetInfo.dateTime2Info.timeInfo, bytes, length - 5, scale, denormalizedScale); // remaining 5 bytes are for date and offset
  817. _value._dateTimeOffsetInfo.dateTime2Info.date = GetDateFromByteArray(bytes, length - 5); // 3 bytes for date
  818. _value._dateTimeOffsetInfo.offset = (Int16)(bytes[length - 2] + (bytes[length - 1] << 8)); // 2 bytes for offset (Int16)
  819. _isNull = false;
  820. }
  821. internal void SetToDateTimeOffset(DateTimeOffset dateTimeOffset, byte scale) {
  822. Debug.Assert(IsEmpty, "setting value a second time?");
  823. _type = StorageType.DateTimeOffset;
  824. DateTime utcDateTime = dateTimeOffset.UtcDateTime; // timeInfo stores the utc datetime of a datatimeoffset
  825. _value._dateTimeOffsetInfo.dateTime2Info.timeInfo.ticks = utcDateTime.TimeOfDay.Ticks;
  826. _value._dateTimeOffsetInfo.dateTime2Info.timeInfo.scale = scale;
  827. _value._dateTimeOffsetInfo.dateTime2Info.date = utcDateTime.Subtract(DateTime.MinValue).Days;
  828. _value._dateTimeOffsetInfo.offset = (Int16)dateTimeOffset.Offset.TotalMinutes;
  829. _isNull = false;
  830. }
  831. private static void FillInTimeInfo(ref TimeInfo timeInfo, byte[] timeBytes, int length, byte scale, byte denormalizedScale) {
  832. Debug.Assert(3 <= length && length <= 5, "invalid data length for timeInfo: " + length);
  833. Debug.Assert(0 <= scale && scale <= 7, "invalid scale: " + scale);
  834. Debug.Assert(0 <= denormalizedScale && denormalizedScale <= 7, "invalid denormalized scale: " + denormalizedScale);
  835. Int64 tickUnits = (Int64)timeBytes[0] + ((Int64)timeBytes[1] << 8) + ((Int64)timeBytes[2] << 16);
  836. if (length > 3) {
  837. tickUnits += ((Int64)timeBytes[3] << 24);
  838. }
  839. if (length > 4) {
  840. tickUnits += ((Int64)timeBytes[4] << 32);
  841. }
  842. timeInfo.ticks = tickUnits * TdsEnums.TICKS_FROM_SCALE[scale];
  843. // Once the deserialization has been completed using the value scale, we need to set the actual denormalized scale,
  844. // coming from the data type, on the original result, so that it has the proper scale setting.
  845. // This only applies for values that got serialized/deserialized for encryption. Otherwise, both scales should be equal.
  846. timeInfo.scale = denormalizedScale;
  847. }
  848. private static Int32 GetDateFromByteArray(byte[] buf, int offset) {
  849. return buf[offset] + (buf[offset + 1] << 8) + (buf[offset + 2] << 16);
  850. }
  851. private void ThrowIfNull() {
  852. if (IsNull) {
  853. throw new SqlNullValueException();
  854. }
  855. }
  856. }
  857. }// namespace