SqlDataReader.cs 29 KB

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