[Sys.Data] Fix Novell Bug #519648
[mono.git] / mcs / class / System.Data / System.Data.Common / DataContainer.cs
index a7a86e73e240b6a0472204dc813228f3ee4e2d24..7a46a04e229bf032d80c816b3db05028a94a5b05 100644 (file)
 //
 using System;
 using System.Collections;
+using System.Reflection;
+#if !FULL_AOT_RUNTIME
+using System.Reflection.Emit;
+#endif
 
 namespace System.Data.Common
 {
-       internal abstract class DataContainer
-       {
+       internal abstract class DataContainer {
                BitArray null_values;
                System.Type _type;
                DataColumn _column;
 
                // implementing class protocol
-               protected abstract object GetValue (int index);
+               protected internal abstract object GetValue (int index);
                internal abstract long GetInt64 (int index);
 
-               protected abstract void SetDefaultValue (int index);
+               // used to set the array value to something neutral when the corresponding item is null (in the database sense)
+               // note: we don't actually ever look at the value written there, but the GC may like us to avoid keeping stale
+               // values in the array.
+               protected abstract void ZeroOut (int index);
                protected abstract void SetValue (int index, object value);
                protected abstract void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field);
 
@@ -48,13 +54,19 @@ namespace System.Data.Common
                        get { return IsNull (index) ? DBNull.Value : GetValue (index); }
                        set {
                                if (value == null) {
-                                       CopyValue (Column.Table.DefaultValuesRowIndex, index);
+                                       // Table might not have a default values row to copy from
+                                       if (Column.Table.DefaultValuesRowIndex == -1) {
+                                               ZeroOut (index);
+                                               null_values [index] = true;
+                                       } else {
+                                               CopyValue (Column.Table.DefaultValuesRowIndex, index);
+                                       }
                                        return;
                                }
 
                                bool is_dbnull = value == DBNull.Value;
                                if (is_dbnull)
-                                       SetDefaultValue (index);
+                                       ZeroOut (index);
                                else
                                        SetValue (index, value);
                                null_values [index] = is_dbnull;
@@ -133,7 +145,7 @@ namespace System.Data.Common
                                container = new DecimalDataContainer ();
                                break;
                        default:
-                               container = new ObjectDataContainer();
+                               container = new ObjectDataContainer ();
                                break;
                        }
                        container._type = type;
@@ -141,9 +153,72 @@ namespace System.Data.Common
                        return container;
                }
 
+               internal static object GetExplicitValue (object value) 
+               {
+                       Type valueType = value.GetType ();
+                       MethodInfo method = valueType.GetMethod ("op_Explicit", new Type[]{valueType});
+                       if (method != null) 
+                               return (method.Invoke (value, new object[]{value}));
+                       return null;
+               }
+               
+               internal object GetContainerData (object value) 
+               {
+                       object obj; 
+                       TypeCode tc;
+                       
+                       if (value == null)
+                               return null;
+                       
+                       if (_type.IsInstanceOfType (value)) {
+                               return value;
+                       } else if ((tc = Type.GetTypeCode (_type)) == TypeCode.String) {
+                               return (Convert.ToString (value));
+                       } else if (value is IConvertible) {
+                               switch (tc) {
+                                       case TypeCode.Int16:
+                                               return (Convert.ToInt16 (value));
+                                       case TypeCode.Int32:
+                                               return (Convert.ToInt32 (value));
+                                       case TypeCode.Int64:
+                                               return (Convert.ToInt64 (value));
+                                       case TypeCode.Boolean:
+                                               return (Convert.ToBoolean (value));
+                                       case TypeCode.Byte:
+                                               return (Convert.ToByte (value));
+                                       case TypeCode.Char:
+                                               return (Convert.ToChar (value));
+                                       case TypeCode.Double:
+                                               return (Convert.ToDouble (value));
+                                       case TypeCode.SByte:
+                                               return (Convert.ToSByte (value));
+                                       case TypeCode.Single:
+                                               return (Convert.ToSingle (value));
+                                       case TypeCode.UInt16:
+                                               return (Convert.ToUInt16 (value));
+                                       case TypeCode.UInt32:
+                                               return (Convert.ToUInt32 (value));
+                                       case TypeCode.UInt64:
+                                               return (Convert.ToUInt64 (value));
+                                       case TypeCode.DateTime:
+                                               if (value == DBNull.Value)
+                                                       return DBNull.Value;
+                                               return (Convert.ToDateTime (value));
+                                       case TypeCode.Decimal:
+                                               return (Convert.ToDecimal (value));
+                                       default:
+                                               throw new InvalidCastException (string.Format ("Cannot convert from {0} to {1}", value.GetType ().FullName, _type.FullName));
+                               }
+                       } else if ((obj = GetExplicitValue (value)) != null) {
+                               return (obj);
+                       } else {
+                               throw new InvalidCastException ();
+                       }
+               }
+               
                internal bool IsNull (int index)
                {
-                       return null_values != null ? null_values [index] : true;
+                       return null_values == null || null_values [index];
                }
 
                internal void FillValues (int fromIndex)
@@ -184,26 +259,22 @@ namespace System.Data.Common
                }
        }
 
