In Test/System.Data:
authorSureshkumar T <suresh@mono-cvs.ximian.com>
Fri, 22 Apr 2005 13:11:40 +0000 (13:11 -0000)
committerSureshkumar T <suresh@mono-cvs.ximian.com>
Fri, 22 Apr 2005 13:11:40 +0000 (13:11 -0000)
2005-04-22  Sureshkumar T  <tsureshkumar@novell.com>

* DataTableLoadRowTest.cs: Added. A test case for testing
LoadDataRow method of DataTable. This tests for various
possiblities of row state and loadoption.

In System.Data.Common:
2005-04-22  Sureshkumar T  <tsureshkumar@novell.com>

* DbDataAdapter.cs: Moved FillTable and BuildSchema as static
methods as they are not operating on the current instance. This
could be reused to fill any table from a data reader.

* RecordCache.cs: While disposing records, make sure that the
record is not already disposed. i.e. to make sure later the same
record is not reused. Implemented a static method to compare two
version of records in a container.

In .:
2005-04-22  Sureshkumar T  <tsureshkumar@novell.com>

* System.Data_test.dll.sources: Added DataTableLoadRowTest.cs.

In System.Data:
2005-04-22  Sureshkumar T  <tsureshkumar@novell.com>

* LoadOption.cs: Changed the enums. Keeping old values for
migration.

* DataTable.cs: Implemented methods Load and its overloads. Also
implemented LoadDataRow.

* DataRowCollection.cs: Added a variation of the Find method to
return a row even if it is of state Deleted. This is required for
DataTable.LoadDataRow method.

* DataRow.cs: Implemented internal helper method Load for loading
values from an object array and given an LoadOption (2.0 feature).

* DataRowAction.cs: Added few more enums for .net 2.0. Sorted
alphabetically.

svn path=/trunk/mcs/; revision=43440

13 files changed:
mcs/class/System.Data/ChangeLog
mcs/class/System.Data/System.Data.Common/ChangeLog
mcs/class/System.Data/System.Data.Common/DbDataAdapter.cs
mcs/class/System.Data/System.Data.Common/RecordCache.cs
mcs/class/System.Data/System.Data/ChangeLog
mcs/class/System.Data/System.Data/DataRow.cs
mcs/class/System.Data/System.Data/DataRowAction.cs
mcs/class/System.Data/System.Data/DataRowCollection.cs
mcs/class/System.Data/System.Data/DataTable.cs
mcs/class/System.Data/System.Data/LoadOption.cs
mcs/class/System.Data/System.Data_test.dll.sources
mcs/class/System.Data/Test/System.Data/ChangeLog
mcs/class/System.Data/Test/System.Data/DataTableLoadRowTest.cs [new file with mode: 0755]

index 3a221fd0eea93211a7dd5ebfbb7779e6d358bcdb..fb65b7175fc5f0757bb8d033a2bcabeb69b20799 100644 (file)
@@ -1,3 +1,7 @@
+2005-04-22  Sureshkumar T  <tsureshkumar@novell.com>
+
+       * System.Data_test.dll.sources: Added DataTableLoadRowTest.cs.
+
 2005-04-08  Raja R Harinath  <rharinath@novell.com>
 
        * Makefile (EXTRA_DISTFILES): Add app_test_2.0.config.
index 9bf153cd0634402b20d0cea08506c4307385f2d5..c0ee834b35b27c0f158d8f6a4d595f5c2e98ac52 100755 (executable)
@@ -1,3 +1,14 @@
+2005-04-22  Sureshkumar T  <tsureshkumar@novell.com>
+
+       * DbDataAdapter.cs: Moved FillTable and BuildSchema as static
+       methods as they are not operating on the current instance. This
+       could be reused to fill any table from a data reader.
+
+       * RecordCache.cs: While disposing records, make sure that the
+       record is not already disposed. i.e. to make sure later the same
+       record is not reused. Implemented a static method to compare two
+       version of records in a container.
+
 2005-04-18  Sureshkumar T  <tsureshkumar@novell.com>
 
        * DataAdapter.cs: Implemenetd OnFillError handler.
index 437fdfdb0f55cb6353b3094a64194aeb1197fe47..563aad68a0bcc92c2edb604b10e86d141dbe5936 100644 (file)
@@ -4,6 +4,7 @@
 // Author:
 //   Rodrigo Moya (rodrigo@ximian.com)
 //   Tim Coleman (tim@timcoleman.com)
+//   Sureshkumar T <tsureshkumar@novell.com>
 //
 // (C) Ximian, Inc
 // Copyright (C) Tim Coleman, 2002-2003
@@ -331,48 +332,100 @@ namespace System.Data.Common {
                        return Fill (dataSet, srcTable, command.ExecuteReader (commandBehavior), startRecord, maxRecords);
                }
 
-               private bool FillTable (DataTable dataTable, IDataReader dataReader, int startRecord, int maxRecords, ref int counter) 
+               private bool FillTable (DataTable dataTable, IDataReader dataReader, int startRecord, int maxRecords, ref int counter)
                {
-                       if (dataReader.FieldCount == 0) {
+                       if (dataReader.FieldCount == 0)
                                return false;
-                       }
 
-                       int counterStart = counter;
-                       
                        int[] mapping = BuildSchema (dataReader, dataTable, SchemaType.Mapped);
-
-                               for (int i = 0; i < startRecord; i++) {
-                                       dataReader.Read ();
-                               }
-
-                       while (dataReader.Read () && (maxRecords == 0 || (counter - counterStart) < maxRecords)) {
-                               try {
-                                       dataTable.BeginLoadData ();
-                                       dataTable.LoadDataRow (dataReader, mapping, AcceptChangesDuringFill);
-                                       dataTable.EndLoadData ();
-                                       counter++;
-                               } 
-                               catch (Exception e) {
-                                       object[] readerArray = new object[dataReader.FieldCount];
-                                       object[] tableArray = new object[dataReader.FieldCount];
-                                       // we get the values from the datareader
-                                       dataReader.GetValues (readerArray);
-                                       // copy from datareader columns to table columns according to given mapping
-                                        int count = 0;
-                                       for (int i = 0; i < dataTable.Columns.Count; i++) {
-                                                if (mapping [i] >= 0)
-                                                        tableArray[count++] = readerArray[mapping[i]];
-                                       }
-                                       FillErrorEventArgs args = CreateFillErrorEvent (dataTable, tableArray, e);
-                                       OnFillError (args);
-                                       if(!args.Continue) {
-                                               return false;
-                                       }
-                               }
-                       }
+                        try {
+                                FillTable (dataTable, dataReader, startRecord, maxRecords, mapping,
+                                           AcceptChangesDuringFill, ref counter);
+                        } catch (Exception e) {
+                                object[] readerArray = new object[dataReader.FieldCount];
+                                object[] tableArray = new object[dataReader.FieldCount];
+                                // we get the values from the datareader
+                                dataReader.GetValues (readerArray);
+                                // copy from datareader columns to table columns according to given mapping
+                                int count = 0;
+                                for (int i = 0; i < dataTable.Columns.Count; i++) {
+                                        if (mapping [i] >= 0)
+                                                tableArray[count++] = readerArray[mapping[i]];
+                                }
+                                FillErrorEventArgs args = CreateFillErrorEvent (dataTable, tableArray, e);
+                                OnFillError (args);
+                                if(!args.Continue) {
+                                        return false;
+                                }
+                        }
                        return true;
                }
 
