SqlDataReader.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056
  1. //
  2. // System.Data.SqlClient.SqlDataReader.cs
  3. //
  4. // Author:
  5. // Rodrigo Moya ([email protected])
  6. // Daniel Morgan ([email protected])
  7. // Tim Coleman ([email protected])
  8. //
  9. // (C) Ximian, Inc 2002
  10. // (C) Daniel Morgan 2002
  11. // Copyright (C) Tim Coleman, 2002
  12. //
  13. //
  14. // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
  15. //
  16. // Permission is hereby granted, free of charge, to any person obtaining
  17. // a copy of this software and associated documentation files (the
  18. // "Software"), to deal in the Software without restriction, including
  19. // without limitation the rights to use, copy, modify, merge, publish,
  20. // distribute, sublicense, and/or sell copies of the Software, and to
  21. // permit persons to whom the Software is furnished to do so, subject to
  22. // the following conditions:
  23. //
  24. // The above copyright notice and this permission notice shall be
  25. // included in all copies or substantial portions of the Software.
  26. //
  27. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  28. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  29. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  30. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  31. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  32. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  33. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  34. //
  35. using Mono.Data.Tds.Protocol;
  36. using System;
  37. using System.Collections;
  38. using System.ComponentModel;
  39. using System.Data;
  40. using System.Data.Common;
  41. using System.Data.SqlTypes;
  42. #if NET_2_0
  43. using System.Data.ProviderBase;
  44. #endif // NET_2_0
  45. namespace System.Data.SqlClient {
  46. #if NET_2_0
  47. public sealed class SqlDataReader : DbDataReaderBase, IEnumerable, IDataReader, IDisposable, IDataRecord
  48. #else
  49. public sealed class SqlDataReader : MarshalByRefObject, IEnumerable, IDataReader, IDisposable, IDataRecord
  50. #endif // NET_2_0
  51. {
  52. #region Fields
  53. SqlCommand command;
  54. ArrayList dataTypeNames;
  55. bool disposed = false;
  56. int fieldCount;
  57. bool isClosed;
  58. bool moreResults;
  59. int resultsRead;
  60. int rowsRead;
  61. DataTable schemaTable;
  62. bool hasRows;
  63. bool haveRead;
  64. bool readResult;
  65. bool readResultUsed;
  66. #endregion // Fields
  67. #region Constructors
  68. internal SqlDataReader (SqlCommand command)
  69. #if NET_2_0
  70. : base (command.CommandBehavior)
  71. #endif // NET_2_0
  72. {
  73. readResult = false;
  74. haveRead = false;
  75. readResultUsed = false;
  76. this.command = command;
  77. schemaTable = ConstructSchemaTable ();
  78. resultsRead = 0;
  79. fieldCount = 0;
  80. isClosed = false;
  81. command.Tds.RecordsAffected = -1;
  82. NextResult ();
  83. }
  84. #endregion // Constructors
  85. #region Properties
  86. public
  87. #if NET_2_0
  88. override
  89. #endif // NET_2_0
  90. int Depth {
  91. get { return 0; }
  92. }
  93. public
  94. #if NET_2_0
  95. override
  96. #endif // NET_2_0
  97. int FieldCount {
  98. get { return fieldCount; }
  99. }
  100. public
  101. #if NET_2_0
  102. override
  103. #endif // NET_2_0
  104. bool IsClosed {
  105. get { return isClosed; }
  106. }
  107. public
  108. #if NET_2_0
  109. override
  110. #endif // NET_2_0
  111. object this [int i] {
  112. get { return GetValue (i); }
  113. }
  114. public
  115. #if NET_2_0
  116. override
  117. #endif // NET_2_0
  118. object this [string name] {
  119. get { return GetValue (GetOrdinal (name)); }
  120. }
  121. public
  122. #if NET_2_0
  123. override
  124. #endif // NET_2_0
  125. int RecordsAffected {
  126. get {
  127. return command.Tds.RecordsAffected;
  128. }
  129. }
  130. public
  131. #if NET_2_0
  132. override
  133. #endif // NET_2_0
  134. bool HasRows {
  135. get {
  136. if (haveRead)
  137. return readResult;
  138. haveRead = true;
  139. readResult = ReadRecord ();
  140. return readResult;
  141. }
  142. }
  143. #endregion // Properties
  144. #region Methods
  145. public
  146. #if NET_2_0
  147. override
  148. #endif // NET_2_0
  149. void Close ()
  150. {
  151. // skip to end & read output parameters.
  152. while (NextResult ())
  153. ;
  154. isClosed = true;
  155. command.Connection.DataReader = null;
  156. command.CloseDataReader (moreResults);
  157. }
  158. private static DataTable ConstructSchemaTable ()
  159. {
  160. Type booleanType = Type.GetType ("System.Boolean");
  161. Type stringType = Type.GetType ("System.String");
  162. Type intType = Type.GetType ("System.Int32");
  163. Type typeType = Type.GetType ("System.Type");
  164. Type shortType = Type.GetType ("System.Int16");
  165. DataTable schemaTable = new DataTable ("SchemaTable");
  166. schemaTable.Columns.Add ("ColumnName", stringType);
  167. schemaTable.Columns.Add ("ColumnOrdinal", intType);
  168. schemaTable.Columns.Add ("ColumnSize", intType);
  169. schemaTable.Columns.Add ("NumericPrecision", shortType);
  170. schemaTable.Columns.Add ("NumericScale", shortType);
  171. schemaTable.Columns.Add ("IsUnique", booleanType);
  172. schemaTable.Columns.Add ("IsKey", booleanType);
  173. schemaTable.Columns.Add ("BaseServerName", stringType);
  174. schemaTable.Columns.Add ("BaseCatalogName", stringType);
  175. schemaTable.Columns.Add ("BaseColumnName", stringType);
  176. schemaTable.Columns.Add ("BaseSchemaName", stringType);
  177. schemaTable.Columns.Add ("BaseTableName", stringType);
  178. schemaTable.Columns.Add ("DataType", typeType);
  179. schemaTable.Columns.Add ("AllowDBNull", booleanType);
  180. schemaTable.Columns.Add ("ProviderType", intType);
  181. schemaTable.Columns.Add ("IsAliased", booleanType);
  182. schemaTable.Columns.Add ("IsExpression", booleanType);
  183. schemaTable.Columns.Add ("IsIdentity", booleanType);
  184. schemaTable.Columns.Add ("IsAutoIncrement", booleanType);
  185. schemaTable.Columns.Add ("IsRowVersion", booleanType);
  186. schemaTable.Columns.Add ("IsHidden", booleanType);
  187. schemaTable.Columns.Add ("IsLong", booleanType);
  188. schemaTable.Columns.Add ("IsReadOnly", booleanType);
  189. return schemaTable;
  190. }
  191. private void Dispose (bool disposing)
  192. {
  193. if (!disposed) {
  194. if (disposing) {
  195. schemaTable.Dispose ();
  196. Close ();
  197. command = null;
  198. }
  199. disposed = true;
  200. }
  201. }
  202. public
  203. #if NET_2_0
  204. override
  205. #endif // NET_2_0
  206. bool GetBoolean (int i)
  207. {
  208. object value = GetValue (i);
  209. if (!(value is bool)) {
  210. if (value is DBNull) throw new SqlNullValueException ();
  211. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  212. }
  213. return (bool) value;
  214. }
  215. public
  216. #if NET_2_0
  217. override
  218. #endif // NET_2_0
  219. byte GetByte (int i)
  220. {
  221. object value = GetValue (i);
  222. if (!(value is byte)) {
  223. if (value is DBNull) throw new SqlNullValueException ();
  224. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  225. }
  226. return (byte) value;
  227. }
  228. public
  229. #if NET_2_0
  230. override
  231. #endif // NET_2_0
  232. long GetBytes (int i, long dataIndex, byte[] buffer, int bufferIndex, int length)
  233. {
  234. object value = GetValue (i);
  235. if (!(value is byte [])) {
  236. if (value is DBNull) throw new SqlNullValueException ();
  237. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  238. }
  239. if ( buffer == null )
  240. return ((byte []) value).Length; // Return length of data
  241. // Copy data into buffer
  242. int availLen = (int) ( ( (byte []) value).Length - dataIndex);
  243. if (availLen < length)
  244. length = availLen;
  245. Array.Copy ((byte []) value, (int) dataIndex, buffer, bufferIndex, length);
  246. return length; // return actual read count
  247. }
  248. [EditorBrowsableAttribute (EditorBrowsableState.Never)]
  249. public
  250. #if NET_2_0
  251. override
  252. #endif // NET_2_0
  253. char GetChar (int i)
  254. {
  255. object value = GetValue (i);
  256. if (!(value is char)) {
  257. if (value is DBNull) throw new SqlNullValueException ();
  258. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  259. }
  260. return (char) value;
  261. }
  262. public
  263. #if NET_2_0
  264. override
  265. #endif // NET_2_0
  266. long GetChars (int i, long dataIndex, char[] buffer, int bufferIndex, int length)
  267. {
  268. object value = GetValue (i);
  269. char [] valueBuffer;
  270. if (value is char[])
  271. valueBuffer = (char[])value;
  272. else if (value is string)
  273. valueBuffer = ((string)value).ToCharArray();
  274. else {
  275. if (value is DBNull) throw new SqlNullValueException ();
  276. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  277. }
  278. if ( buffer == null ) {
  279. // Return length of data
  280. return valueBuffer.Length;
  281. }
  282. else {
  283. // Copy data into buffer
  284. Array.Copy (valueBuffer, (int) dataIndex, buffer, bufferIndex, length);
  285. return valueBuffer.Length - dataIndex;
  286. }
  287. }
  288. [EditorBrowsableAttribute (EditorBrowsableState.Never)]
  289. public new IDataReader GetData (int i)
  290. {
  291. return ( (IDataReader) this [i]);
  292. }
  293. public
  294. #if NET_2_0
  295. override
  296. #endif // NET_2_0
  297. string GetDataTypeName (int i)
  298. {
  299. return (string) dataTypeNames [i];
  300. }
  301. public
  302. #if NET_2_0
  303. override
  304. #endif // NET_2_0
  305. DateTime GetDateTime (int i)
  306. {
  307. object value = GetValue (i);
  308. if (!(value is DateTime)) {
  309. if (value is DBNull) throw new SqlNullValueException ();
  310. else throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  311. }
  312. return (DateTime) value;
  313. }
  314. public
  315. #if NET_2_0
  316. override
  317. #endif // NET_2_0
  318. decimal GetDecimal (int i)
  319. {
  320. object value = GetValue (i);
  321. if (!(value is decimal)) {
  322. if (value is DBNull) throw new SqlNullValueException ();
  323. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  324. }
  325. return (decimal) value;
  326. }
  327. public
  328. #if NET_2_0
  329. override
  330. #endif // NET_2_0
  331. double GetDouble (int i)
  332. {
  333. object value = GetValue (i);
  334. if (!(value is double)) {
  335. if (value is DBNull) throw new SqlNullValueException ();
  336. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  337. }
  338. return (double) value;
  339. }
  340. public
  341. #if NET_2_0
  342. override
  343. #endif // NET_2_0
  344. Type GetFieldType (int i)
  345. {
  346. return (Type) schemaTable.Rows[i]["DataType"];
  347. }
  348. public
  349. #if NET_2_0
  350. override
  351. #endif // NET_2_0
  352. float GetFloat (int i)
  353. {
  354. object value = GetValue (i);
  355. if (!(value is float)) {
  356. if (value is DBNull) throw new SqlNullValueException ();
  357. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  358. }
  359. return (float) value;
  360. }
  361. public
  362. #if NET_2_0
  363. override
  364. #endif // NET_2_0
  365. Guid GetGuid (int i)
  366. {
  367. object value = GetValue (i);
  368. if (!(value is Guid)) {
  369. if (value is DBNull) throw new SqlNullValueException ();
  370. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  371. }
  372. return (Guid) value;
  373. }
  374. public
  375. #if NET_2_0
  376. override
  377. #endif // NET_2_0
  378. short GetInt16 (int i)
  379. {
  380. object value = GetValue (i);
  381. if (!(value is short)) {
  382. if (value is DBNull) throw new SqlNullValueException ();
  383. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  384. }
  385. return (short) value;
  386. }
  387. public
  388. #if NET_2_0
  389. override
  390. #endif // NET_2_0
  391. int GetInt32 (int i)
  392. {
  393. object value = GetValue (i);
  394. if (!(value is int)) {
  395. if (value is DBNull) throw new SqlNullValueException ();
  396. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  397. }
  398. return (int) value;
  399. }
  400. public
  401. #if NET_2_0
  402. override
  403. #endif // NET_2_0
  404. long GetInt64 (int i)
  405. {
  406. object value = GetValue (i);
  407. // TDS 7.0 returns bigint as decimal(19,0)
  408. if (value is decimal) {
  409. TdsDataColumn schema = command.Tds.Columns[i];
  410. if ((byte)schema["NumericPrecision"] == 19 && (byte)schema["NumericScale"] == 0)
  411. value = (long) (decimal) value;
  412. }
  413. if (!(value is long)) {
  414. if (value is DBNull) throw new SqlNullValueException ();
  415. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  416. }
  417. return (long) value;
  418. }
  419. public
  420. #if NET_2_0
  421. override
  422. #endif // NET_2_0
  423. string GetName (int i)
  424. {
  425. return (string) schemaTable.Rows[i]["ColumnName"];
  426. }
  427. public
  428. #if NET_2_0
  429. override
  430. #endif // NET_2_0
  431. int GetOrdinal (string name)
  432. {
  433. foreach (DataRow schemaRow in schemaTable.Rows)
  434. if (((string) schemaRow ["ColumnName"]).Equals (name))
  435. return (int) schemaRow ["ColumnOrdinal"];
  436. foreach (DataRow schemaRow in schemaTable.Rows)
  437. if (String.Compare (((string) schemaRow ["ColumnName"]), name, true) == 0)
  438. return (int) schemaRow ["ColumnOrdinal"];
  439. throw new IndexOutOfRangeException ();
  440. }
  441. public
  442. #if NET_2_0
  443. override
  444. #endif // NET_2_0
  445. DataTable GetSchemaTable ()
  446. {
  447. if (schemaTable.Rows != null && schemaTable.Rows.Count > 0)
  448. return schemaTable;
  449. if (!moreResults)
  450. return null;
  451. fieldCount = 0;
  452. dataTypeNames = new ArrayList ();
  453. foreach (TdsDataColumn schema in command.Tds.Columns) {
  454. DataRow row = schemaTable.NewRow ();
  455. row ["ColumnName"] = GetSchemaValue (schema, "ColumnName");
  456. row ["ColumnSize"] = GetSchemaValue (schema, "ColumnSize");
  457. row ["ColumnOrdinal"] = GetSchemaValue (schema, "ColumnOrdinal");
  458. row ["NumericPrecision"] = GetSchemaValue (schema, "NumericPrecision");
  459. row ["NumericScale"] = GetSchemaValue (schema, "NumericScale");
  460. row ["IsUnique"] = GetSchemaValue (schema, "IsUnique");
  461. row ["IsKey"] = GetSchemaValue (schema, "IsKey");
  462. row ["BaseServerName"] = GetSchemaValue (schema, "BaseServerName");
  463. row ["BaseCatalogName"] = GetSchemaValue (schema, "BaseCatalogName");
  464. row ["BaseColumnName"] = GetSchemaValue (schema, "BaseColumnName");
  465. row ["BaseSchemaName"] = GetSchemaValue (schema, "BaseSchemaName");
  466. row ["BaseTableName"] = GetSchemaValue (schema, "BaseTableName");
  467. row ["AllowDBNull"] = GetSchemaValue (schema, "AllowDBNull");
  468. row ["IsAliased"] = GetSchemaValue (schema, "IsAliased");
  469. row ["IsExpression"] = GetSchemaValue (schema, "IsExpression");
  470. row ["IsIdentity"] = GetSchemaValue (schema, "IsIdentity");
  471. row ["IsAutoIncrement"] = GetSchemaValue (schema, "IsAutoIncrement");
  472. row ["IsRowVersion"] = GetSchemaValue (schema, "IsRowVersion");
  473. row ["IsHidden"] = GetSchemaValue (schema, "IsHidden");
  474. row ["IsReadOnly"] = GetSchemaValue (schema, "IsReadOnly");
  475. // We don't always get the base column name.
  476. if (row ["BaseColumnName"] == DBNull.Value)
  477. row ["BaseColumnName"] = row ["ColumnName"];
  478. switch ((TdsColumnType) schema ["ColumnType"]) {
  479. case TdsColumnType.Int1:
  480. case TdsColumnType.Int2:
  481. case TdsColumnType.Int4:
  482. case TdsColumnType.IntN:
  483. switch ((int) schema ["ColumnSize"]) {
  484. case 1:
  485. dataTypeNames.Add ("tinyint");
  486. row ["ProviderType"] = (int) SqlDbType.TinyInt;
  487. row ["DataType"] = typeof (byte);
  488. row ["IsLong"] = false;
  489. break;
  490. case 2:
  491. dataTypeNames.Add ("smallint");
  492. row ["ProviderType"] = (int) SqlDbType.SmallInt;
  493. row ["DataType"] = typeof (short);
  494. row ["IsLong"] = false;
  495. break;
  496. case 4:
  497. dataTypeNames.Add ("int");
  498. row ["ProviderType"] = (int) SqlDbType.Int;
  499. row ["DataType"] = typeof (int);
  500. row ["IsLong"] = false;
  501. break;
  502. case 8:
  503. dataTypeNames.Add ("bigint");
  504. row ["ProviderType"] = (int) SqlDbType.BigInt;
  505. row ["DataType"] = typeof (long);
  506. row ["IsLong"] = false;
  507. break;
  508. }
  509. break;
  510. case TdsColumnType.Real:
  511. case TdsColumnType.Float8:
  512. case TdsColumnType.FloatN:
  513. switch ((int) schema ["ColumnSize"]) {
  514. case 4:
  515. dataTypeNames.Add ("real");
  516. row ["ProviderType"] = (int) SqlDbType.Real;
  517. row ["DataType"] = typeof (float);
  518. row ["IsLong"] = false;
  519. break;
  520. case 8:
  521. dataTypeNames.Add ("float");
  522. row ["ProviderType"] = (int) SqlDbType.Float;
  523. row ["DataType"] = typeof (double);
  524. row ["IsLong"] = false;
  525. break;
  526. }
  527. break;
  528. case TdsColumnType.Image :
  529. dataTypeNames.Add ("image");
  530. row ["ProviderType"] = (int) SqlDbType.Image;
  531. row ["DataType"] = typeof (byte[]);
  532. row ["IsLong"] = true;
  533. break;
  534. case TdsColumnType.Text :
  535. dataTypeNames.Add ("text");
  536. row ["ProviderType"] = (int) SqlDbType.Text;
  537. row ["DataType"] = typeof (string);
  538. row ["IsLong"] = true;
  539. break;
  540. case TdsColumnType.UniqueIdentifier :
  541. dataTypeNames.Add ("uniqueidentifier");
  542. row ["ProviderType"] = (int) SqlDbType.UniqueIdentifier;
  543. row ["DataType"] = typeof (Guid);
  544. row ["IsLong"] = false;
  545. break;
  546. case TdsColumnType.VarBinary :
  547. case TdsColumnType.BigVarBinary :
  548. dataTypeNames.Add ("varbinary");
  549. row ["ProviderType"] = (int) SqlDbType.VarBinary;
  550. row ["DataType"] = typeof (byte[]);
  551. row ["IsLong"] = true;
  552. break;
  553. case TdsColumnType.VarChar :
  554. case TdsColumnType.BigVarChar :
  555. dataTypeNames.Add ("varchar");
  556. row ["ProviderType"] = (int) SqlDbType.VarChar;
  557. row ["DataType"] = typeof (string);
  558. row ["IsLong"] = false;
  559. break;
  560. case TdsColumnType.Binary :
  561. case TdsColumnType.BigBinary :
  562. dataTypeNames.Add ("binary");
  563. row ["ProviderType"] = (int) SqlDbType.Binary;
  564. row ["DataType"] = typeof (byte[]);
  565. row ["IsLong"] = true;
  566. break;
  567. case TdsColumnType.Char :
  568. case TdsColumnType.BigChar :
  569. dataTypeNames.Add ("char");
  570. row ["ProviderType"] = (int) SqlDbType.Char;
  571. row ["DataType"] = typeof (string);
  572. row ["IsLong"] = false;
  573. break;
  574. case TdsColumnType.Bit :
  575. case TdsColumnType.BitN :
  576. dataTypeNames.Add ("bit");
  577. row ["ProviderType"] = (int) SqlDbType.Bit;
  578. row ["DataType"] = typeof (bool);
  579. row ["IsLong"] = false;
  580. break;
  581. case TdsColumnType.DateTime4 :
  582. case TdsColumnType.DateTime :
  583. case TdsColumnType.DateTimeN :
  584. dataTypeNames.Add ("datetime");
  585. row ["ProviderType"] = (int) SqlDbType.DateTime;
  586. row ["DataType"] = typeof (DateTime);
  587. row ["IsLong"] = false;
  588. break;
  589. case TdsColumnType.Money :
  590. case TdsColumnType.MoneyN :
  591. case TdsColumnType.Money4 :
  592. dataTypeNames.Add ("money");
  593. row ["ProviderType"] = (int) SqlDbType.Money;
  594. row ["DataType"] = typeof (decimal);
  595. row ["IsLong"] = false;
  596. break;
  597. case TdsColumnType.NText :
  598. dataTypeNames.Add ("ntext");
  599. row ["ProviderType"] = (int) SqlDbType.NText;
  600. row ["DataType"] = typeof (string);
  601. row ["IsLong"] = true;
  602. break;
  603. case TdsColumnType.NVarChar :
  604. dataTypeNames.Add ("nvarchar");
  605. row ["ProviderType"] = (int) SqlDbType.NVarChar;
  606. row ["DataType"] = typeof (string);
  607. row ["IsLong"] = false;
  608. break;
  609. case TdsColumnType.Decimal :
  610. case TdsColumnType.Numeric :
  611. dataTypeNames.Add ("decimal");
  612. row ["ProviderType"] = (int) SqlDbType.Decimal;
  613. row ["DataType"] = typeof (decimal);
  614. row ["IsLong"] = false;
  615. break;
  616. case TdsColumnType.NChar :
  617. dataTypeNames.Add ("nchar");
  618. row ["ProviderType"] = (int) SqlDbType.NChar;
  619. row ["DataType"] = typeof (string);
  620. row ["IsLong"] = false;
  621. break;
  622. case TdsColumnType.SmallMoney :
  623. dataTypeNames.Add ("smallmoney");
  624. row ["ProviderType"] = (int) SqlDbType.SmallMoney;
  625. row ["DataType"] = typeof (decimal);
  626. row ["IsLong"] = false;
  627. break;
  628. default :
  629. dataTypeNames.Add ("variant");
  630. row ["ProviderType"] = (int) SqlDbType.Variant;
  631. row ["DataType"] = typeof (object);
  632. row ["IsLong"] = false;
  633. break;
  634. }
  635. schemaTable.Rows.Add (row);
  636. fieldCount += 1;
  637. }
  638. return schemaTable;
  639. }
  640. private static object GetSchemaValue (TdsDataColumn schema, object key)
  641. {
  642. if (schema.ContainsKey (key) && schema [key] != null)
  643. return schema [key];
  644. return DBNull.Value;
  645. }
  646. public SqlBinary GetSqlBinary (int i)
  647. {
  648. throw new NotImplementedException ();
  649. }
  650. public SqlBoolean GetSqlBoolean (int i)
  651. {
  652. object value = GetSqlValue (i);
  653. if (!(value is SqlBoolean))
  654. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  655. return (SqlBoolean) value;
  656. }
  657. public SqlByte GetSqlByte (int i)
  658. {
  659. object value = GetSqlValue (i);
  660. if (!(value is SqlByte))
  661. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  662. return (SqlByte) value;
  663. }
  664. public SqlDateTime GetSqlDateTime (int i)
  665. {
  666. object value = GetSqlValue (i);
  667. if (!(value is SqlDateTime))
  668. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  669. return (SqlDateTime) value;
  670. }
  671. public SqlDecimal GetSqlDecimal (int i)
  672. {
  673. object value = GetSqlValue (i);
  674. if (!(value is SqlDecimal))
  675. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  676. return (SqlDecimal) value;
  677. }
  678. public SqlDouble GetSqlDouble (int i)
  679. {
  680. object value = GetSqlValue (i);
  681. if (!(value is SqlDouble))
  682. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  683. return (SqlDouble) value;
  684. }
  685. public SqlGuid GetSqlGuid (int i)
  686. {
  687. object value = GetSqlValue (i);
  688. if (!(value is SqlGuid))
  689. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  690. return (SqlGuid) value;
  691. }
  692. public SqlInt16 GetSqlInt16 (int i)
  693. {
  694. object value = GetSqlValue (i);
  695. if (!(value is SqlInt16))
  696. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  697. return (SqlInt16) value;
  698. }
  699. public SqlInt32 GetSqlInt32 (int i)
  700. {
  701. object value = GetSqlValue (i);
  702. if (!(value is SqlInt32))
  703. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  704. return (SqlInt32) value;
  705. }
  706. public SqlInt64 GetSqlInt64 (int i)
  707. {
  708. object value = GetSqlValue (i);
  709. // TDS 7.0 returns bigint as decimal(19,0)
  710. if (value is SqlDecimal) {
  711. TdsDataColumn schema = command.Tds.Columns[i];
  712. if ((byte)schema["NumericPrecision"] == 19 && (byte)schema["NumericScale"] == 0)
  713. value = (SqlInt64) (SqlDecimal) value;
  714. }
  715. if (!(value is SqlInt64))
  716. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  717. return (SqlInt64) value;
  718. }
  719. public SqlMoney GetSqlMoney (int i)
  720. {
  721. object value = GetSqlValue (i);
  722. if (!(value is SqlMoney))
  723. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  724. return (SqlMoney) value;
  725. }
  726. public SqlSingle GetSqlSingle (int i)
  727. {
  728. object value = GetSqlValue (i);
  729. if (!(value is SqlSingle))
  730. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  731. return (SqlSingle) value;
  732. }
  733. public SqlString GetSqlString (int i)
  734. {
  735. object value = GetSqlValue (i);
  736. if (!(value is SqlString))
  737. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  738. return (SqlString) value;
  739. }
  740. public object GetSqlValue (int i)
  741. {
  742. SqlDbType type = (SqlDbType) (schemaTable.Rows [i]["ProviderType"]);
  743. object value = GetValue (i);
  744. switch (type) {
  745. case SqlDbType.BigInt:
  746. if (value == DBNull.Value)
  747. return SqlInt64.Null;
  748. return (SqlInt64) ((long) value);
  749. case SqlDbType.Binary:
  750. case SqlDbType.Image:
  751. case SqlDbType.VarBinary:
  752. case SqlDbType.Timestamp:
  753. if (value == DBNull.Value)
  754. return SqlBinary.Null;
  755. return (SqlBinary) ((byte[]) value);
  756. case SqlDbType.Bit:
  757. if (value == DBNull.Value)
  758. return SqlBoolean.Null;
  759. return (SqlBoolean) ((bool) value);
  760. case SqlDbType.Char:
  761. case SqlDbType.NChar:
  762. case SqlDbType.NText:
  763. case SqlDbType.NVarChar:
  764. case SqlDbType.Text:
  765. case SqlDbType.VarChar:
  766. if (value == DBNull.Value)
  767. return SqlString.Null;
  768. return (SqlString) ((string) value);
  769. case SqlDbType.DateTime:
  770. case SqlDbType.SmallDateTime:
  771. if (value == DBNull.Value)
  772. return SqlDateTime.Null;
  773. return (SqlDateTime) ((DateTime) value);
  774. case SqlDbType.Decimal:
  775. if (value == DBNull.Value)
  776. return SqlDecimal.Null;
  777. if (value is TdsBigDecimal)
  778. return SqlDecimal.FromTdsBigDecimal ((TdsBigDecimal) value);
  779. return (SqlDecimal) ((decimal) value);
  780. case SqlDbType.Float:
  781. if (value == DBNull.Value)
  782. return SqlDouble.Null;
  783. return (SqlDouble) ((double) value);
  784. case SqlDbType.Int:
  785. if (value == DBNull.Value)
  786. return SqlInt32.Null;
  787. return (SqlInt32) ((int) value);
  788. case SqlDbType.Money:
  789. case SqlDbType.SmallMoney:
  790. if (value == DBNull.Value)
  791. return SqlMoney.Null;
  792. return (SqlMoney) ((decimal) value);
  793. case SqlDbType.Real:
  794. if (value == DBNull.Value)
  795. return SqlSingle.Null;
  796. return (SqlSingle) ((float) value);
  797. case SqlDbType.UniqueIdentifier:
  798. if (value == DBNull.Value)
  799. return SqlGuid.Null;
  800. return (SqlGuid) ((Guid) value);
  801. case SqlDbType.SmallInt:
  802. if (value == DBNull.Value)
  803. return SqlInt16.Null;
  804. return (SqlInt16) ((short) value);
  805. case SqlDbType.TinyInt:
  806. if (value == DBNull.Value)
  807. return SqlByte.Null;
  808. return (SqlByte) ((byte) value);
  809. }
  810. throw new InvalidOperationException ("The type of this column is unknown.");
  811. }
  812. public int GetSqlValues (object[] values)
  813. {
  814. int count = 0;
  815. int columnCount = schemaTable.Rows.Count;
  816. int arrayCount = values.Length;
  817. if (arrayCount > columnCount)
  818. count = columnCount;
  819. else
  820. count = arrayCount;
  821. for (int i = 0; i < count; i += 1)
  822. values [i] = GetSqlValue (i);
  823. return count;
  824. }
  825. public
  826. #if NET_2_0
  827. override
  828. #endif // NET_2_0
  829. string GetString (int i)
  830. {
  831. object value = GetValue (i);
  832. if (!(value is string)) {
  833. if (value is DBNull) throw new SqlNullValueException ();
  834. throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
  835. }
  836. return (string) value;
  837. }
  838. public
  839. #if NET_2_0
  840. override
  841. #endif // NET_2_0
  842. object GetValue (int i)
  843. {
  844. return command.Tds.ColumnValues [i];
  845. }
  846. public
  847. #if NET_2_0
  848. override
  849. #endif // NET_2_0
  850. int GetValues (object[] values)
  851. {
  852. int len = values.Length;
  853. int bigDecimalIndex = command.Tds.ColumnValues.BigDecimalIndex;
  854. // If a four-byte decimal is stored, then we can't convert to
  855. // a native type. Throw an OverflowException.
  856. if (bigDecimalIndex >= 0 && bigDecimalIndex < len)
  857. throw new OverflowException ();
  858. command.Tds.ColumnValues.CopyTo (0, values, 0, len);
  859. return (len > FieldCount ? len : FieldCount);
  860. }
  861. void IDisposable.Dispose ()
  862. {
  863. Dispose (true);
  864. GC.SuppressFinalize (this);
  865. }
  866. IEnumerator IEnumerable.GetEnumerator ()
  867. {
  868. return new DbEnumerator (this);
  869. }
  870. public
  871. #if NET_2_0
  872. override
  873. #endif // NET_2_0
  874. bool IsDBNull (int i)
  875. {
  876. return GetValue (i) == DBNull.Value;
  877. }
  878. public
  879. #if NET_2_0
  880. override
  881. #endif // NET_2_0
  882. bool NextResult ()
  883. {
  884. if ((command.CommandBehavior & CommandBehavior.SingleResult) != 0 && resultsRead > 0)
  885. return false;
  886. moreResults = command.Tds.NextResult ();
  887. if (!moreResults)
  888. command.GetOutputParameters ();
  889. else {
  890. //new schema
  891. schemaTable = ConstructSchemaTable ();
  892. GetSchemaTable ();
  893. }
  894. rowsRead = 0;
  895. resultsRead += 1;
  896. return moreResults;
  897. }
  898. public
  899. #if NET_2_0
  900. override
  901. #endif // NET_2_0
  902. bool Read ()
  903. {
  904. if ((command.CommandBehavior & CommandBehavior.SingleRow) != 0 && rowsRead > 0)
  905. return false;
  906. if ((command.CommandBehavior & CommandBehavior.SchemaOnly) != 0)
  907. return false;
  908. if (!moreResults)
  909. return false;
  910. if ((haveRead) && (!readResultUsed))
  911. {
  912. readResultUsed = true;
  913. return true;
  914. }
  915. return (ReadRecord ());
  916. }
  917. internal bool ReadRecord ()
  918. {
  919. bool result = command.Tds.NextRow ();
  920. rowsRead += 1;
  921. return result;
  922. }
  923. #if NET_2_0
  924. [MonoTODO]
  925. protected override bool IsValidRow
  926. {
  927. get {throw new NotImplementedException ();}
  928. }
  929. [MonoTODO]
  930. public override Type GetFieldProviderSpecificType (int position)
  931. {
  932. throw new NotImplementedException ();
  933. }
  934. [MonoTODO]
  935. public override object GetProviderSpecificValue (int position)
  936. {
  937. throw new NotImplementedException ();
  938. }
  939. [MonoTODO]
  940. public override int GetProviderSpecificValues (object [] values)
  941. {
  942. throw new NotImplementedException ();
  943. }
  944. [MonoTODO]
  945. public override int VisibleFieldCount
  946. {
  947. get {throw new NotImplementedException ();}
  948. }
  949. #endif // NET_2_0
  950. #endregion // Methods
  951. }
  952. }