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