-       sealed class BitDataContainer : DataContainer
-       {
+       sealed class BitDataContainer : DataContainer {
                BitArray _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
 
-               protected override void SetDefaultValue (int index)
+               protected override void ZeroOut (int index)
                {
                        _values [index] = false;
                }
 
                protected override void SetValue (int index, object value)
                {
-                       if (value is bool)
-                               _values [index] = (bool) value;
-                       else
-                               _values [index] = Convert.ToBoolean (value);
+                       _values [index] = (bool) GetContainerData (value);
                }
 
                protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
@@ -213,7 +284,7 @@ namespace System.Data.Common
 
                protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
                {
-                       _values [to_index] = ((BitDataContainer)from)._values [from_index];
+                       _values [to_index] = (bool) GetContainerData (from.GetValue (from_index));
                }
 
                protected override int DoCompareValues (int index1, int index2)
@@ -225,12 +296,10 @@ namespace System.Data.Common
 
                protected override void Resize (int size)
                {
-                       if (_values == null) {
+                       if (_values == null)
                                _values = new BitArray (size);
-                               return;
-                       }
-
-                       _values.Length = size;
+                       else
+                               _values.Length = size;
                }
 
                internal override long GetInt64 (int index)
@@ -239,26 +308,22 @@ namespace System.Data.Common
                }
        }
 
-       sealed class CharDataContainer : DataContainer
-       {
+       sealed class CharDataContainer : DataContainer {
                char [] _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
 
-               protected override void SetDefaultValue (int index)
+               protected override void ZeroOut (int index)
                {
                        _values [index] = '\0';
                }
 
                protected override void SetValue (int index, object value)
                {
-                       if (value is char)
-                               _values [index] = (char) value;
-                       else
-                               _values [index] = Convert.ToChar (value);
+                       _values [index] = (char) GetContainerData (value);
                }
 
                protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
@@ -268,7 +333,7 @@ namespace System.Data.Common
 
                protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
                {
-                       _values [to_index] = ((CharDataContainer)from)._values [from_index];
+                       _values [to_index] = (char) GetContainerData (from.GetValue (from_index));
                }
 
                protected override int DoCompareValues (int index1, int index2)
@@ -296,26 +361,22 @@ namespace System.Data.Common
                }
        }
 
