In System.Data.OleDb:
[mono.git] / mcs / class / System.Data / System.Data / DataRow.cs
index 691b5f878de11ec3de031df979e5c1ed569fd0dd..baee5d293d2308dac165e01c5a6e30d4362f0a68 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
 //
 
 using System;
+using System.Data.Common;
 using System.Collections;
 using System.Globalization;
 using System.Xml;
+#if NET_2_0
+using System.ComponentModel;
+#endif
 
 namespace System.Data {
        /// <summary>
        /// Represents a row of data in a DataTable.
        /// </summary>
+#if !NET_2_0
        [Serializable]
+#endif
        public class DataRow
        {
                #region Fields
@@ -58,11 +65,9 @@ namespace System.Data {
 
                private ArrayList _columnErrors;
                private string rowError;
-               private DataRowState rowState;
                internal int xmlRowID = 0;
                internal bool _nullConstraintViolation;
                private string _nullConstraintMessage;
-               private bool editing = false;
                private bool _hasParentCollection;
                private bool _inChangingEvent;
                private int _rowId;
@@ -84,23 +89,8 @@ namespace System.Data {
                        // Get the row id from the builder.
                        _rowId = builder._rowId;
 
-                       _proposed = _table.RecordCache.NewRecord();
-                       // Initialise the data columns of the row with the dafault values, if any 
-                       // TODO : should proposed version be available immediately after record creation ?
-                       foreach(DataColumn column in _table.Columns) {
-                               column.DataContainer.CopyValue(_table.DefaultValuesRowIndex,_proposed);
-                       }
-                       
                        rowError = String.Empty;
 
-                       //on first creating a DataRow it is always detached.
-                       rowState = DataRowState.Detached;
-                       
-                       ArrayList aiColumns = _table.Columns.AutoIncrmentColumns;
-                       foreach (DataColumn dc in aiColumns) {
-                               this [dc] = dc.AutoIncrementValue();
-                       }
-
                        // create mapped XmlDataElement
                        DataSet ds = _table.DataSet;
                        if (ds != null && ds._xmlDataDocument != null)
@@ -184,7 +174,7 @@ namespace System.Data {
                        set {
                                if (columnIndex < 0 || columnIndex > _table.Columns.Count)
                                        throw new IndexOutOfRangeException ();
-                               if (rowState == DataRowState.Deleted)
+                               if (RowState == DataRowState.Deleted)
                                        throw new DeletedRowInaccessibleException ();
 
                                DataColumn column = _table.Columns[columnIndex];
@@ -195,13 +185,12 @@ namespace System.Data {
                                }
                                
                                CheckValue (value, column);
-
-                               bool orginalEditing = editing;
+                               bool orginalEditing = Proposed >= 0;
                                if (!orginalEditing) {
                                        BeginEdit ();
                                }
                                
-                               column[_proposed] = value;
+                               column[Proposed] = value;
                                _table.ChangedDataColumn (this, column, value);
                                if (!orginalEditing) {
                                        EndEdit ();
@@ -233,6 +222,26 @@ namespace System.Data {
                        }
                }
 
+                /// <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.
@@ -241,26 +250,20 @@ namespace System.Data {
                        get {
                                if (columnIndex < 0 || columnIndex > _table.Columns.Count)
                                        throw new IndexOutOfRangeException ();
-                               // Accessing deleted rows
-                               if (!_inExpressionEvaluation && rowState == DataRowState.Deleted && version != DataRowVersion.Original)
-                                       throw new DeletedRowInaccessibleException ("Deleted row information cannot be accessed through the row.");
                                
                                DataColumn column = _table.Columns[columnIndex];
-                               if (column.Expression != String.Empty) {
-                                       object o = column.CompiledExpression.Eval (this);
-                                       return Convert.ChangeType (o, column.DataType);
-                               }
-                               
                                int recordIndex = IndexFromVersion(version);
 
-                               if (recordIndex >= 0) {
+                               if (column.Expression != String.Empty) {
+                                       object o = column.CompiledExpression.Eval (this);
+                                       if (o != null && o != DBNull.Value) {
+                                               o = Convert.ChangeType (o, column.DataType);
+                                       }
+                                       column[recordIndex] = o;
                                        return column[recordIndex];
                                }
 
-                               if (rowState == DataRowState.Detached && version == DataRowVersion.Default && _proposed < 0)
-                                       throw new RowNotInTableException("This row has been removed from a table and does not have any data.  BeginEdit() will allow creation of new data in this row.");
-                               
-                               throw new VersionNotFoundException (Locale.GetText ("There is no " + version.ToString () + " data to access."));
+                               return column[recordIndex];
                        }
                }
                
@@ -269,44 +272,53 @@ namespace System.Data {
                /// </summary>
                public object[] ItemArray {
                        get { 
-                               // row not in table
-                               if (rowState == DataRowState.Detached)
-                                       throw new RowNotInTableException("This row has been removed from a table and does not have any data.  BeginEdit() will allow creation of new data in this row.");
                                // Accessing deleted rows
-                               if (rowState == DataRowState.Deleted)
+                               if (RowState == DataRowState.Deleted)
                                        throw new DeletedRowInaccessibleException ("Deleted row information cannot be accessed through the row.");
+
+                               int index = 0;
+                               if (RowState == DataRowState.Detached)
+                                       // Check if datarow is removed from the table.
+                                       if (Proposed < 0)
+                                               throw new RowNotInTableException(
+                                                               "This row has been removed from a table and does not have any data."
+                                                               +"  BeginEdit() will allow creation of new data in this row."); 
+                                       else
+                                               index = Proposed;
+                               else
+                                       index = Current;
                                
                                object[] items = new object[_table.Columns.Count];
-                               foreach(DataColumn column in _table.Columns) {
-                                       items[column.Ordinal] = column[_current];
-                               }
+
+                               foreach(DataColumn column in _table.Columns)
+                                       items[column.Ordinal] = column[index];
                                return items;
                        }
                        set {
                                if (value.Length > _table.Columns.Count)
                                        throw new ArgumentException ();
 
-                               if (rowState == DataRowState.Deleted)
+                               if (RowState == DataRowState.Deleted)
                                        throw new DeletedRowInaccessibleException ();
                                
-                               bool orginalEditing = editing;
-                               if (!orginalEditing) { 
-                                       BeginEdit ();
-                               }
-                               object newVal = null;
+                               BeginEdit ();
+
                                DataColumnChangeEventArgs e = new DataColumnChangeEventArgs();
                                foreach(DataColumn column in _table.Columns) {
                                        int i = column.Ordinal;
-                                       newVal = (i < value.Length) ? value[i] : null;
+                                       object newVal = (i < value.Length) ? value[i] : null;
+
+                                       if (newVal == null)
+                                               continue;
                                        
                                        e.Initialize(this, column, newVal);
-                                       _table.RaiseOnColumnChanged(e);
                                        CheckValue (e.ProposedValue, column);
-                                       column[_proposed] = e.ProposedValue;
-                               }
-                               if (!orginalEditing) {
-                                       EndEdit ();
+                                       _table.RaiseOnColumnChanging(e);
+                                       column[Proposed] = e.ProposedValue;
+                                       _table.RaiseOnColumnChanged(e);
                                }
+                               
+                               EndEdit ();
                        }
                }
 
@@ -316,7 +328,16 @@ namespace System.Data {
                /// </summary>
                public DataRowState RowState {
                        get { 
-                               return rowState; 
+                               //return rowState; 
+                               if ((Original == -1) && (Current == -1))
+                                       return DataRowState.Detached;
+                               if (Original == Current)
+                                       return DataRowState.Unchanged;
+                               if (Original == -1)
+                                       return DataRowState.Added;
+                               if (Current == -1)
+                                       return DataRowState.Deleted;
+                               return DataRowState.Modified;
                        }
                }
 
@@ -354,6 +375,48 @@ namespace System.Data {
                        }
                }
 
+               internal int Original
+               {
+                       get {
+                               return _original;
+                       }
+                       set {
+                               if (Table != null) {
+                                       //Table.RecordCache[_original] = null;
+                                       Table.RecordCache[value] = this;
+                               }
+                               _original = value;
+                       }
+               }
+
+               internal int Current
+               {
+                       get {
+                               return _current;
+                       }
+                       set {
+                               if (Table != null) {
+                                       //Table.RecordCache[_current] = null;
+                                       Table.RecordCache[value] = this;
+                               }
+                               _current = value;
+                       }
+               }
+
+               internal int Proposed
+               {
+                       get {
+                               return _proposed;
+                       }
+                       set {
+                               if (Table != null) {
+                                       //Table.RecordCache[_proposed] = null;
+                                       Table.RecordCache[value] = this;
+                               }
+                               _proposed = value;
+                       }
+               }
+
                #endregion
 
                #region Methods
@@ -361,24 +424,58 @@ namespace System.Data {
                //FIXME?: Couldn't find a way to set the RowState when adding the DataRow
                //to a Datatable so I added this method. Delete if there is a better way.
                internal void AttachRow() {
-                       if (_current >= 0) {
-                               Table.RecordCache.DisposeRecord(_current);
+                       if (Proposed != -1) {
+                               if (Current >= 0) {
+                                       Table.RecordCache.DisposeRecord(Current);
+                               }
+                               Current = Proposed;
+                               Proposed = -1;
                        }
-                       _current = _proposed;
-                       _proposed = -1;
-                       rowState = DataRowState.Added;
                }
 
                //FIXME?: Couldn't find a way to set the RowState when removing the DataRow
                //from a Datatable so I added this method. Delete if there is a better way.
                internal void DetachRow() {
-                       if (_proposed >= 0) {
-                               _table.RecordCache.DisposeRecord(_proposed);
-                               _proposed = -1;
+                       if (Proposed >= 0) {
+                               _table.RecordCache.DisposeRecord(Proposed);
+                               if (Proposed == Current) {
+                                       Current = -1;
+                               }
+                               if (Proposed == Original) {
+                                       Original = -1;
+                               }
+                               Proposed = -1;
+                       }
+
+                       if (Current >= 0) {
+                               _table.RecordCache.DisposeRecord(Current);
+                               if (Current == Original) {
+                                       Original = -1;
+                               }
+                               Current = -1;
                        }
+
+                       if (Original >= 0) {
+                               _table.RecordCache.DisposeRecord(Original);
+                               Original = -1;
+                       }
+
                        _rowId = -1;
                        _hasParentCollection = false;
-                       rowState = DataRowState.Detached;
+               }
+
+               internal void ImportRecord(int record)
+               {
+                       if (HasVersion(DataRowVersion.Proposed)) {
+                               Table.RecordCache.DisposeRecord(Proposed);
+                       }
+
+                       Proposed = record;
+
+                       foreach(DataColumn column in Table.Columns.AutoIncrmentColumns) {
+                               column.UpdateAutoIncrementValue(column.DataContainer.GetInt64(Proposed));
+                       }
+
                }
 
                private void CheckValue (object v, DataColumn col) 
@@ -402,40 +499,6 @@ namespace System.Data {
                        }
                }
 
-               internal void SetValuesFromDataRecord(IDataRecord record, int[] mapping)
-               {
-                       if ( mapping.Length > Table.Columns.Count)
-                               throw new ArgumentException ();
-
-//                     bool orginalEditing = editing;
-//                     if (!orginalEditing) { 
-//                             BeginEdit ();
-//                     }
-                       
-                       if (!HasVersion(DataRowVersion.Proposed)) {
-                               _proposed = Table.RecordCache.NewRecord();
-                       }
-
-                       try {
-                               for(int i=0; i < mapping.Length; i++) {
-                                       DataColumn column = Table.Columns[i];
-                                       column.DataContainer.SetItemFromDataRecord(_proposed, record,mapping[i]);
-                                       if ( column.AutoIncrement ) { 
-                                               column.UpdateAutoIncrementValue(column.DataContainer.GetInt64(_proposed));
-                                       }
-                               }
-                       }
-                       catch (Exception e){
-                               Table.RecordCache.DisposeRecord(_proposed);
-                               _proposed = -1;
-                               throw e;
-                       }
-
-//                     if (!orginalEditing) {
-//                             EndEdit ();
-//                     }
-               }
-
                /// <summary>
                /// Gets or sets the custom error description for a row.
                /// </summary>
@@ -450,33 +513,50 @@ namespace System.Data {
 
                internal int IndexFromVersion(DataRowVersion version)
                {
-                       if (HasVersion(version))
-                       {
-                               int recordIndex;
-                               switch (version) {
-                                       case DataRowVersion.Default:
-                                               if (editing || rowState == DataRowState.Detached) {
-                                                       recordIndex = _proposed;
-                                               }
-                                               else {
-                                                       recordIndex = _current;
-                                               }
-                                               break;
-                                       case DataRowVersion.Proposed:
-                                               recordIndex = _proposed;
-                                               break;
-                                       case DataRowVersion.Current:
-                                               recordIndex = _current;
-                                               break;
-                                       case DataRowVersion.Original:
-                                               recordIndex = _original;
-                                               break;
-                                       default:
-                                               throw new ArgumentException ();
-                               }
-                               return recordIndex;
+                       switch (version) {
+                               case DataRowVersion.Default:
+                                       if (Proposed >= 0)
+                                               return Proposed;
+
+                                       if (Current >= 0)
+                                               return Current;
+
+                                       if (Original < 0)
+                                               throw new RowNotInTableException("This row has been removed from a table and does not have any data.  BeginEdit() will allow creation of new data in this row.");
+
+                                       throw new DeletedRowInaccessibleException("Deleted row information cannot be accessed through the row.");
+
+                               case DataRowVersion.Proposed:
+                                       return AssertValidVersionIndex(version, Proposed);
+                               case DataRowVersion.Current:
+                                       return AssertValidVersionIndex(version, Current);
+                               case DataRowVersion.Original:
+                                       return AssertValidVersionIndex(version, Original);
+                               default:
+                                       throw new DataException ("Version must be Original, Current, or Proposed.");
                        }
-                       return -1;
+               }
+
+               private int AssertValidVersionIndex(DataRowVersion version, int index) {
+                       if (index >= 0)
+                               return index;
+
+                       throw new VersionNotFoundException(String.Format("There is no {0} data to accces.", version));
+               }
+
+               internal DataRowVersion VersionFromIndex(int index) {
+                       if (index < 0)
+                               throw new ArgumentException("Index must not be negative.");
+
+                       // the order of ifs matters
+                       if (index == Current)
+                               return DataRowVersion.Current;
+                       if (index == Original)
+                               return DataRowVersion.Original;
+                       if (index == Proposed)
+                               return DataRowVersion.Proposed;
+
+                       throw new ArgumentException(String.Format("The index {0} does not belong to this row.", index)  );
                }
 
                internal XmlDataDocument.XmlDataElement DataElement {
@@ -489,13 +569,11 @@ namespace System.Data {
                        DataColumn column = _table.Columns[columnName];
                        _table.ChangingDataColumn (this, column, val);
                                
-                       if (_original < 0 || _original == _current) { 
-                               // This really creates a new record version if one does not exist
-                               _original = Table.RecordCache.NewRecord();
+                       if (Original < 0 || Original == Current) { 
+                               Original = Table.RecordCache.NewRecord();
                        }
                        CheckValue (val, column);
-                       column[_original] = val;
-                       rowState = DataRowState.Modified;
+                       column[Original] = val;
                }
 
                /// <summary>
@@ -505,60 +583,78 @@ namespace System.Data {
                public void AcceptChanges () 
                {
                        EndEdit(); // in case it hasn't been called
-                       switch (rowState) {
-                               case DataRowState.Unchanged:
+
+                        _table.ChangingDataRow (this, DataRowAction.Commit);
+                       CheckChildRows(DataRowAction.Commit);
+                       switch (RowState) {
+                        case DataRowState.Unchanged:
                                        return;
                        case DataRowState.Added:
                        case DataRowState.Modified:
-                               rowState = DataRowState.Unchanged;
+                                       int original = Original;
+                                       DataRowState oldState = RowState;
+                                if (Original >= 0) {
+                                        Table.RecordCache.DisposeRecord(Original);
+                                }
+                                Original = Current;
+                                       foreach (Index index in Table.Indexes)
+                                               index.Update(this, original, DataRowVersion.Original, oldState);
                                break;
                        case DataRowState.Deleted:
+                               Table.DeleteRowFromIndexes(this);
                                _table.Rows.RemoveInternal (this);
                                DetachRow();
                                break;
                        case DataRowState.Detached:
                                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;
+
+                        _table.ChangedDataRow (this, DataRowAction.Commit);
                }
 
                /// <summary>
                /// Begins an edit operation on a DataRow object.
                /// </summary>
+#if NET_2_0
+               [EditorBrowsable (EditorBrowsableState.Advanced)]
+#endif
                public void BeginEdit () 
                {
                        if (_inChangingEvent)
                                 throw new InRowChangingEventException("Cannot call BeginEdit inside an OnRowChanging event.");
-                       if (rowState == DataRowState.Deleted)
+                       if (RowState == DataRowState.Deleted)
                                throw new DeletedRowInaccessibleException ();
+
                        if (!HasVersion (DataRowVersion.Proposed)) {
-                               _proposed = Table.RecordCache.NewRecord();
-                               foreach(DataColumn column in Table.Columns) {
-                                       column.DataContainer.CopyValue(_current,_proposed);
+                               Proposed = Table.RecordCache.NewRecord();
+                               int from = HasVersion(DataRowVersion.Current) ? Current : Table.DefaultValuesRowIndex;
+                               for(int i = 0; i < Table.Columns.Count; i++){
+                                       DataColumn column = Table.Columns[i];
+                                       column.DataContainer.CopyValue(from,Proposed);
                                }
                        }
-                       // setting editing to true stops validations on the row
-                       editing = true;
                }
 
                /// <summary>
                /// Cancels the current edit on the row.
                /// </summary>
+#if NET_2_0
+               [EditorBrowsable (EditorBrowsableState.Advanced)]
+#endif
                public void CancelEdit () 
                {
-                        if (_inChangingEvent)
+                        if (_inChangingEvent) {
                                 throw new InRowChangingEventException("Cannot call CancelEdit inside an OnRowChanging event.");
-                       editing = false;
+                        }
+
                        if (HasVersion (DataRowVersion.Proposed)) {
-                               Table.RecordCache.DisposeRecord(_proposed);
-                               _proposed = -1;
-                               if (rowState == DataRowState.Modified) {
-                                   rowState = DataRowState.Unchanged;
-                               }
+                               int oldRecord = Proposed;
+                               DataRowState oldState = RowState;
+                               Table.RecordCache.DisposeRecord(Proposed);
+                               Proposed = -1;
+
+                               foreach(Index index in Table.Indexes)
+                                       index.Update(this,oldRecord, DataRowVersion.Proposed, oldState);                                        
                        }
                }
 
@@ -578,7 +674,7 @@ namespace System.Data {
                public void Delete () 
                {
                        _table.DeletingDataRow(this, DataRowAction.Delete);
-                       switch (rowState) {
+                       switch (RowState) {
                        case DataRowState.Added:
                                // check what to do with child rows
                                CheckChildRows(DataRowAction.Delete);
@@ -589,14 +685,23 @@ namespace System.Data {
                                DetachRow();
                                break;
                        case DataRowState.Deleted:
-                               break;          
+                       case DataRowState.Detached:
+                               break;
                        default:
                                // check what to do with child rows
                                CheckChildRows(DataRowAction.Delete);
-                               _table.DeleteRowFromIndexes (this);
-                               rowState = DataRowState.Deleted;
                                break;
                        }
+                       if (Current >= 0) {
+                               int current = Current;
+                               DataRowState oldState = RowState;
+                               if (Current != Original) {
+                                       _table.RecordCache.DisposeRecord(Current);
+                               }
+                               Current = -1;
+                               foreach(Index index in Table.Indexes)
+                                       index.Update(this, current, DataRowVersion.Current, oldState);
+                       }
                        _table.DeletedDataRow(this, DataRowAction.Delete);
                }
 
@@ -617,16 +722,24 @@ namespace System.Data {
                                foreach (DataTable table in _table.DataSet.Tables)
                                {
                                        // loop on all ForeignKeyConstrain of the table.
-                                       foreach (ForeignKeyConstraint fk in table.Constraints.ForeignKeyConstraints)
-                                       {
-                                               if (fk.RelatedTable == _table)
-                                               {
-                                                       Rule rule;
-                                                       if (action == DataRowAction.Delete)
-                                                               rule = fk.DeleteRule;
-                                                       else
-                                                               rule = fk.UpdateRule;
-                                                       CheckChildRows(fk, action, rule);
+                                       foreach (Constraint constraint in table.Constraints) {
+                                               if (constraint is ForeignKeyConstraint) { 
+                                                       ForeignKeyConstraint fk = (ForeignKeyConstraint) constraint;
+                                                       if (fk.RelatedTable == _table) {
+                                                               switch (action) {
+                                                                       case DataRowAction.Delete:
+                                                                               CheckChildRows(fk, action, fk.DeleteRule);
+                                                                               break;
+                                                                       case DataRowAction.Commit:
+                                                                       case DataRowAction.Rollback:
+                                                                               if (fk.AcceptRejectRule != AcceptRejectRule.None)
+                                                                                       CheckChildRows(fk, action, Rule.Cascade);
+                                                                               break;
+                                                                       default:
+                                                                               CheckChildRows(fk, action, fk.UpdateRule);
+                                                                               break;
+                                                               }
+                                                       }                       
                                                }                       
                                        }
                                }
@@ -635,7 +748,7 @@ namespace System.Data {
 
                private void CheckChildRows(ForeignKeyConstraint fkc, DataRowAction action, Rule rule)
                {                               
-                       DataRow[] childRows = GetChildRows(fkc, DataRowVersion.Default);
+                       DataRow[] childRows = GetChildRows(fkc, DataRowVersion.Current);
                        switch (rule)
                        {
                                case Rule.Cascade:  // delete or change all relted rows.
@@ -644,18 +757,29 @@ namespace System.Data {
                                                for (int j = 0; j < childRows.Length; j++)
                                                {
                                                        // if action is delete we delete all child rows
-                                                       if (action == DataRowAction.Delete)
-                                                       {
+                                                       switch(action) {
+                                                               case DataRowAction.Delete: {
                                                                if (childRows[j].RowState != DataRowState.Deleted)
                                                                        childRows[j].Delete();
+
+                                                                       break;
                                                        }
                                                        // if action is change we change the values in the child row
-                                                       else if (action == DataRowAction.Change)
-                                                       {
+                                                               case DataRowAction.Change: {
                                                                // change only the values in the key columns
                                                                // set the childcolumn value to the new parent row value
-                                                               for (int k = 0; k < fkc.Columns.Length; k++)
-                                                                       childRows[j][fkc.Columns[k]] = this[fkc.RelatedColumns[k], DataRowVersion.Proposed];
+                                                                       for (int k = 0; k < fkc.Columns.Length; k++)
+                                                                               if (!fkc.RelatedColumns [k].DataContainer [Original].Equals (fkc.RelatedColumns [k].DataContainer [Proposed]))
+                                                                                       childRows[j][fkc.Columns[k]] = this[fkc.RelatedColumns[k], DataRowVersion.Proposed];
+
+                                                                       break;
+                                                               }
+
+                                                               case DataRowAction.Rollback: {
+                                                                       if (childRows[j].RowState != DataRowState.Unchanged)
+                                                                               childRows[j].RejectChanges ();
+                                                                       break;
+                                                               }
                                                        }
                                                }
                                        }
@@ -710,19 +834,21 @@ namespace System.Data {
                /// <summary>
                /// Ends the edit occurring on the row.
                /// </summary>
+#if NET_2_0
+               [EditorBrowsable (EditorBrowsableState.Advanced)]
+#endif
                public void EndEdit () 
                {
                        if (_inChangingEvent)
                                throw new InRowChangingEventException("Cannot call EndEdit inside an OnRowChanging event.");
-                       if (rowState == DataRowState.Detached)
-                       {
-                               editing = false;
+
+                       if (RowState == DataRowState.Detached)
                                return;
-                       }
                        
-                       CheckReadOnlyStatus();
                        if (HasVersion (DataRowVersion.Proposed))
                        {
+                               CheckReadOnlyStatus();
+
                                _inChangingEvent = true;
                                try
                                {
@@ -732,51 +858,50 @@ namespace System.Data {
                                {
                                        _inChangingEvent = false;
                                }
-                               if (rowState == DataRowState.Unchanged)
-                                       rowState = DataRowState.Modified;
                                
-                               //Calling next method validates UniqueConstraints
-                               //and ForeignKeys.
-                               try
-                               {
-                                       if ((_table.DataSet == null || _table.DataSet.EnforceConstraints) && !_table._duringDataLoad)
-                                               _table.Rows.ValidateDataRowInternal(this);
-                               }
-                               catch (Exception e)
-                               {
-                                       editing = false;
-                                       Table.RecordCache.DisposeRecord(_proposed);
-                                       _proposed = -1;
-                                       throw e;
+                               DataRowState oldState = RowState;
+
+                               int oldRecord = Current;
+                               Current = Proposed;
+                               Proposed = -1;
+
+                               if (!Table._duringDataLoad) {
+                                       foreach(Index index in Table.Indexes) {
+                                               index.Update(this,oldRecord, DataRowVersion.Current, oldState);
+                                       }
                                }
 
-                               // Now we are going to check all child rows of current row.
-                               // In the case the cascade is true the child rows will look up for
-                               // parent row. since lookup in index is always on current,
-                               // we have to move proposed version of current row to current
-                               // in the case of check child row failure we are rolling 
-                               // current row state back.
-                               int backup = _current;
-                               _current = _proposed;
-                               bool editing_backup = editing;
-                               editing = false;
                                try {
-                                       // check all child rows.
+                                       AssertConstraints();
+
+                                       // restore previous state to let the cascade update to find the rows
+                                       Proposed = Current;
+                                       Current = oldRecord;
+
                                        CheckChildRows(DataRowAction.Change);
-                                       _proposed = -1;
-                                       if (_original != backup) {
-                                               Table.RecordCache.DisposeRecord(backup);
+
+                                       // apply new state
+                                       Current = Proposed;
+                                       Proposed = -1;
+                               }
+                               catch {
+                                       int proposed = Proposed >= 0 ? Proposed : Current;
+                                       Current = oldRecord;
+                                       if (!Table._duringDataLoad) {
+                                               foreach(Index index in Table.Indexes) {
+                                                       index.Update(this,proposed, DataRowVersion.Current, RowState);
+                                               }
                                        }
+                                       throw;
                                }
-                               catch (Exception ex) {
-                                       // if check child rows failed - rollback to previous state
-                                       // i.e. restore proposed and current versions
-                                       _proposed = _current;
-                                       _current = backup;
-                                       editing = editing_backup;
-                                       // since we failed - propagate an exception
-                                       throw ex;
+
+                               if (Original != oldRecord) {
+                                       Table.RecordCache.DisposeRecord(oldRecord);
                                }
+
+                               // Note : row state must not be changed before all the job on indexes finished,
+                               // since the indexes works with recods rather than with rows and the decision
+                               // which of row records to choose depends on row state.
                                _table.ChangedDataRow(this, DataRowAction.Change);
                        }
                }
@@ -805,9 +930,8 @@ namespace System.Data {
                public DataRow[] GetChildRows (DataRelation relation, DataRowVersion version) 
                {
                        if (relation == null)
-                               return new DataRow[0];
+                               return Table.NewRowArray(0);
 
-                       //if (this.Table == null || RowState == DataRowState.Detached)
                        if (this.Table == null)
                                throw new RowNotInTableException("This row has been removed from a table and does not have any data.  BeginEdit() will allow creation of new data in this row.");
 
@@ -824,23 +948,34 @@ namespace System.Data {
                        DataColumn[] parentColumns = relation.ParentColumns;
                        DataColumn[] childColumns = relation.ChildColumns;
                        int numColumn = parentColumns.Length;
-                       if (HasVersion(version))
-                       {
-                               object[] vals = new object[parentColumns.Length];
-                               for (int i = 0; i < vals.Length; i++)
-                                       vals[i] = this[parentColumns[i], version];
-                               
-                               foreach (DataRow row in relation.ChildTable.Rows) 
-                               {
-                                       bool allColumnsMatch = false;
-                                       if (row.HasVersion(DataRowVersion.Default))
-                                       {
-                                               allColumnsMatch = true;
-                                               for (int columnCnt = 0; columnCnt < numColumn; ++columnCnt) 
-                                               {
-                                                       if (!vals[columnCnt].Equals(
-                                                               row[childColumns[columnCnt], DataRowVersion.Default])) 
-                                                       {
+                       DataRow[] result = null;
+
+                       int versionIndex = IndexFromVersion(version);
+                       int tmpRecord = relation.ChildTable.RecordCache.NewRecord();
+
+                       try {
+                               for (int i = 0; i < numColumn; i++) {
+                                       // according to MSDN: the DataType value for both columns must be identical.
+                                       childColumns[i].DataContainer.CopyValue(parentColumns[i].DataContainer, versionIndex, tmpRecord);
+                               }
+
+                               Index index = relation.ChildTable.FindIndex(childColumns);
+
+                               if (index != null) {
+                                       int[] records = index.FindAll(tmpRecord);
+                                       result = relation.ChildTable.NewRowArray(records.Length);
+                                       for(int i=0; i < records.Length; i++) {
+                                               result[i] = relation.ChildTable.RecordCache[records[i]];
+                                       }
+                               }
+                               else {
+                                       foreach (DataRow row in relation.ChildTable.Rows) {
+                                               bool allColumnsMatch = false;
+                                               if (row.HasVersion(DataRowVersion.Default)) {
+                                                       allColumnsMatch = true;
+                                                       int childIndex = row.IndexFromVersion(DataRowVersion.Default);
+                                                       for (int columnCnt = 0; columnCnt < numColumn; ++columnCnt) {
+                                                               if (childColumns[columnCnt].DataContainer.CompareValues(childIndex, tmpRecord) != 0) {
                                                                allColumnsMatch = false;
                                                                break;
                                                        }
@@ -848,11 +983,14 @@ namespace System.Data {
                                        }
                                        if (allColumnsMatch) rows.Add(row);
                                }
-                       }else
-                               throw new VersionNotFoundException("There is no " + version + " data to accces.");
+                                       result = relation.ChildTable.NewRowArray(rows.Count);
+                                       rows.CopyTo(result, 0);
+                               }
+                       }
+                       finally {
+                               relation.ChildTable.RecordCache.DisposeRecord(tmpRecord);
+                       }                       
 
-                       DataRow[] result = relation.ChildTable.NewRowArray(rows.Count);
-                       rows.CopyTo(result, 0);
                        return result;
                }
 
@@ -871,25 +1009,25 @@ namespace System.Data {
                        DataColumn[] parentColumns = fkc.RelatedColumns;
                        DataColumn[] childColumns = fkc.Columns;
                        int numColumn = parentColumns.Length;
-                       if (HasVersion(version)) {
+
                                Index index = fkc.Index;
+
+                       int curIndex = IndexFromVersion(version);
+                       int tmpRecord = fkc.Table.RecordCache.NewRecord();
+                       for (int i = 0; i < numColumn; i++) {
+                               // according to MSDN: the DataType value for both columns must be identical.
+                               childColumns[i].DataContainer.CopyValue(parentColumns[i].DataContainer, curIndex, tmpRecord);
+                       }
+
+                       try {
                                if (index != null) {
                                        // get the child rows from the index
-                                       Node[] childNodes = index.FindAllSimple (parentColumns, IndexFromVersion(version));
-                                       for (int i = 0; i < childNodes.Length; i++) {
-                                               rows.Add (childNodes[i].Row);
+                                       int[] childRecords = index.FindAll(tmpRecord);
+                                       for (int i = 0; i < childRecords.Length; i++) {
+                                               rows.Add (childColumns[i].Table.RecordCache[childRecords[i]]);
                                        }
                                }
                                else { // if there is no index we search manualy.
-                                       int curIndex = IndexFromVersion(DataRowVersion.Default);
-                                       int tmpRecord = fkc.Table.RecordCache.NewRecord();
-
-                                       try {
-                                               for (int i = 0; i < numColumn; i++) {
-                                                       // according to MSDN: the DataType value for both columns must be identical.
-                                                       childColumns[i].DataContainer.CopyValue(parentColumns[i].DataContainer, curIndex, tmpRecord);
-                                               }
-
                                                foreach (DataRow row in fkc.Table.Rows) {
                                                        bool allColumnsMatch = false;
                                                        if (row.HasVersion(DataRowVersion.Default)) {
@@ -907,12 +1045,10 @@ namespace System.Data {
                                                        }
                                                }
                                        }
+                       }
                                        finally {
                                                fkc.Table.RecordCache.DisposeRecord(tmpRecord);
                                        }
-                               }
-                       }else
-                               throw new VersionNotFoundException("There is no " + version + " data to accces.");
 
                        DataRow[] result = fkc.Table.NewRowArray(rows.Count);
                        rows.CopyTo(result, 0);
@@ -924,7 +1060,14 @@ namespace System.Data {
                /// </summary>
                public string GetColumnError (DataColumn column) 
                {
-                       return GetColumnError (_table.Columns.IndexOf(column));
+                       if (column == null)
+                               throw new ArgumentNullException("column");
+
+                       int index = _table.Columns.IndexOf(column);
+                       if (index < 0)
+                               throw new ArgumentException(String.Format("Column '{0}' does not belong to table {1}.", column.ColumnName, Table.TableName));
+
+                       return GetColumnError (index);
                }
 
                /// <summary>
@@ -1030,7 +1173,7 @@ namespace System.Data {
                {
                        // TODO: Caching for better preformance
                        if (relation == null)
-                               return new DataRow[0];
+                               return Table.NewRowArray(0);
 
                        if (this.Table == null)
                                throw new RowNotInTableException("This row has been removed from a table and does not have any data.  BeginEdit() will allow creation of new data in this row.");
@@ -1045,25 +1188,23 @@ namespace System.Data {
                        DataColumn[] parentColumns = relation.ParentColumns;
                        DataColumn[] childColumns = relation.ChildColumns;
                        int numColumn = parentColumns.Length;
-                       if (HasVersion(version)) {
-                               Index indx = relation.ParentTable.GetIndexByColumns (parentColumns);
-                               if (indx != null && 
-    (Table == null || Table.DataSet == null || 
-     Table.DataSet.EnforceConstraints)) { // get the child rows from the index
-                                       Node[] childNodes = indx.FindAllSimple(childColumns, IndexFromVersion(version));
-                                       for (int i = 0; i < childNodes.Length; i++) {
-                                               rows.Add (childNodes[i].Row);
-                                       }
-                               }
-                               else { // no index so we have to search manualy.
-                                       int curIndex = IndexFromVersion(DataRowVersion.Default);
+
+                       int curIndex = IndexFromVersion(version);
                                        int tmpRecord = relation.ParentTable.RecordCache.NewRecord();
-                                       try {
                                                for (int i = 0; i < numColumn; i++) {
                                                        // according to MSDN: the DataType value for both columns must be identical.
                                                        parentColumns[i].DataContainer.CopyValue(childColumns[i].DataContainer, curIndex, tmpRecord);
                                                }
 
+                       try {
+                               Index index = relation.ParentTable.FindIndex(parentColumns);
+                               if (index != null) { // get the parent rows from the index
+                                       int[] parentRecords = index.FindAll(tmpRecord);
+                                       for (int i = 0; i < parentRecords.Length; i++) {
+                                               rows.Add (parentColumns[i].Table.RecordCache[parentRecords[i]]);
+                                       }
+                               }
+                               else { // no index so we have to search manualy.
                                                foreach (DataRow row in relation.ParentTable.Rows) {
                                                        bool allColumnsMatch = false;
                                                        if (row.HasVersion(DataRowVersion.Default)) {
@@ -1081,12 +1222,10 @@ namespace System.Data {
                                                        }
                                                }
                                        }
+                       }
                                        finally {
                                                relation.ParentTable.RecordCache.DisposeRecord(tmpRecord);
                                        }
-                               }
-                       }else
-                               throw new VersionNotFoundException("There is no " + version + " data to accces.");
 
                        DataRow[] result = relation.ParentTable.NewRowArray(rows.Count);
                        rows.CopyTo(result, 0);
@@ -1109,25 +1248,16 @@ namespace System.Data {
                {
                        switch (version) {
                                case DataRowVersion.Default:
-                                       if (rowState == DataRowState.Deleted && !_inExpressionEvaluation)
-                                               return false;
-                                       if (rowState == DataRowState.Detached)
-                                               return _proposed >= 0;
-                                       return true;
+                                       return (Proposed >= 0 || Current >= 0);
                                case DataRowVersion.Proposed:
-                                       if (rowState == DataRowState.Deleted && !_inExpressionEvaluation)
-                                               return false;
-                                       return _proposed >= 0;
+                                       return Proposed >= 0;
                                case DataRowVersion.Current:
-                                       if ((rowState == DataRowState.Deleted && !_inExpressionEvaluation) || rowState == DataRowState.Detached)
-                                               return false;
-                                       return _current >= 0;
+                                       return Current >= 0;
                                case DataRowVersion.Original:
-                                       if (rowState == DataRowState.Detached)
-                                               return false;
-                                       return _original >= 0;
+                                       return Original >= 0;
+                               default:
+                                       return IndexFromVersion(version) >= 0;
                        }
-                       return false;
                }
 
                /// <summary>
@@ -1161,6 +1291,7 @@ namespace System.Data {
                /// </summary>
                public bool IsNull (DataColumn column, DataRowVersion version) 
                {
+                       object o = this[column,version];
                        return column.DataContainer.IsNull(IndexFromVersion(version));
                }
 
@@ -1190,46 +1321,28 @@ namespace System.Data {
                                throw new RowNotInTableException("This row has been removed from a table and does not have any data.  BeginEdit() will allow creation of new data in this row.");
                        // If original is null, then nothing has happened since AcceptChanges
                        // was last called.  We have no "original" to go back to.
-                       if (HasVersion(DataRowVersion.Original)) {
-                               if (_current >= 0 ) {
-                                       Table.RecordCache.DisposeRecord(_current);
-                               }
-                               _current = _original;
-                              
-                               _table.ChangedDataRow (this, DataRowAction.Rollback);
-                               CancelEdit ();
-                               switch (rowState)
-                               {
-                                       case DataRowState.Added:
-                                               _table.DeleteRowFromIndexes (this);
-                                               _table.Rows.RemoveInternal (this);
-                                               break;
-                                       case DataRowState.Modified:
-                                               if ((_table.DataSet == null || _table.DataSet.EnforceConstraints) && !_table._duringDataLoad)
-                                                       _table.Rows.ValidateDataRowInternal(this);
-                                               rowState = DataRowState.Unchanged;
-                                               break;
-                                       case DataRowState.Deleted:
-                                               rowState = DataRowState.Unchanged;
-                                               if ((_table.DataSet == null || _table.DataSet.EnforceConstraints) && !_table._duringDataLoad)
-                                                       _table.Rows.ValidateDataRowInternal(this);
-                                               break;
-                               } 
-                               
-                       }                       
-                       else {
-                               // If rows are just loaded via Xml the original values are null.
-                               // So in this case we have to remove all columns.
-                               // FIXME: I'm not realy sure, does this break something else, but
-                               // if so: FIXME ;)
-                               
-                               if ((rowState & DataRowState.Added) > 0)
-                               {
-                                       _table.DeleteRowFromIndexes (this);
-                                       _table.Rows.RemoveInternal (this);
-                                       // if row was in Added state we move it to Detached.
-                                       DetachRow();
-                               }
+                       
+                       _table.ChangedDataRow (this, DataRowAction.Rollback);
+                       CancelEdit ();
+
+                       //TODO : Need to Verify the constraints.. 
+                       switch (RowState) {
+                       case DataRowState.Added:
+                               _table.DeleteRowFromIndexes (this);
+                               _table.Rows.RemoveInternal (this);
+                               DetachRow ();
+                               break;
+                       case DataRowState.Modified:
+                               Table.RecordCache.DisposeRecord (Current);
+                               CheckChildRows (DataRowAction.Rollback);
+                               Table.DeleteRowFromIndexes(this);
+                               Current = Original;
+                               break;
+                       case DataRowState.Deleted:
+                               CheckChildRows (DataRowAction.Rollback);
+                               Table.DeleteRowFromIndexes(this);
+                               Current = Original;
+                               break;
                        }
                }
 
@@ -1290,42 +1403,44 @@ namespace System.Data {
 
                        if (parentRow != null && _table.DataSet != parentRow.Table.DataSet)
                                throw new ArgumentException();
+
+                       if (RowState == DataRowState.Detached && !HasVersion(DataRowVersion.Default)) {
+                               // the row should have default data to access, i.e. we can do this for the newly created row, but not for the row once deleted from the table
+                               throw new RowNotInTableException("This row has been removed from a table and does not have any data.  BeginEdit() will allow creation of new data in this row.");
+                       }
                        
                        BeginEdit();
-                       if (relation == null)
-                       {
-                               foreach (DataRelation parentRel in _table.ParentRelations)
-                               {
-                                       DataColumn[] childCols = parentRel.ChildKeyConstraint.Columns;
-                                       DataColumn[] parentCols = parentRel.ChildKeyConstraint.RelatedColumns;
-                                       
-                                       for (int i = 0; i < parentCols.Length; i++)
-                                       {
-                                               if (parentRow == null)
-                                                       this[childCols[i].Ordinal] = DBNull.Value;
-                                               else
-                                                       this[childCols[i].Ordinal] = parentRow[parentCols[i]];
-                                       }
-                                       
-                               }
+
+                       IEnumerable relations; 
+                       if (relation == null) {
+                               relations = _table.ParentRelations;
+                       }
+                       else {
+                               relations = new DataRelation[] { relation };
                        }
-                       else
+
+                       foreach (DataRelation rel in relations)
                        {
-                               DataColumn[] childCols = relation.ChildKeyConstraint.Columns;
-                               DataColumn[] parentCols = relation.ChildKeyConstraint.RelatedColumns;
-                                       
+                               DataColumn[] childCols = rel.ChildColumns;
+                               DataColumn[] parentCols = rel.ParentColumns;
+                               
                                for (int i = 0; i < parentCols.Length; i++)
                                {
-                                       if (parentRow == null)
-                                               this[childCols[i].Ordinal] = DBNull.Value;
-                                       else
-                                               this[childCols[i].Ordinal] = parentRow[parentCols[i]];
+                                       if (parentRow == null) {
+                                               childCols[i].DataContainer[Proposed] = DBNull.Value;
+                                       }
+                                       else {
+                                               int defaultIdx = parentRow.IndexFromVersion(DataRowVersion.Default);
+                                               childCols[i].DataContainer.CopyValue(parentCols[i].DataContainer,defaultIdx,Proposed);
+                                       }
                                }
+                               
                        }
+
                        EndEdit();
                }
                
-               //Copy all values of this DataaRow to the row parameter.
+               //Copy all values of this DataRow to the row parameter.
                internal void CopyValuesToRow(DataRow row)
                {
                        if (row == null)
@@ -1333,50 +1448,145 @@ namespace System.Data {
                        if (row == this)
                                throw new ArgumentException("'row' is the same as this object");
 
+                       // create target records if missing.
+                       if (HasVersion(DataRowVersion.Original)) {
+                               if (row.Original < 0)
+                                       row.Original = row.Table.RecordCache.NewRecord();
+                               else if (row.Original == row.Current) {
+                                       row.Original = row.Table.RecordCache.NewRecord();
+                                       row.Table.RecordCache.CopyRecord (row.Table, row.Current, row.Original);
+                               }
+                       } else {
+                               if (row.Original > 0) {
+                                       if (row.Original != row.Current)
+                                               row.Table.RecordCache.DisposeRecord(row.Original);
+                                       row.Original = -1;
+                               }
+                       }
+
+                       if (HasVersion(DataRowVersion.Current)) {
+                               if (Current == Original) {
+                                       if (row.Current >= 0)
+                                               row.Table.RecordCache.DisposeRecord(row.Current);
+                                       row.Current = row.Original;
+                               }else {
+                                       if (row.Current < 0)
+                                               row.Current = row.Table.RecordCache.NewRecord();
+                               }
+                       } else {
+                               if (row.Current > 0) {
+                                       row.Table.RecordCache.DisposeRecord(row.Current);
+                                       row.Current = -1;
+                               }
+                       }
+
+                       if (HasVersion(DataRowVersion.Proposed)) {
+                               if (row.Proposed < 0)
+                                       row.Proposed = row.Table.RecordCache.NewRecord();
+                       } else {
+                               if (row.Proposed > 0) {
+                                       row.Table.RecordCache.DisposeRecord(row.Proposed);
+                                       row.Proposed = -1;
+                               }
+                       }
+                       
+                       // copy source record values to target records
                        foreach(DataColumn column in Table.Columns) {
                                DataColumn targetColumn = row.Table.Columns[column.ColumnName];
                                //if a column with the same name exists in both rows copy the values
                                if(targetColumn != null) {
-                                       int index = targetColumn.Ordinal;
                                        if (HasVersion(DataRowVersion.Original)) {
-                                               if (row._original < 0) {
-                                                       row._original = row.Table.RecordCache.NewRecord();
-                                               }
-                                               object val = column[_original];
+                                               object val = column[Original];
                                                row.CheckValue(val, targetColumn);
-                                               targetColumn[row._original] = val;
+                                               targetColumn[row.Original] = val;
                                        }
-                                       if (HasVersion(DataRowVersion.Current)) {
-                                               if (row._current < 0) {
-                                                       row._current = row.Table.RecordCache.NewRecord();
-                                               }
-                                               object val = column[_current];
+
+                                       if (HasVersion(DataRowVersion.Current)
+                                           && Current != Original) {
+                                               object val = column[Current];
                                                row.CheckValue(val, targetColumn);
-                                               targetColumn[row._current] = val;
+                                               targetColumn[row.Current] = val;
                                        }
+
                                        if (HasVersion(DataRowVersion.Proposed)) {
-                                               if (row._proposed < 0) {
-                                                       row._proposed = row.Table.RecordCache.NewRecord();
-                                               }
-                                               object val = column[row._proposed];
+                                               object val = column[row.Proposed];
                                                row.CheckValue(val, targetColumn);
-                                               targetColumn[row._proposed] = val;
+                                               targetColumn[row.Proposed] = val;
                                        }
-                                       
-                                       //Saving the current value as the column value
-                                       row[index] = targetColumn[row._current];
-                                       
                                }
                        }
-                       CopyState(row);
+                       if (HasErrors) {
+                               CopyErrors(row);
+                       }
                }
 
-               // Copy row state - rowState and errors
-               internal void CopyState(DataRow row)
+               //Merge all values of this DataRow to the row parameter according to merge rules.
+               internal void MergeValuesToRow(DataRow row, bool preserveChanges)
+               {
+                       if (row == null)
+                               throw new ArgumentNullException("row");
+                       if (row == this)
+                               throw new ArgumentException("'row' is the same as this object");
+
+                       // Original values are anyway copied
+                       if (HasVersion(DataRowVersion.Original)) {
+                               if (row.Original < 0)
+                                       row.Original = row.Table.RecordCache.NewRecord();
+                               else if (row.Original == row.Current
+                                         && !(Original == Current && ! preserveChanges)) {
+                                       row.Original = row.Table.RecordCache.NewRecord();
+                                       row.Table.RecordCache.CopyRecord (row.Table, row.Current, row.Original);
+                               }
+                       } else {
+                               if (row.Original == row.Current) { // if target has same current, better create new original
+                                       row.Original = row.Table.RecordCache.NewRecord();
+                                       row.Table.RecordCache.CopyRecord (row.Table, row.Current, row.Original);
+                               }
+                       }
+
+                       // if i have current, push all
+                       if (HasVersion(DataRowVersion.Current)) {
+                               if (! preserveChanges && row.Current < 0)
+                                       row.Current = row.Table.RecordCache.NewRecord();
+                       } else {
+                               if (row.Current > 0 && ! preserveChanges) {
+                                       row.Table.RecordCache.DisposeRecord(row.Current);
+                                       row.Current = -1;
+                               }
+                       }
+
+                       // copy source record values to target records
+                       foreach(DataColumn column in Table.Columns) {
+                               DataColumn targetColumn = row.Table.Columns[column.ColumnName];
+                               //if a column with the same name exists in both rows copy the values
+                               if(targetColumn != null) {
+                                       if (HasVersion(DataRowVersion.Original)) {
+                                               object val = column[Original];
+                                               row.CheckValue(val, targetColumn);
+                                               targetColumn[row.Original] = val;
+                                       }
+
+                                       if (HasVersion(DataRowVersion.Current)
+                                           && !preserveChanges) {
+                                               object val = column[Current];
+                                               row.CheckValue(val, targetColumn);
+                                               targetColumn[row.Current] = val;
+                                       }
+                               }
+                       }
+                       if (HasErrors) {
+                               CopyErrors(row);
+                       }
+               }
+
+               internal void CopyErrors(DataRow row)
                {
-                       row.rowState = RowState;
                        row.RowError = RowError;
-                       row.ColumnErrors = (ArrayList)ColumnErrors.Clone();
+                       DataColumn[] errorColumns = GetColumnsInError();
+                       foreach(DataColumn col in errorColumns) {
+                               DataColumn targetColumn = row.Table.Columns[col.ColumnName];
+                               row.SetColumnError(targetColumn,GetColumnError(col));
+                       }
                }
 
                internal bool IsRowChanged(DataRowState rowState) {
@@ -1414,6 +1624,34 @@ namespace System.Data {
                        }
                }
 
+               internal void Validate() {
+                       Table.AddRowToIndexes(this);
+                       AssertConstraints();
+               }
+
+               void AssertConstraints() {
+                       if (Table == null || Table._duringDataLoad)
+                               return;
+                               
+                       if (Table.DataSet != null && !Table.DataSet.EnforceConstraints)
+                               return;
+                       foreach(DataColumn column in Table.Columns) {
+                               if (!column.AllowDBNull && IsNull(column)) {
+                                       throw new NoNullAllowedException(_nullConstraintMessage);
+                               }
+                       }
+
+                       foreach(Constraint constraint in Table.Constraints) {
+                               try {
+                                       constraint.AssertConstraint(this);
+                               }
+                               catch(Exception e) {
+                                       Table.DeleteRowFromIndexes(this);
+                                       throw e;
+                               }
+                       }
+               }
+
                internal void CheckNullConstraints()
                {
                        if (_nullConstraintViolation) {
@@ -1428,21 +1666,82 @@ namespace System.Data {
                        }
                }
                
-               internal void CheckReadOnlyStatus()
-                {
-                       if (HasVersion(DataRowVersion.Proposed)) {
+               internal void CheckReadOnlyStatus() {
                                int defaultIdx = IndexFromVersion(DataRowVersion.Default); 
                                foreach(DataColumn column in Table.Columns) {
-                                       if ((column.DataContainer.CompareValues(defaultIdx,_proposed) != 0) && column.ReadOnly) {
+                               if ((column.DataContainer.CompareValues(defaultIdx,Proposed) != 0) && column.ReadOnly) {
                                        throw new ReadOnlyException();
                         }
                 }
                        }                       
-                }
        
                #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>
+                internal void Load (object [] values, LoadOption loadOption)
+                {
+                        Index index = null;
+                        int temp = -1;
+
+                        if (loadOption == LoadOption.OverwriteChanges 
+                            || (loadOption == LoadOption.PreserveChanges
+                                && RowState == DataRowState.Unchanged)) {
+                               Table.ChangingDataRow (this, DataRowAction.ChangeCurrentAndOriginal);
+                               temp = Table.CreateRecord (values);
+                                                               Table.DeleteRowFromIndexes(this);
+                                if (HasVersion (DataRowVersion.Original) && Current != Original)
+                                        Table.RecordCache.DisposeRecord (Original);
+                                Original = temp;
+
+                                if (HasVersion (DataRowVersion.Current))
+                                        Table.RecordCache.DisposeRecord (Current);
+                                Current = temp;
+                                                               Table.AddRowToIndexes(this);
+                               Table.ChangedDataRow (this, DataRowAction.ChangeCurrentAndOriginal);
+                                return;
+                        }
+
+                        if (loadOption == LoadOption.PreserveChanges) {
+                               Table.ChangingDataRow (this, DataRowAction.ChangeOriginal);
+                               temp = Table.CreateRecord (values);
+                               if (HasVersion (DataRowVersion.Original) && Current != Original)
+                                       Table.RecordCache.DisposeRecord (Original);
+                               Original = temp;
+                               Table.ChangedDataRow (this, DataRowAction.ChangeOriginal);
+                                return;
+                        }
+                                
+                        // Upsert
+                        if (RowState != DataRowState.Deleted) {
+                                int rindex = HasVersion (DataRowVersion.Proposed) ? Proposed : Current;
+                               temp = Table.CreateRecord (values);
+                               if (RowState == DataRowState.Added 
+                                   || Table.CompareRecords (rindex, temp) != 0) {
+                                       Table.ChangingDataRow (this, DataRowAction.Change);
+                                                                               Table.DeleteRowFromIndexes(this);
+                                        if (HasVersion (DataRowVersion.Proposed)) {
+                                                Table.RecordCache.DisposeRecord (Proposed);
+                                                Proposed = -1;
+                                        }
+  
+                                        if (Original != Current)
+                                                Table.RecordCache.DisposeRecord (Current);
+                                        Current = temp;
+                                                                               Table.AddRowToIndexes(this);
+                                       Table.ChangedDataRow (this, DataRowAction.Change);
+                                } else {
+                                       Table.ChangingDataRow (this, DataRowAction.Nothing);
+                                       Table.RecordCache.DisposeRecord (temp);
+                                       Table.ChangedDataRow (this, DataRowAction.Nothing);
+                               }
+                        }
 
+                }
+#endif // NET_2_0
+       }
 }