+                /// <summary>
+                ///     Fills the given datatable using values from reader. if a column 
+                ///     does not have a mapped reader column (-1 in mapping), that will 
+                ///     be filled with default value. 
+                /// </summary>
+               internal static void FillTable (DataTable dataTable, 
+                                               IDataReader dataReader, 
+                                               int startRecord, 
+                                               int maxRecords, 
+                                               int [] mapping,
+                                               bool acceptChanges,
+                                               ref int counter) 
+                {
+                        if (dataReader.FieldCount == 0)
+                               return ;
+
+                        for (int i = 0; i < startRecord; i++)
+                                dataReader.Read ();
+
+                        int counterStart = counter;
+                        while (dataReader.Read () && (maxRecords == 0 || (counter - counterStart) < maxRecords)) {
+                                dataTable.BeginLoadData ();
+                                dataTable.LoadDataRow (dataReader, mapping, acceptChanges);
+                                dataTable.EndLoadData ();
+                                counter++;
+                        }
+                }
+#if NET_2_0
+                /// <summary>
+                ///     Fills the given datatable using values from reader. if a value 
+                ///     for a column is  null, that will be filled with default value. 
+                /// </summary>
+                /// <returns>No. of rows affected </returns>
+               internal static int FillFromReader (DataTable table,
+                                                    IDataReader reader,
+                                                    int start, 
+                                                    int length,
+                                                    int [] mapping,
+                                                    LoadOption loadOption
+                                                    )
+                {
+                        if (reader.FieldCount == 0)
+                               return 0 ;
+
+                        for (int i = 0; i < start; i++)
+                                reader.Read ();
+
+                        int counter = 0;
+                        object [] values = new object [mapping.Length];
+                        while (reader.Read () &&
+                               (length == 0 || counter < length)) {
+                                
+                                for (int i = 0 ; i < mapping.Length; i++)
+                                        values [i] = mapping [i] < 0 ? null : reader [mapping [i]];
+                                        
+                                table.BeginLoadData ();
+                                table.LoadDataRow (values, loadOption);
+                                table.EndLoadData ();
+                                counter++;
+                        }
+                        return counter;
+                }
+
+#endif // NET_2_0
+
                public override DataTable[] FillSchema (DataSet dataSet, SchemaType schemaType) 
                {
                        return FillSchema (dataSet, schemaType, SelectCommand, DefaultSourceTableName, CommandBehavior.Default);
@@ -495,6 +548,22 @@ namespace System.Data.Common {
                // the int array represents this match.
                [MonoTODO ("Test")]
                private int[] BuildSchema (IDataReader reader, DataTable table, SchemaType schemaType)
+               {
+                        return BuildSchema (reader, table, schemaType, MissingSchemaAction,
+                                            MissingMappingAction, TableMappings);
+               }
+
+                /// <summary>
+                ///     Creates or Modifies the schema of the given DataTable based on the schema of
+                ///     the reader and the arguments passed.
+                /// </summary>
+                internal static int[] BuildSchema (IDataReader reader, 
+                                                   DataTable table, 
+                                                   SchemaType schemaType,
+                                                   MissingSchemaAction missingSchAction,
+                                                   MissingMappingAction missingMapAction,
+                                                   DataTableMappingCollection dtMapping
+                                                   )
                {
                        int readerIndex = 0;
                        int[] mapping = new int[reader.FieldCount + table.Columns.Count]; // mapping the reader indexes to the datatable indexes
@@ -521,33 +590,32 @@ namespace System.Data.Common {
                                // generate DataSetColumnName from DataTableMapping, if any
                                string dsColumnName = realSourceColumnName;
                                DataTableMapping tableMapping = null;
-                               tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction (TableMappings, table.TableName, table.TableName, MissingMappingAction); 
+                               tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction (dtMapping, table.TableName, table.TableName, missingMapAction); 
                                if (tableMapping != null) 
                                {
                                        
                                        table.TableName = tableMapping.DataSetTable;
                                        // check to see if the column mapping exists
-                                       DataColumnMapping columnMapping = DataColumnMappingCollection.GetColumnMappingBySchemaAction(tableMapping.ColumnMappings, realSourceColumnName, MissingMappingAction);
+                                       DataColumnMapping columnMapping = DataColumnMappingCollection.GetColumnMappingBySchemaAction(tableMapping.ColumnMappings, realSourceColumnName, missingMapAction);
                                        if (columnMapping != null)
                                        {
                                                DataColumn col =
                                                        columnMapping.GetDataColumnBySchemaAction(
                                                        table ,
                                                        (Type)schemaRow["DataType"],
-                                                       MissingSchemaAction);
+                                                       missingSchAction);
 
                                                if (col != null)
                                                {
                                                        // if the column is not in the table - add it.
                                                        if (table.Columns.IndexOf(col) == -1)
                                                        {
-                                                               if (MissingSchemaAction == MissingSchemaAction.Add 
-                                                                    || MissingSchemaAction == MissingSchemaAction.AddWithKey)
+                                                               if (missingSchAction == MissingSchemaAction.Add 
+                                                                    || missingSchAction == MissingSchemaAction.AddWithKey)
                                                                        table.Columns.Add(col);
                                                        }
 
-
-                                                        if (MissingSchemaAction == MissingSchemaAction.AddWithKey) {
+                                                        if (missingSchAction == MissingSchemaAction.AddWithKey) {
                                                                 if (!schemaRow["IsKey"].Equals (DBNull.Value))
                                                                         if ((bool) (schemaRow ["IsKey"]))
                                                                                 primaryKey.Add (col);
@@ -566,7 +634,8 @@ namespace System.Data.Common {
                                table.PrimaryKey = (DataColumn[])(primaryKey.ToArray(typeof (DataColumn)));
 
                        return mapping;
-               }
+                        
+                }
 
                [MonoTODO]
                object ICloneable.Clone ()
index 67b47e41cce8bd4383541f8a56196b2d66e1c442..92bf0d239bcabe2c93acf1d5b4a08cb5b236fc24 100644 (file)
@@ -64,7 +64,7 @@ namespace System.Data.Common
                internal int NewRecord()
                {
                        if (_records.Count > 0) {
-                               return (int)_records.Pop();
+                                return (int)_records.Pop();
                        }
                        else {
                                DataColumnCollection cols = _table.Columns;
@@ -86,7 +86,9 @@ namespace System.Data.Common
                        if ( index < 0 ) {
                                throw new ArgumentException();
                        }
-                       _records.Push(index);
+                        if (! _records.Contains (index)) {
+                                _records.Push(index);
+                        }
                }
 
                internal int CopyRecord(DataTable fromTable,int fromRecordIndex,int toRecordIndex)
@@ -106,6 +108,19 @@ namespace System.Data.Common
                        return recordIndex;
                }
 
+                /// <summary>
+                ///     Compares two records in the given data table. The numbers are the offset
+                ///     into the container tables.
+                /// </summary>
+                internal static bool CompareRecords (DataTable table, int x, int y)
+                {
+                        foreach (DataColumn dc in table.Columns) {
+                                if (dc.DataContainer.CompareValues (x, y) != 0)
+                                        return false;
+                        }
+                        return true;
+                }
+                
                #endregion // Methods
 
        }
index f71cae160aa8ceed53bcd013b75ec2870fe69c16..becadf74d6e9d50662b0a943b8cf3220f8135ae4 100644 (file)
@@ -1,3 +1,21 @@
+2005-04-22  Sureshkumar T  <tsureshkumar@novell.com>
+
+       * LoadOption.cs: Changed the enums. Keeping old values for
+       migration.
+
+       * DataTable.cs: Implemented methods Load and its overloads. Also
+       implemented LoadDataRow.
+
+       * DataRowCollection.cs: Added a variation of the Find method to
+       return a row even if it is of state Deleted. This is required for
+       DataTable.LoadDataRow method.
+
+       * DataRow.cs: Implemented internal helper method Load for loading
+       values from an object array and given an LoadOption (2.0 feature).
+
+       * DataRowAction.cs: Added few more enums for .net 2.0. Sorted
+       alphabetically.
+
 2005-04-20  Jordi Mas i Hernandez <jordi@ximian.com>
 
        * DataViewManager.cs: implements TypedList.GetListName used in SWF
index aae0b49781cf2657946802c7e01b49a2a62fc7e6..cbc95c861ae1b5836f75fb6277d032ffd4e338ab 100644 (file)
@@ -7,6 +7,7 @@
 //   Tim Coleman <tim@timcoleman.com>
 //   Ville Palo <vi64pa@koti.soon.fi>
 //   Alan Tam Siu Lung <Tam@SiuLung.com>
+//   Sureshkumar T <tsureshkumar@novell.com>
 //
 // (C) Ximian, Inc 2002
 // (C) Daniel Morgan 2002, 2003
@@ -37,6 +38,7 @@
 //
 
 using System;
+using System.Data.Common;
 using System.Collections;
 using System.Globalization;
 using System.Xml;
@@ -233,6 +235,82 @@ namespace System.Data {
                        }
                }
 
+                /// <summary>
+                /// Sets the index into the container records for the original version. Apart
+                /// from that, it makes sure it pools the record used earlier if they are not
+                /// used by other versions.
+                /// </summary>
+                internal int Original 
+                {
+                        get { return _original;}
+                        set {
+                                if (_original == value) 
+                                        return;
+                                
+                                if (_original >= 0 
+                                    && _current != _original
+                                    && _proposed != _original)
+                                        Table.RecordCache.DisposeRecord (_original);
+                                _original = value;
+                        }
+                }
+
+                /// <summary>
+                /// Sets the index into the container records for the proposed version. Apart
+                /// from that, it makes sure it pools the record used earlier if they are not
+                /// used by other versions.
+                internal int Proposed
+                {
+                        get { return _proposed;}
+                        set {
+                                if (_proposed == value)
+                                        return;
+                                if (_proposed >= 0
+                                    && _proposed != _current
+                                    && _proposed != _original)
+                                        Table.RecordCache.DisposeRecord (_proposed);
+                                _proposed = value;
+                        }
+                }
+
+                /// <summary>
+                /// Sets the index into the container records for the current version. Apart
+                /// from that, it makes sure it pools the record used earlier if they are not
+                /// used by other versions.
+                internal int Current 
+                {
+                        get { return _current;}
+                        set {
+                                if (_current == value)
+                                        return;
+                                if (_current >= 0
+                                    && _current != _original
+                                    && _current != _proposed)
+                                        Table.RecordCache.DisposeRecord (_current);
+                                _current = value;
+                        }
+                }
+
+                /// <summary>
+                /// Set a value for the column into the offset specified by the version.<br>
+                /// If the value is auto increment or null, necessary auto increment value
+                /// or the default value will be used.
+                /// </summary>
+                internal void SetValue (int column, object value, int version)
+                {
+                        DataColumn dc = Table.Columns[column];
+
+                        if (value == null && ! dc.AutoIncrement) // set default value / auto increment
+                                value = dc.DefaultValue;
+
+                       Table.ChangingDataColumn (this, dc, value);     
+                        CheckValue (value, dc);
+                        if ( ! dc.AutoIncrement)
+                                dc [version] = value;
+                        else if (_proposed >= 0 && _proposed != version) // proposed holds the AI
+                                dc [version] = dc [_proposed];
+                }
+
                /// <summary>
                /// Gets the data stored in the column, specified by index and version of the data to
                /// retrieve.
@@ -358,7 +436,7 @@ namespace System.Data {
                        }
                }
 
-               #endregion
+               #endregion // Properties
 
                #region Methods
 
@@ -527,10 +605,8 @@ namespace System.Data {
                                throw new RowNotInTableException("Cannot perform this operation on a row not in the table.");
                        }
                        // Accept from detached
-                       if (_original >= 0) {
-                               Table.RecordCache.DisposeRecord(_original);
-                       }
-                       _original = _current;
+                       if (_original != _current)
+                               Original = Current;
                }
 
                /// <summary>
@@ -1114,26 +1190,26 @@ namespace System.Data {
                /// </summary>
                public bool HasVersion (DataRowVersion version) 
                {
-                       switch (version) {
-                               case DataRowVersion.Default:
-                                       if (rowState == DataRowState.Deleted && !_inExpressionEvaluation)
-                                               return false;
-                                       if (rowState == DataRowState.Detached)
-                                               return _proposed >= 0;
-                                       return true;
-                               case DataRowVersion.Proposed:
-                                       if (rowState == DataRowState.Deleted && !_inExpressionEvaluation)
-                                               return false;
-                                       return _proposed >= 0;
-                               case DataRowVersion.Current:
-                                       if ((rowState == DataRowState.Deleted && !_inExpressionEvaluation) || rowState == DataRowState.Detached)
-                                               return false;
-                                       return _current >= 0;
-                               case DataRowVersion.Original:
-                                       if (rowState == DataRowState.Detached)
-                                               return false;
-                                       return _original >= 0;
-                       }
+                        switch (version) {
+                        case DataRowVersion.Default:
+                                if (rowState == DataRowState.Deleted && !_inExpressionEvaluation)
+                                        return false;
+                                if (rowState == DataRowState.Detached)
+                                        return _proposed >= 0;
+                                return true;
+                        case DataRowVersion.Proposed:
+                                if (rowState == DataRowState.Deleted && !_inExpressionEvaluation)
+                                        return false;
+                                return _proposed >= 0;
+                        case DataRowVersion.Current:
+                                if ((rowState == DataRowState.Deleted && !_inExpressionEvaluation) || rowState == DataRowState.Detached)
+                                        return false;
+                                return _current >= 0;
+                        case DataRowVersion.Original:
+                                if (rowState == DataRowState.Detached)
+                                        return false;
+                                return _original >= 0;
+                        }
                        return false;
                }
 
@@ -1448,6 +1524,71 @@ namespace System.Data {
                 }
        
                #endregion // Methods
+
+#if NET_2_0
+                /// <summary>
+                ///    This method loads a given value into the existing row affecting versions,
+                ///    state based on the LoadOption.  The matrix of changes for this method are as
+                ///    mentioned in the DataTable.Load (IDataReader, LoadOption) method.
+                /// </summary>
+                [MonoTODO ("Raise necessary Events")]
+                internal void Load (object [] values, LoadOption loadOption, bool is_new)
+                {
+                        DataRowAction action = DataRowAction.Change;
+
+                        int temp = Table.RecordCache.NewRecord ();
+                        for (int i = 0 ; i < Table.Columns.Count; i++)
+                                SetValue (i, values [i], temp);
+
+                        if (is_new) { // new row
+                                if (editing || RowState == DataRowState.Detached)
+                                        Proposed = temp;
+                                else
+                                        Current = temp;
+                                return;
+                        }
+
+                        if (loadOption == LoadOption.OverwriteChanges 
+                            || (loadOption == LoadOption.PreserveChanges
+                                && rowState == DataRowState.Unchanged)) {
+                                Original = temp;
+                                if (editing)
+                                        Proposed = temp;
+                                else
+                                        Current = temp;
+                                rowState = DataRowState.Unchanged;
+                                action = DataRowAction.ChangeCurrentAndOriginal;
+                                return;
+                        }
+
+                        if (loadOption == LoadOption.PreserveChanges) {
+                                if (rowState != DataRowState.Deleted) {
+                                        Original = temp;
+                                        rowState = DataRowState.Modified;
+                                        action   = DataRowAction.ChangeOriginal;
+                                }
+                                return;
+                        }
+                                
+                        bool not_used = true;
+                        // Upsert
+                        if (rowState != DataRowState.Deleted) {
+                                int index = editing ? _proposed : _current;
+                                if (! RecordCache.CompareRecords (Table, index, temp)) {
+                                        if (editing)
+                                                Proposed = temp;
+                                        else
+                                                Current = temp;
+                                        not_used = false;
+                                        if (rowState == DataRowState.Unchanged)
+                                                rowState = DataRowState.Modified;
+                                }
+                        }
+                                
+                        if (not_used)
+                                Table.RecordCache.DisposeRecord (temp);
+                }
+#endif // NET_2_0
        }
 
        
index e55fb453afd765699b988cc747e0ad6025ddc9a7..d9ad2a47bb9b71d9edc37ac087c3690c99bace1f 100644 (file)
@@ -3,6 +3,7 @@
 //
 // Author:
 //   Christopher Podurgiel (cpodurgiel@msn.com)
+//   Sureshkumar T <tsureshkumar@novell.com>
 //
 // (C) Chris Podurgiel
 //
@@ -40,12 +41,15 @@ namespace System.Data
        [Serializable]
        public enum DataRowAction
        {
-               Nothing = 0,
-               Delete = 1,
-               Change = 2,
-               Rollback = 4,
-               Commit = 8,
-               Add = 16
+                Add                             = 16,
+                Change                          = 2,
+#if NET_2_0
+                ChangeCurrentAndOriginal        = 64,
+                ChangeOriginal                  = 32,
+#endif // NET_2_0
+                Commit                          = 8,
+                Delete                          = 1,
+                Nothing                         = 0,
+                Rollback                        = 4
        }
-
-}
\ No newline at end of file
+}
index e42a10ac123672889277871f61e0a5e88550678d..89d33e468f5ff58abf1ce8aa60f864bdb3af56f1 100644 (file)
@@ -179,7 +179,44 @@ namespace System.Data
                /// </summary>
                public DataRow Find (object key) 
                {
-                       if (table.PrimaryKey.Length == 0)
+                       return Find (key, // primary key value
+                                     true // ignore deleted records
+                                     );
+               }
+
+                /// <summary>
+                ///     Searches records for the given primary key values.
+                /// </summary>
+                public DataRow Find (object [] keys)
+                {
+                        return Find (keys, // primary key values
+                                     true  // ignore deleted records
+                                     );
+                }
+                
+                /// <summary>
+                ///     Searches records for the given primary key values populated into
+                ///     a temporary cache index.
+                /// </summary>
+                internal DataRow Find (int index, int length)
+                {
+                        return Find (index,     // record to find
+                                     length,    // length of primary key
+                                     true       // ignore deleted records
+                                     );
+                }
+
+                /// <summary>
+                ///     Searches records for the given single primary key.
+                /// </summary>
+                /// <param name='key'>Primary key value to be searched </param>
+                /// <param name='ignoreDeleted'>
+                ///    Ignore the records with row state DataRowState.Deleted
+                ///    if true.
+                /// </param>
+                internal DataRow Find (object key, bool ignoreDeleted)
+                {
+                        if (table.PrimaryKey.Length == 0)
                                throw new MissingPrimaryKeyException ("Table doesn't have a primary key.");
                        if (table.PrimaryKey.Length > 1)
                                throw new ArgumentException ("Expecting " + table.PrimaryKey.Length +" value(s) for the key being indexed, but received 1 value(s).");
@@ -208,11 +245,13 @@ namespace System.Data
                        
                                //loop through all collection rows                      
                                foreach (DataRow row in this) {
-                                       if (row.RowState != DataRowState.Deleted) {
-                                               int index = row.IndexFromVersion(DataRowVersion.Default); 
-                                               if (primaryKey.DataContainer.CompareValues(index, tmpRecord) == 0) {
-                                                       return row;
-                                               }
+                                       if (ignoreDeleted && row.RowState == DataRowState.Deleted)
+                                                continue;
+                                        int index = row.IndexFromVersion(DataRowVersion.Default);
+                                        if (row.RowState == DataRowState.Deleted)
+                                                index = row.Current;
+                                        if (primaryKey.DataContainer.CompareValues(index, tmpRecord) == 0) {
+                                                return row;
                                        }
                                }
                                return null;
@@ -220,21 +259,20 @@ namespace System.Data
                        finally {
                                table.RecordCache.DisposeRecord(tmpRecord);
                        }
-               }
+                }
 
-               /// <summary>
-               /// Gets the row containing the specified primary key values.
-               /// </summary>
-               public DataRow Find (object[] keys) 
+                /// <summary>
+                ///     Searches records for the given primary key values.
+                /// </summary>
+                /// <param name='keys'>Primary key values to be searched </param>
+                /// <param name='ignoreDeleted'>
+                ///    Ignore the records with row state DataRowState.Deleted
+                ///    if true.
+                /// </param>
+               internal DataRow Find (object[] keys, bool ignoreDeleted) 
                {
-                       if (table.PrimaryKey.Length == 0)
-                               throw new MissingPrimaryKeyException ("Table doesn't have a primary key.");
+                        AssertFind (keys);
 
-                       if (keys == null)
-                               throw new ArgumentException ("Expecting " + table.PrimaryKey.Length +" value(s) for the key being indexed, but received 0 value(s).");
-                       if (table.PrimaryKey.Length != keys.Length)
-                               throw new ArgumentException ("Expecting " + table.PrimaryKey.Length +" value(s) for the key being indexed, but received " + keys.Length +  " value(s).");
-                                                                                                    
                        DataColumn[] primaryKey = table.PrimaryKey;
                        int tmpRecord = table.RecordCache.NewRecord();
                        try {
@@ -243,44 +281,153 @@ namespace System.Data
                                        // according to MSDN: the DataType value for both columns must be identical.
                                        primaryKey[i].DataContainer[tmpRecord] = keys[i];
                                }
-                               return Find(tmpRecord,numColumn);
+                               return Find(tmpRecord, numColumn, ignoreDeleted);
                        }
                        finally {
                                table.RecordCache.DisposeRecord(tmpRecord);
                        }
                }
 
