fix index updates
authorKonstantin Triger <kostat@mono-cvs.ximian.com>
Thu, 15 Dec 2005 14:17:30 +0000 (14:17 -0000)
committerKonstantin Triger <kostat@mono-cvs.ximian.com>
Thu, 15 Dec 2005 14:17:30 +0000 (14:17 -0000)
svn path=/trunk/mcs/; revision=54453

mcs/class/System.Data/System.Data.Common/ChangeLog
mcs/class/System.Data/System.Data.Common/Index.cs
mcs/class/System.Data/System.Data.Common/Key.cs
mcs/class/System.Data/System.Data/ChangeLog
mcs/class/System.Data/System.Data/DataRow.cs
mcs/class/System.Data/System.Data/DataRowCollection.cs
mcs/class/System.Data/System.Data/DataTable.cs
mcs/class/System.Data/Test/System.Data/ChangeLog
mcs/class/System.Data/Test/System.Data/DataTableTest.cs

index 3d97317380f9770a450ca457b1895b6980656e12..a33733f1c3822198f369f049f40c20f8f2895ab3 100644 (file)
@@ -1,3 +1,11 @@
+2005-12-12  Konstantin Triger <kostat@mainsoft.com>
+
+       * Key.cs: Added ContainsVersion function, refactoring.
+       * Index.cs: Fixed Reset() to be ready for Update() calls.
+          Otherwise the index can be rebuilt with new values inside the
+          Update() call itself.
+          Fixed FindIndexExact(), Update(), Delete().
+
 2005-11-22  Konstantin Triger <kostat@mainsoft.com>
 
        * DbProviderFactory.cs: TARGET_JVM ifdef.
index cfe1170c96e605ad9baebfee22bc1b278326c482..21c87478f9bfaff99eb09b6e33f25d730dce81dc 100644 (file)
@@ -162,6 +162,7 @@ namespace System.Data.Common
                internal void Reset()\r
                {\r
                        _array = null;\r
+                       RebuildIndex();\r
                }\r
 \r
                private void RebuildIndex()\r
