Merge pull request #1949 from lewurm/fixtype
[mono.git] / mcs / class / System.Data / System.Data.SqlClient / SqlDataReader.cs
index 53f80db97852b96a93145e1cf503a997b8f6053e..7410c36c2a1c1829f16c27403512cf8b23c5758f 100644 (file)
@@ -43,19 +43,16 @@ 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
        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;
                bool isClosed;
                bool moreResults;
@@ -65,9 +62,7 @@ namespace System.Data.SqlClient
                bool haveRead;
                bool readResult;
                bool readResultUsed;
-#if NET_2_0
                int visibleFieldCount;
-#endif
 
                #endregion // Fields
 
@@ -94,21 +89,21 @@ namespace System.Data.SqlClient
                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)
                {
-                       readResult = false;
-                       haveRead = false;
-                       readResultUsed = false;
                        this.command = command;
-                       resultsRead = 0;
-                       isClosed = false;
                        command.Tds.RecordsAffected = -1;
-#if NET_2_0
-                       visibleFieldCount = 0;
-#endif
                        NextResult ();
                }
 
@@ -117,70 +112,59 @@ namespace System.Data.SqlClient
                #region Properties
 
                public
-#if NET_2_0
                override
-#endif // NET_2_0
                int Depth {
                        get { return 0; }
                }
 
                public
-#if NET_2_0
                override
-#endif // NET_2_0
                int FieldCount {
-                       get { return command.Tds.Columns.Count; }
+                       get {
+                               ValidateState ();
+                               return command.Tds.Columns.Count;
+                       }
                }
 
                public
-#if NET_2_0
                override
-#endif // NET_2_0
                bool IsClosed {
                        get { return isClosed; }
                }
 
                public
-#if NET_2_0
                override
-#endif // NET_2_0
                object this [int i] {
                        get { return GetValue (i); }
                }
 
                public
-#if NET_2_0
                override
-#endif // NET_2_0
                object this [string name] {
                        get { return GetValue (GetOrdinal (name)); }
                }
        
                public
-#if NET_2_0
                override
-#endif // NET_2_0
                int RecordsAffected {
                        get {
-                               return command.Tds.RecordsAffected; 
+                               return command.Tds.RecordsAffected;
                        }
                }
 
                public
-#if NET_2_0
                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 {
                        get { return visibleFieldCount; }
                }
@@ -192,16 +176,13 @@ namespace System.Data.SqlClient
                protected bool IsCommandBehavior (CommandBehavior condition) {
                        return condition == command.CommandBehavior;
                }
-#endif
 
                #endregion // Properties
 
                #region Methods
 
                public
-#if NET_2_0
                override
-#endif // NET_2_0
                void Close ()
                {
                        if (IsClosed)
@@ -245,40 +226,79 @@ 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;
                }
                
-               private void GetSchemaRowTypeName (TdsColumnType ctype, int csize, out string typeName) 
+               private string GetSchemaRowTypeName (TdsColumnType ctype, int csize, short precision, short scale)
                {
                        int dbType;
                        bool isLong;
                        Type fieldType;
-                       
-                       GetSchemaRowType (ctype, csize, out dbType, out fieldType, out isLong, out typeName);
+
+                       string typeName;
+                       GetSchemaRowType (ctype, csize, precision, scale,
+                               out dbType, out fieldType, out isLong,
+                               out typeName);
+                       return typeName;
                }
 
-               private void GetSchemaRowFieldType (TdsColumnType ctype, int csize, out Type fieldType) 
+               private Type GetSchemaRowFieldType (TdsColumnType ctype, int csize, short precision, short scale)
                {
                        int dbType;
                        bool isLong;
+                       Type fieldType;
                        string typeName;
-                       
-                       GetSchemaRowType (ctype, csize, out dbType, out fieldType, out isLong, out typeName);
+
+                       GetSchemaRowType (ctype, csize, precision, scale,
+                               out dbType, out fieldType, out isLong,
+                               out typeName);
+                       return fieldType;
                }
 
