2008-07-01 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mcs / class / System.Data / System.Data.SqlClient / SqlDataReader.cs
index e28529c847f2d4ced3398556a102827798a6fcbf..da688c7adb20f321c1909896e465e6c3173f9d0e 100644 (file)
@@ -36,6 +36,7 @@
 
 using Mono.Data.Tds.Protocol;
 using System;
+using System.IO;
 using System.Text;
 using System.Collections;
 using System.ComponentModel;
@@ -43,9 +44,10 @@ using System.Data;
 using System.Data.Common;
 using System.Data.SqlTypes;
 
-namespace System.Data.SqlClient {
+namespace System.Data.SqlClient
+{
 #if NET_2_0
-       public sealed class SqlDataReader : DbDataReader, IDataReader, IDisposable, IDataRecord
+       public class SqlDataReader : DbDataReader, IDataReader, IDisposable, IDataRecord
 #else
        public sealed class SqlDataReader : MarshalByRefObject, IEnumerable, IDataReader, IDisposable, IDataRecord
 #endif // NET_2_0
@@ -54,7 +56,7 @@ namespace System.Data.SqlClient {
 
                SqlCommand command;
                ArrayList dataTypeNames;
-               bool disposed = false;
+               bool disposed;
                int fieldCount;
                bool isClosed;
                bool moreResults;
@@ -65,22 +67,51 @@ namespace System.Data.SqlClient {
                bool haveRead;
                bool readResult;
                bool readResultUsed;
+#if NET_2_0
+               int visibleFieldCount;
+#endif
 
                #endregion // Fields
 
+               const int COLUMN_NAME_IDX = 0;
+               const int COLUMN_ORDINAL_IDX = 1;
+               const int COLUMN_SIZE_IDX = 2;
+               const int NUMERIC_PRECISION_IDX = 3;
+               const int NUMERIC_SCALE_IDX = 4;
+               const int IS_UNIQUE_IDX = 5;
+               const int IS_KEY_IDX = 6;
+               const int BASE_SERVER_NAME_IDX = 7;
+               const int BASE_CATALOG_NAME_IDX = 8;
+               const int BASE_COLUMN_NAME_IDX = 9;
+               const int BASE_SCHEMA_NAME_IDX = 10;
+               const int BASE_TABLE_NAME_IDX = 11;
+               const int DATA_TYPE_IDX = 12;
+               const int ALLOW_DBNULL_IDX = 13;
+               const int PROVIDER_TYPE_IDX = 14;
+               const int IS_ALIASED_IDX = 15;
+               const int IS_EXPRESSION_IDX = 16;
+               const int IS_IDENTITY_IDX = 17;
+               const int IS_AUTO_INCREMENT_IDX = 18;
+               const int IS_ROW_VERSION_IDX = 19;
+               const int IS_HIDDEN_IDX = 20;
+               const int IS_LONG_IDX = 21;
+               const int IS_READ_ONLY_IDX = 22;
+
                #region Constructors
 
-               internal SqlDataReader (SqlCommand command) 
+               internal SqlDataReader (SqlCommand command)
                {
                        readResult = false;
                        haveRead = false;
                        readResultUsed = false;
                        this.command = command;
-                       schemaTable = ConstructSchemaTable ();
                        resultsRead = 0;
                        fieldCount = 0;
                        isClosed = false;
                        command.Tds.RecordsAffected = -1;
+#if NET_2_0
+                       visibleFieldCount = 0;
+#endif
                        NextResult ();
                }
 
@@ -88,80 +119,93 @@ namespace System.Data.SqlClient {
 
                #region Properties
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                int Depth {
+               int Depth {
                        get { return 0; }
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                int FieldCount {
+               int FieldCount {
                        get { return fieldCount; }
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                bool IsClosed {
+               bool IsClosed {
                        get { return isClosed; }
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                object this [int i] {
+               object this [int i] {
                        get { return GetValue (i); }
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                object this [string name] {
+               object this [string name] {
                        get { return GetValue (GetOrdinal (name)); }
                }
        
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                int RecordsAffected {
-                       get { 
+               int RecordsAffected {
+                       get {
                                return command.Tds.RecordsAffected; 
                        }
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                bool HasRows {
+               bool HasRows {
                        get {
                                if (haveRead) 
                                        return readResult;
                        
                                haveRead = true;
                                readResult = ReadRecord ();
-                               return readResult;                                              
+                               return readResult;
                        }
                }
+#if NET_2_0
+               public override int VisibleFieldCount {
+                       get { return visibleFieldCount; }
+               }
+
+               protected SqlConnection Connection {
+                       get { return command.Connection; }
+               }
+
+               protected bool IsCommandBehavior (CommandBehavior condition) {
+                       return condition == command.CommandBehavior;
+               }
+#endif
 
                #endregion // Properties
 
                #region Methods
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                void Close ()
+               void Close ()
                {
                        if (IsClosed)
                                return;
@@ -169,17 +213,16 @@ namespace System.Data.SqlClient {
                        while (NextResult ())
                                ;
                        isClosed = true;
-                       command.Connection.DataReader = null;
                        command.CloseDataReader (moreResults);
                }
 
                private static DataTable ConstructSchemaTable ()
                {
-                       Type booleanType = Type.GetType ("System.Boolean");
-                       Type stringType = Type.GetType ("System.String");
-                       Type intType = Type.GetType ("System.Int32");
-                       Type typeType = Type.GetType ("System.Type");
-                       Type shortType = Type.GetType ("System.Int16");
+                       Type booleanType = typeof (bool);
+                       Type stringType = typeof (string);
+                       Type intType = typeof (int);
+                       Type typeType = typeof (Type);
+                       Type shortType = typeof (short);
 
                        DataTable schemaTable = new DataTable ("SchemaTable");
                        schemaTable.Columns.Add ("ColumnName", stringType);
@@ -208,14 +251,16 @@ namespace System.Data.SqlClient {
 
                        return schemaTable;
                }
+
 #if NET_2_0
-               protected override
+               new
 #endif
-               void Dispose (bool disposing) 
+               void Dispose (bool disposing)
                {
                        if (!disposed) {
                                if (disposing) {
-                                       schemaTable.Dispose ();
+                                       if (schemaTable != null)
+                                               schemaTable.Dispose ();
                                        Close ();
                                        command = null;
                                }
@@ -227,7 +272,7 @@ namespace System.Data.SqlClient {
 #if NET_2_0
                override
 #endif // NET_2_0
-                bool GetBoolean (int i)
+               bool GetBoolean (int i)
                {
                        object value = GetValue (i);
                        if (!(value is bool)) {
@@ -237,11 +282,11 @@ namespace System.Data.SqlClient {
                        return (bool) value;
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                byte GetByte (int i)
+               byte GetByte (int i)
                {
                        object value = GetValue (i);
                        if (!(value is byte)) {
@@ -251,19 +296,25 @@ namespace System.Data.SqlClient {
                        return (byte) value;
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                long GetBytes (int i, long dataIndex, byte[] buffer, int bufferIndex, int length)
+               long GetBytes (int i, long dataIndex, byte[] buffer, int bufferIndex, int length)
                {
                        if ((command.CommandBehavior & CommandBehavior.SequentialAccess) != 0) {
-                               long len = ((Tds)command.Tds).GetSequentialColumnValue (i, dataIndex, buffer, bufferIndex, length);
-                               if (len == -1)
-                                       throw new InvalidCastException ("Invalid attempt to GetBytes on column "
-                                                       + "'" + command.Tds.Columns[i]["ColumnName"] + "'." + "The GetBytes function"
-                                                       + " can only be used on columns of type Text, NText, or Image");
-                               return len;
+                               try {
+                                       long len = ((Tds)command.Tds).GetSequentialColumnValue (i, dataIndex, buffer, bufferIndex, length);
+                                       if (len == -1)
+                                               throw new InvalidCastException ("Invalid attempt to GetBytes on column "
+                                                                               + "'" + command.Tds.Columns[i]["ColumnName"] +
+                                                                               "'." + "The GetBytes function"
+                                                                               + " can only be used on columns of type Text, NText, or Image");
+                                       return len;
+                               } catch (TdsInternalException ex) {
+                                       command.Connection.Close ();
+                                       throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
+                               }
                        }
 
                        object value = GetValue (i);
@@ -284,11 +335,11 @@ namespace System.Data.SqlClient {
                }
 
                [EditorBrowsableAttribute (EditorBrowsableState.Never)]
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                char GetChar (int i)
+               char GetChar (int i)
                {
                        object value = GetValue (i);
                        if (!(value is char)) {
@@ -298,11 +349,11 @@ namespace System.Data.SqlClient {
                        return (char) value;
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                long GetChars (int i, long dataIndex, char[] buffer, int bufferIndex, int length)
+               long GetChars (int i, long dataIndex, char[] buffer, int bufferIndex, int length)
                {
                        if ((command.CommandBehavior & CommandBehavior.SequentialAccess) != 0) {
                                Encoding encoding = null;
@@ -319,7 +370,7 @@ namespace System.Data.SqlClient {
                                        case TdsColumnType.NVarChar:
                                        case TdsColumnType.NChar:
                                                encoding = Encoding.Unicode;
-                                               mul = 2 ;
+                                               mul = 2;
                                                break;
                                        default :
                                                return -1;
@@ -365,28 +416,30 @@ namespace System.Data.SqlClient {
                        }
                }
                
-               [EditorBrowsableAttribute (EditorBrowsableState.Never)] 
+#if !NET_2_0
+               [EditorBrowsableAttribute (EditorBrowsableState.Never)]
                public new IDataReader GetData (int i)
                {
                        return ((IDataReader) this [i]);
                }
+#endif
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                string GetDataTypeName (int i)
+               string GetDataTypeName (int i)
                {
                        if (i < 0 || i >= dataTypeNames.Count)
                                throw new IndexOutOfRangeException ();
                        return (string) dataTypeNames [i];
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                DateTime GetDateTime (int i)
+               DateTime GetDateTime (int i)
                {
                        object value = GetValue (i);
                        if (!(value is DateTime)) {
@@ -396,11 +449,11 @@ namespace System.Data.SqlClient {
                        return (DateTime) value;
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                decimal GetDecimal (int i)
+               decimal GetDecimal (int i)
                {
                        object value = GetValue (i);
                        if (!(value is decimal)) {
@@ -410,11 +463,11 @@ namespace System.Data.SqlClient {
                        return (decimal) value;
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                double GetDouble (int i)
+               double GetDouble (int i)
                {
                        object value = GetValue (i);
                        if (!(value is double)) {
@@ -424,22 +477,24 @@ namespace System.Data.SqlClient {
                        return (double) value;
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                Type GetFieldType (int i)
+               Type GetFieldType (int i)
                {
+                       if (schemaTable == null)
+                               schemaTable = ConstructSchemaTable ();
                        if (i < 0 || i >= schemaTable.Rows.Count)
                                throw new IndexOutOfRangeException ();
                        return (Type) schemaTable.Rows[i]["DataType"];
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                float GetFloat (int i)
+               float GetFloat (int i)
                {
                        object value = GetValue (i);
                        if (!(value is float)) {
@@ -449,11 +504,11 @@ namespace System.Data.SqlClient {
                        return (float) value;
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                Guid GetGuid (int i)
+               Guid GetGuid (int i)
                {
                        object value = GetValue (i);
                        if (!(value is Guid)) {
@@ -463,11 +518,11 @@ namespace System.Data.SqlClient {
                        return (Guid) value;
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                short GetInt16 (int i)
+               short GetInt16 (int i)
                {
                        object value = GetValue (i);
                        if (!(value is short)) {
@@ -477,11 +532,11 @@ namespace System.Data.SqlClient {
                        return (short) value;
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                int GetInt32 (int i)
+               int GetInt32 (int i)
                {
                        object value = GetValue (i);
                        if (!(value is int)) {
@@ -491,19 +546,13 @@ namespace System.Data.SqlClient {
                        return (int) value;
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                long GetInt64 (int i)
+               long GetInt64 (int i)
                {
                        object value = GetValue (i);
-                       // TDS 7.0 returns bigint as decimal(19,0)
-                       if (value is decimal) {
-                               TdsDataColumn schema = command.Tds.Columns[i];
-                               if ((byte)schema["NumericPrecision"] == 19 && (byte)schema["NumericScale"] == 0)
-                                       value = (long) (decimal) value;
-                       }
                        if (!(value is long)) {
                                if (value is DBNull) throw new SqlNullValueException ();
                                throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
@@ -511,21 +560,25 @@ namespace System.Data.SqlClient {
                        return (long) value;
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                string GetName (int i)
+               string GetName (int i)
                {
+                       if (schemaTable == null)
+                               schemaTable = ConstructSchemaTable ();
                        return (string) schemaTable.Rows[i]["ColumnName"];
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                int GetOrdinal (string name)
+               int GetOrdinal (string name)
                {
+                       if (schemaTable == null)
+                               schemaTable = ConstructSchemaTable ();
                        foreach (DataRow schemaRow in schemaTable.Rows)
                                if (((string) schemaRow ["ColumnName"]).Equals (name))
                                        return (int) schemaRow ["ColumnOrdinal"];
@@ -535,14 +588,17 @@ namespace System.Data.SqlClient {
                        throw new IndexOutOfRangeException ();
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                DataTable GetSchemaTable ()
+               DataTable GetSchemaTable ()
                {
                        ValidateState ();
 
+                       if (schemaTable == null)
+                               schemaTable = ConstructSchemaTable ();
+
                        if (schemaTable.Rows != null && schemaTable.Rows.Count > 0)
                                return schemaTable;
 
@@ -551,209 +607,267 @@ namespace System.Data.SqlClient {
 
                        fieldCount = 0;
 
-                       dataTypeNames = new ArrayList ();
+                       dataTypeNames = new ArrayList (command.Tds.Columns.Count);
 
                        foreach (TdsDataColumn schema in command.Tds.Columns) {
                                DataRow row = schemaTable.NewRow ();
 
+#if NET_2_0
+                               row [COLUMN_NAME_IDX]           = GetSchemaValue (schema.ColumnName);
+                               row [COLUMN_ORDINAL_IDX]                = GetSchemaValue (schema.ColumnOrdinal);
+                               row [IS_UNIQUE_IDX]             = GetSchemaValue (schema.IsUnique);
+                               row [IS_AUTO_INCREMENT_IDX]             = GetSchemaValue (schema.IsAutoIncrement);
+                               row [IS_ROW_VERSION_IDX]                = GetSchemaValue (schema.IsRowVersion);
+                               row [IS_HIDDEN_IDX]             = GetSchemaValue (schema.IsHidden);
+                               row [IS_IDENTITY_IDX]           = GetSchemaValue (schema.IsIdentity);
+                               row [COLUMN_SIZE_IDX]           = GetSchemaValue (schema.ColumnSize);
+                               row [NUMERIC_PRECISION_IDX]     = GetSchemaValue (schema.NumericPrecision);
+                               row [NUMERIC_SCALE_IDX]         = GetSchemaValue (schema.NumericScale);
+                               row [IS_KEY_IDX]                        = GetSchemaValue (schema.IsKey);
+                               row [IS_ALIASED_IDX]            = GetSchemaValue (schema.IsAliased);
+                               row [IS_EXPRESSION_IDX]         = GetSchemaValue (schema.IsExpression);
+                               row [IS_READ_ONLY_IDX]          = GetSchemaValue (schema.IsReadOnly);
+                               row [BASE_SERVER_NAME_IDX]              = GetSchemaValue (schema.BaseServerName);
+                               row [BASE_CATALOG_NAME_IDX]             = GetSchemaValue (schema.BaseCatalogName);
+                               row [BASE_COLUMN_NAME_IDX]              = GetSchemaValue (schema.BaseColumnName);
+                               row [BASE_SCHEMA_NAME_IDX]              = GetSchemaValue (schema.BaseSchemaName);
+                               row [BASE_TABLE_NAME_IDX]               = GetSchemaValue (schema.BaseTableName);
+                               row [ALLOW_DBNULL_IDX]          = GetSchemaValue (schema.AllowDBNull);
+#else
                                row ["ColumnName"]              = GetSchemaValue (schema, "ColumnName");
-                               row ["ColumnSize"]              = GetSchemaValue (schema, "ColumnSize"); 
                                row ["ColumnOrdinal"]           = GetSchemaValue (schema, "ColumnOrdinal");
+                               row ["IsUnique"]                = GetSchemaValue (schema, "IsUnique");
+                               row ["IsAutoIncrement"]         = GetSchemaValue (schema, "IsAutoIncrement");
+                               row ["IsRowVersion"]            = GetSchemaValue (schema, "IsRowVersion");
+                               row ["IsHidden"]                = GetSchemaValue (schema, "IsHidden");
+                               row ["IsIdentity"]              = GetSchemaValue (schema, "IsIdentity");
+                               row ["ColumnSize"]              = GetSchemaValue (schema, "ColumnSize");
                                row ["NumericPrecision"]        = GetSchemaValue (schema, "NumericPrecision");
                                row ["NumericScale"]            = GetSchemaValue (schema, "NumericScale");
-                               row ["IsUnique"]                = GetSchemaValue (schema, "IsUnique");
                                row ["IsKey"]                   = GetSchemaValue (schema, "IsKey");
+                               row ["IsAliased"]               = GetSchemaValue (schema, "IsAliased");
+                               row ["IsExpression"]            = GetSchemaValue (schema, "IsExpression");
+                               row ["IsReadOnly"]              = GetSchemaValue (schema, "IsReadOnly");
                                row ["BaseServerName"]          = GetSchemaValue (schema, "BaseServerName");
                                row ["BaseCatalogName"]         = GetSchemaValue (schema, "BaseCatalogName");
                                row ["BaseColumnName"]          = GetSchemaValue (schema, "BaseColumnName");
                                row ["BaseSchemaName"]          = GetSchemaValue (schema, "BaseSchemaName");
                                row ["BaseTableName"]           = GetSchemaValue (schema, "BaseTableName");
                                row ["AllowDBNull"]             = GetSchemaValue (schema, "AllowDBNull");
-                               row ["IsAliased"]               = GetSchemaValue (schema, "IsAliased");
-                               row ["IsExpression"]            = GetSchemaValue (schema, "IsExpression");
-                               row ["IsIdentity"]              = GetSchemaValue (schema, "IsIdentity");
-                               row ["IsAutoIncrement"]         = GetSchemaValue (schema, "IsAutoIncrement");
-                               row ["IsRowVersion"]            = GetSchemaValue (schema, "IsRowVersion");
-                               row ["IsHidden"]                = GetSchemaValue (schema, "IsHidden");
-                               row ["IsReadOnly"]              = GetSchemaValue (schema, "IsReadOnly");
-
+#endif
                                // We don't always get the base column name.
-                               if (row ["BaseColumnName"] == DBNull.Value)
-                                       row ["BaseColumnName"] = row ["ColumnName"];
+                               if (row [BASE_COLUMN_NAME_IDX] == DBNull.Value)
+                                       row [BASE_COLUMN_NAME_IDX] = row [COLUMN_NAME_IDX];
 
-                               switch ((TdsColumnType) schema ["ColumnType"]) {
+                               int csize;
+                               TdsColumnType ctype;
+                               
+#if NET_2_0
+                               ctype = (TdsColumnType) schema.ColumnType;
+#else
+                               ctype = (TdsColumnType) schema ["ColumnType"];
+#endif
+                               switch (ctype) {
                                        case TdsColumnType.Int1:
                                        case TdsColumnType.Int2:
                                        case TdsColumnType.Int4:
                                        case TdsColumnType.IntN:
-                                               switch ((int) schema ["ColumnSize"]) {
+#if NET_2_0
+                                               csize = (int) schema.ColumnSize;
+#else
+                                               csize = (int) schema ["ColumnSize"];
+#endif
+                                               switch (csize) {
                                                case 1:
                                                        dataTypeNames.Add ("tinyint");
-                                                       row ["ProviderType"] = (int) SqlDbType.TinyInt;
-                                                       row ["DataType"] = typeof (byte);
-                                                       row ["IsLong"] = false;
+                                                       row [PROVIDER_TYPE_IDX] = (int) SqlDbType.TinyInt;
+                                                       row [DATA_TYPE_IDX] = typeof (byte);
+                                                       row [IS_LONG_IDX] = false;
                                                        break;
                                                case 2:
                                                        dataTypeNames.Add ("smallint");
-                                                       row ["ProviderType"] = (int) SqlDbType.SmallInt;
-                                                       row ["DataType"] = typeof (short);
-                                                       row ["IsLong"] = false;
+                                                       row [PROVIDER_TYPE_IDX] = (int) SqlDbType.SmallInt;
+                                                       row [DATA_TYPE_IDX] = typeof (short);
+                                                       row [IS_LONG_IDX] = false;
                                                        break;
                                                case 4:
                                                        dataTypeNames.Add ("int");
-                                                       row ["ProviderType"] = (int) SqlDbType.Int;
-                                                       row ["DataType"] = typeof (int);
-                                                       row ["IsLong"] = false;
+                                                       row [PROVIDER_TYPE_IDX] = (int) SqlDbType.Int;
+                                                       row [DATA_TYPE_IDX] = typeof (int);
+                                                       row [IS_LONG_IDX] = false;
                                                        break;
                                                case 8:
                                                        dataTypeNames.Add ("bigint");
-                                                       row ["ProviderType"] = (int) SqlDbType.BigInt;
-                                                       row ["DataType"] = typeof (long);
-                                                       row ["IsLong"] = false;
+                                                       row [PROVIDER_TYPE_IDX] = (int) SqlDbType.BigInt;
+                                                       row [DATA_TYPE_IDX] = typeof (long);
+                                                       row [IS_LONG_IDX] = false;
                                                        break;
                                                }
                                                break;
                                        case TdsColumnType.Real:
                                        case TdsColumnType.Float8:
                                        case TdsColumnType.FloatN:
-                                               switch ((int) schema ["ColumnSize"]) {
+#if NET_2_0
+                                               csize = (int) schema.ColumnSize;
+#else
+                                               csize = (int) schema ["ColumnSize"];
+#endif
+                                               switch (csize) {
                                                case 4:
                                                        dataTypeNames.Add ("real");
-                                                       row ["ProviderType"] = (int) SqlDbType.Real;
-                                                       row ["DataType"] = typeof (float);
-                                                       row ["IsLong"] = false;
+                                                       row [PROVIDER_TYPE_IDX] = (int) SqlDbType.Real;
+                                                       row [DATA_TYPE_IDX] = typeof (float);
+                                                       row [IS_LONG_IDX] = false;
                                                        break;
                                                case 8:
                                                        dataTypeNames.Add ("float");
-                                                       row ["ProviderType"] = (int) SqlDbType.Float;
-                                                       row ["DataType"] = typeof (double);
-                                                       row ["IsLong"] = false;
+                                                       row [PROVIDER_TYPE_IDX] = (int) SqlDbType.Float;
+                                                       row [DATA_TYPE_IDX] = typeof (double);
+                                                       row [IS_LONG_IDX] = false;
                                                        break;
                                                }
                                                break;
                                        case TdsColumnType.Image :
                                                dataTypeNames.Add ("image");
-                                               row ["ProviderType"] = (int) SqlDbType.Image;
-                                               row ["DataType"] = typeof (byte[]);
-                                               row ["IsLong"] = true;
+                                               row [PROVIDER_TYPE_IDX] = (int) SqlDbType.Image;
+                                               row [DATA_TYPE_IDX] = typeof (byte[]);
+                                               row [IS_LONG_IDX] = true;
                                                break;
                                        case TdsColumnType.Text :
                                                dataTypeNames.Add ("text");
-                                               row ["ProviderType"] = (int) SqlDbType.Text;
-                                               row ["DataType"] = typeof (string);
-                                               row ["IsLong"] = true;
+                                               row [PROVIDER_TYPE_IDX] = (int) SqlDbType.Text;
+                                               row [DATA_TYPE_IDX] = typeof (string);
+                                               row [IS_LONG_IDX] = true;
                                                break;
                                        case TdsColumnType.UniqueIdentifier :
                                                dataTypeNames.Add ("uniqueidentifier");
-                                               row ["ProviderType"] = (int) SqlDbType.UniqueIdentifier;
-                                               row ["DataType"] = typeof (Guid);
-                                               row ["IsLong"] = false;
+                                               row [PROVIDER_TYPE_IDX] = (int) SqlDbType.UniqueIdentifier;
+                                               row [DATA_TYPE_IDX] = typeof (Guid);
+                                               row [IS_LONG_IDX] = false;
                                                break;
                                        case TdsColumnType.VarBinary :
                                        case TdsColumnType.BigVarBinary :
                                                dataTypeNames.Add ("varbinary");
-                                               row ["ProviderType"] = (int) SqlDbType.VarBinary;
-                                               row ["DataType"] = typeof (byte[]);
-                                               row ["IsLong"] = true;
+                                               row [PROVIDER_TYPE_IDX] = (int) SqlDbType.VarBinary;
+                                               row [DATA_TYPE_IDX] = typeof (byte[]);
+                                               row [IS_LONG_IDX] = true;
                                                break;
                                        case TdsColumnType.VarChar :
                                        case TdsColumnType.BigVarChar :
                                                dataTypeNames.Add ("varchar");
-                                               row ["ProviderType"] = (int) SqlDbType.VarChar;
-                                               row ["DataType"] = typeof (string);
-                                               row ["IsLong"] = false;
+                                               row [PROVIDER_TYPE_IDX] = (int) SqlDbType.VarChar;
+                                               row [DATA_TYPE_IDX] = typeof (string);
+                                               row [IS_LONG_IDX] = false;
                                                break;
                                        case TdsColumnType.Binary :
                                        case TdsColumnType.BigBinary :
                                                dataTypeNames.Add ("binary");
-                                               row ["ProviderType"] = (int) SqlDbType.Binary;
-                                               row ["DataType"] = typeof (byte[]);
-                                               row ["IsLong"] = true;
+                                               row [PROVIDER_TYPE_IDX] = (int) SqlDbType.Binary;
+                                               row [DATA_TYPE_IDX] = typeof (byte[]);
+                                               row [IS_LONG_IDX] = true;
                                                break;
                                        case TdsColumnType.Char :
                                        case TdsColumnType.BigChar :
                                                dataTypeNames.Add ("char");
-                                               row ["ProviderType"] = (int) SqlDbType.Char;
-                                               row ["DataType"] = typeof (string);
-                                               row ["IsLong"] = false;
+                                               row [PROVIDER_TYPE_IDX] = (int) SqlDbType.Char;
+                                               row [DATA_TYPE_IDX] = typeof (string);
+                                               row [IS_LONG_IDX] = false;
                                                break;
                                        case TdsColumnType.Bit :
                                        case TdsColumnType.BitN :
                                                dataTypeNames.Add ("bit");
-                                               row ["ProviderType"] = (int) SqlDbType.Bit;
-                                               row ["DataType"] = typeof (bool);
-                                               row ["IsLong"] = false;
+                                               row [PROVIDER_TYPE_IDX] = (int) SqlDbType.Bit;
+                                               row [DATA_TYPE_IDX] = typeof (bool);
+                                               row [IS_LONG_IDX] = false;
                                                break;
                                        case TdsColumnType.DateTime4 :
                                        case TdsColumnType.DateTime :
                                        case TdsColumnType.DateTimeN :
                                                dataTypeNames.Add ("datetime");
-                                               row ["ProviderType"] = (int) SqlDbType.DateTime;
-                                               row ["DataType"] = typeof (DateTime);
-                                               row ["IsLong"] = false;
+                                               row [PROVIDER_TYPE_IDX] = (int) SqlDbType.DateTime;
+                                               row [DATA_TYPE_IDX] = typeof (DateTime);
+                                               row [IS_LONG_IDX] = false;
                                                break;
                                        case TdsColumnType.Money :
                                        case TdsColumnType.MoneyN :
                                        case TdsColumnType.Money4 :
                                                dataTypeNames.Add ("money");
-                                               row ["ProviderType"] = (int) SqlDbType.Money;
-                                               row ["DataType"] = typeof (decimal);
-                                               row ["IsLong"] = false;
+                                               row [PROVIDER_TYPE_IDX] = (int) SqlDbType.Money;
+                                               row [DATA_TYPE_IDX] = typeof (decimal);
+                                               row [IS_LONG_IDX] = false;
                                                break;
                                        case TdsColumnType.NText :
                                                dataTypeNames.Add ("ntext");
-                                               row ["ProviderType"] = (int) SqlDbType.NText;
-                                               row ["DataType"] = typeof (string);
-                                               row ["IsLong"] = true;
+                                               row [PROVIDER_TYPE_IDX] = (int) SqlDbType.NText;
+                                               row [DATA_TYPE_IDX] = typeof (string);
+                                               row [IS_LONG_IDX] = true;
                                                break;
                                        case TdsColumnType.NVarChar :
                                                dataTypeNames.Add ("nvarchar");
-                                               row ["ProviderType"] = (int) SqlDbType.NVarChar;
-                                               row ["DataType"] = typeof (string);
-                                               row ["IsLong"] = false;
+                                               row [PROVIDER_TYPE_IDX] = (int) SqlDbType.NVarChar;
+                                               row [DATA_TYPE_IDX] = typeof (string);
+                                               row [IS_LONG_IDX] = false;
                                                break;
                                        case TdsColumnType.Decimal :
                                        case TdsColumnType.Numeric :
                                                dataTypeNames.Add ("decimal");
-                                               row ["ProviderType"] = (int) SqlDbType.Decimal;
-                                               row ["DataType"] = typeof (decimal);
-                                               row ["IsLong"] = false;
+                                               row [PROVIDER_TYPE_IDX] = (int) SqlDbType.Decimal;
+                                               row [DATA_TYPE_IDX] = typeof (decimal);
+                                               row [IS_LONG_IDX] = false;
                                                break;
                                        case TdsColumnType.NChar :
                                                dataTypeNames.Add ("nchar");
-                                               row ["ProviderType"] = (int) SqlDbType.NChar;
-                                               row ["DataType"] = typeof (string);
-                                               row ["IsLong"] = false;
+                                               row [PROVIDER_TYPE_IDX] = (int) SqlDbType.NChar;
+                                               row [DATA_TYPE_IDX] = typeof (string);
+                                               row [IS_LONG_IDX] = false;
                                                break;
                                        case TdsColumnType.SmallMoney :
                                                dataTypeNames.Add ("smallmoney");
-                                               row ["ProviderType"] = (int) SqlDbType.SmallMoney;
-                                               row ["DataType"] = typeof (decimal);
-                                               row ["IsLong"] = false;
+                                               row [PROVIDER_TYPE_IDX] = (int) SqlDbType.SmallMoney;
+                                               row [DATA_TYPE_IDX] = typeof (decimal);
+                                               row [IS_LONG_IDX] = false;
                                                break;
                                        default :
                                                dataTypeNames.Add ("variant");
-                                               row ["ProviderType"] = (int) SqlDbType.Variant;
-                                               row ["DataType"] = typeof (object);
-                                               row ["IsLong"] = false;
+                                               row [PROVIDER_TYPE_IDX] = (int) SqlDbType.Variant;
+                                               row [DATA_TYPE_IDX] = typeof (object);
+                                               row [IS_LONG_IDX] = false;
                                                break;
                                }
+#if NET_2_0
+                               if ((bool)row [IS_HIDDEN_IDX] == false)
+                                       visibleFieldCount += 1;
+#endif
 
                                schemaTable.Rows.Add (row);
 
                                fieldCount += 1;
                        }
                        return schemaTable;
-               }               
+               }
 
-               private static object GetSchemaValue (TdsDataColumn schema, object key)
+               private static object GetSchemaValue (TdsDataColumn schema, string key)
                {
-                       if (schema.ContainsKey (key) && schema [key] != null)
-                               return schema [key];
-                       return DBNull.Value;
+                       object val = schema [key];
+                       if (val != null)
+                               return val;
+                       else
+                               return DBNull.Value;
                }
 
-               public SqlBinary GetSqlBinary (int i)
+               static object GetSchemaValue (object value)
+               {
+                       if (value == null)
+                               return DBNull.Value;
+
+                       return value;
+               }
+               
+               public
+#if NET_2_0
+               virtual
+#endif
+               SqlBinary GetSqlBinary (int i)
                {
                        object value = GetSqlValue (i);
                        if (!(value is SqlBinary))
@@ -761,7 +875,11 @@ namespace System.Data.SqlClient {
                        return (SqlBinary) value;
                }
 
-               public SqlBoolean GetSqlBoolean (int i) 
+               public
+#if NET_2_0
+               virtual
+#endif
+               SqlBoolean GetSqlBoolean (int i) 
                {
                        object value = GetSqlValue (i);
                        if (!(value is SqlBoolean))
@@ -769,7 +887,11 @@ namespace System.Data.SqlClient {
                        return (SqlBoolean) value;
                }
 
-               public SqlByte GetSqlByte (int i)
+               public
+#if NET_2_0
+               virtual
+#endif
+               SqlByte GetSqlByte (int i)
                {
                        object value = GetSqlValue (i);
                        if (!(value is SqlByte))
@@ -777,7 +899,11 @@ namespace System.Data.SqlClient {
                        return (SqlByte) value;
                }
 
-               public SqlDateTime GetSqlDateTime (int i)
+               public
+#if NET_2_0
+               virtual
+#endif
+               SqlDateTime GetSqlDateTime (int i)
                {
                        object value = GetSqlValue (i);
                        if (!(value is SqlDateTime))
@@ -785,7 +911,11 @@ namespace System.Data.SqlClient {
                        return (SqlDateTime) value;
                }
 
-               public SqlDecimal GetSqlDecimal (int i)
+               public
+#if NET_2_0
+               virtual
+#endif
+               SqlDecimal GetSqlDecimal (int i)
                {
                        object value = GetSqlValue (i);
                        if (!(value is SqlDecimal))
@@ -793,7 +923,11 @@ namespace System.Data.SqlClient {
                        return (SqlDecimal) value;
                }
 
-               public SqlDouble GetSqlDouble (int i)
+               public
+#if NET_2_0
+               virtual
+#endif
+               SqlDouble GetSqlDouble (int i)
                {
                        object value = GetSqlValue (i);
                        if (!(value is SqlDouble))
@@ -801,7 +935,11 @@ namespace System.Data.SqlClient {
                        return (SqlDouble) value;
                }
 
-               public SqlGuid GetSqlGuid (int i)
+               public
+#if NET_2_0
+               virtual
+#endif
+               SqlGuid GetSqlGuid (int i)
                {
                        object value = GetSqlValue (i);
                        if (!(value is SqlGuid))
@@ -809,7 +947,11 @@ namespace System.Data.SqlClient {
                        return (SqlGuid) value;
                }
 
-               public SqlInt16 GetSqlInt16 (int i)
+               public
+#if NET_2_0
+               virtual
+#endif
+               SqlInt16 GetSqlInt16 (int i)
                {
                        object value = GetSqlValue (i);
                        if (!(value is SqlInt16))
@@ -817,7 +959,11 @@ namespace System.Data.SqlClient {
                        return (SqlInt16) value;
                }
 
-               public SqlInt32 GetSqlInt32 (int i)
+               public
+#if NET_2_0
+               virtual
+#endif
+               SqlInt32 GetSqlInt32 (int i)
                {
                        object value = GetSqlValue (i);
                        if (!(value is SqlInt32))
@@ -825,13 +971,26 @@ namespace System.Data.SqlClient {
                        return (SqlInt32) value;
                }
 
-               public SqlInt64 GetSqlInt64 (int i)
+               public
+#if NET_2_0
+               virtual
+#endif
+               SqlInt64 GetSqlInt64 (int i)
                {
                        object value = GetSqlValue (i);
                        // TDS 7.0 returns bigint as decimal(19,0)
                        if (value is SqlDecimal) {
                                TdsDataColumn schema = command.Tds.Columns[i];
-                               if ((byte)schema["NumericPrecision"] == 19 && (byte)schema["NumericScale"] == 0)
+                               byte precision, scale;
+
+#if NET_2_0
+                               precision = (byte)schema.NumericPrecision;
+                               scale = (byte)schema.NumericScale;
+#else
+                               precision = (byte)schema["NumericPrecision"];
+                               scale = (byte)schema["NumericScale"];
+#endif
+                               if (precision == 19 && scale == 0)
                                        value = (SqlInt64) (SqlDecimal) value;
                        }
                        if (!(value is SqlInt64))
@@ -839,7 +998,11 @@ namespace System.Data.SqlClient {
                        return (SqlInt64) value;
                }
 
-               public SqlMoney GetSqlMoney (int i)
+               public
+#if NET_2_0
+               virtual
+#endif
+               SqlMoney GetSqlMoney (int i)
                {
                        object value = GetSqlValue (i);
                        if (!(value is SqlMoney))
@@ -847,7 +1010,11 @@ namespace System.Data.SqlClient {
                        return (SqlMoney) value;
                }
 
-               public SqlSingle GetSqlSingle (int i)
+               public
+#if NET_2_0
+               virtual
+#endif
+               SqlSingle GetSqlSingle (int i)
                {
                        object value = GetSqlValue (i);
                        if (!(value is SqlSingle))
@@ -855,7 +1022,11 @@ namespace System.Data.SqlClient {
                        return (SqlSingle) value;
                }
 
-               public SqlString GetSqlString (int i)
+               public
+#if NET_2_0
+               virtual
+#endif
+               SqlString GetSqlString (int i)
                {
                        object value = GetSqlValue (i);
                        if (!(value is SqlString))
@@ -863,8 +1034,27 @@ namespace System.Data.SqlClient {
                        return (SqlString) value;
                }
 
-               public object GetSqlValue (int i)
+#if NET_2_0
+               public virtual SqlXml GetSqlXml (int i)
+               {
+                       object value = GetSqlValue (i);
+                       if (!(value is SqlXml)) {
+                               if (value is DBNull) throw new SqlNullValueException ();
+                               throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
+                       }
+                       return (SqlXml) value;
+               }
+#endif // NET_2_0
+
+               public
+#if NET_2_0
+               virtual
+#endif
+               object GetSqlValue (int i)
                {
+                       if (schemaTable == null)
+                               schemaTable = ConstructSchemaTable ();
+
                        SqlDbType type = (SqlDbType) (schemaTable.Rows [i]["ProviderType"]);
                        object value = GetValue (i);
 
@@ -933,13 +1123,26 @@ namespace System.Data.SqlClient {
                                if (value == DBNull.Value)
                                        return SqlByte.Null;
                                return (SqlByte) ((byte) value);
+#if NET_2_0
+                       case SqlDbType.Xml:
+                               if (value == DBNull.Value)
+                                       return SqlByte.Null;
+                               return (SqlXml) value;
+#endif
                        }
 
                        throw new InvalidOperationException ("The type of this column is unknown.");
                }
 
-               public int GetSqlValues (object[] values)
+               public
+#if NET_2_0
+               virtual
+#endif
+               int GetSqlValues (object[] values)
                {
+                       if (schemaTable == null)
+                               schemaTable = ConstructSchemaTable ();
+
                        int count = 0;
                        int columnCount = schemaTable.Rows.Count;
                        int arrayCount = values.Length;
@@ -955,11 +1158,11 @@ namespace System.Data.SqlClient {
                        return count;
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                string GetString (int i)
+               string GetString (int i)
                {
                        object value = GetValue (i);
                        if (!(value is string)) {
@@ -969,27 +1172,32 @@ namespace System.Data.SqlClient {
                        return (string) value;
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                object GetValue (int i)
+               object GetValue (int i)
                {
                        if (i < 0 || i >= command.Tds.Columns.Count)
                                throw new IndexOutOfRangeException ();
 
-                       if ((command.CommandBehavior & CommandBehavior.SequentialAccess) != 0) {
-                               return ((Tds)command.Tds).GetSequentialColumnValue (i);
+                       try {
+                               if ((command.CommandBehavior & CommandBehavior.SequentialAccess) != 0) {
+                                       return ((Tds)command.Tds).GetSequentialColumnValue (i);
+                               }
+                       } catch (TdsInternalException ex) {
+                               command.Connection.Close ();
+                               throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
                        }
 
                        return command.Tds.ColumnValues [i];
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                int GetValues (object[] values)
+               int GetValues (object[] values)
                {
                        int len = values.Length;
                        int bigDecimalIndex = command.Tds.ColumnValues.BigDecimalIndex;
@@ -998,65 +1206,77 @@ namespace System.Data.SqlClient {
                        // a native type.  Throw an OverflowException.
                        if (bigDecimalIndex >= 0 && bigDecimalIndex < len)
                                throw new OverflowException ();
-
-                       command.Tds.ColumnValues.CopyTo (0, values, 0, len);
+                       try {
+                               command.Tds.ColumnValues.CopyTo (0, values, 0,
+                                                                len > command.Tds.ColumnValues.Count ? command.Tds.ColumnValues.Count : len);
+                       } catch (TdsInternalException ex) {
+                               command.Connection.Close ();
+                               throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
+                       }
                        return (len < FieldCount ? len : FieldCount);
                }
 
+#if !NET_2_0
                void IDisposable.Dispose ()
                {
                        Dispose (true);
                        GC.SuppressFinalize (this);
                }
+#endif
 
-               public 
 #if NET_2_0
-               override 
+               public override IEnumerator GetEnumerator ()
+#else
+               IEnumerator IEnumerable.GetEnumerator ()
 #endif
-               IEnumerator GetEnumerator ()
                {
                        return new DbEnumerator (this);
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                bool IsDBNull (int i)
+               bool IsDBNull (int i)
                {
                        return GetValue (i) == DBNull.Value;
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                bool NextResult ()
+               bool NextResult ()
                {
                        ValidateState ();
 
                        if ((command.CommandBehavior & CommandBehavior.SingleResult) != 0 && resultsRead > 0)
                                return false;
 
-                        moreResults = command.Tds.NextResult ();
+                       try {
+                               moreResults = command.Tds.NextResult ();
+                       } catch (TdsInternalException ex) {
+                               command.Connection.Close ();
+                               throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
+                       }
                        if (!moreResults)
                                command.GetOutputParameters ();
-                        else {
-                                //new schema
-                                schemaTable = ConstructSchemaTable ();
-                                GetSchemaTable ();
-                        }
+                       else {
+                               //new schema
+                               schemaTable = null;
+                               GetSchemaTable ();
+                       }
 
                        rowsRead = 0;
                        resultsRead += 1;
                        return moreResults;
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-                bool Read ()
+               bool Read ()
                {
                        ValidateState ();
 
@@ -1072,20 +1292,20 @@ namespace System.Data.SqlClient {
                                readResultUsed = true;
                                return true;
                        }
-                       
-                       
                        return (ReadRecord ());
-
                }
 
                internal bool ReadRecord ()
                {
+                       try {
+                               bool result = command.Tds.NextRow ();
                        
-                       bool result = command.Tds.NextRow ();
-                       
-                       rowsRead += 1;
-                       
-                       return result;
+                               rowsRead += 1;
+                               return result;
+                       } catch (TdsInternalException ex) {
+                               command.Connection.Close ();
+                               throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
+                       }
                }
                
                void ValidateState ()
@@ -1095,24 +1315,30 @@ namespace System.Data.SqlClient {
                }
                
 #if NET_2_0
-                [MonoTODO]
-                public override Type GetProviderSpecificFieldType (int position)
-                {
-                        throw new NotImplementedException ();
-                }
-
-                [MonoTODO]                
-                public override object GetProviderSpecificValue (int position)
-                {
-                        throw new NotImplementedException ();                        
-                }
-                
-                [MonoTODO]
-                public override int GetProviderSpecificValues (object [] values)
-                {
-                        throw new NotImplementedException ();                        
-                }
+               public override Type GetProviderSpecificFieldType (int i)
+               {
+                       return (GetSqlValue (i).GetType());
+               }
+
+               public override object GetProviderSpecificValue (int i)
+               {
+                       return (GetSqlValue (i));
+               }
 
+               public override int GetProviderSpecificValues (object [] values)
+               {
+                       return (GetSqlValues (values));
+               }
+
+               public virtual SqlBytes GetSqlBytes (int i)
+               {
+                       //object value = GetSqlValue (i);
+                       //if (!(value is SqlBinary))
+                       //      throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
+                       Byte[] val = (byte[])GetValue(i);
+                       SqlBytes sb = new SqlBytes (val);
+                       return (sb);
+               }
 #endif // NET_2_0
 
                #endregion // Methods