Migrating from monodoc/class/System.Data to mcs/class/System.Data/Documentation...
[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.IO;
40 using System.Text;
41 using System.Collections;
42 using System.ComponentModel;
43 using System.Data;
44 using System.Data.Common;
45 using System.Data.SqlTypes;
46 using System.Xml;
47
48 namespace System.Data.SqlClient
49 {
50 #if NET_2_0
51         public class SqlDataReader : DbDataReader, IDataReader, IDisposable, IDataRecord
52 #else
53         public sealed class SqlDataReader : MarshalByRefObject, IEnumerable, IDataReader, IDisposable, IDataRecord
54 #endif // NET_2_0
55         {
56                 #region Fields
57
58                 SqlCommand command;
59                 ArrayList dataTypeNames;
60                 bool disposed;
61                 bool isClosed;
62                 bool moreResults;
63                 int resultsRead;
64                 int rowsRead;
65                 DataTable schemaTable;
66                 bool haveRead;
67                 bool readResult;
68                 bool readResultUsed;
69 #if NET_2_0
70                 int visibleFieldCount;
71 #endif
72
73                 #endregion // Fields
74
75                 const int COLUMN_NAME_IDX = 0;
76                 const int COLUMN_ORDINAL_IDX = 1;
77                 const int COLUMN_SIZE_IDX = 2;
78                 const int NUMERIC_PRECISION_IDX = 3;
79                 const int NUMERIC_SCALE_IDX = 4;
80                 const int IS_UNIQUE_IDX = 5;
81                 const int IS_KEY_IDX = 6;
82                 const int BASE_SERVER_NAME_IDX = 7;
83                 const int BASE_CATALOG_NAME_IDX = 8;
84                 const int BASE_COLUMN_NAME_IDX = 9;
85                 const int BASE_SCHEMA_NAME_IDX = 10;
86                 const int BASE_TABLE_NAME_IDX = 11;
87                 const int DATA_TYPE_IDX = 12;
88                 const int ALLOW_DBNULL_IDX = 13;
89                 const int PROVIDER_TYPE_IDX = 14;
90                 const int IS_ALIASED_IDX = 15;
91                 const int IS_EXPRESSION_IDX = 16;
92                 const int IS_IDENTITY_IDX = 17;
93                 const int IS_AUTO_INCREMENT_IDX = 18;
94                 const int IS_ROW_VERSION_IDX = 19;
95                 const int IS_HIDDEN_IDX = 20;
96                 const int IS_LONG_IDX = 21;
97                 const int IS_READ_ONLY_IDX = 22;
98
99                 #region Constructors
100
101                 internal SqlDataReader (SqlCommand command)
102                 {
103                         readResult = false;
104                         haveRead = false;
105                         readResultUsed = false;
106                         this.command = command;
107                         resultsRead = 0;
108                         isClosed = false;
109                         command.Tds.RecordsAffected = -1;
110 #if NET_2_0
111                         visibleFieldCount = 0;
112 #endif
113                         NextResult ();
114                 }
115
116                 #endregion // Constructors
117
118                 #region Properties
119
120                 public
121 #if NET_2_0
122                 override
123 #endif // NET_2_0
124                 int Depth {
125                         get { return 0; }
126                 }
127
128                 public
129 #if NET_2_0
130                 override
131 #endif // NET_2_0
132                 int FieldCount {
133                         get { return command.Tds.Columns.Count; }
134                 }
135
136                 public
137 #if NET_2_0
138                 override
139 #endif // NET_2_0
140                 bool IsClosed {
141                         get { return isClosed; }
142                 }
143
144                 public
145 #if NET_2_0
146                 override
147 #endif // NET_2_0
148                 object this [int i] {
149                         get { return GetValue (i); }
150                 }
151
152                 public
153 #if NET_2_0
154                 override
155 #endif // NET_2_0
156                 object this [string name] {
157                         get { return GetValue (GetOrdinal (name)); }
158                 }
159         
160                 public
161 #if NET_2_0
162                 override
163 #endif // NET_2_0
164                 int RecordsAffected {
165                         get {
166                                 return command.Tds.RecordsAffected; 
167                         }
168                 }
169
170                 public
171 #if NET_2_0
172                 override
173 #endif // NET_2_0
174                 bool HasRows {
175                         get {
176                                 if (haveRead) 
177                                         return readResult;
178                         
179                                 haveRead = true;
180                                 readResult = ReadRecord ();
181                                 return readResult;
182                         }
183                 }
184 #if NET_2_0
185                 public override int VisibleFieldCount {
186                         get { return visibleFieldCount; }
187                 }
188
189                 protected SqlConnection Connection {
190                         get { return command.Connection; }
191                 }
192
193                 protected bool IsCommandBehavior (CommandBehavior condition) {
194                         return condition == command.CommandBehavior;
195                 }
196 #endif
197
198                 #endregion // Properties
199
200                 #region Methods
201
202                 public
203 #if NET_2_0
204                 override
205 #endif // NET_2_0
206                 void Close ()
207                 {
208                         if (IsClosed)
209                                 return;
210                         // skip to end & read output parameters.
211                         while (NextResult ())
212                                 ;
213                         isClosed = true;
214                         command.CloseDataReader ();
215                 }
216
217                 private static DataTable ConstructSchemaTable ()
218                 {
219                         Type booleanType = typeof (bool);
220                         Type stringType = typeof (string);
221                         Type intType = typeof (int);
222                         Type typeType = typeof (Type);
223                         Type shortType = typeof (short);
224
225                         DataTable schemaTable = new DataTable ("SchemaTable");
226                         schemaTable.Columns.Add ("ColumnName", stringType);
227                         schemaTable.Columns.Add ("ColumnOrdinal", intType);
228                         schemaTable.Columns.Add ("ColumnSize", intType);
229                         schemaTable.Columns.Add ("NumericPrecision", shortType);
230                         schemaTable.Columns.Add ("NumericScale", shortType);
231                         schemaTable.Columns.Add ("IsUnique", booleanType);
232                         schemaTable.Columns.Add ("IsKey", booleanType);
233                         schemaTable.Columns.Add ("BaseServerName", stringType);
234                         schemaTable.Columns.Add ("BaseCatalogName", stringType);
235                         schemaTable.Columns.Add ("BaseColumnName", stringType);
236                         schemaTable.Columns.Add ("BaseSchemaName", stringType);
237                         schemaTable.Columns.Add ("BaseTableName", stringType);
238                         schemaTable.Columns.Add ("DataType", typeType);
239                         schemaTable.Columns.Add ("AllowDBNull", booleanType);
240                         schemaTable.Columns.Add ("ProviderType", intType);
241                         schemaTable.Columns.Add ("IsAliased", booleanType);
242                         schemaTable.Columns.Add ("IsExpression", booleanType);
243                         schemaTable.Columns.Add ("IsIdentity", booleanType);
244                         schemaTable.Columns.Add ("IsAutoIncrement", booleanType);
245                         schemaTable.Columns.Add ("IsRowVersion", booleanType);
246                         schemaTable.Columns.Add ("IsHidden", booleanType);
247                         schemaTable.Columns.Add ("IsLong", booleanType);
248                         schemaTable.Columns.Add ("IsReadOnly", booleanType);
249
250                         return schemaTable;
251                 }
252                 
253                 private void GetSchemaRowTypeName (TdsColumnType ctype, int csize, out string typeName) 
254                 {
255                         int dbType;
256                         bool isLong;
257                         Type fieldType;
258                         
259                         GetSchemaRowType (ctype, csize, out dbType, out fieldType, out isLong, out typeName);
260                 }
261
262                 private void GetSchemaRowFieldType (TdsColumnType ctype, int csize, out Type fieldType) 
263                 {
264                         int dbType;
265                         bool isLong;
266                         string typeName;
267                         
268                         GetSchemaRowType (ctype, csize, out dbType, out fieldType, out isLong, out typeName);
269                 }
270
271                 private void GetSchemaRowDbType (TdsColumnType ctype, int csize, out int dbType) 
272                 {
273                         Type fieldType;
274                         bool isLong;
275                         string typeName;
276                         
277                         GetSchemaRowType (ctype, csize, out dbType, out fieldType, out isLong, out typeName);
278                 }
279                 
280                 private void GetSchemaRowType (TdsColumnType ctype, int csize, 
281                                                out int dbType, out Type fieldType, 
282                                                out bool isLong, out string typeName)
283                 {
284                         dbType = -1;
285                         typeName = string.Empty;
286                         isLong = false;
287                         fieldType = typeof (Type);
288                         
289                         switch (ctype) {
290                                 case TdsColumnType.Int1:
291                                 case TdsColumnType.Int2:
292                                 case TdsColumnType.Int4:
293                                 case TdsColumnType.IntN:
294                                         switch (csize) {
295                                         case 1:
296                                                 typeName = "tinyint";
297                                                 dbType = (int) SqlDbType.TinyInt;
298                                                 fieldType = typeof (byte);
299                                                 isLong = false;
300                                                 break;
301                                         case 2:
302                                                 typeName = "smallint";
303                                                 dbType = (int) SqlDbType.SmallInt;
304                                                 fieldType = typeof (short);
305                                                 isLong = false;
306                                                 break;
307                                         case 4:
308                                                 typeName = "int";
309                                                 dbType = (int) SqlDbType.Int;
310                                                 fieldType = typeof (int);
311                                                 isLong = false;
312                                                 break;
313                                         case 8:
314                                                 typeName = "bigint";
315                                                 dbType = (int) SqlDbType.BigInt;
316                                                 fieldType = typeof (long);
317                                                 isLong = false;
318                                                 break;
319                                         }
320                                         break;
321                                 case TdsColumnType.Real:
322                                 case TdsColumnType.Float8:
323                                 case TdsColumnType.FloatN:
324                                         switch (csize) {
325                                         case 4:
326                                                 typeName = "real";
327                                                 dbType = (int) SqlDbType.Real;
328                                                 fieldType = typeof (float);
329                                                 isLong = false;
330                                                 break;
331                                         case 8:
332                                                 typeName = "float";
333                                                 dbType = (int) SqlDbType.Float;
334                                                 fieldType = typeof (double);
335                                                 isLong = false;
336                                                 break;
337                                         }
338                                         break;
339                                 case TdsColumnType.Image :
340                                         typeName = "image";
341                                         dbType = (int) SqlDbType.Image;
342                                         fieldType = typeof (byte[]);
343                                         isLong = true;
344                                         break;
345                                 case TdsColumnType.Text :
346                                         typeName = "text";
347                                         dbType = (int) SqlDbType.Text;
348                                         fieldType = typeof (string);
349                                         isLong = true;
350                                         break;
351                                 case TdsColumnType.UniqueIdentifier :
352                                         typeName = "uniqueidentifier";
353                                         dbType = (int) SqlDbType.UniqueIdentifier;
354                                         fieldType = typeof (Guid);
355                                         isLong = false;
356                                         break;
357                                 case TdsColumnType.VarBinary :
358                                 case TdsColumnType.BigVarBinary :
359                                         typeName = "varbinary";
360                                         dbType = (int) SqlDbType.VarBinary;
361                                         fieldType = typeof (byte[]);
362                                         isLong = true;
363                                         break;
364                                 case TdsColumnType.VarChar :
365                                 case TdsColumnType.BigVarChar :
366                                         typeName = "varchar";
367                                         dbType = (int) SqlDbType.VarChar;
368                                         fieldType = typeof (string);
369                                         isLong = false;
370                                         break;
371                                 case TdsColumnType.Binary :
372                                 case TdsColumnType.BigBinary :
373                                         typeName = "binary";
374                                         dbType = (int) SqlDbType.Binary;
375                                         fieldType = typeof (byte[]);
376                                         isLong = true;
377                                         break;
378                                 case TdsColumnType.Char :
379                                 case TdsColumnType.BigChar :
380                                         typeName = "char";
381                                         dbType = (int) SqlDbType.Char;
382                                         fieldType = typeof (string);
383                                         isLong = false;
384                                         break;
385                                 case TdsColumnType.Bit :
386                                 case TdsColumnType.BitN :
387                                         typeName = "bit";
388                                         dbType = (int) SqlDbType.Bit;
389                                         fieldType = typeof (bool);
390                                         isLong = false;
391                                         break;
392                                 case TdsColumnType.DateTime4 :
393                                 case TdsColumnType.DateTime :
394                                 case TdsColumnType.DateTimeN :
395                                         typeName = "datetime";
396                                         dbType = (int) SqlDbType.DateTime;
397                                         fieldType = typeof (DateTime);
398                                         isLong = false;
399                                         break;
400                                 case TdsColumnType.Money :
401                                 case TdsColumnType.MoneyN :
402                                 case TdsColumnType.Money4 :
403                                         typeName = "money";
404                                         dbType = (int) SqlDbType.Money;
405                                         fieldType = typeof (decimal);
406                                         isLong = false;
407                                         break;
408                                 case TdsColumnType.NText :
409                                         typeName = "ntext";
410                                         dbType = (int) SqlDbType.NText;
411                                         fieldType = typeof (string);
412                                         isLong = true;
413                                         break;
414                                 case TdsColumnType.NVarChar :
415                                         typeName = "nvarchar";
416                                         dbType = (int) SqlDbType.NVarChar;
417                                         fieldType = typeof (string);
418                                         isLong = false;
419                                         break;
420                                 case TdsColumnType.Decimal :
421                                 case TdsColumnType.Numeric :
422                                         typeName = "decimal";
423                                         dbType = (int) SqlDbType.Decimal;
424                                         fieldType = typeof (decimal);
425                                         isLong = false;
426                                         break;
427                                 case TdsColumnType.NChar :
428                                         typeName = "nchar";
429                                         dbType = (int) SqlDbType.NChar;
430                                         fieldType = typeof (string);
431                                         isLong = false;
432                                         break;
433                                 case TdsColumnType.SmallMoney :
434                                         typeName = "smallmoney";
435                                         dbType = (int) SqlDbType.SmallMoney;
436                                         fieldType = typeof (decimal);
437                                         isLong = false;
438                                         break;
439                                 default :
440                                         typeName = "variant";
441                                         dbType = (int) SqlDbType.Variant;
442                                         fieldType = typeof (object);
443                                         isLong = false;
444                                         break;
445                         }
446                 }
447
448 #if NET_2_0
449                 new
450 #endif
451                 void Dispose (bool disposing)
452                 {
453                         if (!disposed) {
454                                 if (disposing) {
455                                         if (schemaTable != null)
456                                                 schemaTable.Dispose ();
457                                         Close ();
458                                         command = null;
459                                 }
460                                 disposed = true;
461                         }
462                 }
463
464                 public 
465 #if NET_2_0
466                 override
467 #endif // NET_2_0
468                 bool GetBoolean (int i)
469                 {
470                         object value = GetValue (i);
471                         if (!(value is bool)) {
472                                 if (value is DBNull) throw new SqlNullValueException ();
473                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
474                         }
475                         return (bool) value;
476                 }
477
478                 public
479 #if NET_2_0
480                 override
481 #endif // NET_2_0
482                 byte GetByte (int i)
483                 {
484                         object value = GetValue (i);
485                         if (!(value is byte)) {
486                                 if (value is DBNull) throw new SqlNullValueException ();
487                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
488                         }
489                         return (byte) value;
490                 }
491
492                 public
493 #if NET_2_0
494                 override
495 #endif // NET_2_0
496                 long GetBytes (int i, long dataIndex, byte[] buffer, int bufferIndex, int length)
497                 {
498                         if ((command.CommandBehavior & CommandBehavior.SequentialAccess) != 0) {
499                                 try {
500                                         long len = ((Tds)command.Tds).GetSequentialColumnValue (i, dataIndex, buffer, bufferIndex, length);
501                                         if (len == -1)
502                                                 throw new InvalidCastException ("Invalid attempt to GetBytes on column "
503                                                                                 + "'" + command.Tds.Columns[i]["ColumnName"] +
504                                                                                 "'." + "The GetBytes function"
505                                                                                 + " can only be used on columns of type Text, NText, or Image");
506                                         return len;
507                                 } catch (TdsInternalException ex) {
508                                         command.Connection.Close ();
509                                         throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
510                                 }
511                         }
512
513                         object value = GetValue (i);
514                         if (!(value is byte [])) {
515                                 if (value is DBNull) throw new SqlNullValueException ();
516                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
517                         }
518                         
519                         if ( buffer == null )
520                                 return ((byte []) value).Length; // Return length of data
521
522                         // Copy data into buffer
523                         int availLen = (int) ( ( (byte []) value).Length - dataIndex);
524                         if (availLen < length)
525                                 length = availLen;
526                         Array.Copy ((byte []) value, (int) dataIndex, buffer, bufferIndex, length);
527                         return length; // return actual read count
528                 }
529
530                 [EditorBrowsableAttribute (EditorBrowsableState.Never)]
531                 public
532 #if NET_2_0
533                 override
534 #endif // NET_2_0
535                 char GetChar (int i)
536                 {
537                         object value = GetValue (i);
538                         if (!(value is char)) {
539                                 if (value is DBNull) throw new SqlNullValueException ();
540                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
541                         }
542                         return (char) value;
543                 }
544
545                 public
546 #if NET_2_0
547                 override
548 #endif // NET_2_0
549                 long GetChars (int i, long dataIndex, char[] buffer, int bufferIndex, int length)
550                 {
551                         if ((command.CommandBehavior & CommandBehavior.SequentialAccess) != 0) {
552                                 Encoding encoding = null;
553                                 byte mul = 1;
554                                 TdsColumnType colType = (TdsColumnType) command.Tds.Columns[i]["ColumnType"];
555                                 switch (colType) {
556                                         case TdsColumnType.Text :
557                                         case TdsColumnType.VarChar:
558                                         case TdsColumnType.Char:
559                                         case TdsColumnType.BigVarChar:
560                                                 encoding = Encoding.ASCII;
561                                                 break;
562                                         case TdsColumnType.NText :
563                                         case TdsColumnType.NVarChar:
564                                         case TdsColumnType.NChar:
565                                                 encoding = Encoding.Unicode;
566                                                 mul = 2;
567                                                 break;
568                                         default :
569                                                 return -1;
570                                 }
571
572                                 long count = 0;
573                                 if (buffer == null) {
574                                         count = GetBytes (i,0,(byte[]) null,0,0);
575                                         return (count/mul);
576                                 }
577
578                                 length *= mul;
579                                 byte[] arr = new byte [length];
580                                 count = GetBytes (i, dataIndex, arr, 0, length);
581                                 if (count == -1)
582                                         throw new InvalidCastException ("Specified cast is not valid");
583
584                                 Char[] val = encoding.GetChars (arr, 0, (int)count);
585                                 val.CopyTo (buffer, bufferIndex);
586                                 return val.Length;
587                         }
588
589                         char [] valueBuffer;
590                         object value = GetValue (i);
591                         
592                         if (value is char[])
593                                 valueBuffer = (char[])value;
594                         else if (value is string)
595                                 valueBuffer = ((string)value).ToCharArray();
596                         else {
597                                 if (value is DBNull) throw new SqlNullValueException ();
598                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
599                         }
600                         
601                         if ( buffer == null ) {
602                                 // Return length of data
603                                 return valueBuffer.Length;
604                         }
605                         else {
606                                 // Copy data into buffer
607                                 Array.Copy (valueBuffer, (int) dataIndex, buffer, bufferIndex, length);
608                                 return valueBuffer.Length - dataIndex;
609                         }
610                 }
611                 
612 #if !NET_2_0
613                 [EditorBrowsableAttribute (EditorBrowsableState.Never)]
614                 public new IDataReader GetData (int i)
615                 {
616                         return ((IDataReader) this [i]);
617                 }
618 #endif
619
620                 public
621 #if NET_2_0
622                 override
623 #endif // NET_2_0
624                 string GetDataTypeName (int i)
625                 {
626                         TdsColumnType ctype;
627                         string datatypeName;
628                         int csize;
629                         
630                         if (i < 0 || i >= command.Tds.Columns.Count)
631                                 throw new IndexOutOfRangeException ();
632 #if NET_2_0
633                         ctype = (TdsColumnType) command.Tds.Columns[i].ColumnType;
634                         csize = (int) command.Tds.Columns[i].ColumnSize;
635 #else
636                         ctype = (TdsColumnType) command.Tds.Columns[i]["ColumnType"];
637                         csize = (int) command.Tds.Columns[i]["ColumnSize"];
638 #endif
639                         GetSchemaRowTypeName (ctype, csize, out datatypeName);
640                         return datatypeName;
641                 }
642
643                 public
644 #if NET_2_0
645                 override
646 #endif // NET_2_0
647                 DateTime GetDateTime (int i)
648                 {
649                         object value = GetValue (i);
650                         if (!(value is DateTime)) {
651                                 if (value is DBNull) throw new SqlNullValueException ();
652                                 else throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
653                         }
654                         return (DateTime) value;
655                 }
656
657                 public
658 #if NET_2_0
659                 override
660 #endif // NET_2_0
661                 decimal GetDecimal (int i)
662                 {
663                         object value = GetValue (i);
664                         if (!(value is decimal)) {
665                                 if (value is DBNull) throw new SqlNullValueException ();
666                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
667                         }
668                         return (decimal) value;
669                 }
670
671                 public
672 #if NET_2_0
673                 override
674 #endif // NET_2_0
675                 double GetDouble (int i)
676                 {
677                         object value = GetValue (i);
678                         if (!(value is double)) {
679                                 if (value is DBNull) throw new SqlNullValueException ();
680                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
681                         }
682                         return (double) value;
683                 }
684
685                 public
686 #if NET_2_0
687                 override
688 #endif // NET_2_0
689                 Type GetFieldType (int i)
690                 {
691                         TdsColumnType ctype;
692                         Type fieldType;
693                         int csize;
694                         
695                         if (i < 0 || i >= command.Tds.Columns.Count)
696                                 throw new IndexOutOfRangeException ();
697 #if NET_2_0
698                         ctype = (TdsColumnType) command.Tds.Columns[i].ColumnType;
699                         csize = (int) command.Tds.Columns[i].ColumnSize;
700 #else
701                         ctype = (TdsColumnType) command.Tds.Columns[i]["ColumnType"];
702                         csize = (int) command.Tds.Columns[i]["ColumnSize"];
703 #endif
704                         GetSchemaRowFieldType (ctype, csize, out fieldType);                    
705                         return fieldType;
706                 }
707
708                 public
709 #if NET_2_0
710                 override
711 #endif // NET_2_0
712                 float GetFloat (int i)
713                 {
714                         object value = GetValue (i);
715                         if (!(value is float)) {
716                                 if (value is DBNull) throw new SqlNullValueException ();
717                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
718                         }
719                         return (float) value;
720                 }
721
722                 public
723 #if NET_2_0
724                 override
725 #endif // NET_2_0
726                 Guid GetGuid (int i)
727                 {
728                         object value = GetValue (i);
729                         if (!(value is Guid)) {
730                                 if (value is DBNull) throw new SqlNullValueException ();
731                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
732                         }
733                         return (Guid) value;
734                 }
735
736                 public
737 #if NET_2_0
738                 override
739 #endif // NET_2_0
740                 short GetInt16 (int i)
741                 {
742                         object value = GetValue (i);
743                         if (!(value is short)) {
744                                 if (value is DBNull) throw new SqlNullValueException ();
745                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
746                         }
747                         return (short) value;
748                 }
749
750                 public
751 #if NET_2_0
752                 override
753 #endif // NET_2_0
754                 int GetInt32 (int i)
755                 {
756                         object value = GetValue (i);
757                         if (!(value is int)) {
758                                 if (value is DBNull) throw new SqlNullValueException ();
759                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
760                         }
761                         return (int) value;
762                 }
763
764                 public
765 #if NET_2_0
766                 override
767 #endif // NET_2_0
768                 long GetInt64 (int i)
769                 {
770                         object value = GetValue (i);
771                         if (!(value is long)) {
772                                 if (value is DBNull) throw new SqlNullValueException ();
773                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
774                         }
775                         return (long) value;
776                 }
777
778                 public
779 #if NET_2_0
780                 override
781 #endif // NET_2_0
782                 string GetName (int i)
783                 {
784                         if (i < 0 || i >= command.Tds.Columns.Count)
785                                 throw new IndexOutOfRangeException ();
786 #if NET_2_0
787                         return (string) command.Tds.Columns[i].ColumnName;
788 #else
789                         return (string) command.Tds.Columns[i]["ColumnName"];
790 #endif
791                 }
792
793                 public
794 #if NET_2_0
795                 override
796 #endif // NET_2_0
797                 int GetOrdinal (string name)
798                 {
799                         string colName;
800                         foreach (TdsDataColumn schema in command.Tds.Columns) {
801 #if NET_2_0
802                                 colName = schema.ColumnName;
803                                 if (colName.Equals (name) || String.Compare (colName, name, true) == 0)
804                                         return (int) schema.ColumnOrdinal;
805 #else
806                                 colName = (string) schema["ColumnName"];
807                                 if (colName.Equals (name) || String.Compare (colName, name, true) == 0)
808                                         return (int) schema["ColumnOrdinal"];
809 #endif                                          
810                         }                       
811                         throw new IndexOutOfRangeException ();
812                 }
813
814                 public
815 #if NET_2_0
816                 override
817 #endif // NET_2_0
818                 DataTable GetSchemaTable ()
819                 {
820                         ValidateState ();
821
822                         if (schemaTable == null)
823                                 schemaTable = ConstructSchemaTable ();
824
825                         if (schemaTable.Rows != null && schemaTable.Rows.Count > 0)
826                                 return schemaTable;
827
828                         if (!moreResults)
829                                 return null;
830
831                         dataTypeNames = new ArrayList (command.Tds.Columns.Count);
832
833                         foreach (TdsDataColumn schema in command.Tds.Columns) {
834                                 DataRow row = schemaTable.NewRow ();
835
836 #if NET_2_0
837                                 row [COLUMN_NAME_IDX]           = GetSchemaValue (schema.ColumnName);
838                                 row [COLUMN_ORDINAL_IDX]                = GetSchemaValue (schema.ColumnOrdinal);
839                                 row [IS_UNIQUE_IDX]             = GetSchemaValue (schema.IsUnique);
840                                 row [IS_AUTO_INCREMENT_IDX]             = GetSchemaValue (schema.IsAutoIncrement);
841                                 row [IS_ROW_VERSION_IDX]                = GetSchemaValue (schema.IsRowVersion);
842                                 row [IS_HIDDEN_IDX]             = GetSchemaValue (schema.IsHidden);
843                                 row [IS_IDENTITY_IDX]           = GetSchemaValue (schema.IsIdentity);
844                                 row [COLUMN_SIZE_IDX]           = GetSchemaValue (schema.ColumnSize);
845                                 row [NUMERIC_PRECISION_IDX]     = GetSchemaValue (schema.NumericPrecision);
846                                 row [NUMERIC_SCALE_IDX]         = GetSchemaValue (schema.NumericScale);
847                                 row [IS_KEY_IDX]                        = GetSchemaValue (schema.IsKey);
848                                 row [IS_ALIASED_IDX]            = GetSchemaValue (schema.IsAliased);
849                                 row [IS_EXPRESSION_IDX]         = GetSchemaValue (schema.IsExpression);
850                                 row [IS_READ_ONLY_IDX]          = GetSchemaValue (schema.IsReadOnly);
851                                 row [BASE_SERVER_NAME_IDX]              = GetSchemaValue (schema.BaseServerName);
852                                 row [BASE_CATALOG_NAME_IDX]             = GetSchemaValue (schema.BaseCatalogName);
853                                 row [BASE_COLUMN_NAME_IDX]              = GetSchemaValue (schema.BaseColumnName);
854                                 row [BASE_SCHEMA_NAME_IDX]              = GetSchemaValue (schema.BaseSchemaName);
855                                 row [BASE_TABLE_NAME_IDX]               = GetSchemaValue (schema.BaseTableName);
856                                 row [ALLOW_DBNULL_IDX]          = GetSchemaValue (schema.AllowDBNull);
857 #else
858                                 row ["ColumnName"]              = GetSchemaValue (schema, "ColumnName");
859                                 row ["ColumnOrdinal"]           = GetSchemaValue (schema, "ColumnOrdinal");
860                                 row ["IsUnique"]                = GetSchemaValue (schema, "IsUnique");
861                                 row ["IsAutoIncrement"]         = GetSchemaValue (schema, "IsAutoIncrement");
862                                 row ["IsRowVersion"]            = GetSchemaValue (schema, "IsRowVersion");
863                                 row ["IsHidden"]                = GetSchemaValue (schema, "IsHidden");
864                                 row ["IsIdentity"]              = GetSchemaValue (schema, "IsIdentity");
865                                 row ["ColumnSize"]              = GetSchemaValue (schema, "ColumnSize");
866                                 row ["NumericPrecision"]        = GetSchemaValue (schema, "NumericPrecision");
867                                 row ["NumericScale"]            = GetSchemaValue (schema, "NumericScale");
868                                 row ["IsKey"]                   = GetSchemaValue (schema, "IsKey");
869                                 row ["IsAliased"]               = GetSchemaValue (schema, "IsAliased");
870                                 row ["IsExpression"]            = GetSchemaValue (schema, "IsExpression");
871                                 row ["IsReadOnly"]              = GetSchemaValue (schema, "IsReadOnly");
872                                 row ["BaseServerName"]          = GetSchemaValue (schema, "BaseServerName");
873                                 row ["BaseCatalogName"]         = GetSchemaValue (schema, "BaseCatalogName");
874                                 row ["BaseColumnName"]          = GetSchemaValue (schema, "BaseColumnName");
875                                 row ["BaseSchemaName"]          = GetSchemaValue (schema, "BaseSchemaName");
876                                 row ["BaseTableName"]           = GetSchemaValue (schema, "BaseTableName");
877                                 row ["AllowDBNull"]             = GetSchemaValue (schema, "AllowDBNull");
878 #endif
879                                 // We don't always get the base column name.
880                                 if (row [BASE_COLUMN_NAME_IDX] == DBNull.Value)
881                                         row [BASE_COLUMN_NAME_IDX] = row [COLUMN_NAME_IDX];
882
883                                 TdsColumnType ctype;
884                                 int csize, dbType;                              
885                                 Type fieldType;
886                                 bool isLong;
887                                 string typeName;
888 #if NET_2_0
889                                 ctype = (TdsColumnType) schema.ColumnType;
890                                 csize = (int) schema.ColumnSize;
891 #else
892                                 ctype = (TdsColumnType) schema ["ColumnType"];
893                                 csize = (int) schema ["ColumnSize"];
894 #endif
895
896                                 GetSchemaRowType (ctype, csize, out dbType, 
897                                                                         out fieldType, out isLong, out typeName);
898                                 
899                                 dataTypeNames.Add (typeName);
900                                 row [PROVIDER_TYPE_IDX] = dbType;
901                                 row [DATA_TYPE_IDX] = fieldType;
902                                 row [IS_LONG_IDX] = isLong;                     
903 #if NET_2_0
904                                 if ((bool)row [IS_HIDDEN_IDX] == false)
905                                         visibleFieldCount += 1;
906 #endif
907
908                                 schemaTable.Rows.Add (row);
909                         }
910                         return schemaTable;
911                 }
912
913                 private static object GetSchemaValue (TdsDataColumn schema, string key)
914                 {
915                         object val = schema [key];
916                         if (val != null)
917                                 return val;
918                         else
919                                 return DBNull.Value;
920                 }
921
922 #if NET_2_0
923                 static object GetSchemaValue (object value)
924                 {
925                         if (value == null)
926                                 return DBNull.Value;
927
928                         return value;
929                 }
930 #endif          
931                 
932                 public
933 #if NET_2_0
934                 virtual
935 #endif
936                 SqlBinary GetSqlBinary (int i)
937                 {
938                         object value = GetSqlValue (i);
939                         if (!(value is SqlBinary))
940                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
941                         return (SqlBinary) value;
942                 }
943
944                 public
945 #if NET_2_0
946                 virtual
947 #endif
948                 SqlBoolean GetSqlBoolean (int i) 
949                 {
950                         object value = GetSqlValue (i);
951                         if (!(value is SqlBoolean))
952                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
953                         return (SqlBoolean) value;
954                 }
955
956                 public
957 #if NET_2_0
958                 virtual
959 #endif
960                 SqlByte GetSqlByte (int i)
961                 {
962                         object value = GetSqlValue (i);
963                         if (!(value is SqlByte))
964                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
965                         return (SqlByte) value;
966                 }
967
968                 public
969 #if NET_2_0
970                 virtual
971 #endif
972                 SqlDateTime GetSqlDateTime (int i)
973                 {
974                         object value = GetSqlValue (i);
975                         if (!(value is SqlDateTime))
976                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
977                         return (SqlDateTime) value;
978                 }
979
980                 public
981 #if NET_2_0
982                 virtual
983 #endif
984                 SqlDecimal GetSqlDecimal (int i)
985                 {
986                         object value = GetSqlValue (i);
987                         if (!(value is SqlDecimal))
988                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
989                         return (SqlDecimal) value;
990                 }
991
992                 public
993 #if NET_2_0
994                 virtual
995 #endif
996                 SqlDouble GetSqlDouble (int i)
997                 {
998                         object value = GetSqlValue (i);
999                         if (!(value is SqlDouble))
1000                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1001                         return (SqlDouble) value;
1002                 }
1003
1004                 public
1005 #if NET_2_0
1006                 virtual
1007 #endif
1008                 SqlGuid GetSqlGuid (int i)
1009                 {
1010                         object value = GetSqlValue (i);
1011                         if (!(value is SqlGuid))
1012                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1013                         return (SqlGuid) value;
1014                 }
1015
1016                 public
1017 #if NET_2_0
1018                 virtual
1019 #endif
1020                 SqlInt16 GetSqlInt16 (int i)
1021                 {
1022                         object value = GetSqlValue (i);
1023                         if (!(value is SqlInt16))
1024                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1025                         return (SqlInt16) value;
1026                 }
1027
1028                 public
1029 #if NET_2_0
1030                 virtual
1031 #endif
1032                 SqlInt32 GetSqlInt32 (int i)
1033                 {
1034                         object value = GetSqlValue (i);
1035                         if (!(value is SqlInt32))
1036                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1037                         return (SqlInt32) value;
1038                 }
1039
1040                 public
1041 #if NET_2_0
1042                 virtual
1043 #endif
1044                 SqlInt64 GetSqlInt64 (int i)
1045                 {
1046                         object value = GetSqlValue (i);
1047                         // TDS 7.0 returns bigint as decimal(19,0)
1048                         if (value is SqlDecimal) {
1049                                 TdsDataColumn schema = command.Tds.Columns[i];
1050                                 byte precision, scale;
1051
1052 #if NET_2_0
1053                                 precision = (byte)schema.NumericPrecision;
1054                                 scale = (byte)schema.NumericScale;
1055 #else
1056                                 precision = (byte)schema["NumericPrecision"];
1057                                 scale = (byte)schema["NumericScale"];
1058 #endif
1059                                 if (precision == 19 && scale == 0)
1060                                         value = (SqlInt64) (SqlDecimal) value;
1061                         }
1062                         if (!(value is SqlInt64))
1063                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1064                         return (SqlInt64) value;
1065                 }
1066
1067                 public
1068 #if NET_2_0
1069                 virtual
1070 #endif
1071                 SqlMoney GetSqlMoney (int i)
1072                 {
1073                         object value = GetSqlValue (i);
1074                         if (!(value is SqlMoney))
1075                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1076                         return (SqlMoney) value;
1077                 }
1078
1079                 public
1080 #if NET_2_0
1081                 virtual
1082 #endif
1083                 SqlSingle GetSqlSingle (int i)
1084                 {
1085                         object value = GetSqlValue (i);
1086                         if (!(value is SqlSingle))
1087                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1088                         return (SqlSingle) value;
1089                 }
1090
1091                 public
1092 #if NET_2_0
1093                 virtual
1094 #endif
1095                 SqlString GetSqlString (int i)
1096                 {
1097                         object value = GetSqlValue (i);
1098                         if (!(value is SqlString))
1099                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1100                         return (SqlString) value;
1101                 }
1102
1103 #if NET_2_0
1104                 public virtual SqlXml GetSqlXml (int i)
1105                 {
1106                         object value = GetSqlValue (i);
1107                         if (!(value is SqlXml)) {
1108                                 if (value is DBNull) {
1109                                         throw new SqlNullValueException ();
1110                                 } else if (command.Tds.TdsVersion == TdsVersion.tds70 && value is SqlString) {
1111                                         // Workaround for TDS 7 clients
1112                                         // Xml column types are supported only from Sql Server 2005 / TDS 8, however
1113                                         // when a TDS 7 client requests for Xml column data, Sql Server 2005 returns
1114                                         // it as NTEXT
1115                                         MemoryStream stream = null;
1116                                         if (!((SqlString) value).IsNull)
1117                                                 stream = new MemoryStream (Encoding.Unicode.GetBytes (value.ToString()));
1118                                         value = new SqlXml (stream);
1119                                 } else {
1120                                         throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1121                                 }
1122                         }
1123                         return (SqlXml) value;
1124                 }
1125 #endif // NET_2_0
1126
1127                 public
1128 #if NET_2_0
1129                 virtual
1130 #endif
1131                 object GetSqlValue (int i)
1132                 {
1133                         int dbType, csize;
1134                         TdsColumnType ctype;
1135                         
1136                         if (i < 0 || i >= command.Tds.Columns.Count)
1137                                 throw new IndexOutOfRangeException ();
1138 #if NET_2_0
1139                         ctype = (TdsColumnType) command.Tds.Columns[i].ColumnType;
1140                         csize = (int) command.Tds.Columns[i].ColumnSize;
1141 #else
1142                         ctype = (TdsColumnType) command.Tds.Columns[i]["ColumnType"];
1143                         csize = (int) command.Tds.Columns[i]["ColumnSize"];
1144 #endif
1145                         GetSchemaRowDbType (ctype, csize, out dbType);
1146                         SqlDbType type = (SqlDbType) dbType;
1147                         object value = GetValue (i);
1148
1149                         switch (type) {
1150                         case SqlDbType.BigInt:
1151                                 if (value == DBNull.Value)
1152                                         return SqlInt64.Null;
1153                                 return (SqlInt64) ((long) value);
1154                         case SqlDbType.Binary:
1155                         case SqlDbType.Image:
1156                         case SqlDbType.VarBinary:
1157                         case SqlDbType.Timestamp:
1158                                 if (value == DBNull.Value)
1159                                         return SqlBinary.Null;
1160                                 return (SqlBinary) ((byte[]) value);
1161                         case SqlDbType.Bit:
1162                                 if (value == DBNull.Value)
1163                                         return SqlBoolean.Null;
1164                                 return (SqlBoolean) ((bool) value);
1165                         case SqlDbType.Char:
1166                         case SqlDbType.NChar:
1167                         case SqlDbType.NText:
1168                         case SqlDbType.NVarChar:
1169                         case SqlDbType.Text:
1170                         case SqlDbType.VarChar:
1171                                 if (value == DBNull.Value)
1172                                         return SqlString.Null;
1173                                 return (SqlString) ((string) value);
1174                         case SqlDbType.DateTime:
1175                         case SqlDbType.SmallDateTime:
1176                                 if (value == DBNull.Value)
1177                                         return SqlDateTime.Null;
1178                                 return (SqlDateTime) ((DateTime) value);
1179                         case SqlDbType.Decimal:
1180                                 if (value == DBNull.Value)
1181                                         return SqlDecimal.Null;
1182                                 if (value is TdsBigDecimal)
1183                                         return SqlDecimal.FromTdsBigDecimal ((TdsBigDecimal) value);
1184                                 return (SqlDecimal) ((decimal) value);
1185                         case SqlDbType.Float:
1186                                 if (value == DBNull.Value)
1187                                         return SqlDouble.Null;
1188                                 return (SqlDouble) ((double) value);
1189                         case SqlDbType.Int:
1190                                 if (value == DBNull.Value)
1191                                         return SqlInt32.Null;
1192                                 return (SqlInt32) ((int) value);
1193                         case SqlDbType.Money:
1194                         case SqlDbType.SmallMoney:
1195                                 if (value == DBNull.Value)
1196                                         return SqlMoney.Null;
1197                                 return (SqlMoney) ((decimal) value);
1198                         case SqlDbType.Real:
1199                                 if (value == DBNull.Value)
1200                                         return SqlSingle.Null;
1201                                 return (SqlSingle) ((float) value);
1202                         case SqlDbType.UniqueIdentifier:
1203                                 if (value == DBNull.Value)
1204                                         return SqlGuid.Null;
1205                                 return (SqlGuid) ((Guid) value);
1206                         case SqlDbType.SmallInt:
1207                                 if (value == DBNull.Value)
1208                                         return SqlInt16.Null;
1209                                 return (SqlInt16) ((short) value);
1210                         case SqlDbType.TinyInt:
1211                                 if (value == DBNull.Value)
1212                                         return SqlByte.Null;
1213                                 return (SqlByte) ((byte) value);
1214 #if NET_2_0
1215                         case SqlDbType.Xml:
1216                                 if (value == DBNull.Value)
1217                                         return SqlByte.Null;
1218                                 return (SqlXml) value;
1219 #endif
1220                         }
1221
1222                         throw new InvalidOperationException ("The type of this column is unknown.");
1223                 }
1224
1225                 public
1226 #if NET_2_0
1227                 virtual
1228 #endif
1229                 int GetSqlValues (object[] values)
1230                 {
1231                         int count = 0;
1232                         int columnCount = command.Tds.Columns.Count;
1233                         int arrayCount = values.Length;
1234
1235                         if (arrayCount > columnCount)
1236                                 count = columnCount;
1237                         else
1238                                 count = arrayCount;
1239
1240                         for (int i = 0; i < count; i += 1) 
1241                                 values [i] = GetSqlValue (i);
1242
1243                         return count;
1244                 }
1245
1246                 public
1247 #if NET_2_0
1248                 override
1249 #endif // NET_2_0
1250                 string GetString (int i)
1251                 {
1252                         object value = GetValue (i);
1253                         if (!(value is string)) {
1254                                 if (value is DBNull) throw new SqlNullValueException ();
1255                                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1256                         }
1257                         return (string) value;
1258                 }
1259
1260                 public
1261 #if NET_2_0
1262                 override
1263 #endif // NET_2_0
1264                 object GetValue (int i)
1265                 {
1266                         if (i < 0 || i >= command.Tds.Columns.Count)
1267                                 throw new IndexOutOfRangeException ();
1268
1269                         try {
1270                                 if ((command.CommandBehavior & CommandBehavior.SequentialAccess) != 0) {
1271                                         return ((Tds)command.Tds).GetSequentialColumnValue (i);
1272                                 }
1273                         } catch (TdsInternalException ex) {
1274                                 command.Connection.Close ();
1275                                 throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
1276                         }
1277
1278                         return command.Tds.ColumnValues [i];
1279                 }
1280
1281                 public
1282 #if NET_2_0
1283                 override
1284 #endif // NET_2_0
1285                 int GetValues (object[] values)
1286                 {
1287                         int len = values.Length;
1288                         int bigDecimalIndex = command.Tds.ColumnValues.BigDecimalIndex;
1289
1290                         // If a four-byte decimal is stored, then we can't convert to
1291                         // a native type.  Throw an OverflowException.
1292                         if (bigDecimalIndex >= 0 && bigDecimalIndex < len)
1293                                 throw new OverflowException ();
1294                         try {
1295                                 command.Tds.ColumnValues.CopyTo (0, values, 0,
1296                                                                  len > command.Tds.ColumnValues.Count ? command.Tds.ColumnValues.Count : len);
1297                         } catch (TdsInternalException ex) {
1298                                 command.Connection.Close ();
1299                                 throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
1300                         }
1301                         return (len < FieldCount ? len : FieldCount);
1302                 }
1303
1304 #if !NET_2_0
1305                 void IDisposable.Dispose ()
1306                 {
1307                         Dispose (true);
1308                         GC.SuppressFinalize (this);
1309                 }
1310 #endif
1311
1312 #if NET_2_0
1313                 public override IEnumerator GetEnumerator ()
1314 #else
1315                 IEnumerator IEnumerable.GetEnumerator ()
1316 #endif
1317                 {
1318                         return new DbEnumerator (this);
1319                 }
1320
1321                 public
1322 #if NET_2_0
1323                 override
1324 #endif // NET_2_0
1325                 bool IsDBNull (int i)
1326                 {
1327                         return GetValue (i) == DBNull.Value;
1328                 }
1329
1330                 public
1331 #if NET_2_0
1332                 override
1333 #endif // NET_2_0
1334                 bool NextResult ()
1335                 {
1336                         ValidateState ();
1337
1338                         if ((command.CommandBehavior & CommandBehavior.SingleResult) != 0 && resultsRead > 0)
1339                                 return false;
1340
1341                         try {
1342                                 moreResults = command.Tds.NextResult ();
1343                         } catch (TdsInternalException ex) {
1344                                 command.Connection.Close ();
1345                                 throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
1346                         }
1347                         if (!moreResults)
1348                                 command.GetOutputParameters ();
1349                         else {
1350                                 // new schema - don't do anything except reset schemaTable as command.Tds.Columns is already updated
1351                                 schemaTable = null;
1352                                 dataTypeNames = null;
1353                         }
1354
1355                         rowsRead = 0;
1356                         resultsRead += 1;
1357                         return moreResults;
1358                 }
1359
1360                 public
1361 #if NET_2_0
1362                 override
1363 #endif // NET_2_0
1364                 bool Read ()
1365                 {
1366                         ValidateState ();
1367
1368                         if ((command.CommandBehavior & CommandBehavior.SingleRow) != 0 && rowsRead > 0)
1369                                 return false;
1370                         if ((command.CommandBehavior & CommandBehavior.SchemaOnly) != 0)
1371                                 return false;
1372                         if (!moreResults)
1373                                 return false;
1374         
1375                         if ((haveRead) && (!readResultUsed))
1376                         {
1377                                 readResultUsed = true;
1378                                 return true;
1379                         }
1380                         return (ReadRecord ());
1381                 }
1382
1383                 internal bool ReadRecord ()
1384                 {
1385                         try {
1386                                 bool result = command.Tds.NextRow ();
1387                         
1388                                 rowsRead += 1;
1389                                 return result;
1390                         } catch (TdsInternalException ex) {
1391                                 command.Connection.Close ();
1392                                 throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
1393                         }
1394                 }
1395                 
1396                 void ValidateState ()
1397                 {
1398                         if (IsClosed)
1399                                 throw new InvalidOperationException ("Invalid attempt to read data when reader is closed");
1400                 }
1401                 
1402 #if NET_2_0
1403                 public override Type GetProviderSpecificFieldType (int i)
1404                 {
1405                         return (GetSqlValue (i).GetType());
1406                 }
1407
1408                 public override object GetProviderSpecificValue (int i)
1409                 {
1410                         return (GetSqlValue (i));
1411                 }
1412
1413                 public override int GetProviderSpecificValues (object [] values)
1414                 {
1415                         return (GetSqlValues (values));
1416                 }
1417
1418                 public virtual SqlBytes GetSqlBytes (int i)
1419                 {
1420                         //object value = GetSqlValue (i);
1421                         //if (!(value is SqlBinary))
1422                         //      throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1423                         Byte[] val = (byte[])GetValue(i);
1424                         SqlBytes sb = new SqlBytes (val);
1425                         return (sb);
1426                 }
1427 #endif // NET_2_0
1428
1429                 #endregion // Methods
1430         }
1431 }