-               private void GetSchemaRowDbType (TdsColumnType ctype, int csize, out int dbType) 
+               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;
-                       
-                       GetSchemaRowType (ctype, csize, out dbType, out fieldType, out isLong, out 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, 
-                                              out int dbType, out Type fieldType, 
-                                              out bool isLong, out string typeName)
+               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;
@@ -290,6 +310,7 @@ namespace System.Data.SqlClient
                                case TdsColumnType.Int2:
                                case TdsColumnType.Int4:
                                case TdsColumnType.IntN:
+                               case TdsColumnType.BigInt:
                                        switch (csize) {
                                        case 1:
                                                typeName = "tinyint";
@@ -358,7 +379,7 @@ namespace System.Data.SqlClient
                                        typeName = "varbinary";
                                        dbType = (int) SqlDbType.VarBinary;
                                        fieldType = typeof (byte[]);
-                                       isLong = true;
+                                       isLong = false;
                                        break;
                                case TdsColumnType.VarChar :
                                case TdsColumnType.BigVarChar :
@@ -372,7 +393,7 @@ namespace System.Data.SqlClient
                                        typeName = "binary";
                                        dbType = (int) SqlDbType.Binary;
                                        fieldType = typeof (byte[]);
-                                       isLong = true;
+                                       isLong = false;
                                        break;
                                case TdsColumnType.Char :
                                case TdsColumnType.BigChar :
@@ -391,18 +412,38 @@ namespace System.Data.SqlClient
                                case TdsColumnType.DateTime4 :
                                case TdsColumnType.DateTime :
                                case TdsColumnType.DateTimeN :
-                                       typeName = "datetime";
-                                       dbType = (int) SqlDbType.DateTime;
-                                       fieldType = typeof (DateTime);
-                                       isLong = false;
+                                       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 :
-                                       typeName = "money";
-                                       dbType = (int) SqlDbType.Money;
-                                       fieldType = typeof (decimal);
-                                       isLong = false;
+                                       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";
@@ -418,9 +459,16 @@ namespace System.Data.SqlClient
                                        break;
                                case TdsColumnType.Decimal :
                                case TdsColumnType.Numeric :
-                                       typeName = "decimal";
-                                       dbType = (int) SqlDbType.Decimal;
-                                       fieldType = typeof (decimal);
+                                       // 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 :
@@ -444,9 +492,7 @@ namespace System.Data.SqlClient
                        }
                }
 
-#if NET_2_0
                new
-#endif
                void Dispose (bool disposing)
                {
                        if (!disposed) {
@@ -461,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);
@@ -475,9 +519,7 @@ namespace System.Data.SqlClient
                }
 
                public
-#if NET_2_0
                override
-#endif // NET_2_0
                byte GetByte (int i)
                {
                        object value = GetValue (i);
@@ -489,19 +531,19 @@ namespace System.Data.SqlClient
                }
 
                public
-#if NET_2_0
                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 ();
@@ -511,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
                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
                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"];
@@ -608,41 +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
                override
