Kaynağa Gözat

Patches from Eran Domb <[email protected]>.

* DbDataAdapter.cs (Fill): Patch from Eran Domb, <[email protected]>.
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
Duncan Mak 22 yıl önce
ebeveyn
işleme
d101df5ef4

+ 7 - 0
mcs/class/System.Data/System.Data.Common/ChangeLog

@@ -1,3 +1,10 @@
+2003-09-25  Duncan Mak  <[email protected]>
+
+	* DbDataAdapter.cs (Fill): Patch from Eran Domb, <[email protected]>.
+	Fixes a possible NullReferenceException, more details here:
+
+	http://lists.ximian.com/archives/public/mono-devel-list/2003-September/002116.html
+
 2003-09-21  eran <[email protected]>
 
 	* DbDataRecord.cs: The method

+ 7 - 3
mcs/class/System.Data/System.Data.Common/DbDataAdapter.cs

@@ -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))

+ 23 - 0
mcs/class/System.Data/System.Data/ChangeLog

@@ -1,3 +1,26 @@
+2003-09-25  Duncan Mak  <[email protected]>
+
+        Patches from Eran Domb <[email protected]>.
+
+	* 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  <[email protected]>
 
 	* DBConcurrencyException.cs: Added new NET_1_1 no-param constructor.

+ 11 - 2
mcs/class/System.Data/System.Data/ConstraintCollection.cs

@@ -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;
 		}
+
 	}
 }

+ 21 - 2
mcs/class/System.Data/System.Data/DataColumn.cs

@@ -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);
+									}
+									
+								}
+							}
 						}
 					}
 

+ 8 - 2
mcs/class/System.Data/System.Data/DataRowCollection.cs

@@ -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
 			}
 
 		}
-
+		
 	}
+
+
 }

+ 1 - 1
mcs/class/System.Data/System.Data/DataTable.cs

@@ -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;

+ 80 - 3
mcs/class/System.Data/System.Data/DataTableCollection.cs

@@ -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
 

+ 17 - 7
mcs/class/System.Data/System.Data/ForeignKeyConstraint.cs

@@ -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 ...

+ 30 - 15
mcs/class/System.Data/System.Data/UniqueConstraint.cs

@@ -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
 	}
 }