+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.
internal void Reset()\r
{\r
_array = null;\r
+ RebuildIndex();\r
}\r
\r
private void RebuildIndex()\r
*/ \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
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
_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
}\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
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
+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
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;
}
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);
}
}
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);
}
_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,
CheckChildRows(DataRowAction.Rollback);
if (Current != Original) {
- foreach(Index index in Table.Indexes) {
- index.Delete (this);
- index.Update(this,Original);
- }
+ Table.DeleteRowFromIndexes(this);
Current = Original;
}
_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;
}
}
}
+ 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) {
&& 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;
}
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);
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);
}
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;
}
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);
{
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;
- }
- }
- }
}
}
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
}\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
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
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
}\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
+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.
}
+ [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()
{