Merge pull request #1949 from lewurm/fixtype
[mono.git] / mcs / class / System.Data / System.Data.SqlClient / SqlDataReader.cs
index e90f1dc589b383718c47c56fac289e6dfa66fe4b..7410c36c2a1c1829f16c27403512cf8b23c5758f 100644 (file)
@@ -43,51 +43,67 @@ using System.ComponentModel;
 using System.Data;
 using System.Data.Common;
 using System.Data.SqlTypes;
+using System.Globalization;
+using System.Xml;
 
-namespace System.Data.SqlClient {
-#if NET_2_0
+namespace System.Data.SqlClient
+{
        public class SqlDataReader : DbDataReader, IDataReader, IDisposable, IDataRecord
-#else
-       public sealed class SqlDataReader : MarshalByRefObject, IEnumerable, IDataReader, IDisposable, IDataRecord
-#endif // NET_2_0
        {
                #region Fields
 
                SqlCommand command;
-               ArrayList dataTypeNames;
-               bool disposed = false;
-               int fieldCount;
+               bool disposed;
                bool isClosed;
                bool moreResults;
                int resultsRead;
                int rowsRead;
                DataTable schemaTable;
-               bool hasRows;
                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;
+               const int PROVIDER_SPECIFIC_TYPE_IDX = 23;
+               const int DATA_TYPE_NAME_IDX = 24;
+               const int XML_SCHEMA_COLLCTN_DB_IDX = 25;
+               const int XML_SCHEMA_COLLCTN_OWN_SCHEMA_IDX = 26;
+               const int XML_SCHEMA_COLLCTN_NAME_IDX = 27;
+               const int UDT_ASMBLY_QUALIFIED_NAME_IDX = 28;
+               const int NON_VER_PROVIDER_TYPE_IDX = 29;
+               const int IS_COLUMN_SET = 30;
+               
                #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 ();
                }
 
@@ -95,92 +111,78 @@ namespace System.Data.SqlClient {
 
                #region Properties
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                int Depth {
                        get { return 0; }
                }
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                int FieldCount {
-                       get { return fieldCount; }
+                       get {
+                               ValidateState ();
+                               return command.Tds.Columns.Count;
+                       }
                }
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                bool IsClosed {
                        get { return isClosed; }
                }
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                object this [int i] {
                        get { return GetValue (i); }
                }
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                object this [string name] {
                        get { return GetValue (GetOrdinal (name)); }
                }
        
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                int RecordsAffected {
-                       get { 
-                               return command.Tds.RecordsAffected; 
+                       get {
+                               return command.Tds.RecordsAffected;
                        }
                }
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                bool HasRows {
                        get {
-                               if (haveRead) 
-                                       return readResult;
-                       
-                               haveRead = true;
-                               readResult = ReadRecord ();
+                               ValidateState ();
+
+                               if (rowsRead > 0)
+                                       return true;
+                               if (!haveRead)
+                                       readResult = ReadRecord ();
                                return readResult;
                        }
                }
-#if NET_2_0
-               public override int VisibleFieldCount { 
+               public override int VisibleFieldCount {
                        get { return visibleFieldCount; }
                }
 
-               protected SqlConnection Connection { 
+               protected SqlConnection Connection {
                        get { return command.Connection; }
                }
 
-               protected bool IsCommandBehavior (CommandBehavior condition) { 
+               protected bool IsCommandBehavior (CommandBehavior condition) {
                        return condition == command.CommandBehavior;
                }
-#endif
 
                #endregion // Properties
 
                #region Methods
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                void Close ()
                {
                        if (IsClosed)
@@ -189,16 +191,16 @@ namespace System.Data.SqlClient {
                        while (NextResult ())
                                ;
                        isClosed = true;
-                       command.CloseDataReader (moreResults);
+                       command.CloseDataReader ();
                }
 
                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);
@@ -224,17 +226,279 @@ namespace System.Data.SqlClient {
                        schemaTable.Columns.Add ("IsHidden", booleanType);
                        schemaTable.Columns.Add ("IsLong", booleanType);
                        schemaTable.Columns.Add ("IsReadOnly", booleanType);
-
+                       schemaTable.Columns.Add ("ProviderSpecificDataType", typeType);
+                       schemaTable.Columns.Add ("DataTypeName", stringType);
+                       schemaTable.Columns.Add ("XmlSchemaCollectionDatabase", stringType);
+                       schemaTable.Columns.Add ("XmlSchemaCollectionOwningSchema", stringType);
+                       schemaTable.Columns.Add ("XmlSchemaCollectionName", stringType);
+                       schemaTable.Columns.Add ("UdtAssemblyQualifiedName", stringType);
+                       schemaTable.Columns.Add ("NonVersionedProviderType", intType);
+                       schemaTable.Columns.Add ("IsColumnSet", booleanType);
+                       
                        return schemaTable;
                }
-#if NET_2_0
+               
+               private string GetSchemaRowTypeName (TdsColumnType ctype, int csize, short precision, short scale)
+               {
+                       int dbType;
+                       bool isLong;
+                       Type fieldType;
+
+                       string typeName;
+                       GetSchemaRowType (ctype, csize, precision, scale,
+                               out dbType, out fieldType, out isLong,
+                               out typeName);
+                       return typeName;
+               }
+
+               private Type GetSchemaRowFieldType (TdsColumnType ctype, int csize, short precision, short scale)
+               {
+                       int dbType;
+                       bool isLong;
+                       Type fieldType;
+                       string typeName;
+
+                       GetSchemaRowType (ctype, csize, precision, scale,
+                               out dbType, out fieldType, out isLong,
+                               out typeName);
+                       return fieldType;
+               }
+
+               SqlDbType GetSchemaRowDbType (int ordinal)
+               {
+                       int csize;
+                       short precision, scale;
+                       TdsColumnType ctype;
+                       TdsDataColumn column;
+
+                       if (ordinal < 0 || ordinal >= command.Tds.Columns.Count)
+                               throw new IndexOutOfRangeException ();
+
+                       column = command.Tds.Columns [ordinal];
+                       ctype = (TdsColumnType) column.ColumnType;
+                       csize = (int) column.ColumnSize;
+                       precision = (short) (column.NumericPrecision ?? 0);
+                       scale = (short) (column.NumericScale ?? 0);
+                       return GetSchemaRowDbType (ctype, csize, precision, scale);
+               }
+
+               private SqlDbType GetSchemaRowDbType (TdsColumnType ctype, int csize, short precision, short scale)
+               {
+                       Type fieldType;
+                       bool isLong;
+                       string typeName;
+                       int dbType;
+
+                       GetSchemaRowType (ctype, csize, precision, scale,
+                               out dbType, out fieldType, out isLong,
+                               out typeName);
+                       return (SqlDbType) dbType;
+               }
+               
+               private void GetSchemaRowType (TdsColumnType ctype, int csize,
+                                               short precision, short scale,
+                                               out int dbType, out Type fieldType,
+                                               out bool isLong, out string typeName)
+               {
+                       dbType = -1;
+                       typeName = string.Empty;
+                       isLong = false;
+                       fieldType = typeof (Type);
+                       
+                       switch (ctype) {
+                               case TdsColumnType.Int1:
+                               case TdsColumnType.Int2:
+                               case TdsColumnType.Int4:
+                               case TdsColumnType.IntN:
+                               case TdsColumnType.BigInt:
+                                       switch (csize) {
+                                       case 1:
+                                               typeName = "tinyint";
+                                               dbType = (int) SqlDbType.TinyInt;
+                                               fieldType = typeof (byte);
+                                               isLong = false;
+                                               break;
+                                       case 2:
+                                               typeName = "smallint";
+                                               dbType = (int) SqlDbType.SmallInt;
+                                               fieldType = typeof (short);
+                                               isLong = false;
+                                               break;
+                                       case 4:
+                                               typeName = "int";
+                                               dbType = (int) SqlDbType.Int;
+                                               fieldType = typeof (int);
+                                               isLong = false;
+                                               break;
+                                       case 8:
+                                               typeName = "bigint";
+                                               dbType = (int) SqlDbType.BigInt;
+                                               fieldType = typeof (long);
+                                               isLong = false;
+                                               break;
+                                       }
+                                       break;
+                               case TdsColumnType.Real:
+                               case TdsColumnType.Float8:
+                               case TdsColumnType.FloatN:
+                                       switch (csize) {
+                                       case 4:
+                                               typeName = "real";
+                                               dbType = (int) SqlDbType.Real;
+                                               fieldType = typeof (float);
+                                               isLong = false;
+                                               break;
+                                       case 8:
+                                               typeName = "float";
+                                               dbType = (int) SqlDbType.Float;
+                                               fieldType = typeof (double);
+                                               isLong = false;
+                                               break;
+                                       }
+                                       break;
+                               case TdsColumnType.Image :
+                                       typeName = "image";
+                                       dbType = (int) SqlDbType.Image;
+                                       fieldType = typeof (byte[]);
+                                       isLong = true;
+                                       break;
+                               case TdsColumnType.Text :
+                                       typeName = "text";
+                                       dbType = (int) SqlDbType.Text;
+                                       fieldType = typeof (string);
+                                       isLong = true;
+                                       break;
+                               case TdsColumnType.UniqueIdentifier :
+                                       typeName = "uniqueidentifier";
+                                       dbType = (int) SqlDbType.UniqueIdentifier;
+                                       fieldType = typeof (Guid);
+                                       isLong = false;
+                                       break;
+                               case TdsColumnType.VarBinary :
+                               case TdsColumnType.BigVarBinary :
+                                       typeName = "varbinary";
+                                       dbType = (int) SqlDbType.VarBinary;
+                                       fieldType = typeof (byte[]);
+                                       isLong = false;
+                                       break;
+                               case TdsColumnType.VarChar :
+                               case TdsColumnType.BigVarChar :
+                                       typeName = "varchar";
+                                       dbType = (int) SqlDbType.VarChar;
+                                       fieldType = typeof (string);
+                                       isLong = false;
+                                       break;
+                               case TdsColumnType.Binary :
+                               case TdsColumnType.BigBinary :
+                                       typeName = "binary";
+                                       dbType = (int) SqlDbType.Binary;
+                                       fieldType = typeof (byte[]);
+                                       isLong = false;
+                                       break;
+                               case TdsColumnType.Char :
+                               case TdsColumnType.BigChar :
+                                       typeName = "char";
+                                       dbType = (int) SqlDbType.Char;
+                                       fieldType = typeof (string);
+                                       isLong = false;
+                                       break;
+                               case TdsColumnType.Bit :
+                               case TdsColumnType.BitN :
+                                       typeName = "bit";
+                                       dbType = (int) SqlDbType.Bit;
+                                       fieldType = typeof (bool);
+                                       isLong = false;
+                                       break;
+                               case TdsColumnType.DateTime4 :
+                               case TdsColumnType.DateTime :
+                               case TdsColumnType.DateTimeN :
+                                       switch (csize) {
+                                       case 4:
+                                               typeName = "smalldatetime";
+                                               dbType = (int) SqlDbType.SmallDateTime;
+                                               fieldType = typeof (DateTime);
+                                               isLong = false;
+                                               break;
+                                       case 8:
+                                               typeName = "datetime";
+                                               dbType = (int) SqlDbType.DateTime;
+                                               fieldType = typeof (DateTime);
+                                               isLong = false;
+                                               break;
+                                       }
+                                       break;
+                               case TdsColumnType.Money :
+                               case TdsColumnType.MoneyN :
+                               case TdsColumnType.Money4 :
+                                       switch (csize) {
+                                       case 4:
+                                               typeName = "smallmoney";
+                                               dbType = (int) SqlDbType.SmallMoney;
+                                               fieldType = typeof (decimal);
+                                               isLong = false;
+                                               break;
+                                       case 8:
+                                               typeName = "money";
+                                               dbType = (int) SqlDbType.Money;
+                                               fieldType = typeof (decimal);
+                                               isLong = false;
+                                               break;
+                                       }
+                                       break;
+                               case TdsColumnType.NText :
+                                       typeName = "ntext";
+                                       dbType = (int) SqlDbType.NText;
+                                       fieldType = typeof (string);
+                                       isLong = true;
+                                       break;
+                               case TdsColumnType.NVarChar :
+                                       typeName = "nvarchar";
+                                       dbType = (int) SqlDbType.NVarChar;
+                                       fieldType = typeof (string);
+                                       isLong = false;
+                                       break;
+                               case TdsColumnType.Decimal :
+                               case TdsColumnType.Numeric :
+                                       // TDS 7.0 returns bigint as decimal(19,0)
+                                       if (precision == 19 && scale == 0) {
+                                               typeName = "bigint";
+                                               dbType = (int) SqlDbType.BigInt;
+                                               fieldType = typeof (long);
+                                       } else {
+                                               typeName = "decimal";
+                                               dbType = (int) SqlDbType.Decimal;
+                                               fieldType = typeof (decimal);
+                                       }
+                                       isLong = false;
+                                       break;
+                               case TdsColumnType.NChar :
+                                       typeName = "nchar";
+                                       dbType = (int) SqlDbType.NChar;
+                                       fieldType = typeof (string);
+                                       isLong = false;
+                                       break;
+                               case TdsColumnType.SmallMoney :
+                                       typeName = "smallmoney";
+                                       dbType = (int) SqlDbType.SmallMoney;
+                                       fieldType = typeof (decimal);
+                                       isLong = false;
+                                       break;
+                               default :
+                                       typeName = "variant";
+                                       dbType = (int) SqlDbType.Variant;
+                                       fieldType = typeof (object);
+                                       isLong = false;
+                                       break;
+                       }
+               }
+
                new
-#endif
-               void Dispose (bool disposing) 
+               void Dispose (bool disposing)
                {
                        if (!disposed) {
                                if (disposing) {
-                                       schemaTable.Dispose ();
+                                       if (schemaTable != null)
+                                               schemaTable.Dispose ();
                                        Close ();
                                        command = null;
                                }
@@ -243,9 +507,7 @@ namespace System.Data.SqlClient {
                }
 
                public 
-#if NET_2_0
                override
-#endif // NET_2_0
                bool GetBoolean (int i)
                {
                        object value = GetValue (i);
@@ -256,10 +518,8 @@ namespace System.Data.SqlClient {
                        return (bool) value;
                }
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                byte GetByte (int i)
                {
                        object value = GetValue (i);
@@ -270,20 +530,20 @@ namespace System.Data.SqlClient {
                        return (byte) value;
                }
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                long GetBytes (int i, long dataIndex, byte[] buffer, int bufferIndex, int length)
                {
                        if ((command.CommandBehavior & CommandBehavior.SequentialAccess) != 0) {
+                               ValidateState ();
+                               EnsureDataAvailable ();
+
                                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");
+                                               throw CreateGetBytesOnInvalidColumnTypeException (i);
+                                       if (len == -2)
+                                               throw new SqlNullValueException ();
                                        return len;
                                } catch (TdsInternalException ex) {
                                        command.Connection.Close ();
@@ -293,43 +553,64 @@ namespace System.Data.SqlClient {
 
                        object value = GetValue (i);
                        if (!(value is byte [])) {
-                               if (value is DBNull) throw new SqlNullValueException ();
-                               throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
+                               SqlDbType type = GetSchemaRowDbType (i);
+                               switch (type) {
+                               case SqlDbType.Image:
+                                       if (value is DBNull)
+                                               throw new SqlNullValueException ();
+                                       break;
+                               case SqlDbType.Text:
+                                       string text = value as string;
+                                       if (text != null)
+                                               value = Encoding.Default.GetBytes (text);
+                                       else
+                                               value = null;
+                                       break;
+                               case SqlDbType.NText:
+                                       string ntext = value as string;
+                                       if (ntext != null)
+                                               value = Encoding.Unicode.GetBytes (ntext);
+                                       else
+                                               value = null;
+                                       break;
+                               default:
+                                       throw CreateGetBytesOnInvalidColumnTypeException (i);
+                               }
                        }
-                       
-                       if ( buffer == null )
+
+                       if (buffer == null)
                                return ((byte []) value).Length; // Return length of data
 
                        // Copy data into buffer
                        int availLen = (int) ( ( (byte []) value).Length - dataIndex);
                        if (availLen < length)
                                length = availLen;
+                       if (dataIndex < 0)
+                               return 0;
+                       
                        Array.Copy ((byte []) value, (int) dataIndex, buffer, bufferIndex, length);
                        return length; // return actual read count
                }
 
                [EditorBrowsableAttribute (EditorBrowsableState.Never)]
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                char GetChar (int i)
                {
-                       object value = GetValue (i);
-                       if (!(value is char)) {
-                               if (value is DBNull) throw new SqlNullValueException ();
-                               throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
-                       }
-                       return (char) value;
+                       throw new NotSupportedException ();
                }
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                long GetChars (int i, long dataIndex, char[] buffer, int bufferIndex, int length)
                {
                        if ((command.CommandBehavior & CommandBehavior.SequentialAccess) != 0) {
+                               ValidateState ();
+                               EnsureDataAvailable ();
+
+                               if (i < 0 || i >= command.Tds.Columns.Count)
+                                       throw new IndexOutOfRangeException ();
+
                                Encoding encoding = null;
                                byte mul = 1;
                                TdsColumnType colType = (TdsColumnType) command.Tds.Columns[i]["ColumnType"];
@@ -344,7 +625,7 @@ namespace System.Data.SqlClient {
                                        case TdsColumnType.NVarChar:
                                        case TdsColumnType.NChar:
                                                encoding = Encoding.Unicode;
-                                               mul = 2 ;
+                                               mul = 2;
                                                break;
                                        default :
                                                return -1;
@@ -390,29 +671,32 @@ namespace System.Data.SqlClient {
                        }
                }
                
-#if !NET_2_0
-               [EditorBrowsableAttribute (EditorBrowsableState.Never)] 
-               public new IDataReader GetData (int i)
-               {
-                       return ((IDataReader) this [i]);
-               }
-#endif
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                string GetDataTypeName (int i)
                {
-                       if (i < 0 || i >= dataTypeNames.Count)
+                       TdsDataColumn column;
+                       TdsColumnType ctype;
+                       int csize;
+                       short precision;
+                       short scale;
+
+                       ValidateState ();
+
+                       if (i < 0 || i >= command.Tds.Columns.Count)
                                throw new IndexOutOfRangeException ();
-                       return (string) dataTypeNames [i];
+
+                       column = command.Tds.Columns [i];
+                       ctype = (TdsColumnType) column.ColumnType;
+                       csize = (int) column.ColumnSize;
+                       precision = (short) (column.NumericPrecision ?? 0);
+                       scale = (short) (column.NumericScale ?? 0);
+                       return GetSchemaRowTypeName (ctype, csize, precision, scale);
                }
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                DateTime GetDateTime (int i)
                {
                        object value = GetValue (i);
@@ -423,10 +707,26 @@ namespace System.Data.SqlClient {
                        return (DateTime) value;
                }
 
-               public 
-#if NET_2_0
+               [MonoTODO]
+               public virtual DateTimeOffset GetDateTimeOffset (int i)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               [MonoTODO]
+               public virtual TimeSpan GetTimeSpan (int i)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               [MonoTODO]
+               public virtual SqlChars GetSqlChars (int i)
+               {
+                       throw new NotImplementedException ();
+               }       
+
+               public
                override
-#endif // NET_2_0
                decimal GetDecimal (int i)
                {
                        object value = GetValue (i);
@@ -437,10 +737,8 @@ namespace System.Data.SqlClient {
                        return (decimal) value;
                }
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                double GetDouble (int i)
                {
                        object value = GetValue (i);
@@ -451,21 +749,32 @@ namespace System.Data.SqlClient {
                        return (double) value;
                }
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                Type GetFieldType (int i)
                {
-                       if (i < 0 || i >= schemaTable.Rows.Count)
+                       TdsDataColumn column;
+                       TdsColumnType ctype;
+                       int csize;
+                       short precision;
+                       short scale;
+
+                       ValidateState ();
+
+                       if (i < 0 || i >= command.Tds.Columns.Count)
                                throw new IndexOutOfRangeException ();
-                       return (Type) schemaTable.Rows[i]["DataType"];
+
+                       column = command.Tds.Columns [i];
+                       ctype = (TdsColumnType) column.ColumnType;
+                       csize = (int) column.ColumnSize;
+                       precision = (short) (column.NumericPrecision ?? 0);
+                       scale = (short) (column.NumericScale ?? 0);
+                       return GetSchemaRowFieldType (ctype, csize, precision,
+                               scale);
                }
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                float GetFloat (int i)
                {
                        object value = GetValue (i);
@@ -476,10 +785,8 @@ namespace System.Data.SqlClient {
                        return (float) value;
                }
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                Guid GetGuid (int i)
                {
                        object value = GetValue (i);
@@ -490,10 +797,8 @@ namespace System.Data.SqlClient {
                        return (Guid) value;
                }
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                short GetInt16 (int i)
                {
                        object value = GetValue (i);
@@ -504,10 +809,8 @@ namespace System.Data.SqlClient {
                        return (short) value;
                }
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                int GetInt32 (int i)
                {
                        object value = GetValue (i);
@@ -518,19 +821,11 @@ namespace System.Data.SqlClient {
                        return (int) value;
                }
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                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 ());
@@ -538,256 +833,132 @@ namespace System.Data.SqlClient {
                        return (long) value;
                }
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                string GetName (int i)
                {
-                       return (string) schemaTable.Rows[i]["ColumnName"];
+                       ValidateState ();
+
+                       if (i < 0 || i >= command.Tds.Columns.Count)
+                               throw new IndexOutOfRangeException ();
+                       return (string) command.Tds.Columns[i].ColumnName;
                }
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                int GetOrdinal (string name)
                {
-                       foreach (DataRow schemaRow in schemaTable.Rows)
-                               if (((string) schemaRow ["ColumnName"]).Equals (name))
-                                       return (int) schemaRow ["ColumnOrdinal"];
-                       foreach (DataRow schemaRow in schemaTable.Rows)
-                               if (String.Compare (((string) schemaRow ["ColumnName"]), name, true) == 0)
-                                       return (int) schemaRow ["ColumnOrdinal"];
+                       ValidateState ();
+
+                       if (name == null)
+                               throw new ArgumentNullException ("fieldName");
+
+                       string colName;
+                       foreach (TdsDataColumn schema in command.Tds.Columns) {
+                               colName = schema.ColumnName;
+                               if (colName.Equals (name) || String.Compare (colName, name, true) == 0)
+                                       return (int) schema.ColumnOrdinal;
+                       }
                        throw new IndexOutOfRangeException ();
                }
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                DataTable GetSchemaTable ()
                {
                        ValidateState ();
 
+                       if (schemaTable == null)
+                               schemaTable = ConstructSchemaTable ();
+
                        if (schemaTable.Rows != null && schemaTable.Rows.Count > 0)
                                return schemaTable;
 
                        if (!moreResults)
                                return null;
 
-                       fieldCount = 0;
-
-                       dataTypeNames = new ArrayList ();
-
                        foreach (TdsDataColumn schema in command.Tds.Columns) {
                                DataRow row = schemaTable.NewRow ();
 
-                               row ["ColumnName"]              = GetSchemaValue (schema, "ColumnName");
-                               row ["ColumnSize"]              = GetSchemaValue (schema, "ColumnSize"); 
-                               row ["ColumnOrdinal"]           = GetSchemaValue (schema, "ColumnOrdinal");
-                               row ["NumericPrecision"]        = GetSchemaValue (schema, "NumericPrecision");
-                               row ["NumericScale"]            = GetSchemaValue (schema, "NumericScale");
-                               row ["IsUnique"]                = GetSchemaValue (schema, "IsUnique");
-                               row ["IsKey"]                   = GetSchemaValue (schema, "IsKey");
-                               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");
-
+                               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 [NUMERIC_PRECISION_IDX]     = GetSchemaValue (schema.NumericPrecision);
+                               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);
+                               row [PROVIDER_SPECIFIC_TYPE_IDX] = DBNull.Value;
+                               row [DATA_TYPE_NAME_IDX] = GetSchemaValue (schema.DataTypeName);
+                               row [XML_SCHEMA_COLLCTN_DB_IDX] = DBNull.Value;
+                               row [XML_SCHEMA_COLLCTN_OWN_SCHEMA_IDX] = DBNull.Value;
+                               row [XML_SCHEMA_COLLCTN_NAME_IDX] = DBNull.Value;
+                               row [UDT_ASMBLY_QUALIFIED_NAME_IDX] = DBNull.Value;
+                               row [NON_VER_PROVIDER_TYPE_IDX] = DBNull.Value;
+                               row [IS_COLUMN_SET] = DBNull.Value;
                                // We don't always get the base column name.
-                               if (row ["BaseColumnName"] == DBNull.Value)
-                                       row ["BaseColumnName"] = row ["ColumnName"];
-
-                               switch ((TdsColumnType) schema ["ColumnType"]) {
-                                       case TdsColumnType.Int1:
-                                       case TdsColumnType.Int2:
-                                       case TdsColumnType.Int4:
-                                       case TdsColumnType.IntN:
-                                               switch ((int) schema ["ColumnSize"]) {
-                                               case 1:
-                                                       dataTypeNames.Add ("tinyint");
-                                                       row ["ProviderType"] = (int) SqlDbType.TinyInt;
-                                                       row ["DataType"] = typeof (byte);
-                                                       row ["IsLong"] = false;
-                                                       break;
-                                               case 2:
-                                                       dataTypeNames.Add ("smallint");
-                                                       row ["ProviderType"] = (int) SqlDbType.SmallInt;
-                                                       row ["DataType"] = typeof (short);
-                                                       row ["IsLong"] = false;
-                                                       break;
-                                               case 4:
-                                                       dataTypeNames.Add ("int");
-                                                       row ["ProviderType"] = (int) SqlDbType.Int;
-                                                       row ["DataType"] = typeof (int);
-                                                       row ["IsLong"] = false;
-                                                       break;
-                                               case 8:
-                                                       dataTypeNames.Add ("bigint");
-                                                       row ["ProviderType"] = (int) SqlDbType.BigInt;
-                                                       row ["DataType"] = typeof (long);
-                                                       row ["IsLong"] = false;
-                                                       break;
-                                               }
-                                               break;
-                                       case TdsColumnType.Real:
-                                       case TdsColumnType.Float8:
-                                       case TdsColumnType.FloatN:
-                                               switch ((int) schema ["ColumnSize"]) {
-                                               case 4:
-                                                       dataTypeNames.Add ("real");
-                                                       row ["ProviderType"] = (int) SqlDbType.Real;
-                                                       row ["DataType"] = typeof (float);
-                                                       row ["IsLong"] = false;
-                                                       break;
-                                               case 8:
-                                                       dataTypeNames.Add ("float");
-                                                       row ["ProviderType"] = (int) SqlDbType.Float;
-                                                       row ["DataType"] = typeof (double);
-                                                       row ["IsLong"] = false;
-                                                       break;
-                                               }
-                                               break;
-                                       case TdsColumnType.Image :
-                                               dataTypeNames.Add ("image");
-                                               row ["ProviderType"] = (int) SqlDbType.Image;
-                                               row ["DataType"] = typeof (byte[]);
-                                               row ["IsLong"] = true;
-                                               break;
-                                       case TdsColumnType.Text :
-                                               dataTypeNames.Add ("text");
-                                               row ["ProviderType"] = (int) SqlDbType.Text;
-                                               row ["DataType"] = typeof (string);
-                                               row ["IsLong"] = true;
-                                               break;
-                                       case TdsColumnType.UniqueIdentifier :
-                                               dataTypeNames.Add ("uniqueidentifier");
-                                               row ["ProviderType"] = (int) SqlDbType.UniqueIdentifier;
-                                               row ["DataType"] = typeof (Guid);
-                                               row ["IsLong"] = false;
-                                               break;
-                                       case TdsColumnType.VarBinary :
-                                       case TdsColumnType.BigVarBinary :
-                                               dataTypeNames.Add ("varbinary");
-                                               row ["ProviderType"] = (int) SqlDbType.VarBinary;
-                                               row ["DataType"] = typeof (byte[]);
-                                               row ["IsLong"] = true;
-                                               break;
-                                       case TdsColumnType.VarChar :
-                                       case TdsColumnType.BigVarChar :
-                                               dataTypeNames.Add ("varchar");
-                                               row ["ProviderType"] = (int) SqlDbType.VarChar;
-                                               row ["DataType"] = typeof (string);
-                                               row ["IsLong"] = false;
-                                               break;
-                                       case TdsColumnType.Binary :
-                                       case TdsColumnType.BigBinary :
-                                               dataTypeNames.Add ("binary");
-                                               row ["ProviderType"] = (int) SqlDbType.Binary;
-                                               row ["DataType"] = typeof (byte[]);
-                                               row ["IsLong"] = true;
-                                               break;
-                                       case TdsColumnType.Char :
-                                       case TdsColumnType.BigChar :
-                                               dataTypeNames.Add ("char");
-                                               row ["ProviderType"] = (int) SqlDbType.Char;
-                                               row ["DataType"] = typeof (string);
-                                               row ["IsLong"] = false;
-                                               break;
-                                       case TdsColumnType.Bit :
-                                       case TdsColumnType.BitN :
-                                               dataTypeNames.Add ("bit");
-                                               row ["ProviderType"] = (int) SqlDbType.Bit;
-                                               row ["DataType"] = typeof (bool);
-                                               row ["IsLong"] = 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;
-                                               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;
-                                               break;
-                                       case TdsColumnType.NText :
-                                               dataTypeNames.Add ("ntext");
-                                               row ["ProviderType"] = (int) SqlDbType.NText;
-                                               row ["DataType"] = typeof (string);
-                                               row ["IsLong"] = true;
-                                               break;
-                                       case TdsColumnType.NVarChar :
-                                               dataTypeNames.Add ("nvarchar");
-                                               row ["ProviderType"] = (int) SqlDbType.NVarChar;
-                                               row ["DataType"] = typeof (string);
-                                               row ["IsLong"] = false;
-                                               break;
-                                       case TdsColumnType.Decimal :
-                                       case TdsColumnType.Numeric :
-                                               dataTypeNames.Add ("decimal");
-                                               row ["ProviderType"] = (int) SqlDbType.Decimal;
-                                               row ["DataType"] = typeof (decimal);
-                                               row ["IsLong"] = false;
-                                               break;
-                                       case TdsColumnType.NChar :
-                                               dataTypeNames.Add ("nchar");
-                                               row ["ProviderType"] = (int) SqlDbType.NChar;
-                                               row ["DataType"] = typeof (string);
-                                               row ["IsLong"] = false;
-                                               break;
-                                       case TdsColumnType.SmallMoney :
-                                               dataTypeNames.Add ("smallmoney");
-                                               row ["ProviderType"] = (int) SqlDbType.SmallMoney;
-                                               row ["DataType"] = typeof (decimal);
-                                               row ["IsLong"] = false;
-                                               break;
-                                       default :
-                                               dataTypeNames.Add ("variant");
-                                               row ["ProviderType"] = (int) SqlDbType.Variant;
-                                               row ["DataType"] = typeof (object);
-                                               row ["IsLong"] = false;
-                                               break;
-                               }
-#if NET_2_0
-                               if ((bool)row ["IsHidden"] == false)
+                               if (row [BASE_COLUMN_NAME_IDX] == DBNull.Value)
+                                       row [BASE_COLUMN_NAME_IDX] = row [COLUMN_NAME_IDX];
+
+                               TdsColumnType ctype;
+                               int csize, dbType;
+                               Type fieldType;
+                               bool isLong;
+                               string typeName;
+                               short precision;
+                               short scale;
+                               ctype = (TdsColumnType) schema.ColumnType;
+                               csize = (int) schema.ColumnSize;
+                               precision = (short) GetSchemaValue (schema.NumericPrecision);
+                               scale = (short) GetSchemaValue (schema.NumericScale);
+
+                               GetSchemaRowType (ctype, csize, precision, scale,
+                                       out dbType, out fieldType, out isLong,
+                                       out typeName);
+                               
+                               row [COLUMN_SIZE_IDX] = csize;
+                               row [NUMERIC_PRECISION_IDX] = precision;
+                               row [NUMERIC_SCALE_IDX] = scale;
+                               row [PROVIDER_TYPE_IDX] = dbType;
+                               row [DATA_TYPE_IDX] = fieldType;
+                               row [IS_LONG_IDX] = isLong;
+                               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;
                }
 
+               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);
@@ -797,9 +968,7 @@ namespace System.Data.SqlClient {
                }
 
                public
-#if NET_2_0
                virtual
-#endif
                SqlBoolean GetSqlBoolean (int i) 
                {
                        object value = GetSqlValue (i);
@@ -809,9 +978,7 @@ namespace System.Data.SqlClient {
                }
 
                public
-#if NET_2_0
                virtual
-#endif
                SqlByte GetSqlByte (int i)
                {
                        object value = GetSqlValue (i);
@@ -821,9 +988,7 @@ namespace System.Data.SqlClient {
                }
 
                public
-#if NET_2_0
                virtual
-#endif
                SqlDateTime GetSqlDateTime (int i)
                {
                        object value = GetSqlValue (i);
@@ -833,9 +998,7 @@ namespace System.Data.SqlClient {
                }
 
                public
-#if NET_2_0
                virtual
-#endif
                SqlDecimal GetSqlDecimal (int i)
                {
                        object value = GetSqlValue (i);
@@ -845,9 +1008,7 @@ namespace System.Data.SqlClient {
                }
 
                public
-#if NET_2_0
                virtual
-#endif
                SqlDouble GetSqlDouble (int i)
                {
                        object value = GetSqlValue (i);
@@ -857,9 +1018,7 @@ namespace System.Data.SqlClient {
                }
 
                public
-#if NET_2_0
                virtual
-#endif
                SqlGuid GetSqlGuid (int i)
                {
                        object value = GetSqlValue (i);
@@ -869,9 +1028,7 @@ namespace System.Data.SqlClient {
                }
 
                public
-#if NET_2_0
                virtual
-#endif
                SqlInt16 GetSqlInt16 (int i)
                {
                        object value = GetSqlValue (i);
@@ -881,9 +1038,7 @@ namespace System.Data.SqlClient {
                }
 
                public
-#if NET_2_0
                virtual
-#endif
                SqlInt32 GetSqlInt32 (int i)
                {
                        object value = GetSqlValue (i);
@@ -893,27 +1048,17 @@ namespace System.Data.SqlClient {
                }
 
                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)
-                                       value = (SqlInt64) (SqlDecimal) value;
-                       }
                        if (!(value is SqlInt64))
                                throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
                        return (SqlInt64) value;
                }
 
                public
-#if NET_2_0
                virtual
-#endif
                SqlMoney GetSqlMoney (int i)
                {
                        object value = GetSqlValue (i);
@@ -923,9 +1068,7 @@ namespace System.Data.SqlClient {
                }
 
                public
-#if NET_2_0
                virtual
-#endif
                SqlSingle GetSqlSingle (int i)
                {
                        object value = GetSqlValue (i);
@@ -935,9 +1078,7 @@ namespace System.Data.SqlClient {
                }
 
                public
-#if NET_2_0
                virtual
-#endif
                SqlString GetSqlString (int i)
                {
                        object value = GetSqlValue (i);
@@ -946,27 +1087,36 @@ namespace System.Data.SqlClient {
                        return (SqlString) value;
                }
 
-#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 ());
+                               if (value is DBNull) {
+                                       throw new SqlNullValueException ();
+                               } else if (command.Tds.TdsVersion <= TdsVersion.tds80 && value is SqlString) {
+                                       // Workaround for TDS 7/8/8.1 clients
+                                       // Xml column types are supported only from Sql Server 2005 / TDS 9, however
+                                       // when a TDS 7/8/8.1 client requests for Xml column data, Sql Server 2005 returns
+                                       // it as NTEXT
+                                       MemoryStream stream = null;
+                                       if (!((SqlString) value).IsNull)
+                                               stream = new MemoryStream (Encoding.Unicode.GetBytes (value.ToString()));
+                                       value = new SqlXml (stream);
+                               } else {
+                                       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)
                {
-                       SqlDbType type = (SqlDbType) (schemaTable.Rows [i]["ProviderType"]);
                        object value = GetValue (i);
-
+                       //Console.WriteLine ("Type of value: {0}", value.GetType ());
+                       
+                       SqlDbType type = GetSchemaRowDbType (i);
                        switch (type) {
                        case SqlDbType.BigInt:
                                if (value == DBNull.Value)
@@ -1001,7 +1151,9 @@ namespace System.Data.SqlClient {
                                if (value == DBNull.Value)
                                        return SqlDecimal.Null;
                                if (value is TdsBigDecimal)
-                                       return SqlDecimal.FromTdsBigDecimal ((TdsBigDecimal) value);
+                                       return SqlDecimalExtensions.FromTdsBigDecimal ((TdsBigDecimal) value);
+                               if (value is Int64)
+                                       return (SqlDecimal)((long) value);
                                return (SqlDecimal) ((decimal) value);
                        case SqlDbType.Float:
                                if (value == DBNull.Value)
@@ -1032,25 +1184,27 @@ 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
-#if NET_2_0
                virtual
-#endif
                int GetSqlValues (object[] values)
                {
+                       ValidateState ();
+                       EnsureDataAvailable ();
+
+                       if (values == null)
+                               throw new ArgumentNullException ("values");
+
                        int count = 0;
-                       int columnCount = schemaTable.Rows.Count;
+                       int columnCount = command.Tds.Columns.Count;
                        int arrayCount = values.Length;
 
                        if (arrayCount > columnCount)
@@ -1064,10 +1218,8 @@ namespace System.Data.SqlClient {
                        return count;
                }
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                string GetString (int i)
                {
                        object value = GetValue (i);
@@ -1078,12 +1230,13 @@ namespace System.Data.SqlClient {
                        return (string) value;
                }
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                object GetValue (int i)
                {
+                       ValidateState ();
+                       EnsureDataAvailable ();
+
                        if (i < 0 || i >= command.Tds.Columns.Count)
                                throw new IndexOutOfRangeException ();
 
@@ -1099,12 +1252,16 @@ namespace System.Data.SqlClient {
                        return command.Tds.ColumnValues [i];
                }
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                int GetValues (object[] values)
                {
+                       ValidateState ();
+                       EnsureDataAvailable ();
+
+                       if (values == null)
+                               throw new ArgumentNullException ("values");
+
                        int len = values.Length;
                        int bigDecimalIndex = command.Tds.ColumnValues.BigDecimalIndex;
 
@@ -1122,42 +1279,31 @@ namespace System.Data.SqlClient {
                        return (len < FieldCount ? len : FieldCount);
                }
 
-#if !NET_2_0
-               void IDisposable.Dispose ()
-               {
-                       Dispose (true);
-                       GC.SuppressFinalize (this);
-               }
-#endif
 
-#if NET_2_0
                public override IEnumerator GetEnumerator ()
-#else
-               IEnumerator IEnumerable.GetEnumerator ()
-#endif
                {
                        return new DbEnumerator (this);
                }
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                bool IsDBNull (int i)
                {
                        return GetValue (i) == DBNull.Value;
                }
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                bool NextResult ()
                {
                        ValidateState ();
 
-                       if ((command.CommandBehavior & CommandBehavior.SingleResult) != 0 && resultsRead > 0)
+                       if ((command.CommandBehavior & CommandBehavior.SingleResult) != 0 && resultsRead > 0) {
+                               moreResults = false;
+                               rowsRead = 0;
+                               haveRead = false;
                                return false;
+                       }
 
                        try {
                                moreResults = command.Tds.NextResult ();
@@ -1168,45 +1314,44 @@ namespace System.Data.SqlClient {
                        if (!moreResults)
                                command.GetOutputParameters ();
                        else {
-                               //new schema
-                               schemaTable = ConstructSchemaTable ();
-                               GetSchemaTable ();
+                               // new schema - don't do anything except reset schemaTable as command.Tds.Columns is already updated
+                               schemaTable = null;
                        }
 
                        rowsRead = 0;
+                       haveRead = false;
                        resultsRead += 1;
                        return moreResults;
                }
 
-               public 
-#if NET_2_0
+               public
                override
-#endif // NET_2_0
                bool Read ()
                {
                        ValidateState ();
 
-                       if ((command.CommandBehavior & CommandBehavior.SingleRow) != 0 && rowsRead > 0)
+                       if (!haveRead || readResultUsed)
+                               readResult = ReadRecord ();
+                       readResultUsed = true;
+                       return readResult;
+               }
+
+               internal bool ReadRecord ()
+               {
+                       readResultUsed = false;
+
+                       if ((command.CommandBehavior & CommandBehavior.SingleRow) != 0 && haveRead)
                                return false;
                        if ((command.CommandBehavior & CommandBehavior.SchemaOnly) != 0)
                                return false;
                        if (!moreResults)
                                return false;
-       
-                       if ((haveRead) && (!readResultUsed))
-                       {
-                               readResultUsed = true;
-                               return true;
-                       }
-                       return (ReadRecord ());
-               }
 
-               internal bool ReadRecord ()
-               {
                        try {
                                bool result = command.Tds.NextRow ();
-                       
-                               rowsRead += 1;
+                               if (result)
+                                       rowsRead++;
+                               haveRead = true;
                                return result;
                        } catch (TdsInternalException ex) {
                                command.Connection.Close ();
@@ -1219,17 +1364,31 @@ namespace System.Data.SqlClient {
                        if (IsClosed)
                                throw new InvalidOperationException ("Invalid attempt to read data when reader is closed");
                }
-               
-#if NET_2_0
 
-               public override Type GetProviderSpecificFieldType (int position)
+               void EnsureDataAvailable ()
+               {
+                       if (!readResult || !haveRead || !readResultUsed)
+                               throw new InvalidOperationException ("No data available.");
+               }
+
+               InvalidCastException CreateGetBytesOnInvalidColumnTypeException (int ordinal)
+               {
+                       string message = string.Format (CultureInfo.InvariantCulture,
+                               "Invalid attempt to GetBytes on column '{0}'." +
+                               "The GetBytes function can only be used on " +
+                               "columns of type Text, NText, or Image.",
+                               GetName (ordinal));
+                       return new InvalidCastException (message);
+               }
+
+               public override Type GetProviderSpecificFieldType (int i)
                {
-                       return (GetSqlValue (position).GetType());
+                       return (GetSqlValue (i).GetType());
                }
 
-               public override object GetProviderSpecificValue (int position)
+               public override object GetProviderSpecificValue (int i)
                {
-                       return (GetSqlValue (position));
+                       return (GetSqlValue (i));
                }
 
                public override int GetProviderSpecificValues (object [] values)
@@ -1246,7 +1405,17 @@ namespace System.Data.SqlClient {
                        SqlBytes sb = new SqlBytes (val);
                        return (sb);
                }
-#endif // NET_2_0
+
+               public override T GetFieldValue<T> (int i)
+               {
+                       return (T)GetValue(i);
+               }
+
+               [MonoTODO]
+               public virtual XmlReader GetXmlReader (int i)
+               {
+                       throw new NotImplementedException ();   
+               }
 
                #endregion // Methods
        }