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