-               internal DataRow Find(int index, int length)
+                /// <summary>
+                ///     Searches records for the given primary key values and the 
+                ///     given version.
+                /// </summary>
+                /// <param name='keys'>Primary key values to be searched </param>
+                /// <param name='version'>
+                ///    Version of the rows to be searched for.
+                /// </param>
+                internal DataRow Find (object [] values, DataRowVersion version)
+                {
+                        AssertFind (values);
+                                                                                                    
+                       DataColumn[] pk = table.PrimaryKey;
+                       int temp = table.RecordCache.NewRecord();
+                       try {
+                               for (int i = 0; i < pk.Length; i++)
+                                       pk [i].DataContainer[temp] = values [i];
+                               return Find(temp, version, false); // include deleted records also
+                       }
+                       finally {
+                               table.RecordCache.DisposeRecord(temp);
+                       }
+                }
+
+                /// <summary>
+                ///     Searches records for the given primary key values and the 
+                ///     given version.
+                /// </summary>
+                /// <param name='record'>index of the record which holds the values to be searchd.
+                /// </param>
+                /// <param name='version'>
+                ///    Version of the rows to be searched for.
+                /// </param>
+                /// <param name='ignoreDeleted'>Ignore the records with state Deleted </param>
+               private DataRow Find(int record, DataRowVersion version, bool ignoreDeleted)
                {
-                       DataColumn[] primaryKey = table.PrimaryKey;
-                       Index primaryKeyIndex = table.GetIndexByColumns(primaryKey);
-                       // if we can search through index
-                       if (primaryKeyIndex != null) {
-                               // get the child rows from the index
-                               Node node = primaryKeyIndex.FindSimple(index,length,true);
-                               if ( node != null ) {
-                                       return node.Row;
-                               }
+                        DataRow resultRow = null;
+                        if (version == DataRowVersion.Current) {
+                                // index engine holds only the current records.
+                                resultRow = IndexSearch (record);
+                                if (resultRow != null)
+                                        return resultRow;
+                        }
+
+                       // fallback : loop through all collection rows                  
+                        // if there is a matching record with state deleted, that won't be detected
+                        // in the above search. (deleted records are not part of index.
+                       foreach (DataRow row in this) {
+                               if (ignoreDeleted && row.RowState != DataRowState.Deleted) 
+                                        continue;
+                                
+                                int offset = row.IndexFromVersion(version);
+                                if (offset < 0)
+                                        continue;
+                                bool matching = true;
+                                for (int i = 0; matching && i < table.PrimaryKey.Length; i++) { 
+                                        if (table.PrimaryKey [i].DataContainer.CompareValues(offset, record) != 0)
+                                                matching = false;
+                                }
+                                if (matching) {
+                                        resultRow = row; 
+                                        break;
+                                }
                        }
-               
+                       return resultRow;
+
+                }
+
+                /// <summary>
+                ///     Searches records for the given primary key values and the 
+                ///     given version.
+                /// </summary>
+                /// <param name='index'> index of the record which holds the values to be searchd.
+                /// </param>
+                /// <param name='length'> length of primary keys </param>
+                /// <param name='ignoreDeleted'> Ignore the records with state Deleted </param>
+               private DataRow Find(int index, int length, bool ignoreDeleted)
+               {
+                        DataRow resultRow = IndexSearch (index);
+                        if (resultRow != null)
+                                return resultRow;
+                        
                        //loop through all collection rows                      
                        foreach (DataRow row in this) {
-                               if (row.RowState != DataRowState.Deleted) {
-                                       int rowIndex = row.IndexFromVersion(DataRowVersion.Default);
-                                       bool match = true;
-                                       for (int columnCnt = 0; columnCnt < length; ++columnCnt) { 
-                                               if (primaryKey[columnCnt].DataContainer.CompareValues(rowIndex, index) != 0) {
-                                                       match = false;
-                                               }
-                                       }
-                                       if ( match ) {
-                                               return row;
-                                       }
-                               }
+                               if (ignoreDeleted && row.RowState != DataRowState.Deleted) 
+                                        continue;
+                                
+                                int rowIndex = row.IndexFromVersion(DataRowVersion.Default);
+                                if (row.RowState == DataRowState.Deleted)
+                                        rowIndex = row.Current;
+                                bool match = true;
+                                for (int columnCnt = 0; columnCnt < length; ++columnCnt) { 
+                                        if (table.PrimaryKey[columnCnt].DataContainer.CompareValues(rowIndex, index) != 0) {
+                                                match = false;
+                                        }
+                                }
+                                if ( match ) {
+                                        return row;
+                                }
                        }
                        return null;
                }
 
+
+                /// <summary>
+                ///   Asserts the validity of the search.
+                /// </summary>
+                private void AssertFind (object [] values)
+                {
+                        if (table.PrimaryKey.Length == 0)
+                                throw new MissingPrimaryKeyException ("Table doesn't have a primary key.");
+
+                       if (values == null)
+                               throw new ArgumentException ("Expecting " + table.PrimaryKey.Length +" value(s) for the key being indexed, but received 0 value(s).");
+
+                       if (table.PrimaryKey.Length != values.Length)
+                               throw new ArgumentException ("Expecting " + table.PrimaryKey.Length +" value(s) for the key being indexed, but received " + values.Length +  " value(s).");
+        
+                }
+
+                /// <summary>
+                ///   Search for the record using the index.
+                /// </summary>
+                private DataRow IndexSearch (int record)
+                {
+                        Index index = table.GetIndexByColumns(table.PrimaryKey);
+                        // search in index
+                        // priority is the non-deleted recrod
+                       if (index != null) {
+                               // get the child rows from the index
+                               Node node = index.FindSimple(record,
+                                                             table.PrimaryKey.Length, 
+                                                             true
+                                                             );
+                               if (node != null)
+                                       return node.Row;
+                       }
+                        return null;
+                }                
+
                /// <summary>
                /// Inserts a new row into the collection at the specified location.
                /// </summary>
index 9b37065389ceb66358f07e6c457bcb2b2fcd1f3f..3cac780de9bca21c29b29f2a41faef811f966bdc 100644 (file)
@@ -8,6 +8,7 @@
 //   Rodrigo Moya <rodrigo@ximian.com>
 //   Tim Coleman (tim@timcoleman.com)
 //   Ville Palo <vi64pa@koti.soon.fi>
+//   Sureshkumar T <tsureshkumar@novell.com>
 //
 // (C) Chris Podurgiel
 // (C) Ximian, Inc 2002
@@ -991,17 +992,40 @@ namespace System.Data {
                }
 
 #if NET_2_0
-               [MonoTODO]
+                /// <summary>
+                ///     Loads the table with the values from the reader
+                /// </summary>
                public void Load (IDataReader reader)
                {
-                       throw new NotImplementedException ();
+                        Load (reader, LoadOption.PreserveChanges);
                }
 
-               [MonoTODO]
+                /// <summary>
+                ///     Loads the table with the values from the reader and the pattern
+                ///     of the changes to the existing rows or the new rows are based on
+                ///     the LoadOption passed.
+                /// </summary>
                public void Load (IDataReader reader, LoadOption loadOption)
                {
-                       throw new NotImplementedException ();
-               }
+                        bool prevEnforceConstr = this.EnforceConstraints;
+                        try {
+                                this.EnforceConstraints = false;
+                                int [] mapping = DbDataAdapter.BuildSchema (reader, this, SchemaType.Mapped, 
+                                                                            MissingSchemaAction.AddWithKey,
+                                                                            MissingMappingAction.Passthrough, 
+                                                                            new DataTableMappingCollection ());
+                                DbDataAdapter.FillFromReader (this,
+                                                              reader,
+                                                              0, // start from
+                                                              0, // all records
+                                                              mapping,
+                                                              loadOption);
+                        } finally {
+                                this.EnforceConstraints = prevEnforceConstr;
+                        }
+               }
+
+                
 #endif
 
                /// <summary>
