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