@@ -333,8 +334,11 @@ namespace System.Data.Common
                 */ \r
                private int FindIndexExact(int record)\r
                {\r
-                       int index = System.Array.BinarySearch(Array,record);\r
-                       return (index > 0) ? index : -1;\r
+                       for (int i = 0, size = Size; i < size; i++)\r
+                               if (Array[i] == record)\r
+                                       return i;\r
+\r
+                       return -1;\r
                }\r
 \r
                /*\r
@@ -359,7 +363,7 @@ namespace System.Data.Common
                        if (oldRecord == -1)\r
                                return;\r
 \r
-                       int index = FindIndex(oldRecord);\r
+                       int index = FindIndexExact(oldRecord);\r
                        if (index != -1) {\r
                                if ((_hasDuplicates == IndexDuplicatesState.True)) {\r
                                        int c1 = 1;\r
@@ -388,18 +392,29 @@ namespace System.Data.Common
                        _size--;\r
                }\r
 \r
-               internal void Update(DataRow row,int newRecord)\r
-               {\r
-                       int oldRecord = Key.GetRecord(row);\r
 \r
-                       if (oldRecord == -1 || Size == 0) {\r
-                               Add(row,newRecord);\r
+               internal void Update(DataRow row,int oldRecord, DataRowVersion oldVersion, DataRowState oldState)\r
+               {                       \r
+                       bool contains = Key.ContainsVersion (oldState, oldVersion);\r
+                       int newRecord = Key.GetRecord(row);     \r
+                       // the record did not appeared in the index before update\r
+                       if (oldRecord == -1 || Size == 0 || !contains) {\r
+                               if (newRecord >= 0) {\r
+                                       if (FindIndexExact(newRecord) < 0)\r
+                                               Add(row,newRecord);\r
+                               }\r
+                               return;\r
+                       }\r
+                       \r
+                       // the record will not appeare in the index after update\r
+                       if (newRecord < 0 || !Key.CanContain (newRecord)) {\r
+                               Delete (oldRecord);\r
                                return;\r
                        }\r
 \r
-                       int oldIdx = FindIndex(oldRecord);\r
+                       int oldIdx = FindIndexExact(oldRecord);\r
 \r
-                       if( oldIdx == -1 || Key.Table.RecordCache[Array[oldIdx]] != row ) {\r
+                       if( oldIdx == -1 ) {\r
                                Add(row,newRecord);\r
                                return;\r
                        }\r
@@ -477,11 +492,15 @@ namespace System.Data.Common
                        }\r
                }\r
 \r
+               internal void Add(DataRow row) {\r
+                       Add(row, Key.GetRecord(row));\r
+               }\r
+\r
                private void Add(DataRow row,int newRecord)\r
                {\r
                        int newIdx;\r
 \r
-                       if (!Key.CanContain (newRecord))\r
+                       if (newRecord < 0 || !Key.CanContain (newRecord))\r
                                return;\r
 \r
                        if (Size == 0) {\r
index 989e86316788303abecd4ff3ed727454341df033..4c1d26a2d2bca52c7ffbcc0fd00110a7a8a23fe8 100644 (file)
@@ -163,29 +163,77 @@ namespace System.Data.Common
                        return _filter.EvalBoolean(_tmpRow);\r
                }\r
 \r
-               internal static int GetRecord(DataRow row, DataViewRowState rowStateFilter)\r
+               internal bool ContainsVersion (DataRowState state, DataRowVersion version)\r
                {\r
+                       switch (state) {\r
+                               case DataRowState.Unchanged: {\r
+                                       if ((_rowStateFilter & DataViewRowState.Unchanged) != DataViewRowState.None) {\r
+                                               return ((version & DataRowVersion.Default) != 0);\r
+                                       }\r
 \r
-                       if (row.Original == row.Current) {\r
-                                if ((rowStateFilter & DataViewRowState.Unchanged) != DataViewRowState.None) {\r
-                                        return row.Current;\r
-                                }\r
-                       }\r
-                       else if (row.Original == -1) {\r
-                                 if ((rowStateFilter & DataViewRowState.Added) != DataViewRowState.None) {\r
-                                       return row.Current;\r
-                                 }\r
+                                       break;\r
+                               }\r
+                               case DataRowState.Added: {\r
+                                       if ((_rowStateFilter & DataViewRowState.Added) != DataViewRowState.None) {\r
+                                               return ((version & DataRowVersion.Default) != 0);\r
+                                       }\r
+\r
+                                       break;\r
+                               }\r
+                               case DataRowState.Deleted: {\r
+                                       if ((_rowStateFilter & DataViewRowState.Deleted) != DataViewRowState.None) {\r
+                                               return (version == DataRowVersion.Original);\r
+                                       }\r
+\r
+                                       break;\r
+                               }\r
+                               default:\r
+                                       if ((_rowStateFilter & DataViewRowState.ModifiedCurrent) != DataViewRowState.None) {\r
+                                               return ((version & DataRowVersion.Default) != 0);\r
+                                       }\r
+                                       else if ((_rowStateFilter & DataViewRowState.ModifiedOriginal) != DataViewRowState.None) {\r
+                                               return (version == DataRowVersion.Original);\r
+                                       }\r
+\r
+                                       break;\r
                        }\r
-                       else if (row.Current == -1) {\r
-                                    if ((rowStateFilter & DataViewRowState.Deleted) != DataViewRowState.None) {\r
+\r
+            return false;\r
+               }\r
+\r
+               internal static int GetRecord(DataRow row, DataViewRowState rowStateFilter)\r
+               {\r
+                       switch (row.RowState) {\r
+                               case DataRowState.Unchanged: {\r
+                                       if ((rowStateFilter & DataViewRowState.Unchanged) != DataViewRowState.None) {\r
+                                               return row.Proposed >= 0 ? row.Proposed : row.Current;\r
+                                       }\r
+\r
+                                       break;\r
+                               }\r
+                               case DataRowState.Added: {\r
+                                       if ((rowStateFilter & DataViewRowState.Added) != DataViewRowState.None) {\r
+                                               return row.Proposed >= 0 ? row.Proposed : row.Current;\r
+                                       }\r
+\r
+                                       break;\r
+                               }\r
+                               case DataRowState.Deleted: {\r
+                                       if ((rowStateFilter & DataViewRowState.Deleted) != DataViewRowState.None) {\r
                                                return row.Original;\r
-                                        }\r
-                       }\r
-                       else if ((rowStateFilter & DataViewRowState.ModifiedCurrent) != DataViewRowState.None) {\r
-                               return row.Current;\r
-                       }\r
-                       else if ((rowStateFilter & DataViewRowState.ModifiedOriginal) != DataViewRowState.None) {\r
-                               return row.Original;\r
+                                       }\r
+\r
+                                       break;\r
+                               }\r
+                               default:\r
+                                       if ((rowStateFilter & DataViewRowState.ModifiedCurrent) != DataViewRowState.None) {\r
+                                               return row.Proposed >= 0 ? row.Proposed : row.Current;\r
+                                       }\r
+                                       else if ((rowStateFilter & DataViewRowState.ModifiedOriginal) != DataViewRowState.None) {\r
+                                               return row.Original;\r
+                                       }\r
+\r
+                                       break;\r
                        }\r
 \r
             return -1;\r
index db26ac531455604a478ab133c037f49d204a7492..328eab571f7906411dbbc8139ab241c3845b58f0 100644 (file)
@@ -1,3 +1,12 @@
+2005-12-12  Konstantin Triger <kostat@mainsoft.com>
+
+       * DataRow.cs: Added index Updates.
+               EndEdit() fixed to first update indices and then AssertConstraints
+               based on those indices.
+               Added Validate() and AssertConstraints() functions.
+       * DataRowCollection.cs: Removed ValidateDataRowInternal().
+       * DataTable: Fixed Clear().
+
 2005-12-06  Atsushi Enomoto  <atsushi@ximian.com>
 
        * CustomDataClassGenerator.cs : (InitializeFields) handle AllowDBNull
index b7d2a55412438ca10fe39499c9421592d679ae02..c8a6fe4380ede8fdd3e1723e51f0e94babc17dbf 100644 (file)
@@ -592,12 +592,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;
@@ -638,12 +643,13 @@ namespace System.Data {
                         }
 
                        if (HasVersion (DataRowVersion.Proposed)) {
+                               int oldRecord = Proposed;
+                               DataRowState oldState = RowState;
                                Table.RecordCache.DisposeRecord(Proposed);
                                Proposed = -1;
 
-                               int newVersion = (HasVersion (DataRowVersion.Current)) ? Current : Original;                                    
                                foreach(Index index in Table.Indexes)
-                                       index.Update(this,newVersion);                                  
+                                       index.Update(this,oldRecord, DataRowVersion.Proposed, oldState);                                        
                        }
                }
 
@@ -679,14 +685,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);
                }
@@ -843,36 +852,44 @@ 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,
@@ -1304,10 +1321,7 @@ namespace System.Data {
                                CheckChildRows(DataRowAction.Rollback);
 
                                if (Current != Original) {
-                                       foreach(Index index in Table.Indexes) {
-                                               index.Delete (this);
-                                               index.Update(this,Original);
-                                       }
+                                       Table.DeleteRowFromIndexes(this);
                                        Current = Original;
                                }
                               
@@ -1320,12 +1334,9 @@ namespace System.Data {
                                                _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);
+                                               Table.AddRowToIndexes(this);
+                                               AssertConstraints();
                                                break;
                                } 
                                
@@ -1624,6 +1635,35 @@ 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) {
@@ -1665,17 +1705,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;
                         }
@@ -1697,19 +1735,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);
index a6363a30583fdc3ad46327759a4fa8e442c5999f..a6344d16c2bd7b50e5f831ca3fdaffe6c506d7a8 100644 (file)
@@ -95,9 +95,7 @@ namespace System.Data
                        
                        row.BeginEdit();
 
-                       if (!table._duringDataLoad)
-                               // we have to check that the new row doesn't colide with existing row
-                               ValidateDataRowInternal(row);
+                       row.Validate();
 
                        AddInternal(row);
                }
@@ -124,9 +122,8 @@ namespace System.Data
                        DataRow row = table.NewNotInitializedRow();
                        int newRecord = table.CreateRecord(values);
                        row.ImportRecord(newRecord);
-                       if ((table.DataSet == null || table.DataSet.EnforceConstraints) && !table._duringDataLoad)
-                               // we have to check that the new row doesn't colide with existing row
-                               ValidateDataRowInternal(row);
+
+                       row.Validate();
                        AddInternal (row);
                        return row;
                }
@@ -277,9 +274,7 @@ namespace System.Data
                        if (row.RowID != -1)
                                throw new ArgumentException ("This row already belongs to this table.");
                        
-                       if ((table.DataSet == null || table.DataSet.EnforceConstraints) && !table._duringDataLoad)
-                               // we have to check that the new row doesn't colide with existing row
-                               ValidateDataRowInternal(row);
+                       row.Validate();
                                
                        row.Table.ChangingDataRow (row, DataRowAction.Add);
 
@@ -340,41 +335,5 @@ namespace System.Data
                {                       
                        Remove(this[index]);
                }
-
-               ///<summary>
-               ///Internal method used to validate a given DataRow with respect
-               ///to the DataRowCollection
-               ///</summary>
-               [MonoTODO]
-               internal void ValidateDataRowInternal(DataRow row)
-               {
-                       int newRecord = (row.Proposed >= 0) ? row.Proposed : row.Current;
-                       if (newRecord < 0)
-                               return;
-
-                       foreach(Index index in table.Indexes) {
-                               index.Update(row,newRecord);
-                       }
-
-                       if (!(table.DataSet == null || table.DataSet.EnforceConstraints))
-                               return;
-
-                       //first check for null violations.
-                       row._nullConstraintViolation = true;
-                       row.CheckNullConstraints();
-
-                       foreach(Constraint constraint in table.Constraints) {
-                               try {
-                                       constraint.AssertConstraint(row);
-                               }
-                               catch(Exception e) {
-                                       // remove row from indexes
-                                       foreach(Index index in table.Indexes) {
-                                               index.Delete(newRecord);
-                                       }
-                                       throw e;
-                               }
-                       }
-               }
        }
 }
index 147e910c572964a75dfa33f3762da3c6c9ab8625..1582dd6cc87af706a1e840a8c69a60ecefb03dae 100644 (file)
@@ -713,6 +713,8 @@ namespace System.Data {
                public void Clear () {\r
                         // Foriegn key constraints are checked in _rows.Clear method\r
                        _rows.Clear ();\r
+                       foreach(Index index in Indexes)\r
+                               index.Reset();\r
 #if NET_2_0\r
                         OnTableCleared (new DataTableClearEventArgs (this));\r
 #endif // NET_2_0\r
@@ -1018,9 +1020,7 @@ namespace System.Data {
                                }\r
                        }\r
 \r
-                       if (EnforceConstraints)\r
-                               // we have to check that the new row doesn't colide with existing row\r
-                               Rows.ValidateDataRowInternal(newRow);\r
+                       newRow.Validate();\r
 \r
                        Rows.AddInternal(newRow);               \r
        \r
@@ -1175,11 +1175,8 @@ namespace System.Data {
                                        row.AcceptChanges();\r
                                }\r
                                \r
-                               if (shouldUpdateIndex || !fAcceptChanges) {\r
-                                       // AcceptChanges not always updates indexes because it calls EndEdit\r
-                                       foreach(Index index in Indexes) {\r
-                                               index.Update(row,tmpRecord);\r
-                                       }\r
+                               if (shouldUpdateIndex && !fAcceptChanges) {\r
+                                       AddRowToIndexes(row);\r
                                }\r
 \r
                        }\r
@@ -1222,9 +1219,7 @@ namespace System.Data {
                                 row = NewNotInitializedRow ();\r
                                 row.ImportRecord (CreateRecord(values));\r
 \r
-                                if (EnforceConstraints) \r
-                                        // we have to check that the new row doesn't colide with existing row\r
-                                        Rows.ValidateDataRowInternal(row); // this adds to index ;-)\r
+                                row.Validate(); // this adds to index ;-)\r
                                      \r
                                 if (loadOption == LoadOption.OverwriteChanges ||\r
                                     loadOption == LoadOption.PreserveChanges) {\r
@@ -1588,6 +1583,14 @@ namespace System.Data {
                        }\r
                }\r
 \r
+               internal void AddRowToIndexes (DataRow row) {\r
+                       if (_indexes != null) {\r
+                               foreach (Index indx in _indexes) {\r
+                                       indx.Add (row);\r
+                               }\r
+                       }\r
+               }\r
+\r
                internal void DeleteRowFromIndexes (DataRow row)\r
                {\r
                        if (_indexes != null) {\r
index 637c7c3bb3a9a1e222781eeda0a4b65bfa9f823a..97345b377b848cc506485df96259907739bd77df 100644 (file)
@@ -1,3 +1,7 @@
+2005-12-15 Konstantin Triger <kostat@mainsoft.com>
+
+       * DataTableTest.cs: added SelectRowState test.
+
 2005-12-07 Boris Kirzner <borisk@mainsoft.com>
        * DataTableTest.cs: added ifdef for feature not supported in TARGET_JVM.
 
index 2cf338c44c6c3fcf4cbc5a520fafb0a75e591933..4672c895157b6a023f5daed8edd0f2b578797957 100644 (file)
@@ -720,6 +720,19 @@ namespace MonoTests.System.Data
                        
                }
 
+               [Test]
+               public void SelectRowState()
+               {
+                       DataTable d = new DataTable();
+                       d.Columns.Add (new DataColumn ("aaa"));
+                       DataRow [] rows = d.Select (null, null, DataViewRowState.Deleted);
+                       AssertEquals(0, rows.Length);
+                       d.Rows.Add (new object [] {"bbb"});
+                       d.Rows.Add (new object [] {"bbb"});
+                       rows = d.Select (null, null, DataViewRowState.Deleted);
+                       AssertEquals(0, rows.Length);
+               }
+
                [Test]
                public void ToStringTest()
                {