-       sealed class ByteDataContainer : DataContainer
-       {
+       sealed class ByteDataContainer : DataContainer {
                byte [] _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
 
-               protected override void SetDefaultValue (int index)
+               protected override void ZeroOut (int index)
                {
                        _values [index] = 0;
                }
 
                protected override void SetValue (int index, object value)
                {
-                       if (value is byte)
-                               _values [index] = (byte) value;
-                       else
-                               _values [index] = Convert.ToByte (value);
+                       _values [index] = (byte) GetContainerData (value);
                }
 
                protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
@@ -325,7 +386,7 @@ namespace System.Data.Common
 
                protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
                {
-                       _values [to_index] = ((ByteDataContainer)from)._values [from_index];
+                       _values [to_index] = (byte) GetContainerData (from.GetValue (from_index));
                }
 
                protected override int DoCompareValues (int index1, int index2)
@@ -353,26 +414,22 @@ namespace System.Data.Common
                }
        }
 
-       sealed class SByteDataContainer : DataContainer
-       {
+       sealed class SByteDataContainer : DataContainer {
                sbyte [] _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
 
-               protected override void SetDefaultValue (int index)
+               protected override void ZeroOut (int index)
                {
                        _values [index] = 0;
                }
 
                protected override void SetValue (int index, object value)
                {
-                       if (value is sbyte)
-                               _values [index] = (sbyte) value;
-                       else
-                               _values [index] = Convert.ToSByte (value);
+                       _values [index] = (sbyte) GetContainerData (value);
                }
 
                protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
@@ -382,7 +439,7 @@ namespace System.Data.Common
 
                protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
                {
-                       _values [to_index] = ((SByteDataContainer)from)._values [from_index];
+                       _values [to_index] = (sbyte) GetContainerData (from.GetValue (from_index));
                }
 
                protected override int DoCompareValues (int index1, int index2)
@@ -410,26 +467,22 @@ namespace System.Data.Common
                }
        }
 
-       sealed class Int16DataContainer : DataContainer
-       {
+       sealed class Int16DataContainer : DataContainer {
                short [] _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
 
-               protected override void SetDefaultValue (int index)
+               protected override void ZeroOut (int index)
                {
                        _values [index] = 0;
                }
 
                protected override void SetValue (int index, object value)
                {
-                       if (value is short)
-                               _values [index] = (short) value;
-                       else
-                               _values [index] = Convert.ToInt16 (value);
+                       _values [index] = (short) GetContainerData (value);
                }
 
                protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
@@ -439,7 +492,7 @@ namespace System.Data.Common
 
                protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
                {
-                       _values [to_index] = ((Int16DataContainer)from)._values [from_index];
+                       _values [to_index] = (short) GetContainerData (from.GetValue (from_index));
                }
 
                protected override int DoCompareValues (int index1, int index2)
@@ -467,26 +520,22 @@ namespace System.Data.Common
                }
        }
 
-       sealed class UInt16DataContainer : DataContainer
-       {
+       sealed class UInt16DataContainer : DataContainer {
                ushort [] _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
 
-               protected override void SetDefaultValue (int index)
+               protected override void ZeroOut (int index)
                {
                        _values [index] = 0;
                }
 
                protected override void SetValue (int index, object value)
                {
-                       if (value is ushort)
-                               _values [index] = (ushort) value;
-                       else
-                               _values [index] = Convert.ToUInt16 (value);
+                       _values [index] = (ushort) GetContainerData (value);
                }
 
                protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
@@ -496,7 +545,7 @@ namespace System.Data.Common
 
                protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
                {
-                       _values [to_index] = ((UInt16DataContainer)from)._values [from_index];
+                       _values [to_index] = (ushort) GetContainerData (from.GetValue (from_index));
                }
 
                protected override int DoCompareValues (int index1, int index2)
@@ -524,26 +573,22 @@ namespace System.Data.Common
                }
        }
 
-       sealed class Int32DataContainer : DataContainer
-       {
+       sealed class Int32DataContainer : DataContainer {
                int [] _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
 
-               protected override void SetDefaultValue (int index)
+               protected override void ZeroOut (int index)
                {
                        _values [index] = 0;
                }
 
                protected override void SetValue (int index, object value)
                {
-                       if (value is int)
-                               _values [index] = (int) value;
-                       else
-                               _values [index] = Convert.ToInt32 (value);
+                       _values [index] = (int) GetContainerData (value);
                }
 
                protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
@@ -553,7 +598,7 @@ namespace System.Data.Common
 
                protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
                {
-                       _values [to_index] = ((Int32DataContainer)from)._values [from_index];
+                       _values [to_index] = (int) GetContainerData (from.GetValue (from_index));
                }
 
                protected override int DoCompareValues (int index1, int index2)
@@ -581,26 +626,22 @@ namespace System.Data.Common
                }
        }
 
