System.Data: DataTable.ImportRow should be able to handle columns with different...
authorRolf Bjarne Kvinge <rolf@xamarin.com>
Tue, 17 Jan 2012 21:15:31 +0000 (22:15 +0100)
committerRolf Bjarne Kvinge <rolf@xamarin.com>
Tue, 17 Jan 2012 21:15:51 +0000 (22:15 +0100)
mcs/class/System.Data/System.Data.Common/DataContainer.cs
mcs/class/System.Data/Test/System.Data/DataTableTest.cs

index 321620fd01f5247973b5768b6fc6131de66af893..29e7b11efc1e3f05e274a1dbc8136a0681672a67 100644 (file)
@@ -33,7 +33,7 @@ namespace System.Data.Common
                DataColumn _column;
 
                // implementing class protocol
-               protected abstract object GetValue (int index);
+               protected internal abstract object GetValue (int index);
                internal abstract long GetInt64 (int index);
 
                // used to set the array value to something neutral when the corresponding item is null (in the database sense)
@@ -158,7 +158,10 @@ namespace System.Data.Common
                {
                        object obj; 
                        TypeCode tc;
-
+                       
+                       if (value == null)
+                               return null;
+                       
                        if (_type.IsInstanceOfType (value)) {
                                return value;
                        } else if ((tc = Type.GetTypeCode (_type)) == TypeCode.String) {
@@ -190,11 +193,13 @@ namespace System.Data.Common
                                        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 ();
+                                               throw new InvalidCastException (string.Format ("Cannot convert from {0} to {1}", value.GetType ().FullName, _type.FullName));
                                }
                        } else if ((obj = GetExplicitValue (value)) != null) {
                                return (obj);
@@ -249,7 +254,7 @@ namespace System.Data.Common
        sealed class BitDataContainer : DataContainer {
                BitArray _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
@@ -271,7 +276,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)
@@ -298,7 +303,7 @@ namespace System.Data.Common
        sealed class CharDataContainer : DataContainer {
                char [] _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
@@ -320,7 +325,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)
@@ -351,7 +356,7 @@ namespace System.Data.Common
        sealed class ByteDataContainer : DataContainer {
                byte [] _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
@@ -373,7 +378,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)
@@ -404,7 +409,7 @@ namespace System.Data.Common
        sealed class SByteDataContainer : DataContainer {
                sbyte [] _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
@@ -426,7 +431,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)
@@ -457,7 +462,7 @@ namespace System.Data.Common
        sealed class Int16DataContainer : DataContainer {
                short [] _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
@@ -479,7 +484,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)
@@ -510,7 +515,7 @@ namespace System.Data.Common
        sealed class UInt16DataContainer : DataContainer {
                ushort [] _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
@@ -532,7 +537,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)
@@ -563,7 +568,7 @@ namespace System.Data.Common
        sealed class Int32DataContainer : DataContainer {
                int [] _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
@@ -585,7 +590,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)
@@ -616,7 +621,7 @@ namespace System.Data.Common
        sealed class UInt32DataContainer : DataContainer {
                uint [] _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
@@ -638,7 +643,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)
@@ -669,7 +674,7 @@ namespace System.Data.Common
        sealed class Int64DataContainer : DataContainer {
                long [] _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
@@ -691,7 +696,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)
@@ -722,7 +727,7 @@ namespace System.Data.Common
        sealed class UInt64DataContainer : DataContainer {
                ulong [] _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
@@ -744,7 +749,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)
@@ -775,7 +780,7 @@ namespace System.Data.Common
        sealed class SingleDataContainer : DataContainer {
                float [] _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
@@ -797,7 +802,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)
@@ -828,7 +833,7 @@ namespace System.Data.Common
        sealed class DoubleDataContainer : DataContainer {
                double [] _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
@@ -850,7 +855,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)
@@ -881,7 +886,7 @@ namespace System.Data.Common
        class ObjectDataContainer : DataContainer {
                object [] _values;
 
-               protected override object GetValue (int index)
+               protected internal override object GetValue (int index)
                {
                        return _values [index];
                }
@@ -903,7 +908,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)
index c397ce6fe903003cd890e179b3561ea95aedea0d..f1c7f78b463b61ce4658cc5552701eed0875a23f 100644 (file)
@@ -35,6 +35,7 @@
 
 using System;
 using System.Collections;
+using System.Collections.Generic;
 using System.Data;
 using System.Data.SqlTypes;
 using System.Globalization;
@@ -1316,7 +1317,83 @@ namespace MonoTests.System.Data
                                Assert.IsTrue (ex.Message.IndexOf ("'1'") != -1, "#B6");
                        }
                }
