In System.Data.OleDb:
[mono.git] / mcs / class / System.Data / System.Data / DataRow.cs
index 923b5e8a1d99d705c799f193d6db156988bc53c4..baee5d293d2308dac165e01c5a6e30d4362f0a68 100644 (file)
@@ -42,12 +42,17 @@ 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
@@ -180,7 +185,6 @@ namespace System.Data {
                                }
                                
                                CheckValue (value, column);
-
                                bool orginalEditing = Proposed >= 0;
                                if (!orginalEditing) {
                                        BeginEdit ();
@@ -246,9 +250,6 @@ 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];
                                int recordIndex = IndexFromVersion(version);
@@ -262,9 +263,6 @@ namespace System.Data {
                                        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.");
-                               
                                return column[recordIndex];
                        }
                }
@@ -274,17 +272,26 @@ 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)
                                        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 {
@@ -322,23 +329,15 @@ namespace System.Data {
                public DataRowState RowState {
                        get { 
                                //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;
+                               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;
                        }
                }
 
@@ -592,12 +591,17 @@ namespace System.Data {
                                        return;
                        case DataRowState.Added:
                        case DataRowState.Modified:
+                                       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;
@@ -611,6 +615,9 @@ namespace System.Data {
                /// <summary>
                /// Begins an edit operation on a DataRow object.
                /// </summary>
+#if NET_2_0
+               [EditorBrowsable (EditorBrowsableState.Advanced)]
+#endif
                public void BeginEdit () 
                {
                        if (_inChangingEvent)
@@ -631,6 +638,9 @@ namespace System.Data {
                /// <summary>
                /// Cancels the current edit on the row.
                /// </summary>
+#if NET_2_0
+               [EditorBrowsable (EditorBrowsableState.Advanced)]
+#endif
                public void CancelEdit () 
                {
                         if (_inChangingEvent) {
@@ -638,8 +648,13 @@ namespace System.Data {
                         }
 
                        if (HasVersion (DataRowVersion.Proposed)) {
+                               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);                                        
                        }
                }
 
@@ -675,14 +690,17 @@ namespace System.Data {
                        default:
                                // check what to do with child rows
                                CheckChildRows(DataRowAction.Delete);
-                               _table.DeleteRowFromIndexes (this);
                                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);
                }
@@ -760,7 +778,6 @@ namespace System.Data {
                                                                case DataRowAction.Rollback: {
                                                                        if (childRows[j].RowState != DataRowState.Unchanged)
                                                                                childRows[j].RejectChanges ();
-
                                                                        break;
                                                                }
                                                        }
@@ -817,6 +834,9 @@ 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)
@@ -839,38 +859,46 @@ namespace System.Data {
                                        _inChangingEvent = false;
                                }
                                
-                               //Calling next method validates UniqueConstraints
-                               //and ForeignKeys.
-                               bool rowValidated = false;
-                               try
-                               {
-                                       if ((_table.DataSet == null || _table.DataSet.EnforceConstraints) && !_table._duringDataLoad) {
-                                               _table.Rows.ValidateDataRowInternal(this);
-                                               rowValidated = true;
-                                       }
-                               }
-                               catch (Exception e)
-                               {
-                                       Table.RecordCache.DisposeRecord(Proposed);
-                                       Proposed = -1;
-                                       throw e;
-                               }
-
-                               CheckChildRows(DataRowAction.Change);
-                               if (Original != Current) {
-                                       Table.RecordCache.DisposeRecord(Current);
-                               }
+                               DataRowState oldState = RowState;
 
+                               int oldRecord = Current;
                                Current = Proposed;
                                Proposed = -1;
 
-                               if (!rowValidated) {
-                                       // keep indexes updated even if there was no need to validate row
+                               if (!Table._duringDataLoad) {
                                        foreach(Index index in Table.Indexes) {
-                                               index.Update(this,Current); //FIXME: why Current ?!
+                                               index.Update(this,oldRecord, DataRowVersion.Current, oldState);
                                        }
                                }
 
+                               try {
+                                       AssertConstraints();
+
+                                       // restore previous state to let the cascade update to find the rows
+                                       Proposed = Current;
+                                       Current = oldRecord;
+
+                                       CheckChildRows(DataRowAction.Change);
+
+                                       // 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;
+                               }
+
+                               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.
@@ -1293,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 && Current != Original) {
-                                       Table.RecordCache.DisposeRecord(Current);
-                               }
-                               CheckChildRows(DataRowAction.Rollback);
+                       
+                       _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;
-                              
-                               _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);
-                                               break;
-                                       case DataRowState.Deleted:
-                                               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();
-                               }
+                               break;
+                       case DataRowState.Deleted:
+                               CheckChildRows (DataRowAction.Rollback);
+                               Table.DeleteRowFromIndexes(this);
+                               Current = Original;
+                               break;
                        }
                }
 
@@ -1614,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) {
@@ -1655,17 +1693,15 @@ namespace System.Data {
                                 && 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;
-                                // update the pk index
-                                index = Table.GetIndex(Table.PrimaryKey,null,DataViewRowState.None,null,false);
-                                if (index != null)
-                                        index.Update (this, temp);
 
                                 if (HasVersion (DataRowVersion.Current))
                                         Table.RecordCache.DisposeRecord (Current);
                                 Current = temp;
+                                                               Table.AddRowToIndexes(this);
                                Table.ChangedDataRow (this, DataRowAction.ChangeCurrentAndOriginal);
                                 return;
                         }
@@ -1687,19 +1723,16 @@ namespace System.Data {
                                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;
                                         }
-                                        
-                                        // update the pk index
-                                        index = Table.GetIndex(Table.PrimaryKey,null,DataViewRowState.None,null,false);
-                                        if (index != null)
-                                                index.Update (this, temp);
-
+  
                                         if (Original != Current)
                                                 Table.RecordCache.DisposeRecord (Current);
                                         Current = temp;
+                                                                               Table.AddRowToIndexes(this);
                                        Table.ChangedDataRow (this, DataRowAction.Change);
                                 } else {
                                        Table.ChangingDataRow (this, DataRowAction.Nothing);