@@ -1064,7 +1088,7 @@ namespace System.Data {
                                        for (int i = 0; i < PrimaryKey.Length && hasPrimaryValues; i++) {
                                                DataColumn primaryKeyColumn = PrimaryKey[i];
                                                int ordinal = primaryKeyColumn.Ordinal;
-                                               if(ordinal < mapping.Length) {
+                                               if(mapping [ordinal] >= 0) {
                                                        primaryKeyColumn.DataContainer.SetItemFromDataRecord(tmpRecord,record,mapping[ordinal]);
                                                }
                                                else {
@@ -1074,7 +1098,7 @@ namespace System.Data {
                                        
                                        if (hasPrimaryValues) {
                                                // find the row in the table.
-                                               row = Rows.Find(tmpRecord,PrimaryKey.Length);
+                                               row = Rows.Find(tmpRecord, PrimaryKey.Length);
                                        }
                                }
                                finally {
@@ -1098,10 +1122,57 @@ namespace System.Data {
                }
 
 #if NET_2_0
-               [MonoTODO]
-               public DataRow LoadDataRow (object[] values, LoadOption loadOption)
-               {
-                       throw new NotImplementedException ();
+                /// <summary>
+                ///     Loads the given values into an existing row if matches or creates
+                ///     the new row popluated with the values.
+                /// </summary>
+                /// <remarks>
+                ///     This method searches for the values using primary keys and it first
+                ///     searches using the original values of the rows and if not found, it
+                ///     searches using the current version of the row.
+                /// </remarks>
+               public DataRow LoadDataRow (object [] values, LoadOption loadOption)
+               {
+                        DataRow row  = null;
+                        bool new_row = false;
+                        
+                        // Find Data DataRow
+                        if (this.PrimaryKey.Length > 0) {
+                                object [] keyValues = new object [this.PrimaryKey.Length];
+                                for (int i = 0; i < keyValues.Length; i++)
+                                        keyValues [i] = values [this.PrimaryKey [i].Ordinal];
+                                row = this.Rows.Find (keyValues, DataRowVersion.Original );
+                                if (row == null) 
+                                        row = this.Rows.Find (keyValues, DataRowVersion.Current);
+                        }
+                                
+                        // If not found, add new row
+                        if (row == null) {
+                                row = this.NewRow ();
+                                new_row = true;
+                        }
+
+                        bool deleted = row.RowState == DataRowState.Deleted;
+
+                        if (deleted && loadOption == LoadOption.OverwriteChanges)
+                                row.RejectChanges ();                        
+
+                        row.Load (values, loadOption, new_row);
+
+                        if (deleted && loadOption == LoadOption.Upsert) {
+                                row = this.NewRow ();
+                                row.Load (values, loadOption, new_row = true);
+                        }
+
+                        if (new_row) {
+                                this.Rows.Add (row);
+                                if (loadOption == LoadOption.OverwriteChanges ||
+                                    loadOption == LoadOption.PreserveChanges) {
+                                        row.AcceptChanges ();
+                                }
+                        }
+
+                        return row;
                }
 
                [MonoTODO]
index 5bb1139bcbd7c37f50848f00131d6263d626ead5..8e9f51748295f5a21cc6d52e5fc6cb980d6c67c0 100644 (file)
@@ -3,6 +3,7 @@
 //
 // Author:
 //   Tim Coleman (tim@timcoleman.com)
+//   Sureshkumar T <tsureshkumar@novell.com>
 //
 // Copyright (C) Tim Coleman, 2003
 //
 namespace System.Data {
        public enum LoadOption 
        {
-               OverwriteRow,
-               PreserveCurrentValues,
-               UpdateCurrentValues
+                OverwriteChanges        = 2,
+                PreserveChanges         = 3,
+                Upsert                  = 1,
+                [Obsolete ("Use OverwriteChanges insted")]
+                OverwriteRow            = 2,
+                [Obsolete ("Use PreserveChanges insted")]
+               PreserveCurrentValues   = 3,
+                [Obsolete ("Use Upsert insted")]
+               UpdateCurrentValues     = 1
        }
 }
 
index cad17ebe8e387cf6b98364e594e5464e09b34c97..cd37280dec060e31788296439968f661f58ea1d2 100644 (file)
@@ -27,6 +27,7 @@ System.Data/DataSetReadXmlTest.cs
 System.Data/DataSetReadXmlSchemaTest.cs
 System.Data/DataSetInferXmlSchemaTest.cs
 System.Data/DataTableTest.cs
+System.Data/DataTableLoadRowTest.cs
 System.Data/DataViewManagerTest.cs
 System.Data/DataViewTest.cs
 System.Data/ForeignKeyConstraintTest.cs
index c9d25fd05d5e308ea3b257ae0717e9a0f5da56d8..027a7a8d9f6aecf956ae2b39328ab88940719c5e 100644 (file)
@@ -1,3 +1,9 @@
+2005-04-22  Sureshkumar T  <tsureshkumar@novell.com>
+
+       * DataTableLoadRowTest.cs: Added. A test case for testing
+       LoadDataRow method of DataTable. This tests for various
+       possiblities of row state and loadoption.
+
 2005-04-19  Atsushi Enomoto  <atsushi@ximian.com>
 
        * DataViewTest.cs : added more RowStateFilter test (bug #74650).
diff --git a/mcs/class/System.Data/Test/System.Data/DataTableLoadRowTest.cs b/mcs/class/System.Data/Test/System.Data/DataTableLoadRowTest.cs
new file mode 100755 (executable)
index 0000000..3b17ae8
--- /dev/null
@@ -0,0 +1,278 @@
+//
+// DataTableLoadRowTest.cs - NUnit Test Cases for testing the
+//                          DataTable's LoadRow method
+// Author:
+//      Sureshkumar T (tsureshkumar@novell.com)
+//
+// Copyright (c) 2004 Novell Inc., and the individuals listed
+// on the ChangeLog entries.
+//
+// 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.
+//
+
+#if NET_2_0
+
+using System;
+using System.Data;
+using System.Data.SqlClient;
+using System.Text;
+
+using NUnit.Framework;
+
+namespace MonoTests.System.Data.SqlClient
+{
+        [TestFixture]
+        public class DataTableLoadRowTest
+        {
+                [Test]
+                public void LoadRowTest ()
+                {
+                        DataTable dt = new DataTable ();
+                        dt.Columns.Add ("id", typeof (int));
+                        dt.Columns.Add ("name", typeof (string));
+
+                        dt.Rows.Add (new object [] { 1, "mono 1" });
+                        dt.Rows.Add (new object [] { 2, "mono 2" });
+                        dt.Rows.Add (new object [] { 3, "mono 3" });
+
+                        dt.PrimaryKey = new DataColumn [] { dt.Columns ["id"] };
+                        dt.AcceptChanges ();
+
+                        dt.LoadDataRow (new object [] { 4, "mono 4" }, LoadOption.Upsert);
+                        Assert.AreEqual (4, dt.Rows.Count, "#1 has not added a new row");
+                }
+
+                [Test]
+                public void LoadRowTestUpsert ()
+                {
+                        DataTable dt = new DataTable ();
+                        dt.Columns.Add ("id", typeof (int));
+                        dt.Columns.Add ("name", typeof (string));
+
+                        dt.Rows.Add (new object [] { 1, "mono 1" });
+                        dt.Rows.Add (new object [] { 2, "mono 2" });
+                        dt.Rows.Add (new object [] { 3, "mono 3" });
+
+                        dt.PrimaryKey = new DataColumn [] { dt.Columns ["id"] };
+
+                        dt.AcceptChanges ();
+
+                        dt.LoadDataRow (new object [] { 2, "mono test" }, LoadOption.Upsert);
+                        Assert.AreEqual (3, dt.Rows.Count, "#1 should not add a row");
+                        Assert.AreEqual ("mono test", dt.Rows [1] [1], "#2 should change the current");
+                        Assert.AreEqual ("mono 2", dt.Rows [1] [1, DataRowVersion.Original], "#3 should not change original");
+                        Assert.AreEqual (DataRowState.Modified, dt.Rows [1].RowState, "#4 should change state");
+
+
+                        // Row State tests
+                        // current - modified ; result - modified
+                        dt.LoadDataRow (new object [] { 2, "mono test 2" }, LoadOption.Upsert);
+                        Assert.AreEqual ("mono test 2", dt.Rows [1] [1], "#c1 should change the current");
+                        Assert.AreEqual ("mono 2", dt.Rows [1] [1, DataRowVersion.Original], "#c2 should not change original");
+                        Assert.AreEqual (DataRowState.Modified, dt.Rows [1].RowState, "#c3 should not change state");
+
+                        // current - Unchanged; result - Unchanged if no new value
+                        dt.AcceptChanges ();
+                        dt.LoadDataRow (new object [] { 2, "mono test 2" }, LoadOption.Upsert);
+                        Assert.AreEqual ("mono test 2", dt.Rows [1] [1], "#c4 should change the current");
+                        Assert.AreEqual ("mono test 2", dt.Rows [1] [1, DataRowVersion.Original], "#c5 should not change original");
+                        Assert.AreEqual (DataRowState.Unchanged, dt.Rows [1].RowState, "#c6 should not change state");
+                        // not the same value again
+                        dt.RejectChanges ();
+                        dt.LoadDataRow (new object [] { 2, "mono test 3" }, LoadOption.Upsert);
+                        Assert.AreEqual (DataRowState.Modified, dt.Rows [1].RowState, "#c7 should not change state");
+
+                        // current - added; result - added
+                        dt.Rows.Add (new object [] { 4, "mono 4" });
+                        dt.LoadDataRow (new object [] { 4, "mono 4" }, LoadOption.Upsert);
+                        Assert.AreEqual ("mono 4", dt.Rows [3] [1], "#c8 should change the current");
+                        try {
+                                object o = dt.Rows [3] [1, DataRowVersion.Original];
+                                Assert.Fail ("#c9 should have thrown version not found exception");
+                        } catch (VersionNotFoundException) { }
+                        Assert.AreEqual (DataRowState.Added, dt.Rows [3].RowState, "#c10 should not change state");
+
+                        // current - new; result - added
+                        dt.LoadDataRow (new object [] { 5, "mono 5" }, LoadOption.Upsert);
+                        Assert.AreEqual ("mono 5", dt.Rows [4] [1], "#c11 should change the current");
+                        try {
+                                object o = dt.Rows [4] [1, DataRowVersion.Original];
+                                Assert.Fail ("#c12 should have thrown version not found exception");
+                        } catch (VersionNotFoundException) { }
+                        Assert.AreEqual (DataRowState.Added, dt.Rows [4].RowState, "#c13 should change state");
+
+                        // current - deleted; result - added a new row
+                        dt.AcceptChanges ();
+                        dt.Rows [4].Delete ();
+                        dt.LoadDataRow (new object [] { 5, "mono 5" }, LoadOption.Upsert);
+                        Assert.AreEqual (6, dt.Rows.Count, "#c14 should not add a row");
+                        Assert.AreEqual ("mono 5", dt.Rows [5] [1], "#c15 should change the current");
+                        try {
+                                object o = dt.Rows [5] [1, DataRowVersion.Original];
+                                Assert.Fail ("#c16 expected version not found exception ");
+                        } catch (VersionNotFoundException) {}
+                        Assert.AreEqual (DataRowState.Added, dt.Rows [5].RowState, "#c17 should change state");
+                }
+
+                [Test]
+                public void LoadRowTestOverwriteChanges ()
+                {
+                        DataTable dt = new DataTable ();
+                        dt.Columns.Add ("id", typeof (int));
+                        dt.Columns.Add ("name", typeof (string));
+
+                        dt.Rows.Add (new object [] { 1, "mono 1" });
+                        dt.Rows.Add (new object [] { 2, "mono 2" });
+                        dt.Rows.Add (new object [] { 3, "mono 3" });
+
+                        dt.PrimaryKey = new DataColumn [] { dt.Columns ["id"] };
+                        dt.AcceptChanges ();
+
+                        dt.Rows [1] [1] = "overwrite";
+                        Assert.AreEqual (DataRowState.Modified, dt.Rows [1].RowState, "#1 has not changed the row state");
+
+                        dt.LoadDataRow (new object [] { 2, "mono test" }, LoadOption.OverwriteChanges);
+                        Assert.AreEqual (3, dt.Rows.Count, "#2 has not added a new row");
+                        Assert.AreEqual ("mono test", dt.Rows [1] [1], "#3 should change the current");
+                        Assert.AreEqual ("mono test", dt.Rows [1] [1, DataRowVersion.Original], "#4 should change the original");
+                        Assert.AreEqual (DataRowState.Unchanged, dt.Rows [1].RowState, "#5 has not changed the row state");
+
+                        DataRow r = dt.Rows [1];
+                        r [1] = "test";
+                        Assert.AreEqual ("test", dt.Rows [1] [1], "#6 should change the current");
+                        Assert.AreEqual ("mono test", dt.Rows [1] [1, DataRowVersion.Original], "#7 should change the original");
+                        //Assert.AreEqual ("ramesh", dt.Rows [1] [1, DataRowVersion.Proposed], "#8 should change the original");
+
+                        // Row State tests
+                        // current - modified ; result - modified
+                        dt.LoadDataRow (new object [] { 2, "mono test 2" }, LoadOption.OverwriteChanges);
+                        Assert.AreEqual ("mono test 2", dt.Rows [1] [1], "#c1 should change the current");
+                        Assert.AreEqual ("mono test 2", dt.Rows [1] [1, DataRowVersion.Original], "#c2 should change original");
+                        Assert.AreEqual (DataRowState.Unchanged, dt.Rows [1].RowState, "#c3 should not change state");
+
+                        // current - Unchanged; result - Unchanged if no new value
+                        dt.AcceptChanges ();
+                        dt.LoadDataRow (new object [] { 2, "mono test 2" }, LoadOption.OverwriteChanges);
+                        Assert.AreEqual ("mono test 2", dt.Rows [1] [1], "#c4 should change the current");
+                        Assert.AreEqual ("mono test 2", dt.Rows [1] [1, DataRowVersion.Original], "#c5 should change original");
+                        Assert.AreEqual (DataRowState.Unchanged, dt.Rows [1].RowState, "#c6 should not change state");
+                        
+                        // current - added; result - added
+                        dt.Rows.Add (new object [] { 4, "mono 4" });
+                        dt.LoadDataRow (new object [] { 4, "mono 4" }, LoadOption.OverwriteChanges);
+                        Assert.AreEqual ("mono 4", dt.Rows [3] [1], "#c8 should change the current");
+                        Assert.AreEqual ("mono 4", dt.Rows [3] [1, DataRowVersion.Original], "#c9 should change the original");
+                        Assert.AreEqual (DataRowState.Unchanged, dt.Rows [3].RowState, "#c10 should not change state");
+
+                        // current - new; result - added
+                        dt.LoadDataRow (new object [] { 5, "mono 5" }, LoadOption.OverwriteChanges);
+                        Assert.AreEqual ("mono 5", dt.Rows [4] [1], "#c11 should change the current");
+                        Assert.AreEqual ("mono 5", dt.Rows [4] [1, DataRowVersion.Original], "#c12 should change original");
+                        Assert.AreEqual (DataRowState.Unchanged, dt.Rows [4].RowState, "#c13 should change state");
+
+                        // current - deleted; result - added a new row
+                        dt.AcceptChanges ();
+                        dt.Rows [4].Delete ();
+                        dt.LoadDataRow (new object [] { 5, "mono 51" }, LoadOption.OverwriteChanges);
+                        Assert.AreEqual (5, dt.Rows.Count, "#c14 should not add a row");
+                        Assert.AreEqual ("mono 51", dt.Rows [4] [1], "#c15 should change the current");
+                        Assert.AreEqual ("mono 51", dt.Rows [4] [1, DataRowVersion.Original], "#c16 should change the current");
+                        Assert.AreEqual (DataRowState.Unchanged, dt.Rows [4].RowState, "#c17 should change state");
+                }
+
+                [Test]
+                public void LoadRowTestPreserveChanges ()
+                {
+                        DataTable dt = new DataTable ();
+                        dt.Columns.Add ("id", typeof (int));
+                        dt.Columns.Add ("name", typeof (string));
+
+                        dt.Rows.Add (new object [] { 1, "mono 1" });
+                        dt.Rows.Add (new object [] { 2, "mono 2" });
+                        dt.Rows.Add (new object [] { 3, "mono 3" });
+
+                        dt.PrimaryKey = new DataColumn [] { dt.Columns ["id"] };
+         
+                        dt.LoadDataRow (new object [] { 2, "mono test" }, LoadOption.PreserveChanges);
+                        Assert.AreEqual (3, dt.Rows.Count, "#1 should not add a new row");
+                        Assert.AreEqual ("mono 2", dt.Rows [1] [1], "#2 should not change the current");
+                        Assert.AreEqual ("mono test", dt.Rows [1] [1, DataRowVersion.Original], "#3 should change the original");
+
+                        dt.LoadDataRow (new object [] { 4, "mono 4" }, LoadOption.PreserveChanges);
+                        Assert.AreEqual (4, dt.Rows.Count, "#5 should add a new row");
+                        Assert.AreEqual ("mono 4", dt.Rows [3] [1], "#6 should change the current");
+                        Assert.AreEqual ("mono 4", dt.Rows [3] [1, DataRowVersion.Original], "#7 should change the original");
+                }
+
+                [Test]
+                public void LoadRowDefaultValueTest ()
+                {
+                        DataTable dt = new DataTable ();
+                        dt.Columns.Add ("id", typeof (int));
+                        dt.Columns.Add ("age", typeof (int));
+                        dt.Columns.Add ("name", typeof (string));
+
+                        dt.Columns [1].DefaultValue = 20;
+
+                        dt.Rows.Add (new object [] {1, 15, "mono 1"});
+                        dt.Rows.Add (new object [] { 2, 25, "mono 2" });
+                        dt.Rows.Add (new object [] { 3, 35, "mono 3" });
+
+                        dt.PrimaryKey = new DataColumn [] { dt.Columns ["id"] };
+
+                        dt.AcceptChanges ();
+
+                        dt.LoadDataRow (new object [] { 2, null, "mono test" }, LoadOption.OverwriteChanges);
+                        Assert.AreEqual ( 3, dt.Rows.Count, "#1 should not have added a row");
+                        Assert.AreEqual (20, dt.Rows [1] [1], "#2 should be default value");
+                        Assert.AreEqual (20, dt.Rows [1] [1, DataRowVersion.Original], "#3 should be default value");
+
+                }
+
+                [Test]
+                public void LoadRowAutoIncrementTest ()
+                {
+                        DataTable dt = new DataTable ();
+                        dt.Columns.Add ("id", typeof (int));
+                        dt.Columns.Add ("age", typeof (int));
+                        dt.Columns.Add ("name", typeof (string));
+
+                        dt.Columns [0].AutoIncrementSeed = 10;
+                        dt.Columns [0].AutoIncrementStep = 5;
+                        dt.Columns [0].AutoIncrement = true;
+
+                        dt.Rows.Add (new object [] { null, 15, "mono 1" });
+                        dt.Rows.Add (new object [] { null, 25, "mono 2" });
+                        dt.Rows.Add (new object [] { null, 35, "mono 3" });
+
+                        dt.PrimaryKey = new DataColumn [] { dt.Columns ["id"] };
+
+                        dt.AcceptChanges ();
+
+                        dt.LoadDataRow (new object [] { null, 20, "mono test" }, LoadOption.OverwriteChanges);
+                        Assert.AreEqual (4, dt.Rows.Count, "#1 has not added a new row");
+                        Assert.AreEqual (25, dt.Rows [3] [0], "#2 current should be ai");
+                        Assert.AreEqual (25, dt.Rows [3] [0, DataRowVersion.Original], "#3 original should be ai");
+
+                }
+        }
+}
+
+#endif // NET_2_0