Patches from Eran Domb <erand@mainsoft.com>.
authorDuncan Mak <duncan@mono-cvs.ximian.com>
Thu, 25 Sep 2003 17:33:15 +0000 (17:33 -0000)
committerDuncan Mak <duncan@mono-cvs.ximian.com>
Thu, 25 Sep 2003 17:33:15 +0000 (17:33 -0000)
* DbDataAdapter.cs (Fill): Patch from Eran Domb, <eran@mainsoft.com>.
Fixes a possible NullReferenceException, more details here:

* DataColumn.cs (Unique): Implemented.

* DataTable.cs:
* ConstraintCollection.cs:
* ForeignKeyConstraint.cs (_ensureUniqueConstraintExists): Fixes
an Exception thrown. Details:
http://lists.ximian.com/archives/public/mono-devel-list/2003-September/002130.html

* DataRowCollection.cs (Add): There is no checking that there is
no violation of the unique constrains.

* UniqueConstraint.cs (AssertConstraint): There is no checking on
all columns in the constraint.

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

mcs/class/System.Data/System.Data.Common/ChangeLog
mcs/class/System.Data/System.Data.Common/DbDataAdapter.cs
mcs/class/System.Data/System.Data/ChangeLog
mcs/class/System.Data/System.Data/ConstraintCollection.cs
mcs/class/System.Data/System.Data/DataColumn.cs
mcs/class/System.Data/System.Data/DataRowCollection.cs
mcs/class/System.Data/System.Data/DataTable.cs
mcs/class/System.Data/System.Data/DataTableCollection.cs
mcs/class/System.Data/System.Data/ForeignKeyConstraint.cs
mcs/class/System.Data/System.Data/UniqueConstraint.cs

index eba1b763c57b7e3c7ba0dc2f0d12d3f73afce9b5..312b2a8e41ce6c79c7fcf157736ae6e788c5f13c 100755 (executable)
@@ -1,3 +1,10 @@
+2003-09-25  Duncan Mak  <duncan@ximian.com>
+
+       * DbDataAdapter.cs (Fill): Patch from Eran Domb, <eran@mainsoft.com>.
+       Fixes a possible NullReferenceException, more details here:
+
+       http://lists.ximian.com/archives/public/mono-devel-list/2003-September/002116.html
+
 2003-09-21  eran <erand@mainsoft.com>
 
        * DbDataRecord.cs: The method
index a1e110f51e58ac91144bcf8f5b0bcf1deae9f444..4b01669af5a28eeaed20f5d6223f2a20e2b2d6c4 100644 (file)
@@ -169,8 +169,12 @@ namespace System.Data.Common {
                                dataTable = new DataTable ();
                                SetupSchema (SchemaType.Mapped, tableName, dataTable);
 
-                               if (dataSet.Tables.Contains (dataTable.TableName))
-                                       dataTable = dataSet.Tables [tableName];
+                               // check if the table exists in the dataset
+                               if (dataSet.Tables.Contains (dataTable.TableName)) 
+                                       // get the table from the dataset
+                                       dataTable = dataSet.Tables [dataTable.TableName];
+                               else
+                                       dataSet.Tables.Add (dataTable);
                                BuildSchema (dataReader, dataTable, SchemaType.Mapped);
 
                                for (int i = 0; i < startRecord; i += 1)
@@ -191,7 +195,6 @@ namespace System.Data.Common {
                                        }
                                }
 
-                               dataSet.Tables.Add (dataTable);
                                        tableName = String.Format ("{0}{1}", srcTable, ++resultIndex);
 
                                startRecord = 0;