-       sealed class UInt32DataContainer : DataContainer
-       {
+       sealed class UInt32DataContainer : DataContainer {
                uint [] _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
 
-               protected override void SetDefaultValue (int index)
+               protected override void ZeroOut (int index)
                {
                        _values [index] = 0;
                }
 
                protected override void SetValue (int index, object value)
                {
-                       if (value is uint)
-                               _values [index] = (uint) value;
-                       else
-                               _values [index] = Convert.ToUInt32 (value);
+                       _values [index] = (uint) GetContainerData (value);
                }
 
                protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
@@ -610,7 +651,7 @@ namespace System.Data.Common
 
                protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
                {
-                       _values [to_index] = ((UInt32DataContainer)from)._values [from_index];
+                       _values [to_index] = (uint) GetContainerData (from.GetValue (from_index));
                }
 
                protected override int DoCompareValues (int index1, int index2)
@@ -638,26 +679,22 @@ namespace System.Data.Common
                }
        }
 
-       sealed class Int64DataContainer : DataContainer
-       {
+       sealed class Int64DataContainer : DataContainer {
                long [] _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
 
-               protected override void SetDefaultValue (int index)
+               protected override void ZeroOut (int index)
                {
                        _values [index] = 0;
                }
 
                protected override void SetValue (int index, object value)
                {
-                       if (value is long)
-                               _values [index] = (long) value;
-                       else
-                               _values [index] = Convert.ToInt64 (value);
+                       _values [index] = (long) GetContainerData (value);
                }
 
                protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
@@ -667,7 +704,7 @@ namespace System.Data.Common
 
                protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
                {
-                       _values [to_index] = ((Int64DataContainer)from)._values [from_index];
+                       _values [to_index] = (long) GetContainerData (from.GetValue (from_index));
                }
 
                protected override int DoCompareValues (int index1, int index2)
@@ -695,26 +732,22 @@ namespace System.Data.Common
                }
        }
 
-       sealed class UInt64DataContainer : DataContainer
-       {
+       sealed class UInt64DataContainer : DataContainer {
                ulong [] _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
 
-               protected override void SetDefaultValue (int index)
+               protected override void ZeroOut (int index)
                {
                        _values [index] = 0;
                }
 
                protected override void SetValue (int index, object value)
                {
-                       if (value is ulong)
-                               _values [index] = (ulong) value;
-                       else
-                               _values [index] = Convert.ToUInt64 (value);
+                       _values [index] = (ulong) GetContainerData (value);
                }
 
                protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
@@ -724,7 +757,7 @@ namespace System.Data.Common
 
                protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
                {
-                       _values [to_index] = ((UInt64DataContainer)from)._values [from_index];
+                       _values [to_index] = (ulong) GetContainerData (from.GetValue (from_index));
                }
 
                protected override int DoCompareValues (int index1, int index2)
@@ -752,26 +785,22 @@ namespace System.Data.Common
                }
        }
 
-       sealed class SingleDataContainer : DataContainer
-       {
+       sealed class SingleDataContainer : DataContainer {
                float [] _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
 
-               protected override void SetDefaultValue (int index)
+               protected override void ZeroOut (int index)
                {
                        _values [index] = 0;
                }
 
                protected override void SetValue (int index, object value)
                {
-                       if (value is float)
-                               _values [index] = (float) value;
-                       else
-                               _values [index] = Convert.ToSingle (value);
+                       _values [index] = (float) GetContainerData (value);
                }
 
                protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
@@ -781,7 +810,7 @@ namespace System.Data.Common
 
                protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
                {
-                       _values [to_index] = ((SingleDataContainer)from)._values [from_index];
+                       _values [to_index] = (float) GetContainerData (from.GetValue (from_index));
                }
 
                protected override int DoCompareValues (int index1, int index2)
@@ -809,26 +838,22 @@ namespace System.Data.Common
                }
        }
 
