2004-05-15 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.Data / System.Data / DataTable.cs
index 2ac1b706f4121dafa14f836e96221d70d603a30e..39ff652bda047835ec4e1e5b1c055c13a04d5c1d 100644 (file)
@@ -32,7 +32,6 @@ namespace System.Data {
        [DefaultProperty ("TableName")]
        [DesignTimeVisible (false)]
        [EditorAttribute ("Microsoft.VSDesigner.Data.Design.DataTableEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
-       [TypeConverterAttribute("System.ComponentModel.ComponentConverter, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
        [Serializable]
        public class DataTable : MarshalByValueComponent, IListSource, ISupportInitialize, ISerializable 
        {
@@ -59,6 +58,7 @@ namespace System.Data {
                private bool _containsListCollection;
                private string _encodedTableName;
                internal bool _duringDataLoad;
+               internal bool _nullConstraintViolationDuringDataLoad;
                private bool dataSetPrevEnforceConstraints;
                private bool dataTablePrevEnforceConstraints;
                private bool enforceConstraints = true;
@@ -69,6 +69,21 @@ namespace System.Data {
                // If CaseSensitive property is changed once it does not anymore follow owner DataSet's 
                // CaseSensitive property. So when you lost you virginity it's gone for ever
                private bool _virginCaseSensitive = true;
+               
+                /// <summary>
+                 /// An enum variable indicating whether BeginInit() or EndInit() is called.
+                /// Delegate to call a function which performs cleanup after EndInit() is called
+                /// </summary>
+                internal enum initStatus { NotInitialized, BeginInit, EndInit };
+        
+               private initStatus _initStatus;
+        
+               private delegate void PostEndInit();
+                
+               internal initStatus InitStatus{
+                        get{ return( _initStatus ); }
+                }
+       
 
                /// <summary>
                /// Initializes a new instance of the DataTable class with no arguments.
@@ -116,7 +131,16 @@ namespace System.Data {
                {
                        string schema = info.GetString ("XmlSchema");
                        string data = info.GetString ("XmlDiffGram");
-                       
+
+                       DataSet ds = new DataSet ();
+                       ds.ReadXmlSchema (new StringReader (schema));
+                       ds.Tables [0].CopyProperties (this);
+                       ds = new DataSet ();
+                       ds.Tables.Add (this);
+                       ds.ReadXml (new StringReader (data), XmlReadMode.IgnoreSchema);
+                       ds.Tables.Remove (this);
+/* keeping for a while. With the change above, we shouldn't have to consider 
+ * DataTable mode in schema inference/read.
                        XmlSchemaMapper mapper = new XmlSchemaMapper (this);
                        XmlTextReader xtr = new XmlTextReader(new StringReader (schema));
                        mapper.Read (xtr);
@@ -124,9 +148,10 @@ namespace System.Data {
                        XmlDiffLoader loader = new XmlDiffLoader (this);
                        xtr = new XmlTextReader(new StringReader (data));
                        loader.Load (xtr);
+*/
                }
 
-#if NET_1_2
+#if NET_2_0
                public DataTable (string tableName, string tbNamespace)
                        : this (tableName)
                {
@@ -139,7 +164,12 @@ namespace System.Data {
                /// </summary>
                [DataSysDescription ("Indicates whether comparing strings within the table is case sensitive.")]        
                public bool CaseSensitive {
-                       get { return _caseSensitive; }
+                       get { 
+                               if (_virginCaseSensitive && dataSet != null)
+                                       return dataSet.CaseSensitive; 
+                               else
+                                       return _caseSensitive;
+                               }
                        set {
                                if (_childRelations.Count > 0 || _parentRelations.Count > 0) {
                                        throw new ArgumentException ("Cannot change CaseSensitive or Locale property. This change would lead to at least one DataRelation or Constraint to have different Locale or CaseSensitive settings between its related tables.");
@@ -258,7 +288,7 @@ namespace System.Data {
                [DataSysDescription ("The expression used to compute the data-bound value of this row.")]       
                [DefaultValue ("")]
                public string DisplayExpression {
-                       get { return "" + _displayExpression; }
+                       get { return _displayExpression == null ? "" : _displayExpression; }
                        set { _displayExpression = value; }
                }
 
@@ -335,7 +365,7 @@ namespace System.Data {
                [DataCategory ("Data")]
                [DataSysDescription ("Indicates the XML uri namespace for the elements contained in this table.")]
                public string Namespace {
-                       get { return "" + _nameSpace; }
+                       get { return _nameSpace == null ? "" : _nameSpace; }
                        set { _nameSpace = value; }
                }
 
@@ -360,7 +390,7 @@ namespace System.Data {
                [DataSysDescription ("Indicates the Prefix of the namespace used for this table in XML representation.")]
                [DefaultValue ("")]
                public string Prefix {
-                       get { return "" + _prefix; }
+                       get { return _prefix == null ? "" : _prefix; }
                        set {
                                // Prefix cannot contain any special characters other than '_' and ':'
                                for (int i = 0; i < value.Length; i++) {
@@ -472,7 +502,7 @@ namespace System.Data {
                [DefaultValue ("")]     
                [RefreshProperties (RefreshProperties.All)]
                public string TableName {
-                       get { return "" + _tableName; }
+                       get { return _tableName == null ? "" : _tableName; }
                        set { _tableName = value; }
                }
                
@@ -500,7 +530,7 @@ namespace System.Data {
                        }
                }
 
-               public bool RowsExist(Object[] columns, Object[] relatedColumns,DataRow row)
+               internal bool RowsExist(Object[] columns, Object[] relatedColumns,DataRow row)
                {
                        object[] vals = new object[relatedColumns.Length];
                        for (int i = 0; i < vals.Length; i++)
@@ -509,15 +539,18 @@ namespace System.Data {
                        return RowsExist(columns,vals);
                }
 
-               public bool RowsExist(Object[] columns,Object[] values)
+               internal bool RowsExist(Object[] columns,Object[] values)
                {
                        bool rowsExist = false;
                        Index indx = this.GetIndexByColumns ((DataColumn[])columns);
 
                        if (indx != null) { // lookup for a row in index                        
                                rowsExist = (indx.FindSimple (values, false) != null);
-                       } else { // no index we have to perform full-table scan
-                               // check that there is a parent for this row.
+                       } 
+                       
+                       if(indx == null || rowsExist == false) { 
+                               // no index or rowExist= false, we have to perform full-table scan
+                               // check that there is a parent for this row.
                                foreach (DataRow thisRow in this.Rows) {
                                        if (thisRow.RowState != DataRowState.Deleted) {
                                                bool match = true;
@@ -569,6 +602,7 @@ namespace System.Data {
                /// </summary>
                public virtual void BeginInit () 
                {
+                       _initStatus = initStatus.BeginInit;
                }
 
                /// <summary>
@@ -583,6 +617,7 @@ namespace System.Data {
                                //duringDataLoad is important to EndLoadData and
                                //for not throwing unexpected exceptions.
                                this._duringDataLoad = true;
+                               this._nullConstraintViolationDuringDataLoad = false;
                        
                                if (this.dataSet != null)
                                {
@@ -608,10 +643,11 @@ namespace System.Data {
                        //       have enforced child relations 
                        //       that would result in child rows being orphaned
                        // now we check if any ForeignKeyConstraint is referncing 'table'.
-                       if (DataSet._xmlDataDocument != null) 
-                               throw new NotSupportedException ("Clear function on dataset and datatable is not supported on XmlDataDocument.");
                        if (DataSet != null)
                        {
+                               if (DataSet._xmlDataDocument != null) 
+                                       throw new NotSupportedException ("Clear function on dataset and datatable is not supported on XmlDataDocument.");
+
                                IEnumerator tableEnumerator = DataSet.Tables.GetEnumerator();
                        
                                // loop on all tables in dataset
@@ -700,11 +736,13 @@ namespace System.Data {
                        // Copy.DefaultView
                        // Copy.DesignMode
                        Copy.DisplayExpression = DisplayExpression;
-                       //  Cannot copy extended properties directly as the property does not have a set accessor
-                       Array tgtArray = Array.CreateInstance( typeof (object), ExtendedProperties.Count);
-                       ExtendedProperties.Keys.CopyTo (tgtArray, 0);
-                       for (int i=0; i < ExtendedProperties.Count; i++)
-                               Copy.ExtendedProperties.Add (tgtArray.GetValue (i), ExtendedProperties[tgtArray.GetValue (i)]);
+                       if(ExtendedProperties.Count > 0) {
+                               //  Cannot copy extended properties directly as the property does not have a set accessor
+                               Array tgtArray = Array.CreateInstance( typeof (object), ExtendedProperties.Count);
+                               ExtendedProperties.Keys.CopyTo (tgtArray, 0);
+                               for (int i=0; i < ExtendedProperties.Count; i++)
+                                       Copy.ExtendedProperties.Add (tgtArray.GetValue (i), ExtendedProperties[tgtArray.GetValue (i)]);
+                       }
                        Copy.Locale = Locale;
                        Copy.MinimumCapacity = MinimumCapacity;
                        Copy.Namespace = Namespace;
@@ -759,6 +797,11 @@ namespace System.Data {
                [MonoTODO]
                public virtual void EndInit () 
                {
+                        _initStatus = initStatus.EndInit;
+                        // Add the constraints
+                        PostEndInit _postEndInit = new PostEndInit (_constraintCollection.PostEndInit);
+                        _postEndInit();
+
 
                }
 
@@ -781,14 +824,12 @@ namespace System.Data {
                                        //Getting back to the table's previous EnforceConstraint state
                                        this.EnforceConstraints = this.dataTablePrevEnforceConstraints;
                                }
-                               for (i=0 ; i<this.Rows.Count ; i++)
-                               {
-                                       if (this.Rows[i]._nullConstraintViolation )
-                                       {
-                                               throw new ConstraintException ("Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints.");
-                                       }
-                                               
+
+                               if(this._nullConstraintViolationDuringDataLoad) {
+                                       this._nullConstraintViolationDuringDataLoad = false;
+                                       throw new ConstraintException ("Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints.");
                                }
+
                                //Returning from loading mode, raising exceptions as usual
                                this._duringDataLoad = false;
 
@@ -832,7 +873,7 @@ namespace System.Data {
                        return copyTable;
                }
 
-#if NET_1_2
+#if NET_2_0
                [MonoTODO]
                public DataTableReader GetDataReader ()
                {
@@ -926,7 +967,7 @@ namespace System.Data {
                        info.AddValue ("XmlDiffGram", sw.ToString(), typeof(string));
                }
 
-#if NET_1_2
+#if NET_2_0
                [MonoTODO]
                public void Load (IDataReader reader)
                {
@@ -981,7 +1022,7 @@ namespace System.Data {
                        return row;
                }
 
-#if NET_1_2
+#if NET_2_0
                [MonoTODO]
                public DataRow LoadDataRow (object[] values, LoadOption loadOption)
                {
@@ -1040,7 +1081,7 @@ namespace System.Data {
                
                
 
-#if NET_1_2
+#if NET_2_0
                [MonoTODO]
                XmlReadMode ReadXml (Stream stream)
                {
@@ -1175,7 +1216,7 @@ namespace System.Data {
                                if (sortableColumns.Length == 0)
                                        throw new Exception("sort expression result is 0");
 
-                               RowSorter rowSorter = new RowSorter (dataRows, sortableColumns);
+                               RowSorter rowSorter = new RowSorter (this, dataRows, sortableColumns);
                                dataRows = rowSorter.SortRows ();
 
                                sortableColumns = null;
@@ -1294,7 +1335,7 @@ namespace System.Data {
                        return retVal;
                }
 
-#if NET_1_2
+#if NET_2_0
                [MonoTODO]
                public void WriteXml (Stream stream)
                {
@@ -1408,6 +1449,7 @@ namespace System.Data {
                        //      {
                        //              RemoveColumn(this, e);
                        //      }
+                       this.Rows.onColumnRemoved(column.Ordinal);
                }
 
                /// <summary>
@@ -1555,7 +1597,7 @@ namespace System.Data {
                                        string columnName = columnSortInfo[0].Trim ();
                                        string sortOrder = "ASC";
                                        if (columnSortInfo.Length > 1) 
-                                               sortOrder = columnSortInfo[1].Trim ().ToUpper ();
+                                               sortOrder = columnSortInfo[1].Trim ().ToUpper (Locale);
                                        
                                        ListSortDirection sortDirection = ListSortDirection.Ascending;
                                        switch (sortOrder) {
@@ -1615,12 +1657,15 @@ namespace System.Data {
 
                private class RowSorter : IComparer 
                {
+                       private DataTable table;
                        private SortableColumn[] sortColumns;
                        private DataRow[] rowsToSort;
                        
-                       internal RowSorter(DataRow[] unsortedRows, 
+                       internal RowSorter(DataTable table,
+                                       DataRow[] unsortedRows, 
                                        SortableColumn[] sortColumns) 
                        {
+                               this.table = table;
                                this.sortColumns = sortColumns;
                                this.rowsToSort = unsortedRows;
                        }
@@ -1685,8 +1730,8 @@ namespace System.Data {
                                        return 1;
 
                                if((a is string) && (b is string)) {
-                                       a = ((string) a).ToUpper ();
-                                       b = ((string) b).ToUpper ();                    
+                                       a = ((string) a).ToUpper (table.Locale);
+                                       b = ((string) b).ToUpper (table.Locale);                        
                                }
 
                                if (a is IComparable)