2002-11-18 Tim Coleman <tim@timcoleman.com>
[mono.git] / mcs / class / System.Data / System.Data.SqlClient / SqlDataReader.cs
1 //
2 // System.Data.SqlClient.SqlDataReader.cs
3 //
4 // Author:
5 //   Rodrigo Moya (rodrigo@ximian.com)
6 //   Daniel Morgan (danmorg@sc.rr.com)
7 //   Tim Coleman (tim@timcoleman.com)
8 //
9 // (C) Ximian, Inc 2002
10 // (C) Daniel Morgan 2002
11 // Copyright (C) Tim Coleman, 2002
12 //
13
14 using Mono.Data.TdsClient.Internal;
15 using System;
16 using System.Collections;
17 using System.ComponentModel;
18 using System.Data;
19 using System.Data.Common;
20 using System.Data.SqlTypes;
21
22 namespace System.Data.SqlClient {
23         public sealed class SqlDataReader : MarshalByRefObject, IEnumerable, IDataReader, IDisposable, IDataRecord
24         {
25                 #region Fields
26
27                 SqlCommand command;
28                 ArrayList dataTypeNames;
29                 bool disposed = false;
30                 int fieldCount;
31                 bool isClosed;
32                 bool isSelect;
33                 bool moreResults;
34                 int resultsRead;
35                 int rowsRead;
36                 DataTable schemaTable;
37
38                 #endregion // Fields
39
40                 #region Constructors
41
42                 internal SqlDataReader (SqlCommand command)
43                 {
44                         this.command = command;
45                         schemaTable = ConstructSchemaTable ();
46                         resultsRead = 0;
47                         fieldCount = 0;
48                         isClosed = false;
49                         isSelect = (command.CommandText.Trim ().ToUpper ().StartsWith ("SELECT"));
50                         command.Tds.RecordsAffected = 0;
51                         NextResult ();
52                 }
53
54                 #endregion // Constructors
55
56                 #region Properties
57
58                 public int Depth {
59                         get { return 0; }
60                 }
61
62                 public int FieldCount {
63                         get { return fieldCount; }
64                 }
65
66                 public bool IsClosed {
67                         get { return isClosed; }
68                 }
69
70                 public object this [int i] {
71                         get { return GetValue (i); }
72                 }
73
74                 public object this [string name] {
75                         get { return GetValue (GetOrdinal (name)); }
76                 }
77         
78                 public int RecordsAffected {
79                         get { 
80                                 if (isSelect) 
81                                         return -1;
82                                 else
83                                         return command.Tds.RecordsAffected; 
84                         }
85                 }
86
87                 #endregion // Properties
88
89                 #region Methods
90
91                 public void Close ()
92                 {
93                         isClosed = true;
94                         command.CloseDataReader (moreResults);
95                 }
96
97                 private static DataTable ConstructSchemaTable ()
98                 {
99                         Type booleanType = Type.GetType ("System.Boolean");
100                         Type stringType = Type.GetType ("System.String");
101                         Type intType = Type.GetType ("System.Int32");
102                         Type typeType = Type.GetType ("System.Type");
103                         Type shortType = Type.GetType ("System.Int16");
104
105                         DataTable schemaTable = new DataTable ("SchemaTable");
106                         schemaTable.Columns.Add ("ColumnName", stringType);
107                         schemaTable.Columns.Add ("ColumnOrdinal", intType);
108                         schemaTable.Columns.Add ("ColumnSize", intType);
109                         schemaTable.Columns.Add ("NumericPrecision", shortType);
110                         schemaTable.Columns.Add ("NumericScale", shortType);
111                         schemaTable.Columns.Add ("IsUnique", booleanType);
112                         schemaTable.Columns.Add ("IsKey", booleanType);
113                         schemaTable.Columns.Add ("BaseServerName", stringType);
114                         schemaTable.Columns.Add ("BaseCatalogName", stringType);
115                         schemaTable.Columns.Add ("BaseColumnName", stringType);
116                         schemaTable.Columns.Add ("BaseSchemaName", stringType);
117                         schemaTable.Columns.Add ("BaseTableName", stringType);
118                         schemaTable.Columns.Add ("DataType", typeType);
119                         schemaTable.Columns.Add ("AllowDBNull", booleanType);
120                         schemaTable.Columns.Add ("ProviderType", intType);
121                         schemaTable.Columns.Add ("IsAliased", booleanType);
122                         schemaTable.Columns.Add ("IsExpression", booleanType);
123                         schemaTable.Columns.Add ("IsIdentity", booleanType);
124                         schemaTable.Columns.Add ("IsAutoIncrement", booleanType);
125                         schemaTable.Columns.Add ("IsRowVersion", booleanType);
126                         schemaTable.Columns.Add ("IsHidden", booleanType);
127                         schemaTable.Columns.Add ("IsLong", booleanType);
128                         schemaTable.Columns.Add ("IsReadOnly", booleanType);
129
130                         return schemaTable;
131                 }
132
133                 private void Dispose (bool disposing) 
134                 {
135                         if (!disposed) {
136                                 if (disposing) {
137                                         schemaTable.Dispose ();
138                                         Close ();
139                                 }
140                                 disposed = true;
141                         }
142                 }
143
144                 public bool GetBoolean (int i)
145                 {
146                         object value = GetValue (i);
147                         if (!(value is bool))
148                                 throw new InvalidCastException ();
149                         return (bool) value;
150                 }
151
152                 public byte GetByte (int i)
153                 {
154                         object value = GetValue (i);
155                         if (!(value is byte))
156                                 throw new InvalidCastException ();
157                         return (byte) value;
158                 }
159
160                 public long GetBytes (int i, long dataIndex, byte[] buffer, int bufferIndex, int length)
161                 {
162                         object value = GetValue (i);
163                         if (!(value is byte []))
164                                 throw new InvalidCastException ();
165                         Array.Copy ((byte []) value, (int) dataIndex, buffer, bufferIndex, length);
166                         return ((byte []) value).Length - dataIndex;
167                 }
168
169                 public char GetChar (int i)
170                 {
171                         object value = GetValue (i);
172                         if (!(value is char))
173                                 throw new InvalidCastException ();
174                         return (char) value;
175                 }
176
177                 public long GetChars (int i, long dataIndex, char[] buffer, int bufferIndex, int length)
178                 {
179                         object value = GetValue (i);
180                         if (!(value is char[]))
181                                 throw new InvalidCastException ();
182                         Array.Copy ((char []) value, (int) dataIndex, buffer, bufferIndex, length);
183                         return ((char []) value).Length - dataIndex;
184                 }
185
186                 [MonoTODO ("Implement GetData")]
187                 public IDataReader GetData (int i)
188                 {
189                         throw new NotImplementedException ();
190                 }
191
192                 public string GetDataTypeName (int i)
193                 {
194                         return (string) dataTypeNames [i];
195                 }
196
197                 public DateTime GetDateTime (int i)
198                 {
199                         object value = GetValue (i);
200                         if (!(value is DateTime))
201                                 throw new InvalidCastException ();
202                         return (DateTime) value;
203                 }
204
205                 public decimal GetDecimal (int i)
206                 {
207                         object value = GetValue (i);
208                         if (!(value is decimal))
209                                 throw new InvalidCastException ();
210                         return (decimal) value;
211                 }
212
213                 public double GetDouble (int i)
214                 {
215                         object value = GetValue (i);
216                         if (!(value is double))
217                                 throw new InvalidCastException ();
218                         return (double) value;
219                 }
220
221                 public Type GetFieldType (int i)
222                 {
223                         return (Type) schemaTable.Rows[i]["DataType"];
224                 }
225
226                 public float GetFloat (int i)
227                 {
228                         object value = GetValue (i);
229                         if (!(value is float))
230                                 throw new InvalidCastException ();
231                         return (float) value;
232                 }
233
234                 public Guid GetGuid (int i)
235                 {
236                         object value = GetValue (i);
237                         if (!(value is Guid))
238                                 throw new InvalidCastException ();
239                         return (Guid) value;
240                 }
241
242                 public short GetInt16 (int i)
243                 {
244                         object value = GetValue (i);
245                         if (!(value is short))
246                                 throw new InvalidCastException ();
247                         return (short) value;
248                 }
249
250                 public int GetInt32 (int i)
251                 {
252                         object value = GetValue (i);
253                         if (!(value is int))
254                                 throw new InvalidCastException ();
255                         return (int) value;
256                 }
257
258                 public long GetInt64 (int i)
259                 {
260                         object value = GetValue (i);
261                         if (!(value is long))
262                                 throw new InvalidCastException ();
263                         return (long) value;
264                 }
265
266                 public string GetName (int i)
267                 {
268                         return (string) schemaTable.Rows[i]["ColumnName"];
269                 }
270
271                 public int GetOrdinal (string name)
272                 {
273                         foreach (DataRow schemaRow in schemaTable.Rows)
274                                 if (((string) schemaRow ["ColumnName"]).Equals (name))
275                                         return (int) schemaRow ["ColumnOrdinal"];
276                         foreach (DataRow schemaRow in schemaTable.Rows)
277                                 if (String.Compare (((string) schemaRow ["ColumnName"]), name, true) == 0)
278                                         return (int) schemaRow ["ColumnOrdinal"];
279                         throw new IndexOutOfRangeException ();
280                 }
281
282                 public DataTable GetSchemaTable ()
283                 {
284                         if (schemaTable.Rows != null && schemaTable.Rows.Count > 0)
285                                 return schemaTable;
286
287                         if (!moreResults)
288                                 return null;
289
290                         fieldCount = 0;
291
292                         dataTypeNames = new ArrayList ();
293
294                         foreach (TdsSchemaInfo schema in command.Tds.Schema) {
295                                 DataRow row = schemaTable.NewRow ();
296
297                                 row ["ColumnName"]              = GetSchemaValue (schema, "ColumnName");
298                                 row ["ColumnSize"]              = GetSchemaValue (schema, "ColumnSize"); 
299                                 row ["ColumnOrdinal"]           = GetSchemaValue (schema, "ColumnOrdinal");
300                                 row ["NumericPrecision"]        = GetSchemaValue (schema, "NumericPrecision");
301                                 row ["NumericScale"]            = GetSchemaValue (schema, "NumericScale");
302                                 row ["IsUnique"]                = GetSchemaValue (schema, "IsUnique");
303                                 row ["IsKey"]                   = GetSchemaValue (schema, "IsKey");
304                                 row ["BaseServerName"]          = GetSchemaValue (schema, "BaseServerName");
305                                 row ["BaseCatalogName"]         = GetSchemaValue (schema, "BaseCatalogName");
306                                 row ["BaseColumnName"]          = GetSchemaValue (schema, "BaseColumnName");
307                                 row ["BaseSchemaName"]          = GetSchemaValue (schema, "BaseSchemaName");
308                                 row ["BaseTableName"]           = GetSchemaValue (schema, "BaseTableName");
309                                 row ["AllowDBNull"]             = GetSchemaValue (schema, "AllowDBNull");
310                                 row ["IsAliased"]               = GetSchemaValue (schema, "IsAliased");
311                                 row ["IsExpression"]            = GetSchemaValue (schema, "IsExpression");
312                                 row ["IsIdentity"]              = GetSchemaValue (schema, "IsIdentity");
313                                 row ["IsAutoIncrement"]         = GetSchemaValue (schema, "IsAutoIncrement");
314                                 row ["IsRowVersion"]            = GetSchemaValue (schema, "IsRowVersion");
315                                 row ["IsHidden"]                = GetSchemaValue (schema, "IsHidden");
316                                 row ["IsReadOnly"]              = GetSchemaValue (schema, "IsReadOnly");
317
318                                 // We don't always get the base column name.
319                                 if (row ["BaseColumnName"] == DBNull.Value)
320                                         row ["BaseColumnName"] = row ["ColumnName"];
321
322                                 switch ((TdsColumnType) schema ["ColumnType"]) {
323                                         case TdsColumnType.Image :
324                                                 dataTypeNames.Add ("image");
325                                                 row ["ProviderType"] = (int) SqlDbType.Image;
326                                                 row ["DataType"] = typeof (byte[]);
327                                                 row ["IsLong"] = true;
328                                                 break;
329                                         case TdsColumnType.Text :
330                                                 dataTypeNames.Add ("text");
331                                                 row ["ProviderType"] = (int) SqlDbType.Text;
332                                                 row ["DataType"] = typeof (string);
333                                                 row ["IsLong"] = true;
334                                                 break;
335                                         case TdsColumnType.UniqueIdentifier :
336                                                 dataTypeNames.Add ("uniqueidentifier");
337                                                 row ["ProviderType"] = (int) SqlDbType.UniqueIdentifier;
338                                                 row ["DataType"] = typeof (Guid);
339                                                 row ["IsLong"] = false;
340                                                 break;
341                                         case TdsColumnType.VarBinary :
342                                         case TdsColumnType.BigVarBinary :
343                                                 dataTypeNames.Add ("varbinary");
344                                                 row ["ProviderType"] = (int) SqlDbType.VarBinary;
345                                                 row ["DataType"] = typeof (byte[]);
346                                                 row ["IsLong"] = true;
347                                                 break;
348                                         case TdsColumnType.IntN :
349                                         case TdsColumnType.Int4 :
350                                                 dataTypeNames.Add ("int");
351                                                 row ["ProviderType"] = (int) SqlDbType.Int;
352                                                 row ["DataType"] = typeof (int);
353                                                 row ["IsLong"] = false;
354                                                 break;
355                                         case TdsColumnType.VarChar :
356                                         case TdsColumnType.BigVarChar :
357                                                 dataTypeNames.Add ("varchar");
358                                                 row ["ProviderType"] = (int) SqlDbType.VarChar;
359                                                 row ["DataType"] = typeof (string);
360                                                 row ["IsLong"] = false;
361                                                 break;
362                                         case TdsColumnType.Binary :
363                                         case TdsColumnType.BigBinary :
364                                                 dataTypeNames.Add ("binary");
365                                                 row ["ProviderType"] = (int) SqlDbType.Binary;
366                                                 row ["DataType"] = typeof (byte[]);
367                                                 row ["IsLong"] = true;
368                                                 break;
369                                         case TdsColumnType.Char :
370                                         case TdsColumnType.BigChar :
371                                                 dataTypeNames.Add ("char");
372                                                 row ["ProviderType"] = (int) SqlDbType.Char;
373                                                 row ["DataType"] = typeof (string);
374                                                 row ["IsLong"] = false;
375                                                 break;
376                                         case TdsColumnType.Int1 :
377                                                 dataTypeNames.Add ("tinyint");
378                                                 row ["ProviderType"] = (int) SqlDbType.TinyInt;
379                                                 row ["DataType"] = typeof (byte);
380                                                 row ["IsLong"] = false;
381                                                 break;
382                                         case TdsColumnType.Bit :
383                                         case TdsColumnType.BitN :
384                                                 dataTypeNames.Add ("bit");
385                                                 row ["ProviderType"] = (int) SqlDbType.Bit;
386                                                 row ["DataType"] = typeof (bool);
387                                                 row ["IsLong"] = false;
388                                                 break;
389                                         case TdsColumnType.Int2 :
390                                                 dataTypeNames.Add ("smallint");
391                                                 row ["ProviderType"] = (int) SqlDbType.SmallInt;
392                                                 row ["DataType"] = typeof (short);
393                                                 row ["IsLong"] = false;
394                                                 break;
395                                         case TdsColumnType.DateTime4 :
396                                         case TdsColumnType.DateTime :
397                                         case TdsColumnType.DateTimeN :
398                                                 dataTypeNames.Add ("datetime");
399                                                 row ["ProviderType"] = (int) SqlDbType.DateTime;
400                                                 row ["DataType"] = typeof (DateTime);
401                                                 row ["IsLong"] = false;
402                                                 break;
403                                         case TdsColumnType.Real :
404                                                 dataTypeNames.Add ("real");
405                                                 row ["ProviderType"] = (int) SqlDbType.Real;
406                                                 row ["DataType"] = typeof (float);
407                                                 break;
408                                         case TdsColumnType.Money :
409                                         case TdsColumnType.MoneyN :
410                                         case TdsColumnType.Money4 :
411                                                 dataTypeNames.Add ("money");
412                                                 row ["ProviderType"] = (int) SqlDbType.Money;
413                                                 row ["DataType"] = typeof (decimal);
414                                                 row ["IsLong"] = false;
415                                                 break;
416                                         case TdsColumnType.Float8 :
417                                         case TdsColumnType.FloatN :
418                                                 dataTypeNames.Add ("float");
419                                                 row ["ProviderType"] = (int) SqlDbType.Float;
420                                                 row ["DataType"] = typeof (double);
421                                                 row ["IsLong"] = false;
422                                                 break;
423                                         case TdsColumnType.NText :
424                                                 dataTypeNames.Add ("ntext");
425                                                 row ["ProviderType"] = (int) SqlDbType.NText;
426                                                 row ["DataType"] = typeof (string);
427                                                 row ["IsLong"] = true;
428                                                 break;
429                                         case TdsColumnType.NVarChar :
430                                                 dataTypeNames.Add ("nvarchar");
431                                                 row ["ProviderType"] = (int) SqlDbType.NVarChar;
432                                                 row ["DataType"] = typeof (string);
433                                                 row ["IsLong"] = false;
434                                                 break;
435                                         case TdsColumnType.Decimal :
436                                         case TdsColumnType.Numeric :
437                                                 dataTypeNames.Add ("decimal");
438                                                 row ["ProviderType"] = (int) SqlDbType.Decimal;
439                                                 row ["DataType"] = typeof (decimal);
440                                                 row ["IsLong"] = false;
441                                                 break;
442                                         case TdsColumnType.NChar :
443                                                 dataTypeNames.Add ("nchar");
444                                                 row ["ProviderType"] = (int) SqlDbType.NChar;
445                                                 row ["DataType"] = typeof (string);
446                                                 row ["IsLong"] = false;
447                                                 break;
448                                         case TdsColumnType.SmallMoney :
449                                                 dataTypeNames.Add ("smallmoney");
450                                                 row ["ProviderType"] = (int) SqlDbType.SmallMoney;
451                                                 row ["DataType"] = typeof (decimal);
452                                                 row ["IsLong"] = false;
453                                                 break;
454                                         default :
455                                                 dataTypeNames.Add ("variant");
456                                                 row ["ProviderType"] = (int) SqlDbType.Variant;
457                                                 row ["DataType"] = typeof (object);
458                                                 row ["IsLong"] = false;
459                                                 break;
460                                 }
461
462                                 schemaTable.Rows.Add (row);
463
464                                 fieldCount += 1;
465                         }
466                         return schemaTable;
467                 }               
468
469                 private static object GetSchemaValue (TdsSchemaInfo schema, object key)
470                 {
471                         if (schema.ContainsKey (key) && schema [key] != null)
472                                 return schema [key];
473                         return DBNull.Value;
474                 }
475
476                 public SqlBinary GetSqlBinary (int i)
477                 {
478                         throw new NotImplementedException ();
479                 }
480
481                 public SqlBoolean GetSqlBoolean (int i) 
482                 {
483                         object value = GetSqlValue (i);
484                         if (!(value is SqlBoolean))
485                                 throw new InvalidCastException ();
486                         return (SqlBoolean) value;
487                 }
488
489                 public SqlByte GetSqlByte (int i)
490                 {
491                         object value = GetSqlValue (i);
492                         if (!(value is SqlByte))
493                                 throw new InvalidCastException ();
494                         return (SqlByte) value;
495                 }
496
497                 public SqlDateTime GetSqlDateTime (int i)
498                 {
499                         object value = GetSqlValue (i);
500                         if (!(value is SqlDateTime))
501                                 throw new InvalidCastException ();
502                         return (SqlDateTime) value;
503                 }
504
505                 public SqlDecimal GetSqlDecimal (int i)
506                 {
507                         object value = GetSqlValue (i);
508                         if (!(value is SqlDecimal))
509                                 throw new InvalidCastException ();
510                         return (SqlDecimal) value;
511                 }
512
513                 public SqlDouble GetSqlDouble (int i)
514                 {
515                         object value = GetSqlValue (i);
516                         if (!(value is SqlDouble))
517                                 throw new InvalidCastException ();
518                         return (SqlDouble) value;
519                 }
520
521                 public SqlGuid GetSqlGuid (int i)
522                 {
523                         object value = GetSqlValue (i);
524                         if (!(value is SqlGuid))
525                                 throw new InvalidCastException ();
526                         return (SqlGuid) value;
527                 }
528
529                 public SqlInt16 GetSqlInt16 (int i)
530                 {
531                         object value = GetSqlValue (i);
532                         if (!(value is SqlInt16))
533                                 throw new InvalidCastException ();
534                         return (SqlInt16) value;
535                 }
536
537                 public SqlInt32 GetSqlInt32 (int i)
538                 {
539                         object value = GetSqlValue (i);
540                         if (!(value is SqlInt32))
541                                 throw new InvalidCastException ();
542                         return (SqlInt32) value;
543                 }
544
545                 public SqlInt64 GetSqlInt64 (int i)
546                 {
547                         object value = GetSqlValue (i);
548                         if (!(value is SqlInt64))
549                                 throw new InvalidCastException ();
550                         return (SqlInt64) value;
551                 }
552
553                 public SqlMoney GetSqlMoney (int i)
554                 {
555                         object value = GetSqlValue (i);
556                         if (!(value is SqlMoney))
557                                 throw new InvalidCastException ();
558                         return (SqlMoney) value;
559                 }
560
561                 public SqlSingle GetSqlSingle (int i)
562                 {
563                         object value = GetSqlValue (i);
564                         if (!(value is SqlSingle))
565                                 throw new InvalidCastException ();
566                         return (SqlSingle) value;
567                 }
568
569                 public SqlString GetSqlString (int i)
570                 {
571                         object value = GetSqlValue (i);
572                         if (!(value is SqlString))
573                                 throw new InvalidCastException ();
574                         return (SqlString) value;
575                 }
576
577                 [MonoTODO ("Implement TdsBigDecimal conversion.  SqlDbType.Real fails tests?")]
578                 public object GetSqlValue (int i)
579                 {
580                         SqlDbType type = (SqlDbType) (schemaTable.Rows [i]["ProviderType"]);
581                         object value = GetValue (i);
582
583                         switch (type) {
584                         case SqlDbType.BigInt:
585                                 if (value == null)
586                                         return SqlInt64.Null;
587                                 return (SqlInt64) ((long) value);
588                         case SqlDbType.Binary:
589                         case SqlDbType.Image:
590                         case SqlDbType.VarBinary:
591                         case SqlDbType.Timestamp:
592                                 if (value == null)
593                                         return SqlBinary.Null;
594                                 return (SqlBinary) ((byte[]) value);
595                         case SqlDbType.Bit:
596                                 if (value == null)
597                                         return SqlBoolean.Null;
598                                 return (SqlBoolean) ((bool) value);
599                         case SqlDbType.Char:
600                         case SqlDbType.NChar:
601                         case SqlDbType.NText:
602                         case SqlDbType.NVarChar:
603                         case SqlDbType.Text:
604                         case SqlDbType.VarChar:
605                                 if (value == null)
606                                         return SqlString.Null;
607                                 return (SqlString) ((string) value);
608                         case SqlDbType.DateTime:
609                         case SqlDbType.SmallDateTime:
610                                 if (value == null)
611                                         return SqlDateTime.Null;
612                                 return (SqlDateTime) ((DateTime) value);
613                         case SqlDbType.Decimal:
614                                 if (value == null)
615                                         return SqlDecimal.Null;
616                                 if (value is TdsBigDecimal)
617                                         return SqlDecimal.FromTdsBigDecimal ((TdsBigDecimal) value);
618                                 return (SqlDecimal) ((decimal) value);
619                         case SqlDbType.Float:
620                                 if (value == null)
621                                         return SqlDouble.Null;
622                                 return (SqlDouble) ((double) value);
623                         case SqlDbType.Int:
624                                 if (value == null)
625                                         return SqlInt32.Null;
626                                 return (SqlInt32) ((int) value);
627                         case SqlDbType.Money:
628                         case SqlDbType.SmallMoney:
629                                 if (value == null)
630                                         return SqlMoney.Null;
631                                 return (SqlMoney) ((decimal) value);
632                         case SqlDbType.Real:
633                                 if (value == null)
634                                         return SqlSingle.Null;
635                                 return (SqlSingle) ((float) value);
636                         case SqlDbType.UniqueIdentifier:
637                                 if (value == null)
638                                         return SqlGuid.Null;
639                                 return (SqlGuid) ((Guid) value);
640                         case SqlDbType.SmallInt:
641                                 if (value == null)
642                                         return SqlInt16.Null;
643                                 return (SqlInt16) ((short) value);
644                         case SqlDbType.TinyInt:
645                                 if (value == null)
646                                         return SqlByte.Null;
647                                 return (SqlByte) ((byte) value);
648                         }
649
650                         throw new InvalidOperationException ("The type of this column is unknown.");
651                 }
652
653                 public int GetSqlValues (object[] values)
654                 {
655                         int count = 0;
656                         int columnCount = schemaTable.Rows.Count;
657                         int arrayCount = values.Length;
658
659                         if (arrayCount > columnCount)
660                                 count = columnCount;
661                         else
662                                 count = arrayCount;
663
664                         for (int i = 0; i < count; i += 1) 
665                                 values [i] = GetSqlValue (i);
666
667                         return count;
668                 }
669
670                 public string GetString (int i)
671                 {
672                         object value = GetValue (i);
673                         if (!(value is string))
674                                 throw new InvalidCastException ();
675                         return (string) value;
676                 }
677
678                 public object GetValue (int i)
679                 {
680                         return command.Tds.ColumnValues [i];
681                 }
682
683                 public int GetValues (object[] values)
684                 {
685                         int len = values.Length;
686                         int bigDecimalIndex = command.Tds.ColumnValues.BigDecimalIndex;
687
688                         // If a four-byte decimal is stored, then we can't convert to
689                         // a native type.  Throw an OverflowException.
690                         if (bigDecimalIndex >= 0 && bigDecimalIndex < len)
691                                 throw new OverflowException ();
692
693                         command.Tds.ColumnValues.CopyTo (0, values, 0, len);
694                         return (len > FieldCount ? len : FieldCount);
695                 }
696
697                 void IDisposable.Dispose ()
698                 {
699                         Dispose (true);
700                         GC.SuppressFinalize (this);
701                 }
702
703                 IEnumerator IEnumerable.GetEnumerator ()
704                 {
705                         return new DbEnumerator (this);
706                 }
707
708                 public bool IsDBNull (int i)
709                 {
710                         return GetValue (i) == null;
711                 }
712
713                 public bool NextResult ()
714                 {
715                         if ((command.CommandBehavior & CommandBehavior.SingleResult) != 0 && resultsRead > 0)
716                                 return false;
717                         if (command.Tds.DoneProc)
718                                 return false;
719
720                         schemaTable.Rows.Clear ();
721
722                         moreResults = command.Tds.NextResult ();
723                         GetSchemaTable ();
724
725                         rowsRead = 0;
726                         resultsRead += 1;
727                         return moreResults;
728                 }
729
730                 public bool Read ()
731                 {
732                         if ((command.CommandBehavior & CommandBehavior.SingleRow) != 0 && rowsRead > 0)
733                                 return false;
734                         if ((command.CommandBehavior & CommandBehavior.SchemaOnly) != 0)
735                                 return false;
736                         if (!moreResults)
737                                 return false;
738
739                         bool result = command.Tds.NextRow ();
740
741                         rowsRead += 1;
742
743                         return result;
744                 }
745
746                 #endregion // Methods
747         }
748 }