-       sealed class DoubleDataContainer : DataContainer
-       {
+       sealed class DoubleDataContainer : DataContainer {
                double [] _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
 
-               protected override void SetDefaultValue (int index)
+               protected override void ZeroOut (int index)
                {
                        _values [index] = 0;
                }
 
                protected override void SetValue (int index, object value)
                {
-                       if (value is double)
-                               _values [index] = (double) value;
-                       else
-                               _values [index] = Convert.ToDouble (value);
+                       _values [index] = (double) GetContainerData (value);
                }
 
                protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
@@ -838,7 +863,7 @@ namespace System.Data.Common
 
                protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
                {
-                       _values [to_index] = ((DoubleDataContainer)from)._values [from_index];
+                       _values [to_index] = (double) GetContainerData (from.GetValue (from_index));
                }
 
                protected override int DoCompareValues (int index1, int index2)
@@ -866,16 +891,15 @@ namespace System.Data.Common
                }
        }
 
-       class ObjectDataContainer : DataContainer
-       {
+       class ObjectDataContainer : DataContainer {
                object [] _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
 
-               protected override void SetDefaultValue (int index)
+               protected override void ZeroOut (int index)
                {
                        _values [index] = null;
                }
@@ -892,7 +916,7 @@ namespace System.Data.Common
 
                protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
                {
-                       _values [to_index] = ((ObjectDataContainer)from)._values [from_index];
+                       _values [to_index] = GetContainerData (from.GetValue (from_index));
                }
 
                protected override int DoCompareValues (int index1, int index2)
@@ -935,8 +959,7 @@ namespace System.Data.Common
                }
        }
 
-       sealed class DateTimeDataContainer : ObjectDataContainer
-       {
+       sealed class DateTimeDataContainer : ObjectDataContainer {
                protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
                {
                        base.SetValue (index, record.GetDateTimeSafe (field));
@@ -944,38 +967,33 @@ namespace System.Data.Common
 
                protected override void SetValue (int index, object value)
                {
-                       base.SetValue (index, Convert.ToDateTime (value));
+                       base.SetValue (index, GetContainerData (value));
                }
        }
 
-       sealed class DecimalDataContainer : ObjectDataContainer
-       {
+       sealed class DecimalDataContainer : ObjectDataContainer {
                protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
                {
                        base.SetValue (index, record.GetDecimalSafe (field));
                }
 
-               protected override void SetValue(int index, object value)
+               protected override void SetValue (int index, object value)
                {
-                       base.SetValue (index, Convert.ToDecimal (value));
+                       base.SetValue (index, GetContainerData (value));
                }
        }
 
-       sealed class StringDataContainer : ObjectDataContainer
-       {
+       sealed class StringDataContainer : ObjectDataContainer {
                private void SetValue (int index, string value)
                {
-                       if (value != null && Column.MaxLength >= 0 && Column.MaxLength < value.Length )
-                               throw new ArgumentException("Cannot set column '" + Column.ColumnName + "' to '" + value + "'. The value violates the MaxLength limit of this column.");
+                       if (value != null && Column.MaxLength >= 0 && Column.MaxLength < value.Length)
+                               throw new ArgumentException ("Cannot set column '" + Column.ColumnName + "' to '" + value + "'. The value violates the MaxLength limit of this column.");
                        base.SetValue (index, value);
                }
 
                protected override void SetValue (int index, object value)
                {
-                       if (value is string)
-                               SetValue (index, (string) value);
-                       else
-                               SetValue (index, Convert.ToString (value));
+                       SetValue (index, (string) GetContainerData (value));
                }
 
                protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)