-#endif // NET_2_0
                string GetDataTypeName (int i)
                {
+                       TdsDataColumn column;
                        TdsColumnType ctype;
-                       string datatypeName;
                        int csize;
-                       
+                       short precision;
+                       short scale;
+
+                       ValidateState ();
+
                        if (i < 0 || i >= command.Tds.Columns.Count)
                                throw new IndexOutOfRangeException ();
-#if NET_2_0
-                       ctype = (TdsColumnType) command.Tds.Columns[i].ColumnType;
-                       csize = (int) command.Tds.Columns[i].ColumnSize;
-#else
-                       ctype = (TdsColumnType) command.Tds.Columns[i]["ColumnType"];
-                       csize = (int) command.Tds.Columns[i]["ColumnSize"];
-#endif
-                       GetSchemaRowTypeName (ctype, csize, out datatypeName);
-                       return datatypeName;
+
+                       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
                override
-#endif // NET_2_0
                DateTime GetDateTime (int i)
                {
                        object value = GetValue (i);
@@ -653,10 +707,26 @@ namespace System.Data.SqlClient
                        return (DateTime) value;
                }
 
+               [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
-#if NET_2_0
                override
-#endif // NET_2_0
                decimal GetDecimal (int i)
                {
                        object value = GetValue (i);
@@ -668,9 +738,7 @@ namespace System.Data.SqlClient
                }
 
                public
-#if NET_2_0
                override
-#endif // NET_2_0
                double GetDouble (int i)
                {
                        object value = GetValue (i);
@@ -682,32 +750,31 @@ namespace System.Data.SqlClient
                }
 
                public
-#if NET_2_0
                override
-#endif // NET_2_0
                Type GetFieldType (int i)
                {
+                       TdsDataColumn column;
                        TdsColumnType ctype;
-                       Type fieldType;
                        int csize;
-                       
+                       short precision;
+                       short scale;
+
+                       ValidateState ();
+
                        if (i < 0 || i >= command.Tds.Columns.Count)
                                throw new IndexOutOfRangeException ();
-#if NET_2_0
-                       ctype = (TdsColumnType) command.Tds.Columns[i].ColumnType;
-                       csize = (int) command.Tds.Columns[i].ColumnSize;
-#else
-                       ctype = (TdsColumnType) command.Tds.Columns[i]["ColumnType"];
-                       csize = (int) command.Tds.Columns[i]["ColumnSize"];
-#endif
-                       GetSchemaRowFieldType (ctype, csize, out fieldType);                    
-                       return fieldType;
+
+                       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
                override
-#endif // NET_2_0
                float GetFloat (int i)
                {
                        object value = GetValue (i);
@@ -719,9 +786,7 @@ namespace System.Data.SqlClient
                }
 
                public
-#if NET_2_0
                override
-#endif // NET_2_0
                Guid GetGuid (int i)
                {
                        object value = GetValue (i);
@@ -733,9 +798,7 @@ namespace System.Data.SqlClient
                }
 
                public
-#if NET_2_0
                override
-#endif // NET_2_0
                short GetInt16 (int i)
                {
                        object value = GetValue (i);
@@ -747,9 +810,7 @@ namespace System.Data.SqlClient
                }
 
                public
-#if NET_2_0
                override
-#endif // NET_2_0
                int GetInt32 (int i)
                {
                        object value = GetValue (i);
@@ -761,9 +822,7 @@ namespace System.Data.SqlClient
                }
 
                public
-#if NET_2_0
                override
-#endif // NET_2_0
                long GetInt64 (int i)
                {
                        object value = GetValue (i);
@@ -775,45 +834,36 @@ namespace System.Data.SqlClient
                }
 
                public
-#if NET_2_0
                override
-#endif // NET_2_0
                string GetName (int i)
                {
+                       ValidateState ();
+
                        if (i < 0 || i >= command.Tds.Columns.Count)
                                throw new IndexOutOfRangeException ();
-#if NET_2_0
                        return (string) command.Tds.Columns[i].ColumnName;
-#else
-                       return (string) command.Tds.Columns[i]["ColumnName"];
-#endif
                }
 
                public
-#if NET_2_0
                override
-#endif // NET_2_0
                int GetOrdinal (string name)
                {
+                       ValidateState ();
+
+                       if (name == null)
+                               throw new ArgumentNullException ("fieldName");
+
                        string colName;
                        foreach (TdsDataColumn schema in command.Tds.Columns) {
-#if NET_2_0
                                colName = schema.ColumnName;
                                if (colName.Equals (name) || String.Compare (colName, name, true) == 0)
                                        return (int) schema.ColumnOrdinal;
-#else
-                               colName = (string) schema["ColumnName"];
-                               if (colName.Equals (name) || String.Compare (colName, name, true) == 0)
-                                       return (int) schema["ColumnOrdinal"];
-#endif                                         
-                       }                       
+                       }
                        throw new IndexOutOfRangeException ();
                }
 
                public
-#if NET_2_0
                override
-#endif // NET_2_0
                DataTable GetSchemaTable ()
                {
                        ValidateState ();
@@ -827,12 +877,9 @@ namespace System.Data.SqlClient
                        if (!moreResults)
                                return null;
 
-                       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);
@@ -840,9 +887,7 @@ namespace System.Data.SqlClient
                                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);
@@ -853,56 +898,42 @@ namespace System.Data.SqlClient
                                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 ["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 ["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");
-#endif
+                               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 [BASE_COLUMN_NAME_IDX] == DBNull.Value)
                                        row [BASE_COLUMN_NAME_IDX] = row [COLUMN_NAME_IDX];
 
                                TdsColumnType ctype;
-                               int csize, dbType;                              
+                               int csize, dbType;
                                Type fieldType;
                                bool isLong;
                                string typeName;
-#if NET_2_0
+                               short precision;
+                               short scale;
                                ctype = (TdsColumnType) schema.ColumnType;
                                csize = (int) schema.ColumnSize;
-#else
-                               ctype = (TdsColumnType) schema ["ColumnType"];
-                               csize = (int) schema ["ColumnSize"];
-#endif
+                               precision = (short) GetSchemaValue (schema.NumericPrecision);
+                               scale = (short) GetSchemaValue (schema.NumericScale);
 
-                               GetSchemaRowType (ctype, csize, out dbType, 
-                                                                       out fieldType, out isLong, out typeName);
+                               GetSchemaRowType (ctype, csize, precision, scale,
+                                       out dbType, out fieldType, out isLong,
+                                       out typeName);
                                
-                               dataTypeNames.Add (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 NET_2_0
+                               row [IS_LONG_IDX] = isLong;
                                if ((bool)row [IS_HIDDEN_IDX] == false)
                                        visibleFieldCount += 1;
-#endif
 
                                schemaTable.Rows.Add (row);
                        }
@@ -918,7 +949,6 @@ namespace System.Data.SqlClient
                                return DBNull.Value;
                }
 
