New test.
[mono.git] / mcs / class / Mono.Data.SybaseClient / Mono.Data.SybaseClient / SybaseDataReader.cs
index 1c1d1d29fcfd82dac8d4614f06598a24ac60ec31..2232938410a56951b684b960691d3f574e7d964c 100644 (file)
@@ -2,12 +2,38 @@
 // Mono.Data.SybaseClient.SybaseDataReader.cs
 //
 // Author:
+//   Rodrigo Moya (rodrigo@ximian.com)
+//   Daniel Morgan (danmorg@sc.rr.com)
 //   Tim Coleman (tim@timcoleman.com)
 //
+// (C) Ximian, Inc 2002
+// (C) Daniel Morgan 2002
 // Copyright (C) Tim Coleman, 2002
 //
 
-using Mono.Data.TdsClient.Internal;
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using Mono.Data.SybaseTypes;
+using Mono.Data.Tds.Protocol;
 using System;
 using System.Collections;
 using System.ComponentModel;
@@ -19,37 +45,34 @@ namespace Mono.Data.SybaseClient {
        {
                #region Fields
 
+               SybaseCommand command;
+               ArrayList dataTypeNames;
+               bool disposed = false;
                int fieldCount;
-               bool hasRows;
                bool isClosed;
-               int recordsAffected;
+               bool isSelect;
                bool moreResults;
-
                int resultsRead;
                int rowsRead;
-
-               SybaseCommand command;
                DataTable schemaTable;
 
-               ArrayList dataTypeNames;
-               ArrayList dataTypes;
-
                #endregion // Fields
 
                #region Constructors
 
                internal SybaseDataReader (SybaseCommand command)
                {
-                       schemaTable = ConstructSchemaTable ();
-                       this.resultsRead = 0;
                        this.command = command;
-                       this.fieldCount = 0;
-                       this.isClosed = false;
-
+                       schemaTable = ConstructSchemaTable ();
+                       resultsRead = 0;
+                       fieldCount = 0;
+                       isClosed = false;
+                       isSelect = (command.CommandText.Trim ().ToUpper ().StartsWith ("SELECT"));
+                       command.Tds.RecordsAffected = 0;
                        NextResult ();
                }
 
-               #endregion
+               #endregion // Constructors
 
                #region Properties
 
@@ -61,10 +84,6 @@ namespace Mono.Data.SybaseClient {
                        get { return fieldCount; }
                }
 
-               public bool HasRows {
-                       get { return hasRows; }
-               }
-
                public bool IsClosed {
                        get { return isClosed; }
                }
@@ -76,17 +95,21 @@ namespace Mono.Data.SybaseClient {
                public object this [string name] {
                        get { return GetValue (GetOrdinal (name)); }
                }
-               
-
+       
                public int RecordsAffected {
-                       get { return recordsAffected; }
+                       get { 
+                               if (isSelect) 
+                                       return -1;
+                               else
+                                       return command.Tds.RecordsAffected; 
+                       }
                }
 
                #endregion // Properties
 
                #region Methods
 
-               public void Close()
+               public void Close ()
                {
                        isClosed = true;
                        command.CloseDataReader (moreResults);
@@ -128,49 +151,70 @@ namespace Mono.Data.SybaseClient {
                        return schemaTable;
                }
 
+               private void Dispose (bool disposing) 
+               {
+                       if (!disposed) {
+                               if (disposing) {
+                                       schemaTable.Dispose ();
+                                       Close ();
+                               }
+                               disposed = true;
+                       }
+               }
+
                public bool GetBoolean (int i)
                {
                        object value = GetValue (i);
-                       if (!(value is bool))
+                       if (!(value is bool)) {
+                               if (value is DBNull) throw new SybaseNullValueException ();
                                throw new InvalidCastException ();
+                       }
                        return (bool) value;
                }
 
                public byte GetByte (int i)
                {
                        object value = GetValue (i);
-                       if (!(value is byte))
+                       if (!(value is byte)) {
+                               if (value is DBNull) throw new SybaseNullValueException ();
                                throw new InvalidCastException ();
+                       }
                        return (byte) value;
                }
 
-               [MonoTODO]
                public long GetBytes (int i, long dataIndex, byte[] buffer, int bufferIndex, int length)
                {
                        object value = GetValue (i);
-                       if (!(value is byte []))
+                       if (!(value is byte [])) {
+                               if (value is DBNull) throw new SybaseNullValueException ();
                                throw new InvalidCastException ();
+                       }
                        Array.Copy ((byte []) value, (int) dataIndex, buffer, bufferIndex, length);
                        return ((byte []) value).Length - dataIndex;
                }
 
-               [MonoTODO]
                public char GetChar (int i)
                {
-                       throw new NotImplementedException ();
+                       object value = GetValue (i);
+                       if (!(value is char)) {
+                               if (value is DBNull) throw new SybaseNullValueException ();
+                               throw new InvalidCastException ();
+                       }
+                       return (char) value;
                }
 
-               [MonoTODO]
                public long GetChars (int i, long dataIndex, char[] buffer, int bufferIndex, int length)
                {
                        object value = GetValue (i);
-                       if (!(value is char []))
+                       if (!(value is char[])) {
+                               if (value is DBNull) throw new SybaseNullValueException ();
                                throw new InvalidCastException ();
+                       }
                        Array.Copy ((char []) value, (int) dataIndex, buffer, bufferIndex, length);
                        return ((char []) value).Length - dataIndex;
                }
 
-               [MonoTODO]
+               [MonoTODO ("Implement GetData")]
                public IDataReader GetData (int i)
                {
                        throw new NotImplementedException ();
@@ -184,23 +228,30 @@ namespace Mono.Data.SybaseClient {
                public DateTime GetDateTime (int i)
                {
                        object value = GetValue (i);
-                       if (!(value is DateTime))
+                       if (!(value is DateTime)) {
+                               if (value is DBNull) throw new SybaseNullValueException ();
                                throw new InvalidCastException ();
+                       }
                        return (DateTime) value;
                }
 
                public decimal GetDecimal (int i)
                {
                        object value = GetValue (i);
-                       if (!(value is decimal))
+                       if (!(value is decimal)) {
+                               if (value is DBNull) throw new SybaseNullValueException ();
                                throw new InvalidCastException ();
+                       }
                        return (decimal) value;
                }
+
                public double GetDouble (int i)
                {
                        object value = GetValue (i);
-                       if (!(value is double))
+                       if (!(value is double)) {
+                               if (value is DBNull) throw new SybaseNullValueException ();
                                throw new InvalidCastException ();
+                       }
                        return (double) value;
                }
 
@@ -212,38 +263,50 @@ namespace Mono.Data.SybaseClient {
                public float GetFloat (int i)
                {
                        object value = GetValue (i);
-                       if (!(value is float))
+                       if (!(value is float)) {
+                               if (value is DBNull) throw new SybaseNullValueException ();
                                throw new InvalidCastException ();
+                       }
                        return (float) value;
                }
 
-               [MonoTODO]
                public Guid GetGuid (int i)
                {
-                       throw new NotImplementedException ();
+                       object value = GetValue (i);
+                       if (!(value is Guid)) {
+                               if (value is DBNull) throw new SybaseNullValueException ();
+                               throw new InvalidCastException ();
+                       }
+                       return (Guid) value;
                }
 
                public short GetInt16 (int i)
                {
                        object value = GetValue (i);
-                       if (!(value is short))
+                       if (!(value is short)) {
+                               if (value is DBNull) throw new SybaseNullValueException ();
                                throw new InvalidCastException ();
+                       }
                        return (short) value;
                }
 
                public int GetInt32 (int i)
                {
                        object value = GetValue (i);
-                       if (!(value is int))
+                       if (!(value is int)) {
+                               if (value is DBNull) throw new SybaseNullValueException ();
                                throw new InvalidCastException ();
+                       }
                        return (int) value;
                }
 
                public long GetInt64 (int i)
                {
                        object value = GetValue (i);
-                       if (!(value is long))
+                       if (!(value is long)) {
+                               if (value is DBNull) throw new SybaseNullValueException ();
                                throw new InvalidCastException ();
+                       }
                        return (long) value;
                }
 
@@ -252,7 +315,6 @@ namespace Mono.Data.SybaseClient {
                        return (string) schemaTable.Rows[i]["ColumnName"];
                }
 
-               [MonoTODO]
                public int GetOrdinal (string name)
                {
                        foreach (DataRow schemaRow in schemaTable.Rows)
@@ -275,74 +337,107 @@ namespace Mono.Data.SybaseClient {
                        fieldCount = 0;
 
                        dataTypeNames = new ArrayList ();
-                       dataTypes = new ArrayList ();
 
-                       foreach (TdsSchemaInfo schema in command.Tds.Schema) {
+                       foreach (TdsDataColumn schema in command.Tds.Columns) {
                                DataRow row = schemaTable.NewRow ();
 
-
-                               switch (schema.ColumnType) {
+                               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");
+
+                               // We don't always get the base column name.
+                               if (row ["BaseColumnName"] == DBNull.Value)
+                                       row ["BaseColumnName"] = row ["ColumnName"];
+
+                               switch ((TdsColumnType) schema ["ColumnType"]) {
                                        case TdsColumnType.Image :
                                                dataTypeNames.Add ("image");
                                                row ["ProviderType"] = (int) SybaseType.Image;
                                                row ["DataType"] = typeof (byte[]);
+                                               row ["IsLong"] = true;
                                                break;
                                        case TdsColumnType.Text :
-                                               dataTypes.Add (typeof (string));
                                                dataTypeNames.Add ("text");
                                                row ["ProviderType"] = (int) SybaseType.Text;
                                                row ["DataType"] = typeof (string);
+                                               row ["IsLong"] = true;
                                                break;
                                        case TdsColumnType.UniqueIdentifier :
                                                dataTypeNames.Add ("uniqueidentifier");
                                                row ["ProviderType"] = (int) SybaseType.UniqueIdentifier;
                                                row ["DataType"] = typeof (Guid);
+                                               row ["IsLong"] = false;
                                                break;
                                        case TdsColumnType.VarBinary :
                                        case TdsColumnType.BigVarBinary :
                                                dataTypeNames.Add ("varbinary");
                                                row ["ProviderType"] = (int) SybaseType.VarBinary;
                                                row ["DataType"] = typeof (byte[]);
+                                               row ["IsLong"] = true;
                                                break;
                                        case TdsColumnType.IntN :
                                        case TdsColumnType.Int4 :
                                                dataTypeNames.Add ("int");
                                                row ["ProviderType"] = (int) SybaseType.Int;
                                                row ["DataType"] = typeof (int);
+                                               row ["IsLong"] = false;
                                                break;
                                        case TdsColumnType.VarChar :
                                        case TdsColumnType.BigVarChar :
                                                dataTypeNames.Add ("varchar");
                                                row ["ProviderType"] = (int) SybaseType.VarChar;
                                                row ["DataType"] = typeof (string);
+                                               row ["IsLong"] = false;
                                                break;
                                        case TdsColumnType.Binary :
                                        case TdsColumnType.BigBinary :
                                                dataTypeNames.Add ("binary");
                                                row ["ProviderType"] = (int) SybaseType.Binary;
                                                row ["DataType"] = typeof (byte[]);
+                                               row ["IsLong"] = true;
                                                break;
                                        case TdsColumnType.Char :
                                        case TdsColumnType.BigChar :
                                                dataTypeNames.Add ("char");
                                                row ["ProviderType"] = (int) SybaseType.Char;
                                                row ["DataType"] = typeof (string);
+                                               row ["IsLong"] = false;
                                                break;
                                        case TdsColumnType.Int1 :
                                                dataTypeNames.Add ("tinyint");
                                                row ["ProviderType"] = (int) SybaseType.TinyInt;
                                                row ["DataType"] = typeof (byte);
+                                               row ["IsLong"] = false;
                                                break;
                                        case TdsColumnType.Bit :
                                        case TdsColumnType.BitN :
                                                dataTypeNames.Add ("bit");
                                                row ["ProviderType"] = (int) SybaseType.Bit;
                                                row ["DataType"] = typeof (bool);
+                                               row ["IsLong"] = false;
                                                break;
                                        case TdsColumnType.Int2 :
                                                dataTypeNames.Add ("smallint");
                                                row ["ProviderType"] = (int) SybaseType.SmallInt;
                                                row ["DataType"] = typeof (short);
+                                               row ["IsLong"] = false;
                                                break;
                                        case TdsColumnType.DateTime4 :
                                        case TdsColumnType.DateTime :
@@ -350,6 +445,7 @@ namespace Mono.Data.SybaseClient {
                                                dataTypeNames.Add ("datetime");
                                                row ["ProviderType"] = (int) SybaseType.DateTime;
                                                row ["DataType"] = typeof (DateTime);
+                                               row ["IsLong"] = false;
                                                break;
                                        case TdsColumnType.Real :
                                                dataTypeNames.Add ("real");
@@ -362,105 +458,295 @@ namespace Mono.Data.SybaseClient {
                                                dataTypeNames.Add ("money");
                                                row ["ProviderType"] = (int) SybaseType.Money;
                                                row ["DataType"] = typeof (decimal);
+                                               row ["IsLong"] = false;
                                                break;
                                        case TdsColumnType.Float8 :
                                        case TdsColumnType.FloatN :
                                                dataTypeNames.Add ("float");
                                                row ["ProviderType"] = (int) SybaseType.Float;
                                                row ["DataType"] = typeof (double);
+                                               row ["IsLong"] = false;
                                                break;
                                        case TdsColumnType.NText :
                                                dataTypeNames.Add ("ntext");
                                                row ["ProviderType"] = (int) SybaseType.NText;
                                                row ["DataType"] = typeof (string);
+                                               row ["IsLong"] = true;
                                                break;
                                        case TdsColumnType.NVarChar :
                                                dataTypeNames.Add ("nvarchar");
                                                row ["ProviderType"] = (int) SybaseType.NVarChar;
                                                row ["DataType"] = typeof (string);
+                                               row ["IsLong"] = false;
                                                break;
                                        case TdsColumnType.Decimal :
                                        case TdsColumnType.Numeric :
                                                dataTypeNames.Add ("decimal");
                                                row ["ProviderType"] = (int) SybaseType.Decimal;
                                                row ["DataType"] = typeof (decimal);
+                                               row ["IsLong"] = false;
                                                break;
                                        case TdsColumnType.NChar :
                                                dataTypeNames.Add ("nchar");
-                                               row ["ProviderType"] = (int) SybaseType.Char;
+                                               row ["ProviderType"] = (int) SybaseType.NChar;
                                                row ["DataType"] = typeof (string);
+                                               row ["IsLong"] = false;
                                                break;
                                        case TdsColumnType.SmallMoney :
                                                dataTypeNames.Add ("smallmoney");
                                                row ["ProviderType"] = (int) SybaseType.SmallMoney;
                                                row ["DataType"] = typeof (decimal);
+                                               row ["IsLong"] = false;
                                                break;
                                        default :
                                                dataTypeNames.Add ("variant");
                                                row ["ProviderType"] = (int) SybaseType.Variant;
                                                row ["DataType"] = typeof (object);
+                                               row ["IsLong"] = false;
                                                break;
                                }
 
-                               row ["BaseColumnName"] = DBNull.Value;
-                               row ["BaseTableName"] = DBNull.Value;
-                               row ["ColumnName"] = DBNull.Value;
-                               row ["NumericPrecision"] = DBNull.Value;
-                               row ["NumericScale"] = DBNull.Value;
+                               schemaTable.Rows.Add (row);
+
+                               fieldCount += 1;
+                       }
+                       return schemaTable;
+               }               
+
+               private static object GetSchemaValue (TdsDataColumn schema, object key)
+               {
+                       if (schema.ContainsKey (key) && schema [key] != null)
+                               return schema [key];
+                       return DBNull.Value;
+               }
+
+               public SybaseBinary GetSybaseBinary (int i)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               public SybaseBoolean GetSybaseBoolean (int i) 
+               {
+                       object value = GetSybaseValue (i);
+                       if (!(value is SybaseBoolean))
+                               throw new InvalidCastException ();
+                       return (SybaseBoolean) value;
+               }
+
+               public SybaseByte GetSybaseByte (int i)
+               {
+                       object value = GetSybaseValue (i);
+                       if (!(value is SybaseByte))
+                               throw new InvalidCastException ();
+                       return (SybaseByte) value;
+               }
 
-                               row ["ColumnOrdinal"] = schema.ColumnOrdinal;
-                               row ["ColumnSize"] = schema.ColumnSize;
-                               row ["AllowDBNull"] = schema.AllowDBNull;
-                               row ["IsReadOnly"] = schema.IsReadOnly;
-                               row ["IsIdentity"] = schema.IsIdentity;
-                               row ["IsKey"] = schema.IsKey;
+               public SybaseDateTime GetSybaseDateTime (int i)
+               {
+                       object value = GetSybaseValue (i);
+                       if (!(value is SybaseDateTime))
+                               throw new InvalidCastException ();
+                       return (SybaseDateTime) value;
+               }
 
-                               if (schema.BaseColumnName != null)
-                                       row ["BaseColumnName"] = schema.BaseColumnName;
+               public SybaseDecimal GetSybaseDecimal (int i)
+               {
+                       object value = GetSybaseValue (i);
+                       if (!(value is SybaseDecimal))
+                               throw new InvalidCastException ();
+                       return (SybaseDecimal) value;
+               }
 
-                               if (schema.ColumnName != null)
-                                       row ["ColumnName"] = schema.ColumnName;
+               public SybaseDouble GetSybaseDouble (int i)
+               {
+                       object value = GetSybaseValue (i);
+                       if (!(value is SybaseDouble))
+                               throw new InvalidCastException ();
+                       return (SybaseDouble) value;
+               }
 
-                               if (schema.BaseTableName != null)
-                                       row ["BaseTableName"] = schema.BaseTableName;
+               public SybaseGuid GetSybaseGuid (int i)
+               {
+                       object value = GetSybaseValue (i);
+                       if (!(value is SybaseGuid))
+                               throw new InvalidCastException ();
+                       return (SybaseGuid) value;
+               }
 
-                               if (schema.NumericScale != 0)
-                                       row ["NumericPrecision"] = schema.NumericPrecision;
+               public SybaseInt16 GetSybaseInt16 (int i)
+               {
+                       object value = GetSybaseValue (i);
+                       if (!(value is SybaseInt16))
+                               throw new InvalidCastException ();
+                       return (SybaseInt16) value;
+               }
 
-                               if (schema.NumericScale != 0)
-                                       row ["NumericScale"] = schema.NumericScale;
+               public SybaseInt32 GetSybaseInt32 (int i)
+               {
+                       object value = GetSybaseValue (i);
+                       if (!(value is SybaseInt32))
+                               throw new InvalidCastException ();
+                       return (SybaseInt32) value;
+               }
 
-                               schemaTable.Rows.Add (row);
+               public SybaseInt64 GetSybaseInt64 (int i)
+               {
+                       object value = GetSybaseValue (i);
+                       if (!(value is SybaseInt64))
+                               throw new InvalidCastException ();
+                       return (SybaseInt64) value;
+               }
 
-                               fieldCount += 1;
+               public SybaseMoney GetSybaseMoney (int i)
+               {
+                       object value = GetSybaseValue (i);
+                       if (!(value is SybaseMoney))
+                               throw new InvalidCastException ();
+                       return (SybaseMoney) value;
+               }
+
+               public SybaseSingle GetSybaseSingle (int i)
+               {
+                       object value = GetSybaseValue (i);
+                       if (!(value is SybaseSingle))
+                               throw new InvalidCastException ();
+                       return (SybaseSingle) value;
+               }
+
+               public SybaseString GetSybaseString (int i)
+               {
+                       object value = GetSybaseValue (i);
+                       if (!(value is SybaseString))
+                               throw new InvalidCastException ();
+                       return (SybaseString) value;
+               }
+
+               [MonoTODO ("Implement TdsBigDecimal conversion.  SybaseType.Real fails tests?")]
+               public object GetSybaseValue (int i)
+               {
+                       SybaseType type = (SybaseType) (schemaTable.Rows [i]["ProviderType"]);
+                       object value = GetValue (i);
+
+                       switch (type) {
+                       case SybaseType.BigInt:
+                               if (value == DBNull.Value)
+                                       return SybaseInt64.Null;
+                               return (SybaseInt64) ((long) value);
+                       case SybaseType.Binary:
+                       case SybaseType.Image:
+                       case SybaseType.VarBinary:
+                       case SybaseType.Timestamp:
+                               if (value == DBNull.Value)
+                                       return SybaseBinary.Null;
+                               return (SybaseBinary) ((byte[]) value);
+                       case SybaseType.Bit:
+                               if (value == DBNull.Value)
+                                       return SybaseBoolean.Null;
+                               return (SybaseBoolean) ((bool) value);
+                       case SybaseType.Char:
+                       case SybaseType.NChar:
+                       case SybaseType.NText:
+                       case SybaseType.NVarChar:
+                       case SybaseType.Text:
+                       case SybaseType.VarChar:
+                               if (value == DBNull.Value)
+                                       return SybaseString.Null;
+                               return (SybaseString) ((string) value);
+                       case SybaseType.DateTime:
+                       case SybaseType.SmallDateTime:
+                               if (value == DBNull.Value)
+                                       return SybaseDateTime.Null;
+                               return (SybaseDateTime) ((DateTime) value);
+                       case SybaseType.Decimal:
+                               if (value == DBNull.Value)
+                                       return SybaseDecimal.Null;
+                               if (value is TdsBigDecimal)
+                                       return SybaseDecimal.FromTdsBigDecimal ((TdsBigDecimal) value);
+                               return (SybaseDecimal) ((decimal) value);
+                       case SybaseType.Float:
+                               if (value == DBNull.Value)
+                                       return SybaseDouble.Null;
+                               return (SybaseDouble) ((double) value);
+                       case SybaseType.Int:
+                               if (value == DBNull.Value)
+                                       return SybaseInt32.Null;
+                               return (SybaseInt32) ((int) value);
+                       case SybaseType.Money:
+                       case SybaseType.SmallMoney:
+                               if (value == DBNull.Value)
+                                       return SybaseMoney.Null;
+                               return (SybaseMoney) ((decimal) value);
+                       case SybaseType.Real:
+                               if (value == DBNull.Value)
+                                       return SybaseSingle.Null;
+                               return (SybaseSingle) ((float) value);
+                       case SybaseType.UniqueIdentifier:
+                               if (value == DBNull.Value)
+                                       return SybaseGuid.Null;
+                               return (SybaseGuid) ((Guid) value);
+                       case SybaseType.SmallInt:
+                               if (value == DBNull.Value)
+                                       return SybaseInt16.Null;
+                               return (SybaseInt16) ((short) value);
+                       case SybaseType.TinyInt:
+                               if (value == DBNull.Value)
+                                       return SybaseByte.Null;
+                               return (SybaseByte) ((byte) value);
                        }
-                       return schemaTable;
-               }               
+
+                       throw new InvalidOperationException ("The type of this column is unknown.");
+               }
+
+               public int GetSybaseValues (object[] values)
+               {
+                       int count = 0;
+                       int columnCount = schemaTable.Rows.Count;
+                       int arrayCount = values.Length;
+
+                       if (arrayCount > columnCount)
+                               count = columnCount;
+                       else
+                               count = arrayCount;
+
+                       for (int i = 0; i < count; i += 1) 
+                               values [i] = GetSybaseValue (i);
+
+                       return count;
+               }
 
                public string GetString (int i)
                {
                        object value = GetValue (i);
-                       if (!(value is string))
+                       if (!(value is string)) {
+                               if (value is DBNull) throw new SybaseNullValueException ();
                                throw new InvalidCastException ();
+                       }
                        return (string) value;
                }
 
                public object GetValue (int i)
                {
-                       return command.Tds.ColumnValues[i];
+                       return command.Tds.ColumnValues [i];
                }
 
                public int GetValues (object[] values)
                {
                        int len = values.Length;
+                       int bigDecimalIndex = command.Tds.ColumnValues.BigDecimalIndex;
+
+                       // If a four-byte decimal is stored, then we can't convert to
+                       // a native type.  Throw an OverflowException.
+                       if (bigDecimalIndex >= 0 && bigDecimalIndex < len)
+                               throw new OverflowException ();
+
                        command.Tds.ColumnValues.CopyTo (0, values, 0, len);
                        return (len > FieldCount ? len : FieldCount);
                }
 
-               [MonoTODO]
                void IDisposable.Dispose ()
                {
-                       throw new NotImplementedException ();
+                       Dispose (true);
+                       GC.SuppressFinalize (this);
                }
 
                IEnumerator IEnumerable.GetEnumerator ()
@@ -470,17 +756,21 @@ namespace Mono.Data.SybaseClient {
 
                public bool IsDBNull (int i)
                {
-                       return GetValue (i) == null;
+                       return GetValue (i) == DBNull.Value;
                }
 
                public bool NextResult ()
                {
                        if ((command.CommandBehavior & CommandBehavior.SingleResult) != 0 && resultsRead > 0)
                                return false;
+                       if (command.Tds.DoneProc)
+                               return false;
 
                        schemaTable.Rows.Clear ();
 
                        moreResults = command.Tds.NextResult ();
+                       GetSchemaTable ();
+
                        rowsRead = 0;
                        resultsRead += 1;
                        return moreResults;