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