-
+               
+#if NET_4_0
+               [Test]
+               public void ImportRowTypeChangeTest ()
+               {
+                       // this is from http://bugzilla.xamarin.com/show_bug.cgi?id=2926
+       
+                       Type [] types = new Type [] { typeof (string), typeof (sbyte), typeof (byte), typeof (short), typeof (ushort), typeof (int), typeof (uint), typeof (long), typeof (ulong), typeof (float), typeof (double), typeof (char), typeof (decimal), typeof (DateTime) };
+                       object [] values = new object [] { "1", (sbyte) 1, (byte) 2, (short) 3, (ushort) 4, (int) 5, (uint) 6, (long) 7, (ulong) 8, (float) 9, (double) 10, 'z', (decimal) 13, new DateTime (24) };
+                       int length = types.Length;
+       
+                       HashSet<Tuple<Type, Type>> invalid = new HashSet<Tuple<Type, Type>> () {
+                               Tuple.Create (typeof (string), typeof (DateTime)), 
+                               Tuple.Create (typeof (sbyte), typeof (DateTime)), 
+                               Tuple.Create (typeof (byte), typeof (DateTime)), 
+                               Tuple.Create (typeof (short), typeof (DateTime)), 
+                               Tuple.Create (typeof (ushort), typeof (DateTime)), 
+                               Tuple.Create (typeof (int), typeof (DateTime)), 
+                               Tuple.Create (typeof (uint), typeof (DateTime)), 
+                               Tuple.Create (typeof (long), typeof (DateTime)), 
+                               Tuple.Create (typeof (ulong), typeof (DateTime)), 
+                               Tuple.Create (typeof (float), typeof (char)), 
+                               Tuple.Create (typeof (float), typeof (DateTime)), 
+                               Tuple.Create (typeof (double), typeof (char)), 
+                               Tuple.Create (typeof (double), typeof (DateTime)), 
+                               Tuple.Create (typeof (char), typeof (float)), 
+                               Tuple.Create (typeof (char), typeof (double)), 
+                               Tuple.Create (typeof (char), typeof (decimal)), 
+                               Tuple.Create (typeof (char), typeof (DateTime)), 
+                               Tuple.Create (typeof (Decimal), typeof (char)), 
+                               Tuple.Create (typeof (Decimal), typeof (DateTime)), 
+                               Tuple.Create (typeof (DateTime), typeof (sbyte)), 
+                               Tuple.Create (typeof (DateTime), typeof (byte)), 
+                               Tuple.Create (typeof (DateTime), typeof (short)), 
+                               Tuple.Create (typeof (DateTime), typeof (ushort)), 
+                               Tuple.Create (typeof (DateTime), typeof (int)), 
+                               Tuple.Create (typeof (DateTime), typeof (uint)), 
+                               Tuple.Create (typeof (DateTime), typeof (long)), 
+                               Tuple.Create (typeof (DateTime), typeof (ulong)), 
+                               Tuple.Create (typeof (DateTime), typeof (float)), 
+                               Tuple.Create (typeof (DateTime), typeof (double)), 
+                               Tuple.Create (typeof (DateTime), typeof (char)), 
+                               Tuple.Create (typeof (DateTime), typeof (decimal)), 
+                       };
+       
+                       for (int a = 0; a < length; a++) {
+                               for (int b = 0; b < length; b++) {
+                                       DataSet ds = new DataSet ();
+                                       DataTable dt1 = ds.Tables.Add ("T1");
+                                       DataTable dt2 = ds.Tables.Add ("T2");
+       
+                                       string name = "C-" + types [a].Name + "-to-" + types [b].Name;
+                                       dt1.Columns.Add (name, types [a]);
+                                       dt2.Columns.Add (name, types [b]);
+       
+                                       DataRow r1 = dt1.NewRow ();
+                                       dt1.Rows.Add (r1);
+       
+                                       r1 [0] = values [a];
+       
+                                       if (invalid.Contains (Tuple.Create (types [a], types [b]))) {
+                                               try {
+                                                       dt2.ImportRow (r1);
+                                                       Assert.Fail ("#B: " + name + " expected ArgumentException");
+                                               } catch /*(ArgumentException)*/ {
+                                                       continue;
+                                               }
+                                       } else {
+                                               dt2.ImportRow (r1);
+                                               DataRow r2 = dt2.Rows [0];
+                                               Assert.AreEqual (types [b], r2 [0].GetType (), "#A: " + name);
+                                       }
+                               }
+                       }
+               }
+#endif
+                       
                [Test]
                public void ClearReset () //To test Clear and Reset methods
                {