-#if NET_2_0
                static object GetSchemaValue (object value)
                {
                        if (value == null)
@@ -926,12 +956,9 @@ namespace System.Data.SqlClient
 
                        return value;
                }
-#endif         
                
                public
-#if NET_2_0
                virtual
-#endif
                SqlBinary GetSqlBinary (int i)
                {
                        object value = GetSqlValue (i);
@@ -941,9 +968,7 @@ namespace System.Data.SqlClient
                }
 
                public
-#if NET_2_0
                virtual
-#endif
                SqlBoolean GetSqlBoolean (int i) 
                {
                        object value = GetSqlValue (i);
@@ -953,9 +978,7 @@ namespace System.Data.SqlClient
                }
 
                public
-#if NET_2_0
                virtual
-#endif
                SqlByte GetSqlByte (int i)
                {
                        object value = GetSqlValue (i);
@@ -965,9 +988,7 @@ namespace System.Data.SqlClient
                }
 
                public
-#if NET_2_0
                virtual
-#endif
                SqlDateTime GetSqlDateTime (int i)
                {
                        object value = GetSqlValue (i);
@@ -977,9 +998,7 @@ namespace System.Data.SqlClient
                }
 
                public
-#if NET_2_0
                virtual
-#endif
                SqlDecimal GetSqlDecimal (int i)
                {
                        object value = GetSqlValue (i);
@@ -989,9 +1008,7 @@ namespace System.Data.SqlClient
                }
 
                public
-#if NET_2_0
                virtual
-#endif
                SqlDouble GetSqlDouble (int i)
                {
                        object value = GetSqlValue (i);
@@ -1001,9 +1018,7 @@ namespace System.Data.SqlClient
                }
 
                public
