SqlDataReader.cs 31 KB

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