@@ -264,6 +267,7 @@ namespace System.Data.Common {
                        int index = 0;
 
                        do {
+                               // FixMe: Allocate table only if it doesn't exist already!
                                DataTable table = new DataTable ();
                                SetupSchema (schemaType, tableName, table);
                                if (dataSet.Tables.Contains (table.TableName))
index f20637c185579848f90338f453313ce134d97dc7..19f8d5a501a8837c473913f0840c6f886b13f76d 100644 (file)
@@ -1,3 +1,26 @@
+2003-09-25  Duncan Mak  <duncan@ximian.com>
+
+        Patches from Eran Domb <erand@mainsoft.com>.
+
+       * DataColumn.cs (Unique): Implemented.
+       
+       * DataTable.cs:
+       * ConstraintCollection.cs:
+       * ForeignKeyConstraint.cs (_ensureUniqueConstraintExists): Fixes
+       an Exception thrown. Details:
+       http://lists.ximian.com/archives/public/mono-devel-list/2003-September/002130.html
+       
+       * DataRowCollection.cs (Add): There is no checking that there is
+       no violation of the unique constrains.
+
+       * UniqueConstraint.cs (AssertConstraint): There is no checking on
+       all columns in the constraint.
+
+       * DataTableCollection (Add): Correctly throw an Exception, more
+       details here:
+       http://lists.ximian.com/archives/public/mono-devel-list/2003-September/002117.html
+       (Remove, RemoveAt): Implemented.
+
 2003-07-31  Duncan Mak  <duncan@ximian.com>
 
        * DBConcurrencyException.cs: Added new NET_1_1 no-param constructor.
index 88d8a4caa9cc881fdd593add7024d7c48d7a4cca..6711c4b69ef8e2c419ce473dc5aa64ffe105ca18 100644 (file)
@@ -30,10 +30,18 @@ namespace System.Data {
                
                public event CollectionChangeEventHandler CollectionChanged;
                internal event DelegateValidateRemoveConstraint ValidateRemoveConstraint;
-               
+               private DataTable table;
                //Don't allow public instantiation
                //Will be instantianted from DataTable
-               internal ConstraintCollection(){} 
+               internal ConstraintCollection(DataTable table){
+                       this.table = table;
+               } 
+
+               internal DataTable Table{
+                       get{
+                               return this.table;
+                       }
+               }
 
                public virtual Constraint this[string name] {
                        get {
@@ -342,5 +350,6 @@ namespace System.Data {
                        failReason = tmp;
                        return !cancel;
                }
+
        }
 }
index 2333a3421fd8b5440a67f8eb0e104e1cefcd93cc..064b0c23d9c3e65e0de274a6f85205c6d3668116 100644 (file)
@@ -479,6 +479,8 @@ namespace System.Data {
 
                                        if( value )
                                        {
+                                               if (Expression != null && Expression != "")
+                                                       throw new ArgumentException("Cannot change Unique property for the expression column.");
                                                if( _table != null )
                                                {
                                                        UniqueConstraint uc = new UniqueConstraint(this);
@@ -489,8 +491,25 @@ namespace System.Data {
                                        {
                                                if( _table != null )
                                                {
-                                                       //FIXME: Add code to remove constraint from DataTable
-                                                       throw new NotImplementedException ();
+                                                       ConstraintCollection cc = _table.Constraints;
+                                                       //foreach (Constraint c in cc) 
+                                                       for (int i = 0; i < cc.Count; i++)
+                                                       {
+                                                               Constraint c = cc[i];
+                                                               if (c is UniqueConstraint)
+                                                               {
+                                                                       DataColumn[] cols = ((UniqueConstraint)c).Columns;
+                                                                       
+                                                                       if (cols.Length == 1 && cols[0] == this)
+                                                                       {
+                                                                               if (!cc.CanRemove(c))
+                                                                                       throw new ArgumentException("Cannot remove unique constraint '" + c.ConstraintName + "'. Remove foreign key constraint first.");
+
+                                                                               cc.Remove(c);
+                                                                       }
+                                                                       
+                                                               }
+                                                       }
                                                }
                                        }
 
index 8d6b07c65afd0c152e8bafeb77841818a1593d4b..eb303d97846a48eacd92bc95a2360db248495b0f 100644 (file)
@@ -64,7 +64,11 @@ namespace System.Data
 
                        if (list.IndexOf(row) != -1)
                                throw new ArgumentException ("This row already belongs to this table.");
-                               
+                       
+                       if (table.DataSet.EnforceConstraints)
+                               // we have to check that the new row doesn't colide with existing row
+                               ValidateDataRowInternal(row);
+                       
                        list.Add (row);
                        row.AttachRow ();
                        row.Table.ChangedDataRow (row, DataRowAction.Add);
@@ -251,6 +255,8 @@ namespace System.Data
                        }
 
                }
-
+               
        }
+
+
 }
index 80a94ce1118ac66520156e0da89c6236613c1eaa..85e83829e11281eb0c7cd038f1f610b89df2b299 100644 (file)
@@ -66,7 +66,7 @@ namespace System.Data {
                {
                        dataSet = null;
                        _columnCollection = new DataColumnCollection(this);
-                       _constraintCollection = new ConstraintCollection(); 
+                       _constraintCollection = new ConstraintCollection(this); 
                        _extendedProperties = new PropertyCollection();
                        _tableName = "";
                        _nameSpace = null;
index a77d641e827db65eb54aa3f29f9c9a54d8d78b9d..3c302444a285ef2b2b4e4a4297f761b4531abd1e 100644 (file)
@@ -66,8 +66,23 @@ namespace System.Data {
 
                public virtual void Add (DataTable table) 
                {
+                       
+                       // check if the reference is a null reference
+                       if(table == null)
+                               throw new ArgumentNullException("table");
+            
+                       // check if the list already contains this tabe.
+                       if(list.Contains(table))
+                               throw new ArgumentException("DataTable already belongs to this DataSet.");
+            
+                       // if the table name is null or empty string.
+                       // give her a name. 
                        if (table.TableName == null || table.TableName == string.Empty)
                                NameTable (table);
+                   
+                       // check if the collection has a table with the same name.
+                       if(Contains(table.TableName))
+                               throw new DuplicateNameException("A DataTable named '" + table.TableName + "' already belongs to this DataSet.");
                                
                        list.Add (table);
                        table.dataSet = dataSet;
@@ -90,7 +105,7 @@ namespace System.Data {
                [MonoTODO]
                public bool CanRemove (DataTable table) 
                {
-                       throw new NotImplementedException ();
+                       return CanRemove(table, false);
                }
 
                public void Clear () 
@@ -115,18 +130,22 @@ namespace System.Data {
 
                public void Remove (DataTable table) 
                {
-                       this.Remove (table.TableName);
+                       CanRemove(table, true);
+                       list.Remove(table);
                        OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, table));
                }
 
                public void Remove (string name) 
                {
-                       list.Remove (this [name]);
+                       Remove (this [name]);
                }
 
                public void RemoveAt (int index) 
                {
+                       DataTable t = this[index];
+                       CanRemove(t, true);
                        list.RemoveAt (index);
+                       OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, t));
                }
 
                #endregion
@@ -182,6 +201,64 @@ namespace System.Data {
 
                        Table.TableName = Name + i;                            
                }
+               
+               // check if a table can be removed from this collectiuon.
+               // if the table can not be remved act according to throwException parameter.
+               // if it is true throws an Exception, else return false.
+               private bool CanRemove(DataTable table, bool throwException)
+               {
+                       // check if table is null reference
+                       if (table == null)
+                       {
+                               if(throwException)
+                                       throw new ArgumentNullException("table");
+                               return false;
+                       }
+                       
+                       // check if the table has the same DataSet as this collection.
+                       if(table.DataSet != this.dataSet)
+                       {
+                               if(throwException)
+                                       throw new ArgumentException("Table " + table.TableName + " does not belong to this DataSet.");
+                               return false;
+                       }
+                       
+                       // check the table has a relation attached to it.
+                       if (table.ParentRelations.Count > 0 || table.ChildRelations.Count > 0)
+                       {
+                               if(throwException)
+                                       throw new ArgumentException("Cannot remove a table that has existing relations. Remove relations first.");
+                               return false;
+                       }
+                       
+
+                       // now we check if any ForeignKeyConstraint is referncing 'table'.
+                       IEnumerator tableEnumerator = this.dataSet.Tables.GetEnumerator();
+                       
+                       // loop on all tables in dataset
+                       while (tableEnumerator.MoveNext())
+                       {
+                               IEnumerator constraintEnumerator = ((DataTable) tableEnumerator.Current).Constraints.GetEnumerator();
+                               // loop on all constrains in the current table
+                               while (constraintEnumerator.MoveNext())
+                               {
+                                       Object o = (Constraint) constraintEnumerator.Current;
+                                       // we only check ForeignKeyConstraint
+                                       if (o is ForeignKeyConstraint)
+                                       {
+                                               ForeignKeyConstraint fc = (ForeignKeyConstraint) o;
+                                               if(fc.Table == table || fc.RelatedTable == table)
+                                               {
+                                                       if(throwException)
+                                                               throw new ArgumentException("Cannot remove table " + table.TableName + ", because it referenced in ForeignKeyConstraint " + fc.ConstraintName + ". Remove the constraint first.");
+                                                       return false;
+                                               }
+                                       }
+                               }
+                       }
+
+                       return true;
+               }
 
                #endregion // Private methods
 
index 59d549eb43714ebd2fdeb1386bdbbc572c2c915a..d6b3fee0b05d1461e8c873a99f8214244bf7b3ee 100644 (file)
@@ -195,17 +195,25 @@ namespace System.Data {
                        
                        //see if unique constraint already exists
                        //if not create unique constraint
-                       uc = UniqueConstraint.GetUniqueConstraintForColumnSet(collection, parentColumns);
+                       if(parentColumns[0] != null)
+                               uc = UniqueConstraint.GetUniqueConstraintForColumnSet(parentColumns[0].Table.Constraints, parentColumns);
 
-                       if (null == uc) uc = new UniqueConstraint(parentColumns, false); //could throw
+                       if (null == uc) {
+                               uc = new UniqueConstraint(parentColumns, false); //could throw
+                               parentColumns [0].Table.Constraints.Add (uc);
+                       }
 
                        //keep reference
                        _parentUniqueConstraint = uc;
-                       parentColumns [0].Table.Constraints.Add (uc);
+                       //parentColumns [0].Table.Constraints.Add (uc);
                        //if this unique constraint is attempted to be removed before us
                        //we can fail the validation
-                       collection.ValidateRemoveConstraint += new DelegateValidateRemoveConstraint(
-                                       _validateRemoveParentConstraint);
+                       //collection.ValidateRemoveConstraint += new DelegateValidateRemoveConstraint(
+                       //              _validateRemoveParentConstraint);
+
+                       parentColumns [0].Table.Constraints.ValidateRemoveConstraint += new DelegateValidateRemoveConstraint(
+                               _validateRemoveParentConstraint);
+
                }
                
                
@@ -333,7 +341,7 @@ namespace System.Data {
                internal override void AddToConstraintCollectionSetup(
                                ConstraintCollection collection)
                {
-
+                       
                        //run Ctor rules again
                        _validateColumns(_parentColumns, _childColumns);
                        
@@ -343,7 +351,8 @@ namespace System.Data {
                        //Make sure we can create this thing
                        AssertConstraint(); //TODO:if this fails and we created a unique constraint
                                                //we should probably roll it back
-                       
+                       if (collection.Table != Table)
+                               throw new InvalidConstraintException("This constraint cannot be added since ForeignKey doesn't belong to table " + RelatedTable.TableName + ".");
                }
                                        
        
@@ -357,6 +366,7 @@ namespace System.Data {
                [MonoTODO]
                internal override void AssertConstraint()
                {
+
                        //Constraint only works if both tables are part of the same dataset
                        
                        //if DataSet ...
index a4ce914b0fb4b9a6fe009d131b25689b96433b1a..4bfc3dfed1556d2a282f9b50c728ebd865bf53fe 100644 (file)
@@ -405,41 +405,56 @@ namespace System.Data {
                [MonoTODO]
                internal override void AssertConstraint(DataRow row)
                {
-
                        if (_dataTable == null) return; //???
                        if (_dataColumns == null) return; //???
 
-
                        //Unique?
                        DataTable tbl = _dataTable;
-
+                       bool isValid;
                        foreach(DataRow compareRow in tbl.Rows)
                        {
+                               isValid = false;
                                //skip if it is the same row to be validated
                                if(!row.Equals(compareRow))
                                {
-                                       if(compareRow.HasVersion (DataRowVersion.Original))
+                                       //FIXME: should we compare to compareRow[DataRowVersion.Current]?
+                                       //FIXME: We need to compare to all columns the constraint is set to.
+                                       
+                                       for (int i = 0; i < _dataColumns.Length; i++)
                                        {
-                                               //FIXME: should we compare to compareRow[DataRowVersion.Current]?
-                                               //FIXME: We need to compare to all columns the constraint is set to.
-                                               if(row[_dataColumns[0], DataRowVersion.Proposed].Equals( compareRow[_dataColumns[0], DataRowVersion.Current]))
+                                               // if the values in the row are not equal to the values of
+                                               // the original row from the table we can move to the next row.
+                                               if(!row[_dataColumns[i]].Equals( compareRow[_dataColumns[i]]))
                                                {
-                                                       string ExceptionMessage;
-                                                       ExceptionMessage = "Column '" + _dataColumns[0].ColumnName + "' is constrained to be unique.";
-                                                       ExceptionMessage += " Value '" + row[_dataColumns[0], DataRowVersion.Proposed].ToString();
-                                                       ExceptionMessage += "' is already present.";
-
-                                                       throw new ConstraintException (ExceptionMessage);
+                                                       isValid = true;
+                                                       break;
                                                }
-
                                        }
+                               
+                                       if (!isValid)
+                                               throw new ConstraintException(GetErrorMessage(compareRow));
 
-               }
+                               }
 
                        }
 
                }
 
+               private string GetErrorMessage(DataRow row)
+               {
+                       int i;
+                        
+                       System.Text.StringBuilder sb = new System.Text.StringBuilder(row[_dataColumns[0]].ToString());
+                       for (i = 1; i < _dataColumns.Length; i++)
+                               sb = sb.Append(", ").Append(row[_dataColumns[i].ColumnName]);
+                       string valStr = sb.ToString();
+                       sb = new System.Text.StringBuilder(_dataColumns[0].ColumnName);
+                       for (i = 1; i < _dataColumns.Length; i++)
+                               sb = sb.Append(", ").Append(_dataColumns[i].ColumnName);
+                       string colStr = sb.ToString();
+                       return "Column '" + colStr + "' is constrained to be unique.  Value '" + valStr + "' is already present.";
+               }
+
                #endregion // Methods
        }
 }