-#if NET_2_0
                virtual
-#endif
                SqlGuid GetSqlGuid (int i)
                {
                        object value = GetSqlValue (i);
@@ -1013,9 +1028,7 @@ namespace System.Data.SqlClient
                }
 
                public
-#if NET_2_0
                virtual
-#endif
                SqlInt16 GetSqlInt16 (int i)
                {
                        object value = GetSqlValue (i);
@@ -1025,9 +1038,7 @@ namespace System.Data.SqlClient
                }
 
                public
-#if NET_2_0
                virtual
-#endif
                SqlInt32 GetSqlInt32 (int i)
                {
                        object value = GetSqlValue (i);
@@ -1037,36 +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];
-                               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))
                                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);
@@ -1076,9 +1068,7 @@ namespace System.Data.SqlClient
                }
 
                public
-#if NET_2_0
                virtual
-#endif
                SqlSingle GetSqlSingle (int i)
                {
                        object value = GetSqlValue (i);
@@ -1088,9 +1078,7 @@ namespace System.Data.SqlClient
                }
 
                public
-#if NET_2_0
                virtual
-#endif
                SqlString GetSqlString (int i)
                {
                        object value = GetSqlValue (i);
@@ -1099,40 +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)
                {
-                       int dbType, csize;
-                       TdsColumnType ctype;
-                       
-                       if (i < 0 || i >= command.Tds.Columns.Count)
-                               throw new IndexOutOfRangeException ();
-#if NET_2_0
-                       ctype = (TdsColumnType) command.Tds.Columns[i].ColumnType;
-                       csize = (int) command.Tds.Columns[i].ColumnSize;
-#else
-                       ctype = (TdsColumnType) command.Tds.Columns[i]["ColumnType"];
-                       csize = (int) command.Tds.Columns[i]["ColumnSize"];
-#endif
-                       GetSchemaRowDbType (ctype, csize, out dbType);
-                       SqlDbType type = (SqlDbType) dbType;
                        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)
@@ -1167,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)
@@ -1198,23 +1184,25 @@ 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 = command.Tds.Columns.Count;
                        int arrayCount = values.Length;
@@ -1231,9 +1219,7 @@ namespace System.Data.SqlClient
                }
 
                public
-#if NET_2_0
                override
-#endif // NET_2_0
                string GetString (int i)
                {
                        object value = GetValue (i);
@@ -1245,11 +1231,12 @@ namespace System.Data.SqlClient
                }
 
                public
-#if NET_2_0
                override
-#endif // NET_2_0
                object GetValue (int i)
                {
+                       ValidateState ();
+                       EnsureDataAvailable ();
+
                        if (i < 0 || i >= command.Tds.Columns.Count)
                                throw new IndexOutOfRangeException ();
 
@@ -1266,11 +1253,15 @@ namespace System.Data.SqlClient
                }
 
                public
-#if NET_2_0
                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;
 
@@ -1288,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
                override
-#endif // NET_2_0
                bool IsDBNull (int i)
                {
                        return GetValue (i) == DBNull.Value;
                }
 
                public
-#if NET_2_0
                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 ();
@@ -1336,43 +1316,42 @@ namespace System.Data.SqlClient
                        else {
                                // new schema - don't do anything except reset schemaTable as command.Tds.Columns is already updated
                                schemaTable = null;
-                               dataTypeNames = null;
                        }
 
                        rowsRead = 0;
+                       haveRead = false;
                        resultsRead += 1;
                        return moreResults;
                }
 
                public
-#if NET_2_0
                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 ();
@@ -1385,8 +1364,23 @@ namespace System.Data.SqlClient
                        if (IsClosed)
                                throw new InvalidOperationException ("Invalid attempt to read data when reader is closed");
                }
-               
-#if NET_2_0
+
+               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 (i).GetType());
@@ -1411,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
        }