DataTable.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Data / System / Data / DataTable.cs / 1305376 / DataTable.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
//----------------------------------------------------------------------------- 
 
namespace System.Data {
    using System; 
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Diagnostics; 
    using System.Globalization;
    using System.IO; 
    using System.Runtime.Serialization; 
    using System.Text;
    using System.Threading; 
    using System.Xml;
    using System.Xml.Schema;
    using System.Xml.Serialization;
    using System.Data.Common; 
    using System.Runtime.Versioning;
 
    ///  
    ///    Represents one table of in-memory data.
    ///  
    [
    ToolboxItem(false),
    DesignTimeVisible(false),
    DefaultProperty("TableName"), 
    Editor("Microsoft.VSDesigner.Data.Design.DataTableEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing),
    DefaultEvent("RowChanging"), 
    XmlSchemaProvider("GetDataTableSchema"), 
    Serializable
    ] 
    public class DataTable : MarshalByValueComponent, System.ComponentModel.IListSource, ISupportInitializeNotification, ISerializable, IXmlSerializable{
        private DataSet dataSet;
        private DataView defaultView = null;
 
        // rows
        ///  
        /// Monotonically increasing number representing the order  have been added to . 
        /// 
        /// This limits  to  operations. 
        internal long nextRowID;
        internal readonly DataRowCollection rowCollection;

        // columns 
        internal readonly DataColumnCollection columnCollection;
 
        // constraints 
        private readonly ConstraintCollection constraintCollection;
 
        //SimpleContent implementation
        private int elementColumnCount = 0;

        // relations 
        internal DataRelationCollection parentRelationsCollection;
        internal DataRelationCollection childRelationsCollection; 
 
        // RecordManager
        internal readonly RecordManager recordManager; 

        // index mgmt
        internal readonly List indexes;
 
        private List shadowIndexes;
        private int shadowCount; 
 
        // props
        internal PropertyCollection extendedProperties = null; 
        private string tableName = "";
        internal string tableNamespace = null;
        private string tablePrefix = "";
        internal DataExpression displayExpression; 
        internal bool fNestedInDataset = true;
 
        // globalization stuff 
        private CultureInfo _culture;
        private bool _cultureUserSet; 
        private CompareInfo _compareInfo;
        private CompareOptions _compareFlags = CompareOptions.IgnoreCase | CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth;
        private IFormatProvider _formatProvider;
        private StringComparer _hashCodeProvider; 
        private bool _caseSensitive;
        private bool _caseSensitiveUserSet; 
 
        // XML properties
        internal string encodedTableName;           // For XmlDataDocument only 
        internal DataColumn xmlText;            // text values of a complex xml element
        internal DataColumn _colUnique;
        internal bool textOnly = false;         // the table has only text value with possible attributes
        internal decimal minOccurs = 1;    // default = 1 
        internal decimal maxOccurs = 1;    // default = 1
        internal bool repeatableElement = false; 
        private object typeName = null; 

        // primary key info 
        private readonly static Int32[] zeroIntegers = new Int32[0];
        internal readonly static DataColumn[] zeroColumns = new DataColumn[0];
        internal readonly static DataRow[] zeroRows = new DataRow[0];
        internal UniqueConstraint primaryKey; 
        internal readonly static IndexField[] zeroIndexField = new IndexField[0];
        internal IndexField[] _primaryIndex = zeroIndexField; 
        private DataColumn[] delayedSetPrimaryKey = null; 

        // Loading Schema and/or Data related optimization 
        private Index loadIndex;
        private Index loadIndexwithOriginalAdded = null;
        private Index loadIndexwithCurrentDeleted = null;
        private int _suspendIndexEvents; 

        private bool savedEnforceConstraints = false; 
        private bool inDataLoad = false; 
        private bool initialLoad;
        private bool schemaLoading = false; 
        private bool enforceConstraints = true;
        internal bool _suspendEnforceConstraints = false;

        protected internal bool fInitInProgress = false; 
        private bool inLoad = false;
        internal bool fInLoadDiffgram = false; 
 
        private byte _isTypedDataTable; // 0 == unknown, 1 = yes, 2 = No
        private DataRow[] EmptyDataRowArray; 


        // Property Descriptor Cache for DataBinding
        private PropertyDescriptorCollection propertyDescriptorCollectionCache = null; 

        // Cache for relation that has this table as nested child table. 
        private static readonly DataRelation[] EmptyArrayDataRelation = new DataRelation[0]; 
        private DataRelation[] _nestedParentRelations = EmptyArrayDataRelation;
 
        // Dependent column list for expression evaluation
        internal List dependentColumns = null;

        // events 
        private bool mergingData = false;
        private DataRowChangeEventHandler onRowChangedDelegate; 
        private DataRowChangeEventHandler onRowChangingDelegate; 
        private DataRowChangeEventHandler onRowDeletingDelegate;
        private DataRowChangeEventHandler onRowDeletedDelegate; 
        private DataColumnChangeEventHandler onColumnChangedDelegate;
        private DataColumnChangeEventHandler onColumnChangingDelegate;

        private DataTableClearEventHandler onTableClearingDelegate; 
        private DataTableClearEventHandler onTableClearedDelegate;
        private DataTableNewRowEventHandler onTableNewRowDelegate; 
 
        private PropertyChangedEventHandler onPropertyChangingDelegate;
 
        private System.EventHandler  onInitialized;


        // misc 
        private readonly DataRowBuilder rowBuilder;
        private const String KEY_XMLSCHEMA = "XmlSchema"; 
        private const String KEY_XMLDIFFGRAM = "XmlDiffGram"; 
        private const String KEY_NAME = "TableName";
 
        internal readonly List delayedViews = new List();
        private readonly List _dataViewListeners = new List();

//        private bool serializeHierarchy = false; 
        internal Hashtable rowDiffId = null;
        internal readonly ReaderWriterLock indexesLock = new ReaderWriterLock(); 
        internal int ukColumnPositionForInference= -1; 

        // default remoting format is Xml 
        private SerializationFormat _remotingFormat = SerializationFormat.Xml;

        private static int _objectTypeCount; // Bid counter
        private readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount); 

        ///  
        /// Initializes a new instance of the  class with no arguments. 
        /// 
        public DataTable() { 
            GC.SuppressFinalize(this);
            Bid.Trace(" %d#\n", ObjectID);
            nextRowID = 1;
            recordManager = new RecordManager(this); 

            _culture = CultureInfo.CurrentCulture; 
            this.columnCollection = new DataColumnCollection(this); 
            this.constraintCollection = new ConstraintCollection(this);
            this.rowCollection = new DataRowCollection(this); 
            this.indexes = new List();

            rowBuilder = new DataRowBuilder(this, -1);
        } 

        ///  
        /// Intitalizes a new instance of the  class with the specified table 
        ///    name.
        ///  
        public DataTable(string tableName) : this() {
            this.tableName = tableName == null ? "" : tableName;
        }
 
        public DataTable(string tableName, string tableNamespace) : this(tableName) {
            this.Namespace = tableNamespace; 
        } 

//        Deserialize the table from binary/xml stream. 
        protected DataTable(SerializationInfo info, StreamingContext context) : this()
        {
            bool isSingleTable = context.Context != null ? Convert.ToBoolean(context.Context, CultureInfo.InvariantCulture) : true;
            SerializationFormat remotingFormat = SerializationFormat.Xml; 
            SerializationInfoEnumerator e = info.GetEnumerator();
            while (e.MoveNext()) { 
                switch(e.Name) { 
                    case "DataTable.RemotingFormat" : //DataTable.RemotingFormat does not exist in V1/V1.1 versions
                    remotingFormat = (SerializationFormat)e.Value; 
                    break;
                }
            }
 
            DeserializeDataTable(info, context, isSingleTable, remotingFormat);
        } 
 
        [System.Security.Permissions.SecurityPermissionAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Flags=System.Security.Permissions.SecurityPermissionFlag.SerializationFormatter)]
        public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { 
            SerializationFormat remotingFormat = RemotingFormat;
            bool isSingleTable = context.Context != null ? Convert.ToBoolean(context.Context, CultureInfo.InvariantCulture) : true;
            SerializeDataTable(info, context, isSingleTable, remotingFormat);
        } 

//        Serialize the table schema and data. 
        private void SerializeDataTable(SerializationInfo info, StreamingContext context, bool isSingleTable, SerializationFormat remotingFormat) { 
            info.AddValue("DataTable.RemotingVersion", new Version(2, 0));
 
            // SqlHotFix 299, SerializationFormat enumeration types don't exist in V1.1 SP1
            if (SerializationFormat.Xml != remotingFormat) {
                info.AddValue("DataTable.RemotingFormat", remotingFormat);
            } 

            if (remotingFormat != SerializationFormat.Xml) {//Binary 
                SerializeTableSchema(info, context, isSingleTable); 
                if (isSingleTable) {
                    SerializeTableData(info, context, 0); 
                }
            } else {//XML/V1.0/V1.1
                string tempDSNamespace = "";
                Boolean fCreatedDataSet = false; 

                if (dataSet == null) { 
                    DataSet ds = new DataSet("tmpDataSet"); 
                    // if user set values on DataTable, it isn't necessary
                    // to set them on the DataSet because they won't be inherited 
                    // but it is simpler to set them in both places

                    // if user did not set values on DataTable, it is required
                    // to set them on the DataSet so the table will inherit 
                    // the value already on the Datatable
                    ds.SetLocaleValue(_culture, _cultureUserSet); 
                    ds.CaseSensitive = this.CaseSensitive; 
                    ds.namespaceURI  = this.Namespace;
                    Debug.Assert(ds.RemotingFormat == SerializationFormat.Xml, "RemotingFormat must be SerializationFormat.Xml"); 
                    ds.Tables.Add(this);
                    fCreatedDataSet = true;
                } else {
                    tempDSNamespace = this.DataSet.Namespace; 
                    this.DataSet.namespaceURI = this.Namespace; //this.DataSet.Namespace = this.Namespace; ??
                } 
 
                info.AddValue(KEY_XMLSCHEMA, dataSet.GetXmlSchemaForRemoting(this));
                info.AddValue(KEY_XMLDIFFGRAM, dataSet.GetRemotingDiffGram(this)); 

                if (fCreatedDataSet) {
                    dataSet.Tables.Remove(this);
                } 
                else{
                    dataSet.namespaceURI  = tempDSNamespace; 
                } 
            }
        } 

//        Deserialize the table schema and data.
        internal void DeserializeDataTable(SerializationInfo info, StreamingContext context, bool isSingleTable, SerializationFormat remotingFormat) {
            if (remotingFormat != SerializationFormat.Xml) {//Binary 
                DeserializeTableSchema(info, context, isSingleTable);
                if (isSingleTable) { 
                    DeserializeTableData(info, context, 0); 
                    this.ResetIndexes();
                } 
            } else {//XML/V1.0/V1.1
                string strSchema = (String)info.GetValue(KEY_XMLSCHEMA, typeof(System.String));
                string strData = (String)info.GetValue(KEY_XMLDIFFGRAM, typeof(System.String));
 
                if (strSchema != null) {
                    DataSet ds = new DataSet(); 
                    // fxcop: ReadXmlSchema will provide the CaseSensitive, Locale, Namespace information 
                    ds.ReadXmlSchema(new XmlTextReader( new StringReader( strSchema ) ) );
 
                    Debug.Assert(ds.Tables.Count == 1, "There should be exactly 1 table here");
                    DataTable table = ds.Tables[0];
                    table.CloneTo(this, null, false);// WebData 111656
                    //this is to avoid the cascading rules in the namespace 
                    this.Namespace = table.Namespace;
 
                    if (strData != null) { 
                        ds.Tables.Remove(ds.Tables[0]);
                        ds.Tables.Add(this); 
                        ds.ReadXml(new XmlTextReader( new StringReader( strData ) ), XmlReadMode.DiffGram);
                        ds.Tables.Remove(this);
                    }
                } 
            }
        } 
 
//        Serialize the columns
        internal void SerializeTableSchema(SerializationInfo info, StreamingContext context, bool isSingleTable) { 
            //DataTable basic  properties
            info.AddValue("DataTable.TableName", TableName);
            info.AddValue("DataTable.Namespace", Namespace);
            info.AddValue("DataTable.Prefix", Prefix); 
            info.AddValue("DataTable.CaseSensitive", _caseSensitive);
            info.AddValue("DataTable.caseSensitiveAmbient", !_caseSensitiveUserSet); 
            info.AddValue("DataTable.LocaleLCID", Locale.LCID); 
            info.AddValue("DataTable.MinimumCapacity", recordManager.MinimumCapacity);
            //info.AddValue("DataTable.DisplayExpression", DisplayExpression); 

            //DataTable state internal properties
            info.AddValue("DataTable.NestedInDataSet", fNestedInDataset);
            info.AddValue("DataTable.TypeName", TypeName.ToString()); 
            info.AddValue("DataTable.RepeatableElement", repeatableElement);
 
 
            //ExtendedProperties
            info.AddValue("DataTable.ExtendedProperties", ExtendedProperties); 

            //Columns
            info.AddValue("DataTable.Columns.Count", Columns.Count);
 
            //Check for closure of expression in case of single table.
            if (isSingleTable) { 
                List list = new List(); 
                list.Add(this);
                if (!CheckForClosureOnExpressionTables(list)) 
                    throw ExceptionBuilder.CanNotRemoteDataTable();
            }

            IFormatProvider formatProvider = CultureInfo.InvariantCulture; 
            for (int i = 0; i < Columns.Count; i++) {
                //DataColumn basic properties 
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.ColumnName", i), Columns[i].ColumnName); 
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.Namespace", i), Columns[i]._columnUri);
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.Prefix", i), Columns[i].Prefix); 
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.ColumnMapping", i), Columns[i].ColumnMapping);
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.AllowDBNull", i), Columns[i].AllowDBNull);
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.AutoIncrement", i), Columns[i].AutoIncrement);
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.AutoIncrementStep", i), Columns[i].AutoIncrementStep); 
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.AutoIncrementSeed", i), Columns[i].AutoIncrementSeed);
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.Caption", i), Columns[i].Caption); 
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.DefaultValue", i), Columns[i].DefaultValue); 
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.ReadOnly", i), Columns[i].ReadOnly);
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.MaxLength", i), Columns[i].MaxLength); 
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.DataType", i), Columns[i].DataType);

                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.XmlDataType", i), Columns[i].XmlDataType);
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.SimpleType", i), Columns[i].SimpleType); 

                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.DateTimeMode", i), Columns[i].DateTimeMode); 
 
                //DataColumn internal state properties
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.AutoIncrementCurrent", i), Columns[i].AutoIncrementCurrent); 

                //Expression
                if (isSingleTable) {
                    info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.Expression", i), Columns[i].Expression); 
                }
 
                //ExtendedProperties 
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.ExtendedProperties", i), Columns[i].extendedProperties);
            } 

            //Constraints
            if (isSingleTable) {
                SerializeConstraints(info, context, 0, false); 
            }
        } 
 
//        Deserialize all the Columns
        internal void DeserializeTableSchema(SerializationInfo info, StreamingContext context, bool isSingleTable) { 
            //DataTable basic properties
            tableName = info.GetString("DataTable.TableName");
            tableNamespace = info.GetString("DataTable.Namespace");
            tablePrefix = info.GetString("DataTable.Prefix"); 

            bool caseSensitive = info.GetBoolean("DataTable.CaseSensitive"); 
            SetCaseSensitiveValue(caseSensitive, true, false); 
            _caseSensitiveUserSet = !info.GetBoolean("DataTable.caseSensitiveAmbient");
 
            int lcid = (int)info.GetValue("DataTable.LocaleLCID", typeof(int));
            CultureInfo culture = new CultureInfo(lcid);
            SetLocaleValue(culture, true, false);
            _cultureUserSet = true; 

 
            MinimumCapacity = info.GetInt32("DataTable.MinimumCapacity"); 
            //DisplayExpression = info.GetString("DataTable.DisplayExpression");
 
            //DataTable state internal properties
            fNestedInDataset = (bool) info.GetBoolean("DataTable.NestedInDataSet");
            string tName = info.GetString("DataTable.TypeName");
            typeName =  new XmlQualifiedName(tName); 
            repeatableElement = info.GetBoolean("DataTable.RepeatableElement");
 
            //ExtendedProperties 
            extendedProperties = (PropertyCollection) info.GetValue("DataTable.ExtendedProperties", typeof(PropertyCollection));
 
            //Columns
            int colCount = info.GetInt32("DataTable.Columns.Count");
            string [] expressions = new string[colCount];
            Debug.Assert(Columns.Count == 0, "There is column in Table"); 

            IFormatProvider formatProvider = CultureInfo.InvariantCulture; 
            for (int i = 0; i < colCount; i++) { 
                DataColumn dc = new DataColumn();
 
                //DataColumn public state properties
                dc.ColumnName = info.GetString(String.Format(formatProvider, "DataTable.DataColumn_{0}.ColumnName", i));
                dc._columnUri = info.GetString(String.Format(formatProvider, "DataTable.DataColumn_{0}.Namespace", i));
                dc.Prefix = info.GetString(String.Format(formatProvider, "DataTable.DataColumn_{0}.Prefix", i)); 

                dc.DataType = (Type) info.GetValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.DataType", i), typeof(Type)); 
                dc.XmlDataType = (string) info.GetValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.XmlDataType", i), typeof(string)); 
                dc.SimpleType = (SimpleType) info.GetValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.SimpleType", i), typeof(SimpleType));
 
                dc.ColumnMapping = (MappingType) info.GetValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.ColumnMapping", i), typeof(MappingType));
                dc.DateTimeMode = (DataSetDateTime) info.GetValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.DateTimeMode", i), typeof(DataSetDateTime));

                dc.AllowDBNull = info.GetBoolean(String.Format(formatProvider, "DataTable.DataColumn_{0}.AllowDBNull", i)); 
                dc.AutoIncrement = info.GetBoolean(String.Format(formatProvider, "DataTable.DataColumn_{0}.AutoIncrement", i));
                dc.AutoIncrementStep = info.GetInt64(String.Format(formatProvider, "DataTable.DataColumn_{0}.AutoIncrementStep", i)); 
                dc.AutoIncrementSeed = info.GetInt64(String.Format(formatProvider, "DataTable.DataColumn_{0}.AutoIncrementSeed", i)); 
                dc.Caption = info.GetString(String.Format(formatProvider, "DataTable.DataColumn_{0}.Caption", i));
                dc.DefaultValue = info.GetValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.DefaultValue", i), typeof(object)); 
                dc.ReadOnly = info.GetBoolean(String.Format(formatProvider, "DataTable.DataColumn_{0}.ReadOnly", i));
                dc.MaxLength= info.GetInt32(String.Format(formatProvider, "DataTable.DataColumn_{0}.MaxLength", i));

                //DataColumn internal state properties 
                dc.AutoIncrementCurrent = info.GetValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.AutoIncrementCurrent", i), typeof(object));
 
                //Expression 
                if (isSingleTable) {
                    expressions[i] = info.GetString(String.Format(formatProvider, "DataTable.DataColumn_{0}.Expression", i)); 
                }

                //ExtendedProperties
                dc.extendedProperties = (PropertyCollection) info.GetValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.ExtendedProperties", i), typeof(PropertyCollection)); 
                Columns.Add(dc);
            } 
            if (isSingleTable) { 
                for(int i = 0; i < colCount; i++) {
                    if (expressions[i] != null) { 
                        Columns[i].Expression = expressions[i];
                    }
                }
            } 

            //Constraints 
            if (isSingleTable) { 
                DeserializeConstraints(info, context, /*table index */ 0, /* serialize all constraints */false);// since single table, send table index as 0, meanwhile passing
                // false for 'allConstraints' means, handle all the constraint related to the table 
            }
        }

/* 
        Serialize constraints availabe on the table - note this function is marked internal because it is called by the DataSet deserializer.
        ***Schema for Serializing ArrayList of Constraints*** 
        Unique Constraint - ["U"]->[constraintName]->[columnIndexes]->[IsPrimaryKey]->[extendedProperties] 
        Foriegn Key Constraint - ["F"]->[constraintName]->[parentTableIndex, parentcolumnIndexes]->[childTableIndex, childColumnIndexes]->[AcceptRejectRule, UpdateRule, DeleteRule]->[extendedProperties]
*/ 
        internal void SerializeConstraints(SerializationInfo info, StreamingContext context, int serIndex, bool allConstraints) {
            if (allConstraints) {
                Debug.Assert(DataSet != null);
            } 

            ArrayList constraintList = new ArrayList(); 
 
            for (int i = 0; i < Constraints.Count; i++) {
                Constraint c = Constraints[i]; 

                UniqueConstraint uc = c as UniqueConstraint;
                if (uc != null) {
                    int[] colInfo = new int[uc.Columns.Length]; 
                    for (int j = 0; j < colInfo.Length; j++) {
                        colInfo[j] = uc.Columns[j].Ordinal; 
                    } 

                    ArrayList list = new ArrayList(); 
                    list.Add("U");
                    list.Add(uc.ConstraintName);
                    list.Add(colInfo);
                    list.Add(uc.IsPrimaryKey); 
                    list.Add(uc.ExtendedProperties);
 
                    constraintList.Add(list); 
                } else {
                    ForeignKeyConstraint fk = c as ForeignKeyConstraint; 
                    Debug.Assert(fk != null);
                    bool shouldSerialize = (allConstraints == true) || (fk.Table == this && fk.RelatedTable == this);

                    if (shouldSerialize) { 
                        int[] parentInfo = new int[fk.RelatedColumns.Length + 1];
                        parentInfo[0] = allConstraints ? this.DataSet.Tables.IndexOf(fk.RelatedTable) : 0; 
                        for (int j = 1; j < parentInfo.Length; j++) { 
                            parentInfo[j] = fk.RelatedColumns[j - 1].Ordinal;
                        } 

                        int[] childInfo = new int[fk.Columns.Length + 1];
                        childInfo[0] = allConstraints ? this.DataSet.Tables.IndexOf(fk.Table) : 0 ;   //Since the constraint is on the current table, this is the child table.
                        for (int j = 1; j < childInfo.Length; j++) { 
                            childInfo[j] = fk.Columns[j - 1].Ordinal;
                        } 
 
                        ArrayList list = new ArrayList();
                        list.Add("F"); 
                        list.Add(fk.ConstraintName);
                        list.Add(parentInfo);
                        list.Add(childInfo);
                        list.Add(new int[] { (int) fk.AcceptRejectRule, (int) fk.UpdateRule, (int) fk.DeleteRule }); 
                        list.Add(fk.ExtendedProperties);
 
                        constraintList.Add(list); 
                    }
                } 
            }
            info.AddValue(String.Format(CultureInfo.InvariantCulture, "DataTable_{0}.Constraints", serIndex), constraintList);
        }
 
/*
        Deserialize the constraints on the table. 
        ***Schema for Serializing ArrayList of Constraints*** 
        Unique Constraint - ["U"]->[constraintName]->[columnIndexes]->[IsPrimaryKey]->[extendedProperties]
        Foriegn Key Constraint - ["F"]->[constraintName]->[parentTableIndex, parentcolumnIndexes]->[childTableIndex, childColumnIndexes]->[AcceptRejectRule, UpdateRule, DeleteRule]->[extendedProperties] 
*/
        internal void DeserializeConstraints(SerializationInfo info, StreamingContext context, int serIndex, bool allConstraints) {
            ArrayList constraintList = (ArrayList) info.GetValue(String.Format(CultureInfo.InvariantCulture, "DataTable_{0}.Constraints", serIndex), typeof(ArrayList));
 
            foreach (ArrayList list in constraintList) {
                string con = (string) list[0]; 
 
                if (con.Equals("U")) { //Unique Constraints
                    string constraintName = (string) list[1]; 

                    int[] keyColumnIndexes = (int[]) list[2];
                    bool isPrimaryKey = (bool) list[3];
                    PropertyCollection extendedProperties = (PropertyCollection) list[4]; 

                    DataColumn[] keyColumns = new DataColumn[keyColumnIndexes.Length]; 
                    for (int i = 0; i < keyColumnIndexes.Length; i++) { 
                        keyColumns[i] = Columns[keyColumnIndexes[i]];
                    } 

                    //Create the constraint.
                    UniqueConstraint uc = new UniqueConstraint(constraintName, keyColumns, isPrimaryKey);
                    uc.extendedProperties = extendedProperties; 

                    //Add the unique constraint and it will in turn set the primary keys also if needed. 
                    Constraints.Add(uc); 
                } else { //ForeignKeyConstraints
                    Debug.Assert(con.Equals("F")); 

                    string constraintName = (string) list[1];
                    int[] parentInfo = (int[]) list[2];
                    int[] childInfo = (int[]) list[3]; 
                    int[] rules = (int[]) list[4];
                    PropertyCollection extendedProperties = (PropertyCollection) list[5]; 
 
                    //ParentKey Columns.
                    DataTable parentTable = (allConstraints == false) ? this : this.DataSet.Tables[parentInfo[0]]; 
                    DataColumn[] parentkeyColumns = new DataColumn[parentInfo.Length - 1];
                    for (int i = 0; i < parentkeyColumns.Length; i++) {
                        parentkeyColumns[i] = parentTable.Columns[parentInfo[i + 1]];
                    } 

                    //ChildKey Columns. 
                    DataTable childTable = (allConstraints == false) ? this : this.DataSet.Tables[childInfo[0]]; 
                    DataColumn[] childkeyColumns = new DataColumn[childInfo.Length - 1];
                    for (int i = 0; i < childkeyColumns.Length; i++) { 
                        childkeyColumns[i] = childTable.Columns[childInfo[i + 1]];
                    }

                    //Create the Constraint. 
                    ForeignKeyConstraint fk = new ForeignKeyConstraint(constraintName, parentkeyColumns, childkeyColumns);
                    fk.AcceptRejectRule = (AcceptRejectRule) rules[0]; 
                    fk.UpdateRule = (Rule) rules[1]; 
                    fk.DeleteRule = (Rule) rules[2];
                    fk.extendedProperties = extendedProperties; 

                    //Add just the foreign key constraint without creating unique constraint.
                    Constraints.Add(fk, false);
                } 
            }
        } 
 
//        Serialize the expressions on the table - Marked internal so that DataSet deserializer can call into this
        internal void SerializeExpressionColumns(SerializationInfo info, StreamingContext context, int serIndex) { 
            int colCount = Columns.Count;
            for (int i = 0; i < colCount; i++) {
                info.AddValue(String.Format(CultureInfo.InvariantCulture, "DataTable_{0}.DataColumn_{1}.Expression", serIndex, i), Columns[i].Expression);
            } 
        }
 
//        Deserialize the expressions on the table - Marked internal so that DataSet deserializer can call into this 
        internal void DeserializeExpressionColumns(SerializationInfo info, StreamingContext context, int serIndex) {
            int colCount = Columns.Count; 
            for (int i = 0; i < colCount; i++) {
                string expr = info.GetString(String.Format(CultureInfo.InvariantCulture, "DataTable_{0}.DataColumn_{1}.Expression", serIndex, i));
                if (0 != expr.Length) {
                    Columns[i].Expression = expr; 
                }
            } 
        } 

//        Serialize all the Rows. 
        internal void SerializeTableData(SerializationInfo info, StreamingContext context, int serIndex) {
            //Cache all the column count, row count
            int colCount = Columns.Count;
            int rowCount = Rows.Count; 
            int modifiedRowCount = 0;
            int editRowCount = 0; 
 
            //Compute row states and assign the bits accordingly - 00[Unchanged], 01[Added], 10[Modifed], 11[Deleted]
            BitArray rowStates = new BitArray(rowCount * 3, false); //All bit flags are set to false on initialization of the BitArray. 
            for (int i = 0; i < rowCount; i++) {
                int bitIndex = i * 3;
                DataRow row = Rows[i];
                DataRowState rowState = row.RowState; 
                switch (rowState) {
                    case DataRowState.Unchanged: 
                        //rowStates[bitIndex] = false; 
                        //rowStates[bitIndex + 1] = false;
                        break; 
                    case DataRowState.Added:
                        //rowStates[bitIndex] = false;
                        rowStates[bitIndex + 1] = true;
                        break; 
                    case DataRowState.Modified:
                        rowStates[bitIndex] = true; 
                        //rowStates[bitIndex + 1] = false; 
                        modifiedRowCount++;
                        break; 
                    case DataRowState.Deleted:
                        rowStates[bitIndex] = true;
                        rowStates[bitIndex + 1] = true;
                        break; 
                    default:
                        throw ExceptionBuilder.InvalidRowState(rowState); 
                } 
                if (-1 != row.tempRecord) {
                    rowStates[bitIndex + 2] = true; 
                    editRowCount++;
                }
            }
 
            //Compute the actual storage records that need to be created.
            int recordCount = rowCount + modifiedRowCount + editRowCount; 
 
            //Create column storages.
            ArrayList storeList = new ArrayList(); 
            ArrayList nullbitList = new ArrayList();
            if (recordCount > 0) { //Create the storage only if have records.
                for (int i = 0; i < colCount; i++) {
                    object store = Columns[i].GetEmptyColumnStore(recordCount); 
                    storeList.Add(store);
                    BitArray nullbits = new BitArray(recordCount); 
                    nullbitList.Add(nullbits); 
                }
            } 

            //Copy values into column storages
            int recordsConsumed = 0;
            Hashtable rowErrors = new Hashtable(); 
            Hashtable colErrors = new Hashtable();
            for (int i = 0; i < rowCount; i++) { 
                int recordsPerRow = Rows[i].CopyValuesIntoStore(storeList, nullbitList, recordsConsumed); 
                GetRowAndColumnErrors(i, rowErrors, colErrors);
                recordsConsumed += recordsPerRow; 
            }

            IFormatProvider formatProvider = CultureInfo.InvariantCulture;
            //Serialize all the computed values. 
            info.AddValue(String.Format(formatProvider, "DataTable_{0}.Rows.Count", serIndex), rowCount);
            info.AddValue(String.Format(formatProvider, "DataTable_{0}.Records.Count", serIndex), recordCount); 
            info.AddValue(String.Format(formatProvider, "DataTable_{0}.RowStates", serIndex), rowStates); 
            info.AddValue(String.Format(formatProvider, "DataTable_{0}.Records", serIndex), storeList);
            info.AddValue(String.Format(formatProvider, "DataTable_{0}.NullBits", serIndex), nullbitList); 
            info.AddValue(String.Format(formatProvider, "DataTable_{0}.RowErrors", serIndex), rowErrors);
            info.AddValue(String.Format(formatProvider, "DataTable_{0}.ColumnErrors", serIndex), colErrors);
        }
 
//        Deserialize all the Rows.
        internal void DeserializeTableData(SerializationInfo info, StreamingContext context, int serIndex) { 
            bool enforceConstraintsOrg = enforceConstraints; 
            bool inDataLoadOrg = inDataLoad;
 

            try {
                enforceConstraints = false;
                inDataLoad = true; 
                IFormatProvider formatProvider = CultureInfo.InvariantCulture;
                int rowCount = info.GetInt32(String.Format(formatProvider, "DataTable_{0}.Rows.Count", serIndex)); 
                int recordCount = info.GetInt32(String.Format(formatProvider, "DataTable_{0}.Records.Count", serIndex)); 
                BitArray rowStates = (BitArray) info.GetValue(String.Format(formatProvider, "DataTable_{0}.RowStates", serIndex), typeof(BitArray));
                ArrayList storeList = (ArrayList) info.GetValue(String.Format(formatProvider, "DataTable_{0}.Records", serIndex), typeof(ArrayList)); 
                ArrayList nullbitList = (ArrayList) info.GetValue(String.Format(formatProvider, "DataTable_{0}.NullBits", serIndex), typeof(ArrayList));
                Hashtable rowErrors = (Hashtable) info.GetValue(String.Format(formatProvider, "DataTable_{0}.RowErrors", serIndex), typeof(Hashtable));
                rowErrors.OnDeserialization(this);//OnDeSerialization must be called since the hashtable gets deserialized after the whole graph gets deserialized
                Hashtable colErrors = (Hashtable) info.GetValue(String.Format(formatProvider, "DataTable_{0}.ColumnErrors", serIndex), typeof(Hashtable)); 
                colErrors.OnDeserialization(this);//OnDeSerialization must be called since the hashtable gets deserialized after the whole graph gets deserialized
 
 
                if (recordCount <= 0) { //No need for deserialization of the storage and errors if there are no records.
                    return; 
                }

                //Point the record manager storage to the deserialized values.
                for (int i = 0; i < Columns.Count; i++) { 
                    Columns[i].SetStorage(storeList[i], (BitArray) nullbitList[i]);
                } 
 
                //Create rows and set the records appropriately.
                int recordIndex = 0; 
                DataRow[] rowArr = new DataRow[recordCount];
                for (int i = 0; i < rowCount; i++) {
                    //Create a new row which sets old and new records to -1.
                    DataRow row = NewEmptyRow(); 
                    rowArr[recordIndex] = row;
                    int bitIndex = i * 3; 
                    switch (ConvertToRowState(rowStates, bitIndex)) { 
                        case DataRowState.Unchanged:
                            row.oldRecord = recordIndex; 
                            row.newRecord = recordIndex;
                            recordIndex += 1;
                            break;
                        case DataRowState.Added: 
                            row.oldRecord = -1;
                            row.newRecord = recordIndex; 
                            recordIndex += 1; 
                            break;
                        case DataRowState.Modified: 
                            row.oldRecord = recordIndex;
                            row.newRecord = recordIndex + 1;
                            rowArr[recordIndex + 1] = row;
                            recordIndex += 2; 
                            break;
                        case DataRowState.Deleted: 
                            row.oldRecord = recordIndex; 
                            row.newRecord = -1;
                            recordIndex += 1; 
                            break;
                    }
                    if (rowStates[bitIndex + 2]) {
                        row.tempRecord = recordIndex; 
                        rowArr[recordIndex] = row;
                        recordIndex += 1; 
                    } else { 
                        row.tempRecord = -1;
                    } 
                    Rows.ArrayAdd(row);
                    row.rowID = nextRowID;
                    nextRowID++;
                    ConvertToRowError(i, rowErrors, colErrors); 
                }
                recordManager.SetRowCache(rowArr); 
                ResetIndexes(); 
            } finally {
                enforceConstraints = enforceConstraintsOrg; 
                inDataLoad = inDataLoadOrg;
            }
        }
 
//        Constructs the RowState from the two bits in the bitarray.
        private DataRowState ConvertToRowState(BitArray bitStates, int bitIndex) { 
            Debug.Assert(bitStates != null); 
            Debug.Assert(bitStates.Length > bitIndex);
 
            bool b1 = bitStates[bitIndex];
            bool b2 = bitStates[bitIndex + 1];

            if (!b1 && !b2) { 
                return DataRowState.Unchanged;
            } else if (!b1 && b2) { 
                return DataRowState.Added; 
            } else if (b1 && !b2) {
                return DataRowState.Modified; 
            } else if (b1 && b2) {
                return DataRowState.Deleted;
            } else {
                throw ExceptionBuilder.InvalidRowBitPattern(); 
            }
        } 
 
//        Get the error on the row and columns - Marked internal so that DataSet deserializer can call into this
        internal void GetRowAndColumnErrors(int rowIndex, Hashtable rowErrors, Hashtable colErrors) { 
            Debug.Assert(Rows.Count > rowIndex);
            Debug.Assert(rowErrors != null);
            Debug.Assert(colErrors != null);
 
            DataRow row = Rows[rowIndex];
 
            if (row.HasErrors) { 
                rowErrors.Add(rowIndex, row.RowError);
                DataColumn[] dcArr = row.GetColumnsInError(); 
                if (dcArr.Length > 0) {
                    int[] columnsInError = new int[dcArr.Length];
                    string[] columnErrors = new string[dcArr.Length];
                    for (int i = 0; i < dcArr.Length; i++) { 
                        columnsInError[i] = dcArr[i].Ordinal;
                        columnErrors[i] = row.GetColumnError(dcArr[i]); 
                    } 
                    ArrayList list = new ArrayList();
                    list.Add(columnsInError); 
                    list.Add(columnErrors);
                    colErrors.Add(rowIndex, list);
                }
            } 
        }
 
//        Set the row and columns in error.. 
        private void ConvertToRowError(int rowIndex, Hashtable rowErrors, Hashtable colErrors) {
            Debug.Assert(Rows.Count > rowIndex); 
            Debug.Assert(rowErrors != null);
            Debug.Assert(colErrors != null);

            DataRow row = Rows[rowIndex]; 

            if (rowErrors.ContainsKey(rowIndex)) { 
                row.RowError = (string) rowErrors[rowIndex]; 
            }
            if (colErrors.ContainsKey(rowIndex)) { 
                ArrayList list = (ArrayList) colErrors[rowIndex];
                int[] columnsInError = (int[]) list[0];
                string[] columnErrors = (string[]) list[1];
                Debug.Assert(columnsInError.Length == columnErrors.Length); 
                for (int i = 0; i < columnsInError.Length; i++) {
                    row.SetColumnError(columnsInError[i], columnErrors[i]); 
                } 
            }
        } 

        /// 
        ///    Indicates whether string comparisons within the table are case-sensitive.
        ///  
        [ResDescriptionAttribute(Res.DataTableCaseSensitiveDescr)]
        public bool CaseSensitive { 
            get { 
                //The following assert is valid except when calling DataSet.set_CaseSensitive which Validates constraints and failing here
                //Debug.Assert(_caseSensitiveUserSet || (null == dataSet) || (dataSet.CaseSensitive == _caseSensitive), "CaseSensitive mismatch"); 
                return _caseSensitive;
            }
            set {
                if (_caseSensitive != value) { 
                    bool oldValue = _caseSensitive;
                    bool oldUserSet = _caseSensitiveUserSet; 
                    _caseSensitive = value; 
                    _caseSensitiveUserSet = true;
 
                    if (DataSet != null && !DataSet.ValidateCaseConstraint()) {
                        _caseSensitive = oldValue;
                        _caseSensitiveUserSet = oldUserSet;
                        throw ExceptionBuilder.CannotChangeCaseLocale(); 
                    }
                    SetCaseSensitiveValue(value, true, true); 
                } 
                _caseSensitiveUserSet = true;
            } 
        }

        internal bool AreIndexEventsSuspended {
            get { return (0 < _suspendIndexEvents); } 
        }
 
        internal void RestoreIndexEvents(bool forceReset) { 
            Bid.Trace(" %d#, %d\n", ObjectID, _suspendIndexEvents);
            if (0 < _suspendIndexEvents) { 
                _suspendIndexEvents--;
                if (0 == _suspendIndexEvents) {
                    Exception first = null;
                    SetShadowIndexes(); 
                    try{
                    // the length of shadowIndexes will not change 
                    // but the array instance may change during 
                    // events during Index.Reset
                        int numIndexes = shadowIndexes.Count; 
                        for (int i = 0; i < numIndexes; i++) {
                            Index ndx = shadowIndexes[i];// shadowindexes may change, see ShadowIndexCopy()
                            try {
                                if (forceReset || ndx.HasRemoteAggregate) { 
                                    ndx.Reset(); // resets & fires
                                } 
                                else { 
                                    ndx.FireResetEvent(); // fire the Reset event we were firing
                                } 
                            }
                            catch(Exception e) {
                                if (!ADP.IsCatchableExceptionType (e)) {
                                    throw; 
                                }
                                ExceptionBuilder.TraceExceptionWithoutRethrow(e); 
                                if (null == first) { 
                                    first = e;
                                } 
                            }
                        }
                        if (null != first) {
                            throw first; 
                        }
                    } 
                   finally { 
                       RestoreShadowIndexes();
                   } 
                }
            }
        }
 
        internal void SuspendIndexEvents() {
            Bid.Trace(" %d#, %d\n", ObjectID, _suspendIndexEvents); 
            _suspendIndexEvents++; 
        }
 
        [Browsable(false)]
        public bool IsInitialized {
            get {
                return !fInitInProgress; 
            }
        } 
 
        private bool IsTypedDataTable {
            get { 
                switch (_isTypedDataTable) {
                case 0:
                    _isTypedDataTable = (byte)((this.GetType() != typeof(DataTable))? 1 : 2);
                    return (1 == _isTypedDataTable); 
                case 1:
                    return true; 
                default: 
                    return false;
                } 
            }
        }

        internal bool SetCaseSensitiveValue(bool isCaseSensitive, bool userSet, bool resetIndexes) { 
            if (userSet || (!_caseSensitiveUserSet && (_caseSensitive != isCaseSensitive))) {
                _caseSensitive = isCaseSensitive; 
                if (isCaseSensitive) { 
                    _compareFlags = CompareOptions.None;
                } 
                else {
                    _compareFlags = CompareOptions.IgnoreCase | CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth;
                }
                if (resetIndexes) { 
                    ResetIndexes();
                    foreach (Constraint constraint in Constraints) { 
                       constraint.CheckConstraint(); 
                    }
                } 
                return true;
            }
            return false;
        } 

 
        private void ResetCaseSensitive() { 
            // this method is used design-time scenarios via reflection
            //   by the property grid context menu to show the Reset option or not 
            SetCaseSensitiveValue((null != dataSet) && dataSet.CaseSensitive, true, true);
            _caseSensitiveUserSet = false;
        }
 
        internal bool ShouldSerializeCaseSensitive() {
            // this method is used design-time scenarios via reflection 
            //   by the property grid to show the CaseSensitive property in bold or not 
            //   by the code dom for persisting the CaseSensitive property or not
            return _caseSensitiveUserSet; 
        }

        internal bool SelfNested {
            get { 
                // Is this correct? if ((top[i].nestedParentRelation!= null) && (top[i].nestedParentRelation.ParentTable == top[i]))
                foreach(DataRelation rel in ParentRelations) { 
                    if (rel.Nested && rel.ParentTable == this) { 
                        return true;
                    } 
                }
                return false;
            }
        } 
/*        internal bool SelfNestedWithOneRelation {
            get { 
                return (this.ParentRelations.Count == 1 && (this.ParentRelations[0].ParentTable == this)); 
            }
        } 
*/

        [DebuggerBrowsable(DebuggerBrowsableState.Never)] // don't have debugger view expand this
        internal List LiveIndexes { 
            get {
                if (!AreIndexEventsSuspended) { 
                    for (int i = indexes.Count-1; 0 <= i; --i) { 
                        Index index = indexes[i];
                        if (index.RefCount <= 1) { 
                            index.RemoveRef();
                        }
                    }
                } 
                return indexes;
            } 
        } 

        [ 
        DefaultValue(SerializationFormat.Xml)
        ]
        public SerializationFormat RemotingFormat {
            get { 
                return _remotingFormat;
            } 
            set { 
                if (value != SerializationFormat.Binary && value != SerializationFormat.Xml) {
                    throw ExceptionBuilder.InvalidRemotingFormat(value); 
                }
                // table can not have different format than its dataset, unless it is stand alone datatable
                if (this.DataSet != null && value != this.DataSet.RemotingFormat) {
                    throw ExceptionBuilder.CanNotSetRemotingFormat(); 
                }
                _remotingFormat = value; 
            } 
        }
 
// used to keep temporary state of unique Key posiotion to be added for inference only
        internal int UKColumnPositionForInference {
            get {
                return ukColumnPositionForInference; 
            }
            set{ 
                ukColumnPositionForInference= value; 
            }
        } 

        /// 
        /// Gets the collection of child relations for this .
        ///  
        [
        Browsable(false), 
        ResDescriptionAttribute(Res.DataTableChildRelationsDescr), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ] 
        public DataRelationCollection ChildRelations {
            get {
                if (childRelationsCollection == null)
                    childRelationsCollection = new DataRelationCollection.DataTableRelationCollection(this, false); 
                return childRelationsCollection;
            } 
        } 

        ///  
        ///    Gets the collection of columns that belong to this table.
        /// 
        [
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
        ResCategoryAttribute(Res.DataCategory_Data),
        ResDescriptionAttribute(Res.DataTableColumnsDescr) 
        ] 
        public DataColumnCollection Columns {
            get { 
                return columnCollection;
            }
        }
 
        private void ResetColumns() {
            // this method is used design-time scenarios via reflection 
            //   by the property grid context menu to show the Reset option or not 
            Columns.Clear();
        } 

        private CompareInfo CompareInfo {
            get {
                if (null == _compareInfo) { 
                    _compareInfo = Locale.CompareInfo;
                } 
                return _compareInfo; 
            }
        } 

        /// 
        ///    Gets the collection of constraints maintained by this table.
        ///  
        [
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
        ResCategoryAttribute(Res.DataCategory_Data), 
        ResDescriptionAttribute(Res.DataTableConstraintsDescr)
        ] 
        public ConstraintCollection Constraints {
            get {
                return constraintCollection;
            } 
        }
 
        ///  
        ///    
        ///       Resets the  property to its default state. 
        ///    
        /// 
        private void ResetConstraints() {
            Constraints.Clear(); 
        }
 
        ///  
        /// Gets the  that this table belongs to.
        ///  
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false), ResDescriptionAttribute(Res.DataTableDataSetDescr)]
        public DataSet DataSet {
            get {
                return dataSet; 
            }
        } 
 
        /// 
        /// Internal method for setting the DataSet pointer. 
        /// 
        internal void SetDataSet(DataSet dataSet) {
            if (this.dataSet != dataSet) {
                this.dataSet = dataSet; 

                // Inform all the columns of the dataset being set. 
                DataColumnCollection   cols = Columns; 
                for (int i = 0; i < cols.Count; i++)
                    cols[i].OnSetDataSet(); 

                if (this.DataSet != null) {
                    defaultView = null;
                } 
                //Set the remoting format variable directly
                if (dataSet != null) { 
                    _remotingFormat = dataSet.RemotingFormat; 
                }
            } 
        }

        /// 
        ///    Gets a customized view of the table which may include a 
        ///       filtered view, or a cursor position.
        ///  
        [Browsable(false), ResDescriptionAttribute(Res.DataTableDefaultViewDescr)] 
        public DataView DefaultView {
            get { 
                DataView view = defaultView;
                if (null == view) {
                    if (null != dataSet) {
                        view = dataSet.DefaultViewManager.CreateDataView(this); 
                    }
                    else { 
                        view = new DataView(this, true); 
                        view.SetIndex2("", DataViewRowState.CurrentRows, null, true);
                    } 
                    // avoid HostProtectionAttribute(Synchronization=true) by not calling virtual methods from inside a lock
                    view = Interlocked.CompareExchange(ref defaultView, view, null);
                    if (null == view) {
                        view = defaultView; 
                    }
                } 
                return view; 
            }
        } 

        /// 
        ///    Gets or sets the expression that will return a value used to represent
        ///       this table in UI. 
        /// 
        [ 
        DefaultValue(""), 
        ResCategoryAttribute(Res.DataCategory_Data),
        ResDescriptionAttribute(Res.DataTableDisplayExpressionDescr) 
        ]
        public string DisplayExpression {
            get {
                return DisplayExpressionInternal; 
            }
            set { 
                if (value != null && value.Length > 0) { 
                    this.displayExpression = new DataExpression(this, value);
                } 
                else {
                    this.displayExpression = null;
                }
            } 
        }
        internal string DisplayExpressionInternal { 
            get { 
                return(displayExpression != null ? displayExpression.Expression : "");
            } 
        }

        internal bool EnforceConstraints {
            get { 
                if (SuspendEnforceConstraints) {
                    return false; 
                } 
                if (dataSet != null)
                    return dataSet.EnforceConstraints; 

                return this.enforceConstraints;
            }
            set { 
                if (dataSet == null && this.enforceConstraints != value) {
                    if (value) 
                        EnableConstraints(); 

                    this.enforceConstraints = value; 
                }
            }
        }
 
        internal bool SuspendEnforceConstraints {
            get { 
                return _suspendEnforceConstraints ; 
            }
            set { 
                _suspendEnforceConstraints = value;
            }
        }
 
        internal void EnableConstraints()
        { 
            bool errors = false; 
            foreach (Constraint constr in Constraints)
            { 
                if (constr is UniqueConstraint)
                    errors |= constr.IsConstraintViolated();
            }
 
            foreach (DataColumn column in Columns) {
                if (!column.AllowDBNull) { 
                    errors |= column.IsNotAllowDBNullViolated(); 
                }
                if (column.MaxLength >= 0) { 
                    errors |= column.IsMaxLengthViolated();
                }
            }
 
            if (errors) {
                this.EnforceConstraints = false; 
                throw ExceptionBuilder.EnforceConstraint(); 
            }
        } 

        /// 
        ///    Gets the collection of customized user information.
        ///  
        [
        ResCategoryAttribute(Res.DataCategory_Data), 
        Browsable(false), 
        ResDescriptionAttribute(Res.ExtendedPropertiesDescr)
        ] 
        public PropertyCollection ExtendedProperties {
            get {
                if (extendedProperties == null) {
                    extendedProperties = new PropertyCollection(); 
                }
                return extendedProperties; 
            } 
        }
 
        internal IFormatProvider FormatProvider {
            get {
                // used for Formating/Parsing
                // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemglobalizationcultureinfoclassisneutralculturetopic.asp 
                if (null == _formatProvider) {
                    CultureInfo culture = Locale; 
                    if (culture.IsNeutralCulture) { 
                        culture = CultureInfo.InvariantCulture;
                    } 
                    _formatProvider = (IFormatProvider)culture;
                }
                return _formatProvider;
            } 
        }
 
        ///  
        ///    Gets a value indicating whether there are errors in any of the rows in any of
        ///       the tables of the  to which the table belongs. 
        /// 
        [Browsable(false), ResDescriptionAttribute(Res.DataTableHasErrorsDescr)]
        public bool HasErrors {
            get { 
                for (int i = 0; i < Rows.Count; i++) {
                    if (Rows[i].HasErrors) { 
                        return true; 
                    }
                } 
                return false;
            }
        }
 
        /// 
        ///    Gets or sets the locale information used to compare strings within the table. 
        ///    Also used for locale sensitive, case,kana,width insensitive column name lookups 
        ///    Also used for converting values to and from string
        ///  
        [ResDescriptionAttribute(Res.DataTableLocaleDescr)]
        public CultureInfo Locale {
            get {
                // used for Comparing not Formatting/Parsing 
                Debug.Assert(null != _culture, "null culture");
                Debug.Assert(_cultureUserSet || (null == dataSet) || _culture.Equals(dataSet.Locale), "Locale mismatch"); 
                return _culture; 
            }
            set { 
                IntPtr hscp;
                Bid.ScopeEnter(out hscp, " %d#\n", ObjectID);
                try {
                    bool userSet = true; 
                    if (null == value)  {
                        // reset Locale to inherit from DataSet 
                        userSet = false; 
                        value = (null != dataSet) ? dataSet.Locale : _culture;
                    } 
                    if (_culture != value && !_culture.Equals(value)) {
                        bool flag = false;
                        bool exceptionThrown = false;
                        CultureInfo oldLocale = _culture; 
                        bool oldUserSet = _cultureUserSet;
                        try { 
                            _cultureUserSet = true; 
                            SetLocaleValue(value, true, false);
                            if ((null == DataSet) || DataSet.ValidateLocaleConstraint()) { 
                                flag = false;
                                SetLocaleValue(value, true, true);
                                flag = true;
                            } 
                        }
                        catch { 
                            exceptionThrown = true; 
                            throw;
                        } 
                        finally {
                            if (!flag) { // reset old locale if ValidationFailed or exception thrown
                                try {
                                    SetLocaleValue(oldLocale, true, true); 
                                }
                                catch(Exception e) { // failed to reset all indexes for all constraints 
                                    if (!Common.ADP.IsCatchableExceptionType(e)) { 
                                        throw;
                                    } 
                                    Common.ADP.TraceExceptionWithoutRethrow(e);
                                }
                                _cultureUserSet = oldUserSet;
                                if (!exceptionThrown) { 
                                    throw ExceptionBuilder.CannotChangeCaseLocale(null);
                                } 
                            } 
                        }
                        SetLocaleValue(value, true, true); 
                    }
                    _cultureUserSet = userSet;
                }
                finally{ 
                    Bid.ScopeLeave(ref hscp);
                } 
            } 
        }
 
        internal bool SetLocaleValue(CultureInfo culture, bool userSet, bool resetIndexes) {
            Debug.Assert(null != culture, "SetLocaleValue: no locale");
            if (userSet || resetIndexes || (!_cultureUserSet && !_culture.Equals(culture))) {
                _culture = culture; 
                _compareInfo = null;
                _formatProvider = null; 
                _hashCodeProvider = null; 

                foreach(DataColumn column in Columns) { 
                    column._hashCode = GetSpecialHashCode(column.ColumnName);
                }
                if (resetIndexes) {
                    ResetIndexes(); 
                    foreach (Constraint constraint in Constraints) {
                        constraint.CheckConstraint(); 
                    } 
                }
                return true; 
            }
            return false;
        }
 
        internal bool ShouldSerializeLocale() {
            // this method is used design-time scenarios via reflection 
            //   by the property grid to show the Locale property in bold or not 
            //   by the code dom for persisting the Locale property or not
 
            // we always want the locale persisted if set by user or different the current thread if standalone table
            // but that logic should by performed by the serializion code
            return _cultureUserSet;
        } 

        ///  
        ///    Gets or sets the initial starting size for this table. 
        /// 
        [ 
        DefaultValue(50),
        ResCategoryAttribute(Res.DataCategory_Data),
        ResDescriptionAttribute(Res.DataTableMinimumCapacityDescr)
        ] 
        public int MinimumCapacity {
            get { 
                return recordManager.MinimumCapacity; 
            }
            set { 
                if (value != recordManager.MinimumCapacity) {
                    recordManager.MinimumCapacity = value;
                }
            } 
        }
 
        internal int RecordCapacity { 
            get {
                return recordManager.RecordCapacity; 
            }
        }

 
        internal int ElementColumnCount {
            get { 
                return elementColumnCount; 
            }
            set { 
                if ((value > 0) && (xmlText != null))
                    throw ExceptionBuilder.TableCannotAddToSimpleContent();
                else elementColumnCount = value;
            } 
        }
 
        ///  
        /// Gets the collection of parent relations for this .
        ///  
        [
        Browsable(false),
        ResDescriptionAttribute(Res.DataTableParentRelationsDescr),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) 
        ]
        public DataRelationCollection ParentRelations { 
            get { 
                if (parentRelationsCollection == null)
                    parentRelationsCollection = new DataRelationCollection.DataTableRelationCollection(this, true); 
                return parentRelationsCollection;
            }
        }
 
        internal bool MergingData {
            get { 
                return mergingData; 
            }
            set { 
                mergingData = value;
            }
        }
 
        internal DataRelation[] NestedParentRelations {
            get { 
#if DEBUG 
                DataRelation[] nRel = FindNestedParentRelations();
                Debug.Assert(nRel.Length == _nestedParentRelations.Length, "nestedParent cache is broken"); 
                for(int i = 0; i < nRel.Length; i++) {
                    Debug.Assert(null != nRel[i], "null relation");
                    Debug.Assert(null != _nestedParentRelations[i], "null relation");
                    Debug.Assert(nRel[i] == _nestedParentRelations[i], "unequal relations"); 
                }
#endif 
                return _nestedParentRelations; 
            }
        } 

        internal bool SchemaLoading {
            get {
                return schemaLoading; 
            }
        } 
 

        internal void CacheNestedParent() { 
            _nestedParentRelations = FindNestedParentRelations();
        }

        private DataRelation[] FindNestedParentRelations() { 
            List nestedParents = null;
            foreach(DataRelation relation in this.ParentRelations) { 
                if(relation.Nested) { 
                    if (null == nestedParents) {
                        nestedParents = new List(); 
                    }
                    nestedParents.Add(relation);
                }
            } 
            if ((null == nestedParents) || (nestedParents.Count == 0)) {
                return EmptyArrayDataRelation; 
            } 
            return nestedParents.ToArray();
        } 


        internal int NestedParentsCount {
            get { 
                int count = 0;
                foreach(DataRelation relation in this.ParentRelations) { 
                    if(relation.Nested) 
                        count++;
                } 
                return count;
            }
        }
 
        /// 
        ///    Gets or sets an array of columns that function as primary keys for the data 
        ///       table. 
        /// 
        [ 
        TypeConverter(typeof(PrimaryKeyTypeConverter)),
        ResDescriptionAttribute(Res.DataTablePrimaryKeyDescr),
        ResCategoryAttribute(Res.DataCategory_Data),
        Editor("Microsoft.VSDesigner.Data.Design.PrimaryKeyEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing) 
        ]
        public DataColumn[] PrimaryKey { 
            get { 
                UniqueConstraint primayKeyConstraint = primaryKey;
                if (null != primayKeyConstraint) { 
                    Debug.Assert(2 <= primaryKey.ConstraintIndex.RefCount, "bad primaryKey index RefCount");
                    return primayKeyConstraint.Key.ToArray();
                }
                return zeroColumns; 
            }
            set { 
                UniqueConstraint key = null; 
                UniqueConstraint existingKey = null;
 
                // Loading with persisted property
                if (fInitInProgress && value != null) {
                    delayedSetPrimaryKey = value;
                    return; 
                }
 
                if ((value != null) && (value.Length != 0)) { 
                    int count = 0;
                    for (int i = 0; i < value.Length; i++) { 
                        if (value[i] != null)
                            count++;
                        else
                            break; 
                    }
 
                    if (count != 0) { 
                        DataColumn[] newValue = value;
                        if (count != value.Length) { 
                            newValue = new DataColumn[count];
                            for (int i = 0; i < count; i++)
                                newValue[i] = value[i];
                        } 
                        key = new UniqueConstraint(newValue);
                        if (key.Table != this) 
                            throw ExceptionBuilder.TableForeignPrimaryKey(); 
                    }
                } 

                if (key == primaryKey || (key != null && key.Equals(primaryKey)))
                    return;
 
                // Use an existing UniqueConstraint that matches if one exists
                if ((existingKey = (UniqueConstraint)Constraints.FindConstraint(key)) != null) { 
                    key.ColumnsReference.CopyTo(existingKey.Key.ColumnsReference, 0); 
                    key = existingKey;
                } 

                UniqueConstraint oldKey = primaryKey;
                primaryKey = null;
                if (oldKey != null) { 
                    oldKey.ConstraintIndex.RemoveRef();
 
                    // SQLBU 429176: if PrimaryKey is removed, reset LoadDataRow indexes 
                    if (null != loadIndex) {
                        loadIndex.RemoveRef(); 
                        loadIndex = null;
                    }
                    if (null != loadIndexwithOriginalAdded) {
                        loadIndexwithOriginalAdded.RemoveRef(); 
                        loadIndexwithOriginalAdded = null;
                    } 
                    if (null != loadIndexwithCurrentDeleted) { 
                        loadIndexwithCurrentDeleted.RemoveRef();
                        loadIndexwithCurrentDeleted = null; 
                    }
                    Constraints.Remove(oldKey);
                }
 
                // Add the key if there isnt an existing matching key in collection
                if (key != null && existingKey == null) 
                    Constraints.Add(key); 

                primaryKey = key; 

                Debug.Assert(Constraints.FindConstraint(primaryKey) == primaryKey, "PrimaryKey is not in ConstraintCollection");
                _primaryIndex = (key != null) ? key.Key.GetIndexDesc() : zeroIndexField;
 
                if (primaryKey != null) {
                    // must set index for DataView.Sort before setting AllowDBNull which can fail 
                    key.ConstraintIndex.AddRef(); 

                    for (int i = 0; i < key.ColumnsReference.Length; i++) 
                        key.ColumnsReference[i].AllowDBNull = false;
                }
            }
        } 

        ///  
        ///     
        ///       Indicates whether the  property should be persisted.
        ///     
        /// 
        private bool ShouldSerializePrimaryKey() {
            return(primaryKey != null);
        } 

        ///  
        ///     
        ///       Resets the  property to its default state.
        ///     
        /// 
        private void ResetPrimaryKey() {
            PrimaryKey = null;
        } 

        ///  
        ///    Gets the collection of rows that belong to this table. 
        /// 
        [Browsable(false), ResDescriptionAttribute(Res.DataTableRowsDescr)] 
        public DataRowCollection Rows {
            get {
                return rowCollection;
            } 
        }
 
        ///  
        ///    Gets or sets the name of the table.
        ///  
        [
        RefreshProperties(RefreshProperties.All),
        DefaultValue(""),
        ResCategoryAttribute(Res.DataCategory_Data), 
        ResDescriptionAttribute(Res.DataTableTableNameDescr)
        ] 
        public string TableName { 
            get {
                return tableName; 
            }
            set {
                IntPtr hscp;
                Bid.ScopeEnter(out hscp, " %d#, value='%ls'\n", ObjectID, value); 
                try {
                    if (value == null) { 
                        value = ""; 
                    }
                    CultureInfo currentLocale = this.Locale; 
                    if (String.Compare(tableName, value, true, currentLocale) != 0) {
                        if (dataSet != null) {
                            if (value.Length == 0)
                                throw ExceptionBuilder.NoTableName(); 
                            if ((0 == String.Compare(value, dataSet.DataSetName, true, dataSet.Locale)) && !fNestedInDataset)
                               throw ExceptionBuilder.DatasetConflictingName(dataSet.DataSetName); 
 
                            DataRelation[] nestedRelations = NestedParentRelations;
                            if (nestedRelations.Length == 0) { 
                                dataSet.Tables.RegisterName(value, this.Namespace);
                            }
                            else {
                                foreach(DataRelation rel in nestedRelations) { 
                                    if (!rel.ParentTable.Columns.CanRegisterName(value)) {
                                        throw ExceptionBuilder.CannotAddDuplicate2(value); 
                                    } 
                                }
                                // if it cannot register the following line will throw exception 
                                dataSet.Tables.RegisterName(value, this.Namespace);

                                foreach(DataRelation rel in nestedRelations) {
                                    rel.ParentTable.Columns.RegisterColumnName(value, (DataColumn)null, this); 
                                    rel.ParentTable.Columns.UnregisterName(this.TableName);
                                } 
                            } 

                            if (tableName.Length != 0) { 
                                dataSet.Tables.UnregisterName(tableName);
                            }
                        }
                        RaisePropertyChanging("TableName"); 
                        tableName = value;
                        encodedTableName = null; 
                    } 
                    else if (String.Compare(tableName, value, false, currentLocale) != 0) {
                        RaisePropertyChanging("TableName"); 
                        tableName = value;
                        encodedTableName = null;
                    }
                } 
                finally {
                    Bid.ScopeLeave(ref hscp); 
                } 
            }
        } 


        internal string EncodedTableName {
            get { 
                string encodedTblName = this.encodedTableName;
                if (null == encodedTblName) { 
                    encodedTblName = XmlConvert.EncodeLocalName( this.TableName ); 
                    this.encodedTableName = encodedTblName;
                } 
                return encodedTblName;
            }
        }
        private string GetInheritedNamespace(List visitedTables){ 
            // if there is nested relation: ie: this table is nested child of a another table and
            // if it is not self nested, return parent tables NS: Meanwhile make sure SQLBUDT 240219 is FIXED 
            DataRelation[] nestedRelations = NestedParentRelations; 
            if (nestedRelations.Length > 0) {
                for(int i =0; i < nestedRelations.Length; i++) { 
                    DataRelation rel = nestedRelations[i];
                    if (rel.ParentTable.tableNamespace != null) {
                        return rel.ParentTable.tableNamespace; // if parent table has a non-null NS, return it
                    } 
                }
                // Assumption, in hierarchy of multiple nested relation, a child table with no NS, has DataRelation 
                // only and only with parent DataTable witin the same namespace 
                int j = 0;
                while(j < nestedRelations.Length &&((nestedRelations[j].ParentTable == this)||(visitedTables.Contains(nestedRelations[j].ParentTable)))) { 
                    j++;
                }
                if (j < nestedRelations.Length) {
                    DataTable parentTable = nestedRelations[j].ParentTable; 
                    if (!visitedTables.Contains(parentTable))
                        visitedTables.Add(parentTable); 
                        return parentTable.GetInheritedNamespace(visitedTables);// this is the same as return parentTable.Namespace 
                }
            } // dont put else 
            if (DataSet != null) { // if it cant return from parent tables, return NS from dataset, if exists
                return  DataSet.Namespace;
            }
            else { 
                return string.Empty;
            } 
 
        }
 
        /// 
        ///    
        ///       Gets or sets the namespace for the .
        ///     
        /// 
        [ 
        ResCategoryAttribute(Res.DataCategory_Data), 
        ResDescriptionAttribute(Res.DataTableNamespaceDescr)
        ] 
        public string Namespace {
            get {
                if (tableNamespace == null) {
                    return GetInheritedNamespace(new List()); 
                }
                return tableNamespace; 
            } 
            set {
                IntPtr hscp; 
                Bid.ScopeEnter(out hscp, " %d#, value='%ls'\n", ObjectID, value);
                try {
                    if(value != tableNamespace) {
                        if (dataSet != null) { 
                            string realNamespace = (value == null ? GetInheritedNamespace(new List()) : value);
                            if (realNamespace != Namespace) { 
                                // do this extra check only if the namespace is really going to change 
                                // inheritance-wise.
                                if (dataSet.Tables.Contains( this.TableName, realNamespace, true, true)) 
                                    throw ExceptionBuilder.DuplicateTableName2(this.TableName, realNamespace);

                                CheckCascadingNamespaceConflict(realNamespace);
                            } 
                        }
                        CheckNamespaceValidityForNestedRelations(value); 
                        DoRaiseNamespaceChange(); 
                    }
                    tableNamespace = value; 
                }
                finally{
                    Bid.ScopeLeave(ref hscp);
                } 
            }
        } 
        internal bool IsNamespaceInherited() { 
            return (null == tableNamespace);
        } 

        internal void CheckCascadingNamespaceConflict(string realNamespace){
            foreach (DataRelation rel in ChildRelations)
                if ((rel.Nested) && (rel.ChildTable != this) && (rel.ChildTable.tableNamespace == null)) { 
                    DataTable childTable = rel.ChildTable;
                    if (dataSet.Tables.Contains( childTable.TableName, realNamespace, false, true)) 
                        throw ExceptionBuilder.DuplicateTableName2(this.TableName, realNamespace); 

                    childTable.CheckCascadingNamespaceConflict(realNamespace); 
                }

        }
 
        internal void CheckNamespaceValidityForNestedRelations(string realNamespace){
            foreach(DataRelation rel in ChildRelations) { 
                if (rel.Nested) { 
                    if (realNamespace != null) {
                        rel.ChildTable.CheckNamespaceValidityForNestedParentRelations(realNamespace, this); 
                    }
                    else{
                        rel.ChildTable.CheckNamespaceValidityForNestedParentRelations(GetInheritedNamespace(new List()), this);
                    } 
                }
            } 
            if (realNamespace == null) { // this will affect this table if it has parent relations 
                this.CheckNamespaceValidityForNestedParentRelations(GetInheritedNamespace(new List()), this);
            } 

        }
        internal void CheckNamespaceValidityForNestedParentRelations(string ns, DataTable parentTable) {
            foreach(DataRelation rel in ParentRelations){ 
                if (rel.Nested) {
                    if (rel.ParentTable != parentTable && rel.ParentTable.Namespace != ns) { 
                        throw ExceptionBuilder.InValidNestedRelation(this.TableName); 
                    }
                } 
            }

        }
 
        internal void DoRaiseNamespaceChange(){
            RaisePropertyChanging("Namespace"); 
            // raise column Namespace change 

            foreach (DataColumn col in Columns) 
                if (col._columnUri == null)
                    col.RaisePropertyChanging("Namespace");

            foreach (DataRelation rel in ChildRelations) 
                if ((rel.Nested) && (rel.ChildTable != this)) {
                    DataTable childTable = rel.ChildTable; 
 
                    rel.ChildTable.DoRaiseNamespaceChange();
                } 
        }
        /// 
        ///    
        ///       Indicates whether the  property should be persisted. 
        ///    
        ///  
        private bool ShouldSerializeNamespace() { 
            return(tableNamespace != null);
        } 

        /// 
        ///    
        ///       Resets the  property to its default state. 
        ///    
        ///  
        private void ResetNamespace() { 
            this.Namespace = null;
        } 

        /// 
        ///    [To be supplied.]
        ///  
        virtual public void BeginInit() {
            fInitInProgress = true; 
        } 

        ///  
        ///    [To be supplied.]
        /// 
        virtual public void EndInit() {
            if (dataSet == null || !dataSet.fInitInProgress) { 
                Columns.FinishInitCollection();
                Constraints.FinishInitConstraints(); 
                foreach(DataColumn dc in Columns){ 
                    if (dc.Computed) {
                        dc.Expression = dc.Expression; 
                    }
                }
            }
            fInitInProgress = false; // [....] : 77890. It is must that we set off this flag after calling FinishInitxxx(); 
            if (delayedSetPrimaryKey != null) {
                PrimaryKey = delayedSetPrimaryKey; 
                delayedSetPrimaryKey = null; 
            }
            if (delayedViews.Count > 0) { 
                foreach(DataView dv in delayedViews) {
                    dv.EndInit();
                }
                delayedViews.Clear(); 
            }
            OnInitialized(); 
        } 

        ///  
        ///    [To be supplied.]
        /// 
        [
        DefaultValue(""), 
        ResCategoryAttribute(Res.DataCategory_Data),
        ResDescriptionAttribute(Res.DataTablePrefixDescr) 
        ] 
        public string Prefix {
            get { return tablePrefix;} 
            set {
                if (value == null) {
                    value = "";
                } 
                Bid.Trace(" %d#, value='%ls'\n", ObjectID, value);
                if ((XmlConvert.DecodeName(value) == value) && 
                    (XmlConvert.EncodeName(value) != value)) 
                    throw ExceptionBuilder.InvalidPrefix(value);
 

                tablePrefix = value;
            }
        } 

        internal DataColumn XmlText { 
            get { 
                return xmlText;
            } 
            set {
                if (xmlText != value) {
                    if (xmlText != null) {
                        if (value != null) { 
                            throw ExceptionBuilder.MultipleTextOnlyColumns();
                        } 
                        Columns.Remove(xmlText); 
                    }
                    else { 
                        Debug.Assert(value != null, "Value shoud not be null ??");
                        Debug.Assert(value.ColumnMapping == MappingType.SimpleContent, "should be text node here");
                        if (value != Columns[value.ColumnName])
                            Columns.Add(value); 
                    }
                    xmlText = value; 
                } 
            }
        } 

        internal decimal MaxOccurs {
            get {
                return maxOccurs; 
            }
            set { 
                maxOccurs = value; 
            }
        } 

        internal decimal MinOccurs {
            get {
                return minOccurs; 
            }
            set { 
                minOccurs = value; 
            }
        } 

        internal void SetKeyValues(DataKey key, object[] keyValues, int record) {
            for (int i = 0; i < keyValues.Length; i++) {
                key.ColumnsReference[i][record] = keyValues[i]; 
            }
        } 
 
        internal DataRow FindByIndex(Index ndx, object[] key) {
            Range range = ndx.FindRecords(key); 
            if (range.IsNull) {
                return null;
            }
            return this.recordManager[ndx.GetRecord(range.Min)]; 
        }
 
        internal DataRow FindMergeTarget(DataRow row, DataKey key, Index ndx) { 
            DataRow targetRow = null;
 
            // Primary key match
            if (key.HasValue) {
                Debug.Assert(ndx != null);
                int   findRecord = (row.oldRecord == -1) ? row.newRecord : row.oldRecord; 
                object[] values = key.GetKeyValues(findRecord);
                targetRow = FindByIndex(ndx, values); 
            } 
            return targetRow;
        } 

        private void SetMergeRecords(DataRow row, int newRecord, int oldRecord, DataRowAction action) {
            if (newRecord != -1) {
                SetNewRecord(row, newRecord, action, true, true); 
                SetOldRecord(row, oldRecord);
            } 
            else { 
                SetOldRecord(row, oldRecord);
                if (row.newRecord != -1) { 
                    Debug.Assert(action == DataRowAction.Delete, "Unexpected SetNewRecord action in merge function.");
                    SetNewRecord(row, newRecord, action, true, true);
                }
            } 
        }
 
        internal DataRow MergeRow(DataRow row, DataRow targetRow, bool preserveChanges, Index idxSearch) { 
             if (targetRow == null) {
                targetRow = this.NewEmptyRow(); 
                targetRow.oldRecord = recordManager.ImportRecord(row.Table, row.oldRecord);
                targetRow.newRecord = targetRow.oldRecord;
                if(row.oldRecord != row.newRecord) {
                    targetRow.newRecord = recordManager.ImportRecord(row.Table, row.newRecord); 
                }
                InsertRow(targetRow, -1); 
            } 
            else {
                // SQLBU 500789: Record Manager corruption during Merge when target row in edit state 
                // the newRecord would be freed and overwrite tempRecord (which became the newRecord)
                // this would leave the DataRow referencing a freed record and leaking memory for the now lost record
                int proposedRecord = targetRow.tempRecord; // by saving off the tempRecord, EndEdit won't free newRecord
                targetRow.tempRecord = -1; 
                try {
                    DataRowState saveRowState = targetRow.RowState; 
                    int saveIdxRecord = (saveRowState == DataRowState.Added) ? targetRow.newRecord : saveIdxRecord = targetRow.oldRecord; 
                     int newRecord;
                     int oldRecord; 
                    if (targetRow.RowState == DataRowState.Unchanged && row.RowState == DataRowState.Unchanged) {
                        // unchanged row merging with unchanged row
                        oldRecord = targetRow.oldRecord;
                        newRecord = (preserveChanges) ? recordManager.CopyRecord(this, oldRecord, -1) : targetRow.newRecord; 
                        oldRecord = recordManager.CopyRecord(row.Table, row.oldRecord, targetRow.oldRecord);
                        SetMergeRecords(targetRow, newRecord, oldRecord, DataRowAction.Change); 
                    } 
                    else if (row.newRecord == -1) {
                        // Incoming row is deleted 
                        oldRecord = targetRow.oldRecord;
                        if (preserveChanges) {
                          newRecord = (targetRow.RowState == DataRowState.Unchanged)? recordManager.CopyRecord(this, oldRecord, -1) : targetRow.newRecord;
                        } 
                        else
                            newRecord = -1; 
                        oldRecord = recordManager.CopyRecord(row.Table, row.oldRecord, oldRecord); 

                        // Change index record, need to update index 
                        if (saveIdxRecord != ((saveRowState == DataRowState.Added) ? newRecord : oldRecord)) {
                            SetMergeRecords(targetRow, newRecord, oldRecord, (newRecord == -1) ? DataRowAction.Delete : DataRowAction.Change);
                            idxSearch.Reset();
                            saveIdxRecord = ((saveRowState == DataRowState.Added) ? newRecord : oldRecord); 
                        } else {
                            SetMergeRecords(targetRow, newRecord, oldRecord, (newRecord == -1) ? DataRowAction.Delete : DataRowAction.Change); 
                        } 
                    }
                    else { 
                        // incoming row is added, modified or unchanged (targetRow is not unchanged)
                        oldRecord = targetRow.oldRecord;
                        newRecord = targetRow.newRecord;
                        if (targetRow.RowState == DataRowState.Unchanged) { 
                            newRecord = recordManager.CopyRecord(this, oldRecord, -1);
                        } 
                        oldRecord = recordManager.CopyRecord(row.Table, row.oldRecord, oldRecord); 

                        if (!preserveChanges) { 
                            newRecord = recordManager.CopyRecord(row.Table, row.newRecord, newRecord);
                        }
                        SetMergeRecords(targetRow, newRecord, oldRecord, DataRowAction.Change);
                    } 

                    if (saveRowState == DataRowState.Added && targetRow.oldRecord != -1) 
                        idxSearch.Reset(); 
                    Debug.Assert(saveIdxRecord == ((saveRowState == DataRowState.Added) ? targetRow.newRecord : targetRow.oldRecord), "oops, you change index record without noticing it");
                } 
                finally {
                    targetRow.tempRecord = proposedRecord;
                }
            } 

            // Merge all errors 
            if (row.HasErrors) { 
                if (targetRow.RowError.Length == 0) {
                    targetRow.RowError = row.RowError; 
                } else {
                    targetRow.RowError += " ]:[ " + row.RowError;
                }
                DataColumn[] cols = row.GetColumnsInError(); 

                for (int i = 0; i < cols.Length; i++) { 
                    DataColumn col = targetRow.Table.Columns[cols[i].ColumnName]; 
                    targetRow.SetColumnError(col, row.GetColumnError(cols[i]));
                } 
            }else {
                if (!preserveChanges) {
                    targetRow.ClearErrors();
                } 
            }
 
            return targetRow; 
        }
 
        /// 
        /// Commits all the changes made to this table since the last time  was called.
        /// 
        public void AcceptChanges() { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); 
            try { 
                DataRow[] oldRows = new DataRow[Rows.Count];
                Rows.CopyTo(oldRows, 0); 

                // delay updating of indexes until after all
                // AcceptChange calls have been completed
                SuspendIndexEvents(); 
                try {
                    for (int i = 0; i < oldRows.Length; ++i) { 
                        if (oldRows[i].rowID != -1) { 
                            oldRows[i].AcceptChanges();
                        } 
                    }
                }
                finally {
                    RestoreIndexEvents(false); 
                }
            } 
            finally{ 
                Bid.ScopeLeave(ref hscp);
             } 
        }

    protected virtual DataTable CreateInstance() {
        return (DataTable) Activator.CreateInstance(this.GetType(), true); 
    }
 
        public virtual DataTable Clone() { 
            return Clone(null);
        } 

        internal DataTable Clone(DataSet cloneDS) {
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, cloneDS=%d\n", ObjectID, (cloneDS != null) ? cloneDS.ObjectID : 0); 
            try {
                DataTable clone = CreateInstance(); 
                if (clone.Columns.Count > 0) // [....] : To clean up all the schema in strong typed dataset. 
                    clone.Reset();
                return CloneTo(clone, cloneDS, false); 
            }
            finally {
                Bid.ScopeLeave(ref hscp);
            } 
        }
 
 
        private DataTable IncrementalCloneTo (DataTable sourceTable, DataTable targetTable) {
            foreach(DataColumn dc in sourceTable.Columns) { 
                if (targetTable.Columns[dc.ColumnName] == null) {
                    targetTable.Columns.Add(dc.Clone());
                }
            } 

            return targetTable; 
        } 

        private DataTable CloneHierarchy (DataTable sourceTable, DataSet ds, Hashtable visitedMap) { 
            if (visitedMap == null)
                visitedMap = new Hashtable();
            if (visitedMap.Contains(sourceTable))
                return ((DataTable)visitedMap[sourceTable]); 

 
            DataTable destinationTable = ds.Tables[sourceTable.TableName, sourceTable.Namespace]; 

            if ((destinationTable != null && destinationTable.Columns.Count > 0)) { 
                destinationTable = IncrementalCloneTo(sourceTable,destinationTable);
                   // get extra columns from source into destination , increamental read
            }
            else { 
                if (destinationTable == null) {
                    destinationTable = new DataTable(); 
                    // fxcop: new DataTable values for CaseSensitive, Locale, Namespace will come from CloneTo 
                    ds.Tables.Add(destinationTable);
                } 
                destinationTable = sourceTable.CloneTo(destinationTable, ds, true);
            }
            visitedMap[sourceTable] = destinationTable;
 

            // start cloning relation 
            foreach( DataRelation r in sourceTable.ChildRelations ) { 
                DataTable childTable = CloneHierarchy((DataTable)r.ChildTable, ds, visitedMap);
             } 

            return destinationTable;
         }
 

        private DataTable CloneTo(DataTable clone, DataSet cloneDS, bool skipExpressionColumns) { 
// we do clone datatables while we do readxmlschema, so we do not want to clone columnexpressions if we call this from ReadXmlSchema 
// it will cause exception to be thrown in cae expression refers to a table that is not in hirerachy or not created yet
            Debug.Assert(clone != null, "The table passed in has to be newly created empty DataTable."); 

            // set All properties
            clone.tableName = tableName;
 
            clone.tableNamespace = tableNamespace;
            clone.tablePrefix = tablePrefix; 
            clone.fNestedInDataset = fNestedInDataset; 

            clone._culture = _culture; 
            clone._cultureUserSet = _cultureUserSet;
            clone._compareInfo = _compareInfo;
            clone._compareFlags = _compareFlags;
            clone._formatProvider = _formatProvider; 
            clone._hashCodeProvider = _hashCodeProvider;
            clone._caseSensitive = _caseSensitive; 
            clone._caseSensitiveUserSet = _caseSensitiveUserSet; 

            clone.displayExpression = displayExpression; 
            clone.typeName = typeName; //[....]
            clone.repeatableElement = repeatableElement; //[....]
            clone.MinimumCapacity = MinimumCapacity;
            clone.RemotingFormat = RemotingFormat; 
//            clone.SerializeHierarchy = SerializeHierarchy;
 
            // add all columns 
            DataColumnCollection clmns = this.Columns;
            for (int i = 0; i < clmns.Count; i++) { 
                clone.Columns.Add(clmns[i].Clone());
            }

            // add all expressions if Clone is invoked only on DataTable otherwise DataSet.Clone will assign expressions after creating all relationships. 
            if (!skipExpressionColumns && cloneDS == null) {
                for (int i = 0; i < clmns.Count; i++) { 
                    clone.Columns[clmns[i].ColumnName].Expression = clmns[i].Expression; 
                }
            } 

            // Create PrimaryKey
            DataColumn[] pkey = PrimaryKey;
            if (pkey.Length > 0) { 
                DataColumn[] key = new DataColumn[pkey.Length];
                for (int i = 0; i < pkey.Length; i++) { 
                    key[i] = clone.Columns[pkey[i].Ordinal]; 
                }
                clone.PrimaryKey = key; 
            }

            // now clone all unique constraints
            // Rename first 
            for (int j = 0; j < Constraints.Count; j++)  {
                ForeignKeyConstraint foreign = Constraints[j] as ForeignKeyConstraint; 
                UniqueConstraint unique = Constraints[j] as UniqueConstraint; 
                if (foreign  != null) {
                    if (foreign.Table == foreign.RelatedTable) { 
                        ForeignKeyConstraint clonedConstraint = foreign.Clone(clone);
                        Constraint oldConstraint = clone.Constraints.FindConstraint(clonedConstraint);
                        if (oldConstraint != null) {
                            oldConstraint.ConstraintName = Constraints[j].ConstraintName; 
                        }
                    } 
                } 
                else if (unique != null) {
                    UniqueConstraint clonedConstraint = unique.Clone(clone); 
                    Constraint oldConstraint = clone.Constraints.FindConstraint(clonedConstraint);
                    if (oldConstraint != null) {
                        oldConstraint.ConstraintName = Constraints[j].ConstraintName;
                        foreach (Object key in clonedConstraint.ExtendedProperties.Keys) { 
                            oldConstraint.ExtendedProperties[key] = clonedConstraint.ExtendedProperties[key];
                        } 
                    } 
                }
            } 

            // then add
            for (int j = 0; j < Constraints.Count; j++)  {
                if (! clone.Constraints.Contains(Constraints[j].ConstraintName, true)) { 
                    ForeignKeyConstraint foreign = Constraints[j] as ForeignKeyConstraint;
                    UniqueConstraint unique = Constraints[j] as UniqueConstraint; 
                    if (foreign  != null) { 
                        if (foreign.Table == foreign.RelatedTable) {
                            ForeignKeyConstraint newforeign = foreign.Clone(clone); 
                            if (newforeign != null) { // we cant make sure that we recieve a cloned FKC,since it depends if table and relatedtable be the same
                                clone.Constraints.Add(newforeign);
                            }
                        } 
                    }
                    else if (unique != null) { 
                        clone.Constraints.Add(unique.Clone(clone)); 
                    }
                 } 
            }

            // ...Extended Properties...
 
            if (this.extendedProperties != null) {
                foreach(Object key in this.extendedProperties.Keys) { 
                    clone.ExtendedProperties[key]=this.extendedProperties[key]; 
                }
            } 

            return clone;
        }
 

        public DataTable Copy(){ 
            IntPtr hscp; 
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID);
            try { 
                DataTable destTable = this.Clone();

                foreach (DataRow row in Rows)
                    CopyRow(destTable, row); 

                return destTable; 
            } 
            finally {
                Bid.ScopeLeave(ref hscp); 
            }
        }

        ///  
        ///    Occurs when a value has been submitted for this column.
        ///  
        [ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.DataTableColumnChangingDescr)] 
        public event DataColumnChangeEventHandler ColumnChanging {
            add { 
                Bid.Trace(" %d#\n", ObjectID);
                onColumnChangingDelegate += value;
            }
            remove { 
                Bid.Trace(" %d#\n", ObjectID);
                onColumnChangingDelegate -= value; 
            } 
        }
 
        /// 
        ///    [To be supplied.]
        /// 
        [ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.DataTableColumnChangedDescr)] 
        public event DataColumnChangeEventHandler ColumnChanged {
            add  { 
                Bid.Trace(" %d#\n", ObjectID); 
                onColumnChangedDelegate += value;
            } 
            remove {
                Bid.Trace(" %d#\n", ObjectID);
                onColumnChangedDelegate -= value;
            } 
        }
 
        [ 
            ResCategoryAttribute(Res.DataCategory_Action),
            ResDescriptionAttribute(Res.DataSetInitializedDescr) 
        ]
        public event System.EventHandler  Initialized {
            add {
                onInitialized += value; 
            }
            remove { 
                onInitialized -= value; 
            }
        } 

        internal event PropertyChangedEventHandler PropertyChanging {
            add {
                Bid.Trace(" %d#\n", ObjectID); 
                onPropertyChangingDelegate += value;
            } 
            remove { 
                Bid.Trace(" %d#\n", ObjectID);
                onPropertyChangingDelegate -= value; 
            }
        }

        ///  
        ///    
        ///       Occurs after a row in the table has been successfully edited. 
        ///     
        /// 
        [ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.DataTableRowChangedDescr)] 
        public event DataRowChangeEventHandler RowChanged {
            add {
                Bid.Trace(" %d#\n", ObjectID);
                onRowChangedDelegate += value; 
            }
            remove { 
                Bid.Trace(" %d#\n", ObjectID); 
                onRowChangedDelegate -= value;
            } 
        }

        /// 
        ///     
        ///       Occurs when the  is changing.
        ///     
        ///  
        [ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.DataTableRowChangingDescr)]
        public event DataRowChangeEventHandler RowChanging { 
            add {
                Bid.Trace(" %d#\n", ObjectID);
                onRowChangingDelegate += value;
            } 
            remove {
                Bid.Trace(" %d#\n", ObjectID); 
                onRowChangingDelegate -= value; 
            }
        } 

        /// 
        ///    
        ///       Occurs before a row in the table is 
        ///       about to be deleted.
        ///     
        ///  
        [ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.DataTableRowDeletingDescr)]
        public event DataRowChangeEventHandler RowDeleting { 
            add {
                Bid.Trace(" %d#\n", ObjectID);
                onRowDeletingDelegate += value;
            } 
            remove {
                Bid.Trace(" %d#\n", ObjectID); 
                onRowDeletingDelegate -= value; 
            }
        } 

        /// 
        ///    
        ///       Occurs after a row in the 
        ///       table has been deleted.
        ///     
        ///  
        [ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.DataTableRowDeletedDescr)]
        public event DataRowChangeEventHandler RowDeleted { 
            add {
                Bid.Trace(" %d#\n", ObjectID);
                onRowDeletedDelegate += value;
            } 
            remove {
                Bid.Trace(" %d#\n", ObjectID); 
                onRowDeletedDelegate -= value; 
            }
        } 

        [ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.DataTableRowsClearingDescr)]
        public event DataTableClearEventHandler TableClearing {
            add { 
                Bid.Trace(" %d#\n", ObjectID);
                onTableClearingDelegate += value; 
            } 
            remove {
                Bid.Trace(" %d#\n", ObjectID); 
                onTableClearingDelegate -= value;
            }
        }
 
        [ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.DataTableRowsClearedDescr)]
        public event DataTableClearEventHandler TableCleared { 
            add { 
                Bid.Trace(" %d#\n", ObjectID);
                onTableClearedDelegate += value; 
            }
            remove {
                Bid.Trace(" %d#\n", ObjectID);
                onTableClearedDelegate -= value; 
            }
        } 
 
        [ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.DataTableRowsNewRowDescr)]
        public event DataTableNewRowEventHandler TableNewRow { 
            add {
                onTableNewRowDelegate += value;
            }
            remove { 
                onTableNewRowDelegate -= value;
            } 
        } 

        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        public override ISite Site {
            get {
                return base.Site;
            } 
            set {
                ISite oldSite = Site; 
                if (value == null && oldSite != null) { 
                    IContainer cont = oldSite.Container;
 
                    if (cont != null) {
                        for (int i = 0; i < Columns.Count; i++) {
                            if (Columns[i].Site != null) {
                                cont.Remove(Columns[i]); 
                            }
                        } 
                    } 
                }
                base.Site = value; 
            }
        }

        internal DataRow AddRecords(int oldRecord, int newRecord) { 
            DataRow row;
            if (oldRecord == -1 && newRecord == -1) 
            { 
                row = NewRow(-1);
                AddRow(row); 
            }
            else
            {
                row = NewEmptyRow(); 
                row.oldRecord = oldRecord;
                row.newRecord = newRecord; 
                InsertRow(row, -1); 
            }
            return row; 
        }

        internal void AddRow(DataRow row) {
            AddRow(row, -1); 
        }
 
        internal void AddRow(DataRow row, int proposedID) { 
            InsertRow(row, proposedID, -1);
        } 

        internal void InsertRow(DataRow row, int proposedID, int pos) {
            InsertRow(row, proposedID, pos, /*fireEvent*/true);
        } 

        internal void InsertRow(DataRow row, long proposedID, int pos, bool fireEvent) { 
            Exception deferredException = null; 

            if (row == null) { 
                throw ExceptionBuilder.ArgumentNull("row");
            }
            if (row.Table != this) {
                throw ExceptionBuilder.RowAlreadyInOtherCollection(); 
            }
            if (row.rowID != -1) { 
                throw ExceptionBuilder.RowAlreadyInTheCollection(); 
            }
            row.BeginEdit(); // ensure something's there. 

            int record = row.tempRecord;
            row.tempRecord = -1;
 
            if (proposedID == -1) {
                proposedID = this.nextRowID; 
            } 

            bool rollbackOnException; 
            if (rollbackOnException = (nextRowID <= proposedID)) { // WebData 109005
                nextRowID = checked(proposedID + 1);
            }
 
            try {
                try { 
                    row.rowID = proposedID; 
                    // this method may cause DataView.OnListChanged in which another row may be added
                    SetNewRecordWorker(row, record, DataRowAction.Add, false, false, pos, fireEvent, out deferredException); // now we do add the row to collection before OnRowChanged (RaiseRowChanged) 
                }
                catch {
                    if (rollbackOnException && (nextRowID == proposedID+1)) {
                        nextRowID = proposedID; 
                    }
                    row.rowID = -1; 
                    row.tempRecord = record; 
                    throw;
                } 

                // since expression evaluation occurred in SetNewRecordWorker, there may have been a problem that
                // was deferred to this point.  If so, throw now since row has already been added.
                if (deferredException != null) 
                    throw deferredException;
 
                if (EnforceConstraints && !inLoad ) { // if we are evaluating expression, we need to validate constraints 
                    int columnCount = columnCollection.Count;
                    for (int i = 0; i < columnCount; ++i) { 
                        DataColumn column = columnCollection[i];
                        if (column.Computed) {
                            column.CheckColumnConstraint(row, DataRowAction.Add);
                        } 
                    }
                } 
            } 
            finally {
                row.ResetLastChangedColumn();// if expression is evaluated while adding, before  return, we want to clear it 
            }
        }

        internal void CheckNotModifying(DataRow row) { 
            if (row.tempRecord != -1) {
                row.EndEdit(); 
                //throw ExceptionBuilder.ModifyingRow(); 
            }
        } 

        /// 
        ///    
        ///       Clears the table of all data. 
        /// 
 
        public void Clear() { 
            Clear(true);
        } 
        internal void Clear(bool clearAll) {
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, clearAll=%d{bool}\n", ObjectID, clearAll);
 
            try {
                Debug.Assert(null == rowDiffId, "wasn't previously cleared"); 
                rowDiffId = null; 

                if (dataSet != null) 
                    dataSet.OnClearFunctionCalled(this);
                bool shouldFireClearEvents = (this.Rows.Count != 0); // if Rows is already empty, this is noop

                DataTableClearEventArgs e = null; 
                if (shouldFireClearEvents) {
                    e = new DataTableClearEventArgs (this); 
                    OnTableClearing(e); 
                }
 
                if (dataSet != null && dataSet.EnforceConstraints) {

                    for (ParentForeignKeyConstraintEnumerator constraints = new ParentForeignKeyConstraintEnumerator(dataSet, this); constraints.GetNext();) {
                        ForeignKeyConstraint constraint = constraints.GetForeignKeyConstraint(); 
                        constraint.CheckCanClearParentTable(this);
                    } 
                } 

                recordManager.Clear(clearAll); 

                // SQLBU 415729: Serious performance issue when calling Clear()
                // this improves performance by iterating over rows instead of computing by index
                foreach(DataRow row in Rows) { 
                    row.oldRecord = -1;
                    row.newRecord = -1; 
                    row.tempRecord = -1; 
                    row.rowID = -1;
                    row.RBTreeNodeId = 0; 
                }
                Rows.ArrayClear();

                ResetIndexes(); 

                if (shouldFireClearEvents) { 
                    OnTableCleared(e); 
                }
 
                // SQLBU 501916 - DataTable internal index is corrupted:'5'
                foreach(DataColumn column in Columns) {
                    EvaluateDependentExpressions(column);
                } 
            }
            finally { 
                Bid.ScopeLeave(ref hscp); 
            }
        } 

        internal void CascadeAll(DataRow row, DataRowAction action) {
            if (DataSet != null && DataSet.fEnableCascading) {
                for (ParentForeignKeyConstraintEnumerator constraints = new ParentForeignKeyConstraintEnumerator(dataSet, this); constraints.GetNext();) { 
                    constraints.GetForeignKeyConstraint().CheckCascade(row, action);
                } 
            } 
        }
 
        internal void CommitRow(DataRow row) {
            // Fire Changing event
            DataRowChangeEventArgs drcevent = OnRowChanging(null, row, DataRowAction.Commit);
 
            if (!inDataLoad)
                CascadeAll(row, DataRowAction.Commit); 
 
            SetOldRecord(row, row.newRecord);
 
            OnRowChanged(drcevent, row, DataRowAction.Commit);
        }

        internal int Compare(string s1, string s2) { 
            object obj1 = s1;
            object obj2 = s2; 
            if (obj1 == obj2) 
                return 0;
            if (obj1 == null) 
                return -1;
            if (obj2 == null)
                return 1;
 
            int leng1 = s1.Length;
            int leng2 = s2.Length; 
 
            for (; leng1 > 0; leng1--) {
                if (s1[leng1-1] != 0x20 && s1[leng1-1] != 0x3000) // 0x3000 is Ideographic Whitespace 
                    break;
            }
            for (; leng2 > 0; leng2--) {
                if (s2[leng2-1] != 0x20 && s2[leng2-1] != 0x3000) 
                    break;
            } 
 
            return CompareInfo.Compare(s1, 0, leng1, s2, 0, leng2, _compareFlags);
        } 

        internal int IndexOf(string s1, string s2) {
            return CompareInfo.IndexOf(s1, s2, _compareFlags);
        } 

        internal bool IsSuffix(string s1, string s2) { 
            return CompareInfo.IsSuffix(s1, s2, _compareFlags); 
        }
 
        /// 
        ///    Computes the given expression on the current rows that pass the filter criteria.
        /// 
        public object Compute(string expression, string filter) { 
            DataRow[] rows = Select(filter, "", DataViewRowState.CurrentRows);
            DataExpression expr = new DataExpression(this, expression); 
            return expr.Evaluate(rows); 
        }
 
        bool System.ComponentModel.IListSource.ContainsListCollection {
            get {
                return false;
            } 
        }
 
        internal void CopyRow(DataTable table, DataRow row) 
        {
            int oldRecord = -1, newRecord = -1; 

            if (row == null)
                return;
 
            if (row.oldRecord != -1) {
                oldRecord = table.recordManager.ImportRecord(row.Table, row.oldRecord); 
            } 
            if (row.newRecord != -1) {
                if (row.newRecord != row.oldRecord) { 
                    newRecord = table.recordManager.ImportRecord(row.Table, row.newRecord);
                }
                else
                    newRecord = oldRecord; 
            }
 
            DataRow targetRow = table.AddRecords(oldRecord, newRecord); 

            if (row.HasErrors) { 
                targetRow.RowError = row.RowError;

                DataColumn[] cols = row.GetColumnsInError();
 
                for (int i = 0; i < cols.Length; i++) {
                    DataColumn col = targetRow.Table.Columns[cols[i].ColumnName]; 
                    targetRow.SetColumnError(col, row.GetColumnError(cols[i])); 
                }
            } 

       }

 
        internal void DeleteRow(DataRow row) {
            if (row.newRecord == -1) { 
                throw ExceptionBuilder.RowAlreadyDeleted(); 
            }
 
            // Store.PrepareForDelete(row);
            SetNewRecord(row, -1, DataRowAction.Delete, false, true);
        }
 
        private void CheckPrimaryKey() {
            if (primaryKey == null) throw ExceptionBuilder.TableMissingPrimaryKey(); 
        } 

        internal DataRow FindByPrimaryKey(object[] values) { 
            CheckPrimaryKey();
            return FindRow(primaryKey.Key, values);
        }
 
        internal DataRow FindByPrimaryKey(object value) {
            CheckPrimaryKey(); 
            return FindRow(primaryKey.Key, value); 
        }
 
        private DataRow FindRow(DataKey key, object[] values) {
            Index index = GetIndex(NewIndexDesc(key));
            Range range = index.FindRecords(values);
            if (range.IsNull) 
                return null;
            return recordManager[index.GetRecord(range.Min)]; 
        } 

        private DataRow FindRow(DataKey key, object value) { 
            Index index = GetIndex(NewIndexDesc(key));
            Range range = index.FindRecords(value);
            if (range.IsNull)
                return null; 
            return recordManager[index.GetRecord(range.Min)];
        } 
 
        internal string FormatSortString(IndexField[] indexDesc) {
            StringBuilder builder = new StringBuilder(); 
            foreach (IndexField field in indexDesc) {
                if (0 < builder.Length) {
                    builder.Append(", ");
                } 
                builder.Append(field.Column.ColumnName);
                if (field.IsDescending) { 
                    builder.Append(" DESC"); 
                }
            } 
            return builder.ToString();
        }

        internal void FreeRecord(ref int record) { 
            recordManager.FreeRecord(ref record);
        } 
 
        public DataTable GetChanges() {
            IntPtr hscp; 
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID);
            try {
                DataTable dtChanges = this.Clone();
                DataRow row = null; 

                for (int i = 0; i < Rows.Count; i++) { 
                    row = Rows[i]; 
                    if (row.oldRecord != row.newRecord)
                        dtChanges.ImportRow(row); 
                }

                if (dtChanges.Rows.Count == 0)
                    return null; 

                return dtChanges; 
            } 
            finally {
                Bid.ScopeLeave(ref hscp); 
            }
        }

        public DataTable GetChanges(DataRowState rowStates) 
        {
            IntPtr hscp; 
            Bid.ScopeEnter(out hscp, " %d#, rowStates=%d{ds.DataRowState}\n", ObjectID, (int)rowStates); 
            try {
                DataTable dtChanges = this.Clone(); 
                DataRow row = null;

                // check that rowStates is valid DataRowState
                Debug.Assert(Enum.GetUnderlyingType(typeof(DataRowState)) == typeof(Int32), "Invalid DataRowState type"); 

                for (int i = 0; i < Rows.Count; i++) { 
                    row = Rows[i]; 
                    if ((row.RowState & rowStates) != 0)
                        dtChanges.ImportRow(row); 
                }

                if (dtChanges.Rows.Count == 0)
                    return null; 

                return dtChanges; 
            } 
            finally {
                Bid.ScopeLeave(ref hscp); 
            }
        }

        ///  
        /// Returns an array of  objects that contain errors.
        ///  
        public DataRow[] GetErrors() { 
            List errorList = new List();
 
            for (int i = 0; i < Rows.Count; i++) {
                DataRow row = Rows[i];
                if (row.HasErrors) {
                    errorList.Add(row); 
                }
            } 
            DataRow[] temp = NewRowArray(errorList.Count); 
            errorList.CopyTo(temp);
            return temp; 
        }

        internal Index GetIndex(IndexField[] indexDesc) {
            return GetIndex(indexDesc, DataViewRowState.CurrentRows, (IFilter)null); 
        }
 
        internal Index GetIndex(string sort, DataViewRowState recordStates, IFilter rowFilter) { 
            return GetIndex(ParseSortString(sort), recordStates, rowFilter);
        } 

        internal Index GetIndex(IndexField[] indexDesc, DataViewRowState recordStates, IFilter rowFilter) {
            indexesLock.AcquireReaderLock(-1);
            try { 
                for (int i = 0; i < indexes.Count; i++) {
                    Index index = indexes[i]; 
                    if (index != null) { 
                        if (index.Equal(indexDesc, recordStates, rowFilter)) {
                            return index; 
                        }
                    }
                }
            } 
            finally {
                indexesLock.ReleaseReaderLock(); 
            } 
            Index ndx = new Index(this, indexDesc, recordStates, rowFilter);
            ndx.AddRef(); 
            return ndx;
        }

        IList System.ComponentModel.IListSource.GetList() { 
            return DefaultView;
        } 
 

        internal List GetListeners() { 
            return _dataViewListeners;
        }

        // We need a HashCodeProvider for Case, Kana and Width insensitive 
        internal int GetSpecialHashCode(string name) {
            int i; 
            for (i = 0; (i < name.Length) && (0x3000 > name[i]); ++i); 

            if (name.Length == i) { 
                if (null == _hashCodeProvider) {
                    // it should use the CaseSensitive property, but V1 shipped this way
                    _hashCodeProvider = StringComparer.Create(Locale, true);
                } 
                return _hashCodeProvider.GetHashCode(name);
            } 
            else { 
                return 0;
            } 
        }

        public void ImportRow(DataRow row)
        { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); 
            try { 
                int oldRecord = -1, newRecord = -1;
 
                if (row == null)
                    return;

                if (row.oldRecord != -1) { 
                    oldRecord = recordManager.ImportRecord(row.Table, row.oldRecord);
                } 
                if (row.newRecord != -1) {  // row not deleted 
                    if (row.RowState != DataRowState.Unchanged) { // not unchanged, it means Added or modified
                        newRecord = recordManager.ImportRecord(row.Table, row.newRecord); 
                    }
                    else
                        newRecord = oldRecord;
                } 

                if (oldRecord != -1 || newRecord != -1) { 
                    DataRow targetRow = AddRecords(oldRecord, newRecord); 

                    if (row.HasErrors) { 
                        targetRow.RowError = row.RowError;

                        DataColumn[] cols = row.GetColumnsInError();
 
                        for (int i = 0; i < cols.Length; i++) {
                            DataColumn col = targetRow.Table.Columns[cols[i].ColumnName]; 
                            targetRow.SetColumnError(col, row.GetColumnError(cols[i])); 
                        }
                    } 
                }
            }
            finally {
                Bid.ScopeLeave(ref hscp); 
            }
 
       } 

        internal void InsertRow(DataRow row, long proposedID) { 
            IntPtr hscp;

            Bid.ScopeEnter(out hscp, " %d#, row=%d\n", ObjectID, row.ObjectID);
            try { 
                if (row.Table != this) {
                    throw ExceptionBuilder.RowAlreadyInOtherCollection(); 
                } 
                if (row.rowID != -1) {
                    throw ExceptionBuilder.RowAlreadyInTheCollection(); 
                }
                if (row.oldRecord == -1 && row.newRecord == -1) {
                    throw ExceptionBuilder.RowEmpty();
                } 

                if (proposedID == -1) 
                    proposedID = nextRowID; 

                row.rowID = proposedID; 
                if (nextRowID <= proposedID)
                    nextRowID = checked(proposedID + 1);

                DataRowChangeEventArgs drcevent = null; 

 
                if (row.newRecord != -1) { 
                    row.tempRecord = row.newRecord;
                    row.newRecord = -1; 

                    try {
                        drcevent = RaiseRowChanging(null, row, DataRowAction.Add, true);
                    } 
                    catch {
                        row.tempRecord = -1; 
                        throw; 
                    }
 
                    row.newRecord = row.tempRecord;
                    row.tempRecord = -1;
                }
 
                if (row.oldRecord != -1)
                    recordManager[row.oldRecord] = row; 
 
                if (row.newRecord != -1)
                    recordManager[row.newRecord] = row; 

                Rows.ArrayAdd(row); // SQL BU Defect Tracking 247738, 323482 row should be in the
                                    // collection when maintaining the indexes
 
                if (row.RowState == DataRowState.Unchanged){ //  how about row.oldRecord == row.newRecord both == -1
                    RecordStateChanged(row.oldRecord, DataViewRowState.None, DataViewRowState.Unchanged); 
                } 
                else {
                    RecordStateChanged(row.oldRecord, DataViewRowState.None, row.GetRecordState(row.oldRecord), 
                                       row.newRecord, DataViewRowState.None, row.GetRecordState(row.newRecord));
                }

                if (dependentColumns != null && dependentColumns.Count > 0) 
                    EvaluateExpressions(row, DataRowAction.Add, null);
 
                RaiseRowChanged(drcevent, row, DataRowAction.Add); 
            }
            finally { 
                Bid.ScopeLeave(ref hscp);
            }
        }
 
        private IndexField [] NewIndexDesc(DataKey key) {
            Debug.Assert(key.HasValue); 
            IndexField[] indexDesc = key.GetIndexDesc(); 
            IndexField[] newIndexDesc = new IndexField[indexDesc.Length];
            Array.Copy(indexDesc, 0, newIndexDesc, 0, indexDesc.Length); 
            return newIndexDesc;
        }

        internal int NewRecord() { 
            return NewRecord(-1);
        } 
 
        internal int NewUninitializedRecord() {
            return recordManager.NewRecordBase(); 
        }

        internal int NewRecordFromArray(object[] value) {
            int colCount = columnCollection.Count; // Perf: use the readonly columnCollection field directly 
            if (colCount < value.Length) {
                throw ExceptionBuilder.ValueArrayLength(); 
            } 
            int record = recordManager.NewRecordBase();
            try { 
                for (int i = 0; i < value.Length; i++) {
                    if (null != value[i]) {
                        columnCollection[i][record] = value[i];
                    } 
                    else {
                        columnCollection[i].Init(record);  // Increase AutoIncrementCurrent 
                    } 
                }
                for (int i = value.Length; i < colCount; i++) { 
                    columnCollection[i].Init(record);
                }
                return record;
            } 
            catch (Exception e) {
                // 
                if (Common.ADP.IsCatchableOrSecurityExceptionType (e)) { 
                    FreeRecord(ref record); // WebData 104246
                } 
                throw;
            }
        }
 
        internal int NewRecord(int sourceRecord) {
            int record = recordManager.NewRecordBase(); 
 
            int count = columnCollection.Count;
            if (-1 == sourceRecord) { 
                for (int i = 0; i < count; ++i) {
                    columnCollection[i].Init(record);
                }
            } 
            else {
                for (int i = 0; i < count; ++i) { 
                    columnCollection[i].Copy(sourceRecord, record); 
                }
            } 
            return record;
        }

        internal DataRow NewEmptyRow() { 
            rowBuilder._record = -1;
            DataRow dr = NewRowFromBuilder( rowBuilder ); 
            if (dataSet != null) { 
                DataSet.OnDataRowCreated( dr );
            } 
            return dr;
        }

        private DataRow NewUninitializedRow() { 
            DataRow dr = NewRow(NewUninitializedRecord());
            return dr; 
        } 

        ///  
        /// Creates a new 
        /// with the same schema as the table.
        /// 
        public DataRow NewRow() { 
            DataRow dr = NewRow(-1);
            NewRowCreated(dr); // this is the only API we want this event to be fired 
            return dr; 
        }
 
        // Only initialize DataRelation mapping columns (approximately hidden columns)
        internal DataRow CreateEmptyRow() {
            DataRow row = this.NewUninitializedRow();
 
            foreach( DataColumn c in this.Columns ) {
                if (!XmlToDatasetMap.IsMappedColumn(c)) { 
                    if (!c.AutoIncrement) { 
                        if (c.AllowDBNull) {
                            row[c] = DBNull.Value; 
                        }
                        else if(c.DefaultValue!=null){
                            row[c] = c.DefaultValue;
                        } 
                    }
                    else { 
                        c.Init(row.tempRecord); 
                    }
                } 
            }
            return row;
        }
 
        private void NewRowCreated(DataRow row) {
            if (null != onTableNewRowDelegate) { 
                DataTableNewRowEventArgs eventArg =  new DataTableNewRowEventArgs(row); 
                OnTableNewRow(eventArg);
            } 
        }

        internal DataRow NewRow(int record) {
            if (-1 == record) { 
                record = NewRecord(-1);
            } 
 
            rowBuilder._record = record;
            DataRow row = NewRowFromBuilder( rowBuilder ); 
            recordManager[record] = row;

            if (dataSet != null)
                DataSet.OnDataRowCreated( row ); 

            return row; 
        } 

        // This is what a subclassed dataSet overrides to create a new row. 
        protected virtual DataRow NewRowFromBuilder(DataRowBuilder builder) {
            return new DataRow(builder);
        }
 
        /// 
        ///    Gets the row type. 
        ///  
        protected virtual Type GetRowType() {
            return typeof(DataRow); 
        }

        protected internal DataRow[] NewRowArray(int size) {
            if (IsTypedDataTable) { 
                if (0 == size) {
                    if (null == EmptyDataRowArray) { 
                        EmptyDataRowArray = (DataRow[]) Array.CreateInstance(GetRowType(), 0); 
                    }
                    return EmptyDataRowArray; 
                }
                return (DataRow[]) Array.CreateInstance(GetRowType(), size);
            }
            else { 
                return ((0 == size) ? DataTable.zeroRows : new DataRow[size]);
            } 
        } 

        internal bool NeedColumnChangeEvents { 
            get {
                return (IsTypedDataTable || (null != onColumnChangingDelegate) || (null != onColumnChangedDelegate));
            }
        } 

        protected internal virtual void OnColumnChanging(DataColumnChangeEventArgs e) { 
            // intentionally allow exceptions to bubble up.  We haven't committed anything yet. 
            Debug.Assert(e != null, "e should not be null");
            if (onColumnChangingDelegate != null) { 
                Bid.Trace(" %d#\n", ObjectID);
                onColumnChangingDelegate(this, e);
            }
        } 

        protected internal virtual void OnColumnChanged(DataColumnChangeEventArgs e) { 
            Debug.Assert(e != null, "e should not be null"); 
            if (onColumnChangedDelegate != null) {
                Bid.Trace(" %d#\n", ObjectID); 
                onColumnChangedDelegate(this, e);
            }
        }
 
        protected virtual void OnPropertyChanging(PropertyChangedEventArgs pcevent) {
            if (onPropertyChangingDelegate != null) { 
                Bid.Trace(" %d#\n", ObjectID); 
                onPropertyChangingDelegate(this, pcevent);
            } 
        }

        internal void OnRemoveColumnInternal(DataColumn column) {
            OnRemoveColumn(column); 
        }
 
        ///  
        /// Notifies the  that a  is
        ///    being removed. 
        /// 
        protected virtual void OnRemoveColumn(DataColumn column) {
        }
 
        private DataRowChangeEventArgs OnRowChanged(DataRowChangeEventArgs args, DataRow eRow, DataRowAction eAction) {
            if ((null != onRowChangedDelegate) || IsTypedDataTable) { 
                if (null == args) { 
                    args = new DataRowChangeEventArgs(eRow, eAction);
                } 
                OnRowChanged(args);
            }
            return args;
        } 

        private DataRowChangeEventArgs OnRowChanging(DataRowChangeEventArgs args, DataRow eRow, DataRowAction eAction) { 
            if ((null != onRowChangingDelegate) || IsTypedDataTable) { 
                if (null == args) {
                    args = new DataRowChangeEventArgs(eRow, eAction); 
                }
                OnRowChanging(args);
            }
            return args; 
        }
 
        ///  
        ///    
        ///       Raises the  event. 
        ///    
        /// 
        protected virtual void OnRowChanged(DataRowChangeEventArgs e) {
            Debug.Assert((null != e) && ((null != onRowChangedDelegate) || IsTypedDataTable), "OnRowChanged arguments"); 
            if (onRowChangedDelegate != null) {
                Bid.Trace(" %d#\n", ObjectID); 
                onRowChangedDelegate(this, e); 
            }
        } 

        /// 
        ///    
        ///       Raises the  event. 
        ///    
        ///  
        protected virtual void OnRowChanging(DataRowChangeEventArgs e) { 
            Debug.Assert((null != e) && ((null != onRowChangingDelegate) || IsTypedDataTable), "OnRowChanging arguments");
            if (onRowChangingDelegate != null) { 
                Bid.Trace(" %d#\n", ObjectID);
                onRowChangingDelegate(this, e);
           }
        } 

        ///  
        ///     
        ///       Raises the  event.
        ///     
        /// 
        protected virtual void OnRowDeleting(DataRowChangeEventArgs e) {
            Debug.Assert((null != e) && ((null != onRowDeletingDelegate) || IsTypedDataTable), "OnRowDeleting arguments");
            if (onRowDeletingDelegate != null) { 
                Bid.Trace(" %d#\n", ObjectID);
                onRowDeletingDelegate(this, e); 
            } 
        }
 
        /// 
        ///    
        ///       Raises the  event.
        ///     
        /// 
        protected virtual void OnRowDeleted(DataRowChangeEventArgs e) { 
            Debug.Assert((null != e) && ((null != onRowDeletedDelegate) || IsTypedDataTable), "OnRowDeleted arguments"); 
            if (onRowDeletedDelegate != null) {
                Bid.Trace(" %d#\n", ObjectID); 
                onRowDeletedDelegate(this, e);
            }
        }
 
        protected virtual void OnTableCleared(DataTableClearEventArgs e) {
            if (onTableClearedDelegate != null) { 
                Bid.Trace(" %d#\n", ObjectID); 
                onTableClearedDelegate(this, e);
            } 
        }

        protected virtual void OnTableClearing(DataTableClearEventArgs e) {
            if (onTableClearingDelegate != null) { 
                Bid.Trace(" %d#\n", ObjectID);
                onTableClearingDelegate(this, e); 
            } 
        }
 
        protected virtual void OnTableNewRow(DataTableNewRowEventArgs  e) {
            if (onTableNewRowDelegate != null) {
                Bid.Trace(" %d#\n", ObjectID);
                onTableNewRowDelegate(this, e); 
            }
        } 
 
        private void OnInitialized() {
            if (onInitialized != null) { 
                Bid.Trace(" %d#\n", ObjectID);
                onInitialized(this, EventArgs.Empty);
            }
        } 

 
        internal IndexField[] ParseSortString(string sortString) { 
            IndexField[] indexDesc = zeroIndexField;
            if ((null != sortString) && (0 < sortString.Length)) { 
                string[] split = sortString.Split(new char[] { ','});
                indexDesc = new IndexField[split.Length];

                for (int i = 0; i < split.Length; i++) { 
                    string current = split[i].Trim();
 
                    // handle ASC and DESC. 
                    int length = current.Length;
                    bool descending = false; 
                    if (length >= 5 && String.Compare(current, length - 4, " ASC", 0, 4, StringComparison.OrdinalIgnoreCase) == 0) {
                        current = current.Substring(0, length - 4).Trim();
                    }
                    else if (length >= 6 && String.Compare(current, length - 5, " DESC", 0, 5, StringComparison.OrdinalIgnoreCase) == 0) { 
                        descending = true;
                        current = current.Substring(0, length - 5).Trim(); 
                    } 

                    // handle brackets. 
                    if (current.StartsWith("[", StringComparison.Ordinal)) {
                        if (current.EndsWith("]", StringComparison.Ordinal)) {
                            current = current.Substring(1, current.Length - 2);
                        } 
                        else {
                            throw ExceptionBuilder.InvalidSortString(split[i]); 
                        } 
                    }
 
                    // find the column.
                    DataColumn column = Columns[current];
                    if(column == null) {
                        throw ExceptionBuilder.ColumnOutOfRange(current); 
                    }
                    indexDesc[i] = new IndexField(column, descending); 
                } 
            }
            return indexDesc; 
        }

        internal void RaisePropertyChanging(string name) {
            OnPropertyChanging(new PropertyChangedEventArgs(name)); 
        }
 
        // Notify all indexes that record changed. 
        // Only called when Error was changed.
        internal void RecordChanged(int record) { 
            Debug.Assert (record != -1, "Record number must be given");
            SetShadowIndexes(); // how about new assert?
            try {
                int numIndexes = shadowIndexes.Count; 
                for (int i = 0; i < numIndexes; i++) {
                    Index ndx = shadowIndexes[i];// shadowindexes may change, see ShadowIndexCopy() 
                    if (0 < ndx.RefCount) { 
                        ndx.RecordChanged(record);
                    } 
                }
            }
            finally{
                RestoreShadowIndexes(); 
            }
        } 
 
// for each index in liveindexes invok RecordChanged
// oldIndex and newIndex keeps  position of record before delete and after insert in each index in order 
// LiveIndexes[n-m] will have its information in oldIndex[n-m] and  newIndex[n-m]
        internal void RecordChanged(int[] oldIndex, int[] newIndex) {
            SetShadowIndexes();
            Debug.Assert (oldIndex.Length == newIndex.Length,  "Size oldIndexes and newIndexes should be the same"); 
            Debug.Assert (oldIndex.Length == shadowIndexes.Count, "Size of OldIndexes should be the same as size of Live indexes");
            try{ 
                int numIndexes = shadowIndexes.Count; 
                for (int i = 0; i < numIndexes; i++) {
                    Index ndx = shadowIndexes[i];// shadowindexes may change, see ShadowIndexCopy() 
                    if (0 < ndx.RefCount) {
                        ndx.RecordChanged(oldIndex[i], newIndex[i]);
                    }
                } 

            } 
            finally{ 
                RestoreShadowIndexes();
            } 
        }

        internal void RecordStateChanged(int record, DataViewRowState oldState, DataViewRowState newState) {
            SetShadowIndexes(); 
            try{
                int numIndexes = shadowIndexes.Count; 
                for (int i = 0; i < numIndexes; i++) { 
                    Index ndx = shadowIndexes[i];// shadowindexes may change, see ShadowIndexCopy()
                    if (0 < ndx.RefCount) { 
                        ndx.RecordStateChanged(record, oldState, newState);
                    }
                }
            } 
            finally{
                RestoreShadowIndexes(); 
            } 
            // System.Data.XML.Store.Store.OnROMChanged(record, oldState, newState);
        } 


        internal void RecordStateChanged(int record1, DataViewRowState oldState1, DataViewRowState newState1,
                                         int record2, DataViewRowState oldState2, DataViewRowState newState2) { 
            SetShadowIndexes();
            try{ 
                int numIndexes = shadowIndexes.Count; 
                for (int i = 0; i < numIndexes; i++) {
                    Index ndx = shadowIndexes[i];// shadowindexes may change, see ShadowIndexCopy() 
                    if (0 < ndx.RefCount) {
                        if (record1 != -1 && record2 != -1)
                            ndx.RecordStateChanged(record1, oldState1, newState1,
                                                   record2, oldState2, newState2); 
                        else if (record1 != -1)
                            ndx.RecordStateChanged(record1, oldState1, newState1); 
                        else if (record2 != -1) 
                            ndx.RecordStateChanged(record2, oldState2, newState2);
                    } 
                }
            }
            finally {
                RestoreShadowIndexes(); 
            }
            // System.Data.XML.Store.Store.OnROMChanged(record1, oldState1, newState1, record2, oldState2, newState2); 
        } 

 
// RemoveRecordFromIndexes removes the given record (using row and version) from all indexes and it  stores and returns the position of deleted
// record from each index
// IT SHOULD NOT CAUSE ANY EVENT TO BE FIRED
        internal int[] RemoveRecordFromIndexes(DataRow row, DataRowVersion  version) { 
            int    indexCount          =  LiveIndexes.Count;
            int [] positionIndexes =  new int[indexCount]; 
 
            int recordNo = row.GetRecordFromVersion(version);
            DataViewRowState states = row.GetRecordState(recordNo); 

            while (--indexCount >= 0) {
                if (row.HasVersion(version) && ((states & indexes[indexCount].RecordStates) != DataViewRowState.None)) {
                    int index = indexes[indexCount].GetIndex(recordNo); 
                    if (index > -1) {
                        positionIndexes [indexCount] = index; 
                        indexes[indexCount].DeleteRecordFromIndex(index); // this will delete the record from index and MUSt not fire event 
                    }
                    else { 
                        positionIndexes [indexCount] = -1; // this means record was not in index
                    }
                }
                else { 
                    positionIndexes [indexCount] = -1; // this means record was not in index
                } 
            } 
            return positionIndexes;
        } 

// InsertRecordToIndexes inserts the given record (using row and version) to all indexes and it  stores and returns the position of inserted
// record to each index
// IT SHOULD NOT CAUSE ANY EVENT TO BE FIRED 
        internal int[] InsertRecordToIndexes(DataRow row, DataRowVersion  version) {
            int    indexCount          =  LiveIndexes.Count; 
            int [] positionIndexes =  new int[indexCount]; 

            int recordNo = row.GetRecordFromVersion(version); 
            DataViewRowState states = row.GetRecordState(recordNo);

            while (--indexCount >= 0) {
                if (row.HasVersion(version)) { 
                    if ((states & indexes[indexCount].RecordStates) != DataViewRowState.None) {
                        positionIndexes [indexCount] = indexes[indexCount].InsertRecordToIndex(recordNo); 
                    } 
                    else {
                        positionIndexes [indexCount] = -1; 
                    }
                }
            }
            return positionIndexes; 
        }
 
        internal void SilentlySetValue(DataRow dr, DataColumn dc, DataRowVersion version, object newValue) { 
            // get record for version
            int record = dr.GetRecordFromVersion(version); 

            bool equalValues = false;
            if (DataStorage.IsTypeCustomType(dc.DataType) && newValue != dc[record]) {
                // if UDT storage, need to check if reference changed. See bug 385182 
                equalValues = false;
            } 
            else { 
                equalValues = dc.CompareValueTo(record, newValue, true);
            } 

            // if expression has changed
            if (!equalValues) {
                int[] oldIndex = dr.Table.RemoveRecordFromIndexes(dr, version);// conditional, if it exists it will try to remove with no event fired 
                dc.SetValue(record, newValue);
                int[] newIndex = dr.Table.InsertRecordToIndexes(dr, version);// conditional, it will insert if it qualifies, no event will be fired 
                if (dr.HasVersion(version)) { 
                    if (version != DataRowVersion.Original) {
                        dr.Table.RecordChanged(oldIndex, newIndex); 
                    }
                    if (dc.dependentColumns != null) {
                        //BugBug - passing in null for cachedRows.  This means expression columns as keys does not work when key changes.
                        dc.Table.EvaluateDependentExpressions(dc.dependentColumns, dr, version, null); 
                    }
                } 
             } 
             dr.ResetLastChangedColumn();
        } 

        /// 
        ///    Rolls back all changes that have been made to the table
        ///       since it was loaded, or the last time  was called. 
        /// 
        public void RejectChanges() { 
            IntPtr hscp; 
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID);
            try{ 
                DataRow[] oldRows = new DataRow[Rows.Count];
                Rows.CopyTo(oldRows, 0);

                for (int i = 0; i < oldRows.Length; i++) { 
                    RollbackRow(oldRows[i]);
                } 
            } 
            finally{
                Bid.ScopeLeave(ref hscp); 
            }

        }
 
        internal void RemoveRow(DataRow row, bool check) {
            if (row.rowID == -1) { 
                throw ExceptionBuilder.RowAlreadyRemoved(); 
            }
 
            if (check && dataSet != null) {
                for (ParentForeignKeyConstraintEnumerator constraints = new ParentForeignKeyConstraintEnumerator(dataSet, this); constraints.GetNext();) {
                    constraints.GetForeignKeyConstraint().CheckCanRemoveParentRow(row);
                } 
            }
 
            int oldRecord = row.oldRecord; 
            int newRecord = row.newRecord;
 
            DataViewRowState oldRecordStatePre = row.GetRecordState(oldRecord);
            DataViewRowState newRecordStatePre = row.GetRecordState(newRecord);

            row.oldRecord = -1; 
            row.newRecord = -1;
 
            if (oldRecord == newRecord) { 
                oldRecord = -1;
            } 

            RecordStateChanged(oldRecord, oldRecordStatePre, DataViewRowState.None,
                               newRecord, newRecordStatePre, DataViewRowState.None);
 
            FreeRecord(ref oldRecord);
            FreeRecord(ref newRecord); 
 
            row.rowID = -1;
            Rows.ArrayRemove(row); 
        }

        // Resets the table back to its original state.
        public virtual void Reset() { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); 
            try { 
                Clear();
                ResetConstraints(); 

                DataRelationCollection dr = this.ParentRelations;
                int count = dr.Count;
                  while (count > 0) { 
                   count--;
                   dr.RemoveAt(count); 
                } 

                dr = this.ChildRelations; 
                count = dr.Count;
                  while (count > 0) {
                   count--;
                   dr.RemoveAt(count); 
                }
 
                Columns.Clear(); 
                indexes.Clear();
            } 
            finally{
                Bid.ScopeLeave(ref hscp);
            }
        } 

        internal void ResetIndexes() { 
            ResetInternalIndexes(null); 
        }
 
        internal void ResetInternalIndexes(DataColumn column) {
            Debug.Assert(null != indexes, "unexpected null indexes");
            SetShadowIndexes();
            try{ 
                // the length of shadowIndexes will not change
                // but the array instance may change during 
                // events during Index.Reset 
                int numIndexes = shadowIndexes.Count;
                for (int i = 0; i < numIndexes; i++) { 
                    Index ndx = shadowIndexes[i];// shadowindexes may change, see ShadowIndexCopy()
                    if (0 < ndx.RefCount) {
                        if (null == column) {
                            ndx.Reset(); 
                        }
                        else { 
                            // SQLBU 501916: DataTable internal index is corrupted:'5' 
                            bool found = false;
                            foreach(IndexField field in ndx.IndexFields) { 
                                if (Object.ReferenceEquals(column, field.Column)) {
                                    found = true;
                                    break;
 
                                }
                            } 
                            if (found) { 
                                ndx.Reset();
                            } 
                        }
                    }
                }
            } 
            finally {
                RestoreShadowIndexes(); 
            } 
        }
 
        internal void RollbackRow(DataRow row) {
            row.CancelEdit();
            SetNewRecord(row, row.oldRecord, DataRowAction.Rollback, false, true);
        } 

        private DataRowChangeEventArgs RaiseRowChanged(DataRowChangeEventArgs args, DataRow eRow, DataRowAction eAction) { 
            try { 
                if (UpdatingCurrent(eRow, eAction) && (IsTypedDataTable || (null != onRowChangedDelegate))) {
                    args = OnRowChanged(args, eRow, eAction); 
                }
                // check if we deleting good row
                else if (DataRowAction.Delete == eAction && eRow.newRecord == -1 && (IsTypedDataTable || (null != onRowDeletedDelegate))) {
                    if (null == args) { 
                        args = new DataRowChangeEventArgs(eRow, eAction);
                    } 
                    OnRowDeleted(args); 
                }
            } 
            catch (Exception f) {
               //
               if (!Common.ADP.IsCatchableExceptionType(f)) {
                 throw; 
               }
               ExceptionBuilder.TraceExceptionWithoutRethrow(f); 
               // ignore the exception 
            }
            return args; 
        }

        private DataRowChangeEventArgs RaiseRowChanging(DataRowChangeEventArgs args, DataRow eRow, DataRowAction eAction) {
            if (UpdatingCurrent(eRow, eAction) && (IsTypedDataTable || (null != onRowChangingDelegate))) { 
                eRow.inChangingEvent = true;
 
                // don't catch 
                try {
                    args = OnRowChanging(args, eRow, eAction); 
                }
                finally {
                    eRow.inChangingEvent = false;
                } 
            }
            // check if we deleting good row 
            else if (DataRowAction.Delete == eAction && eRow.newRecord != -1 && (IsTypedDataTable || (null != onRowDeletingDelegate))) { 
                eRow.inDeletingEvent = true;
                // don't catch 
                try {
                    if (null == args) {
                        args = new DataRowChangeEventArgs(eRow, eAction);
                    } 
                    OnRowDeleting(args);
                } 
                finally { 
                    eRow.inDeletingEvent = false;
                } 
            }
            return args;
        }
 
        private DataRowChangeEventArgs RaiseRowChanging(DataRowChangeEventArgs args, DataRow eRow, DataRowAction eAction, bool fireEvent) {
 
            // check all constraints 
            if (EnforceConstraints && !inLoad ) {
                int columnCount = columnCollection.Count; 
                for(int i = 0; i < columnCount; ++i) {
                    DataColumn column = columnCollection[i];
                    if (!column.Computed || eAction != DataRowAction.Add) {
                        column.CheckColumnConstraint(eRow, eAction); 
                    }
                } 
 
                int constraintCount = constraintCollection.Count;
                for(int i = 0; i < constraintCount; ++i) { 
                    constraintCollection[i].CheckConstraint(eRow, eAction);
                }
            }
 
            // $$anandra.  Check this event out. May be an issue.
            if (fireEvent) { 
                args = RaiseRowChanging(args, eRow, eAction); 
            }
 
            if (!inDataLoad) {
                // cascade things...
                if (!MergingData && eAction != DataRowAction.Nothing && eAction != DataRowAction.ChangeOriginal) {
                    CascadeAll(eRow, eAction); 
                }
            } 
            return args; 
        }
 
        /// 
        /// Returns an array of all  objects.
        /// 
        public DataRow[] Select() { 
            Bid.Trace(" %d#\n", ObjectID);
            return new Select(this, "", "", DataViewRowState.CurrentRows).SelectRows(); 
        } 

        ///  
        /// Returns an array of all  objects that match the filter criteria in order of
        ///    primary key (or lacking one, order of addition.)
        /// 
        public DataRow[] Select(string filterExpression) { 
            Bid.Trace(" %d#, filterExpression='%ls'\n", ObjectID, filterExpression);
            return new Select(this, filterExpression, "", DataViewRowState.CurrentRows).SelectRows(); 
        } 

        ///  
        /// Returns an array of all  objects that match the filter criteria, in the the
        ///    specified sort order.
        /// 
        public DataRow[] Select(string filterExpression, string sort) { 
            Bid.Trace(" %d#, filterExpression='%ls', sort='%ls'\n", ObjectID, filterExpression, sort);
            return new Select(this, filterExpression, sort, DataViewRowState.CurrentRows).SelectRows(); 
        } 

        ///  
        /// Returns an array of all  objects that match the filter in the order of the
        ///    sort, that match the specified state.
        /// 
        public DataRow[] Select(string filterExpression, string sort, DataViewRowState recordStates) { 
            Bid.Trace(" %d#, filterExpression='%ls', sort='%ls', recordStates=%d{ds.DataViewRowState}\n", ObjectID, filterExpression, sort, (int)recordStates);
            return new Select(this, filterExpression, sort, recordStates).SelectRows(); 
        } 

        internal void SetNewRecord(DataRow row, int proposedRecord, DataRowAction action = DataRowAction.Change, bool isInMerge = false, bool fireEvent = true, bool suppressEnsurePropertyChanged = false) { 
            Exception deferredException = null;
            SetNewRecordWorker(row, proposedRecord, action, isInMerge, suppressEnsurePropertyChanged, -1, fireEvent, out deferredException); // we are going to call below overload from insert
            if (deferredException != null) {
                throw deferredException; 
            }
        } 
 
        private void SetNewRecordWorker(DataRow row, int proposedRecord, DataRowAction action, bool isInMerge, bool suppressEnsurePropertyChanged,
            int position, bool fireEvent, out Exception deferredException) { 

            // this is the event workhorse... it will throw the changing/changed events
            // and update the indexes. Used by change, add, delete, revert.
 
            // order of execution is as follows
            // 
            // 1) set temp record 
            // 2) Check constraints for non-expression columns
            // 3) Raise RowChanging/RowDeleting with temp record 
            // 4) set the new record in storage
            // 5) Update indexes with recordStateChanges - this will fire ListChanged & PropertyChanged events on associated views
            // 6) Evaluate all Expressions (exceptions are deferred)- this will fire ListChanged & PropertyChanged events on associated views
            // 7) Raise RowChanged/ RowDeleted 
            // 8) Check constraints for expression columns
 
            Debug.Assert(row != null, "Row can't be null."); 
            deferredException = null;
 
            if (row.tempRecord != proposedRecord) {
                // $HACK: for performance reasons, EndUpdate calls SetNewRecord with tempRecord == proposedRecord
                if (!inDataLoad) {
                    row.CheckInTable(); 
                    CheckNotModifying(row);
                } 
                if (proposedRecord == row.newRecord) { 
                    if (isInMerge) {
                        Debug.Assert(fireEvent, "SetNewRecord is called with wrong parameter"); 
                        RaiseRowChanged(null, row, action);
                    }
                    return;
                } 

                Debug.Assert(!row.inChangingEvent, "How can this row be in an infinite loop?"); 
 
                row.tempRecord = proposedRecord;
            } 
            DataRowChangeEventArgs drcevent = null;

            try {
                row._action = action; 
                drcevent = RaiseRowChanging(null, row, action, fireEvent);
            } 
            catch { 
                row.tempRecord = -1;
                throw; 
            }
            finally {
                row._action = DataRowAction.Nothing;
            } 

            row.tempRecord = -1; 
 
            int currentRecord = row.newRecord;
 
            // if we're deleting, then the oldRecord value will change, so need to track that if it's distinct from the newRecord.
            int secondRecord = (proposedRecord != -1 ?
                                proposedRecord :
                                (row.RowState != DataRowState.Unchanged ? 
                                 row.oldRecord :
                                 -1)); 
 
            if (action == DataRowAction.Add) { //if we come here from insert we do insert the row to collection
                if (position == -1) 
                    Rows.ArrayAdd(row);
                else
                    Rows.ArrayInsert(row, position);
            } 

            List cachedRows = null; 
            if ((action == DataRowAction.Delete || action == DataRowAction.Change) 
                && dependentColumns != null && dependentColumns.Count > 0) {
                // if there are expression columns, need to cache related rows for deletes and updates (key changes) 
                // before indexes are modified.
                cachedRows = new List();
                for (int j = 0; j < ParentRelations.Count; j++) {
                    DataRelation relation = ParentRelations[j]; 
                    if (relation.ChildTable != row.Table) {
                        continue; 
                    } 
                    cachedRows.InsertRange(cachedRows.Count, row.GetParentRows(relation));
                } 

                for (int j = 0; j < ChildRelations.Count; j++) {
                    DataRelation relation = ChildRelations[j];
                    if (relation.ParentTable != row.Table) { 
                        continue;
                    } 
                    cachedRows.InsertRange(cachedRows.Count, row.GetChildRows(relation)); 
                }
            } 

            // Dev10 Bug 688779: DataRowView.PropertyChanged are not raised on RejectChanges
            // if the newRecord is changing, the propertychanged event should be allowed to triggered for ListChangedType.Changed or .Moved
            // unless the specific condition is known that no data has changed, like DataRow.SetModified() 
            if (!suppressEnsurePropertyChanged && !row.HasPropertyChanged && (row.newRecord != proposedRecord)
                && (-1 != proposedRecord) // explictly not fixing Dev10 Bug 692044: DataRowView.PropertyChanged are not raised on DataTable.Delete when mixing current and original records in RowStateFilter 
                && (-1 != row.newRecord)) // explictly not fixing parts of Dev10 Bug 697909: when mixing current and original records in RowStateFilter 
            {
                // DataRow will believe multiple edits occured and 
                // DataView.ListChanged event w/ ListChangedType.ItemChanged will raise DataRowView.PropertyChanged event and
                // PropertyChangedEventArgs.PropertyName will now be empty string so
                // WPF will refresh the entire row
                row.LastChangedColumn = null; 
                row.LastChangedColumn = null;
            } 
 
                // Check whether we need to update indexes
                if (LiveIndexes.Count != 0) { 

                    // Dev10 bug #463087: DataTable internal index is currupted: '5'
                    if ((-1 == currentRecord) && (-1 != proposedRecord) && (-1 != row.oldRecord) && (proposedRecord != row.oldRecord)) {
                        // the transition from DataRowState.Deleted -> DataRowState.Modified 
                        // with same orginal record but new current record
                        // needs to raise an ItemChanged or ItemMoved instead of ItemAdded in the ListChanged event. 
                        // for indexes/views listening for both DataViewRowState.Deleted | DataViewRowState.ModifiedCurrent 
                        currentRecord = row.oldRecord;
                    } 

                    DataViewRowState currentRecordStatePre = row.GetRecordState(currentRecord);
                    DataViewRowState secondRecordStatePre = row.GetRecordState(secondRecord);
 
                    row.newRecord = proposedRecord;
                    if (proposedRecord != -1) 
                        this.recordManager[proposedRecord] = row; 

                    DataViewRowState currentRecordStatePost = row.GetRecordState(currentRecord); 
                    DataViewRowState secondRecordStatePost = row.GetRecordState(secondRecord);

                    // may raise DataView.ListChanged event
                    RecordStateChanged(currentRecord, currentRecordStatePre, currentRecordStatePost, 
                        secondRecord, secondRecordStatePre, secondRecordStatePost);
                } 
                else { 
                    row.newRecord = proposedRecord;
                    if (proposedRecord != -1) 
                        this.recordManager[proposedRecord] = row;
                }

                // Dev10 Bug 461199 - reset the last changed column here, after all 
                // DataViews have raised their DataRowView.PropertyChanged event
                row.ResetLastChangedColumn(); 
 
                // SQLBU 278737: Record manager corruption when reentrant write operations
                // free the 'currentRecord' only after all the indexes have been updated. 
                // Corruption! { if (currentRecord != row.oldRecord) { FreeRecord(ref currentRecord); } }
                // RecordStateChanged raises ListChanged event at which time user may do work
                if (-1 != currentRecord) {
                    if (currentRecord != row.oldRecord) 
                    {
                        if ((currentRecord != row.tempRecord) &&   // Delete, AcceptChanges, BeginEdit 
                            (currentRecord != row.newRecord) &&    // RejectChanges & SetAdded 
                            (row == recordManager[currentRecord])) // AcceptChanges, NewRow
                        { 
                            FreeRecord(ref currentRecord);
                        }
                    }
                } 

            if (row.RowState == DataRowState.Detached && row.rowID != -1) { 
                RemoveRow(row, false); 
            }
 
            if (dependentColumns != null && dependentColumns.Count > 0) {
                try {
                    EvaluateExpressions(row, action, cachedRows);
                } 
                catch (Exception exc) {
                    // For DataRows being added, throwing of exception from expression evaluation is 
                    // deferred until after the row has been completely added. 
                    if (action != DataRowAction.Add) {
                        throw exc; 
                    }
                    else {
                        deferredException = exc;
                    } 
                }
            } 
 
            try {
                if (fireEvent) { 
                    RaiseRowChanged(drcevent, row, action);
                }
            }
            catch (Exception e) { 
                //
                if (!Common.ADP.IsCatchableExceptionType(e)) { 
                    throw; 
                }
                ExceptionBuilder.TraceExceptionWithoutRethrow(e); 
                // ignore the exception
            }
        }
 
        // this is the event workhorse... it will throw the changing/changed events
        // and update the indexes. 
        internal void SetOldRecord(DataRow row, int proposedRecord) { 
            if (!inDataLoad) {
                row.CheckInTable(); 
                CheckNotModifying(row);
            }

            if (proposedRecord == row.oldRecord) { 
                return;
            } 
 
            int originalRecord = row.oldRecord; // cache old record after potential RowChanging event
            try { 
                // Check whether we need to update indexes
                if (LiveIndexes.Count != 0) {

                    // Dev10 bug #463087: DataTable internal index is currupted: '5' 
                    if ((-1 == originalRecord) && (-1 != proposedRecord) && (-1 != row.newRecord) && (proposedRecord != row.newRecord)) {
                        // the transition from DataRowState.Added -> DataRowState.Modified 
                        // with same current record but new original record 
                        // needs to raise an ItemChanged or ItemMoved instead of ItemAdded in the ListChanged event.
                        // for indexes/views listening for both DataViewRowState.Added | DataViewRowState.ModifiedOriginal 
                        originalRecord = row.newRecord;
                    }

                    DataViewRowState originalRecordStatePre = row.GetRecordState(originalRecord); 
                    DataViewRowState proposedRecordStatePre = row.GetRecordState(proposedRecord);
 
                    row.oldRecord = proposedRecord; 
                    if (proposedRecord != -1)
                        this.recordManager[proposedRecord] = row; 

                    DataViewRowState originalRecordStatePost = row.GetRecordState(originalRecord);
                    DataViewRowState proposedRecordStatePost = row.GetRecordState(proposedRecord);
 
                    RecordStateChanged(originalRecord, originalRecordStatePre, originalRecordStatePost,
                                       proposedRecord, proposedRecordStatePre, proposedRecordStatePost); 
                } 
                else {
                    row.oldRecord = proposedRecord; 
                    if (proposedRecord != -1)
                        this.recordManager[proposedRecord] = row;
                }
            } 
            finally {
                if ((originalRecord != -1) && (originalRecord != row.tempRecord) && 
                    (originalRecord != row.oldRecord) && (originalRecord != row.newRecord)) { 

                    FreeRecord(ref originalRecord); 
                }
                // else during an event 'row.AcceptChanges(); row.BeginEdit(); row.EndEdit();'

                if (row.RowState == DataRowState.Detached && row.rowID != -1) { 
                    RemoveRow(row, false);
                } 
            } 
        }
 
        private void RestoreShadowIndexes() {
            Debug.Assert(1 <= shadowCount, "unexpected negative shadow count");
            shadowCount--;
            if (0 == shadowCount) { 
                shadowIndexes = null;
            } 
        } 

        private void SetShadowIndexes() { 
            if (null == shadowIndexes) {
                Debug.Assert(0 == shadowCount, "unexpected count");
                shadowIndexes = LiveIndexes;
                shadowCount = 1; 
            }
            else { 
                Debug.Assert(1 <= shadowCount, "unexpected negative shadow count"); 
                shadowCount++;
            } 
        }

        internal void ShadowIndexCopy(){
            if (shadowIndexes == indexes) { 
                Debug.Assert(0 < indexes.Count, "unexpected");
                shadowIndexes = new List(indexes); 
            } 
        }
 
        /// 
        /// Returns the  and , if there is one as a concatenated string.
        /// 
        public override string ToString() { 
            if (this.displayExpression == null)
                return this.TableName; 
            else 
                return this.TableName + " + " + this.DisplayExpressionInternal;
        } 

        /// 
        ///    [To be supplied.]
        ///  
        public void BeginLoadData() {
            IntPtr hscp; 
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); 
            try {
                if (inDataLoad) 
                    return;

                inDataLoad = true;
                Debug.Assert(null == loadIndex, "loadIndex should already be null"); 
                loadIndex  = null;
                // LoadDataRow may have been called before BeginLoadData and already 
                // initialized loadIndexwithOriginalAdded & loadIndexwithCurrentDeleted 

                initialLoad = (Rows.Count == 0); 
                if(initialLoad) {
                    SuspendIndexEvents();
                } else {
                    if (primaryKey != null) { 
                        loadIndex = primaryKey.Key.GetSortIndex(DataViewRowState.OriginalRows);
                    } 
                    if(loadIndex != null) { 
                        loadIndex.AddRef();
                    } 
                }

                if (DataSet != null) {
                    savedEnforceConstraints = DataSet.EnforceConstraints; 
                    DataSet.EnforceConstraints = false;
                } 
                else { 
                    this.EnforceConstraints = false;
                } 
            }
            finally{
                Bid.ScopeLeave(ref hscp);
            } 
        }
 
        ///  
        ///    [To be supplied.]
        ///  
        public void EndLoadData() {
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID);
            try { 
                if (!inDataLoad)
                    return; 
 
                if(loadIndex != null) {
                    loadIndex.RemoveRef(); 
                }
                if (loadIndexwithOriginalAdded  != null) {
                    loadIndexwithOriginalAdded.RemoveRef();
                } 
                if (loadIndexwithCurrentDeleted  != null) {
                    loadIndexwithCurrentDeleted.RemoveRef(); 
                } 

                loadIndex  = null; 
                loadIndexwithOriginalAdded = null;
                loadIndexwithCurrentDeleted = null;

                inDataLoad = false; 

                RestoreIndexEvents(false); 
 
                if (DataSet != null)
                    DataSet.EnforceConstraints = savedEnforceConstraints; 
                else
                    this.EnforceConstraints = true;
            }
            finally{ 
                Bid.ScopeLeave(ref hscp);
            } 
        } 

        ///  
        ///    Finds and updates a specific row. If no matching
        ///       row is found, a new row is created using the given values.
        /// 
        public DataRow LoadDataRow(object[] values, bool fAcceptChanges) { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, fAcceptChanges=%d{bool}\n", ObjectID, fAcceptChanges); 
            try { 
                DataRow row;
                if (inDataLoad) { 
                    int record = NewRecordFromArray(values);
                    if (loadIndex != null) {
                        // not expecting LiveIndexes to clear the index we use between calls to LoadDataRow
                        Debug.Assert(2 <= loadIndex.RefCount, "bad loadIndex.RefCount"); 

                        int result = loadIndex.FindRecord(record); 
                        if (result != -1) { 
                            int resultRecord = loadIndex.GetRecord(result);
                            row = recordManager[resultRecord]; 
                            Debug.Assert (row != null, "Row can't be null for index record");
                            row.CancelEdit();
                            if (row.RowState == DataRowState.Deleted)
                                SetNewRecord(row, row.oldRecord, DataRowAction.Rollback, false, true); 
                            SetNewRecord(row, record, DataRowAction.Change, false, true);
                            if (fAcceptChanges) 
                                row.AcceptChanges(); 
                            return row;
                        } 
                    }
                    row = NewRow(record);
                    AddRow(row);
                    if (fAcceptChanges) 
                        row.AcceptChanges();
                    return row; 
                } 
                else {
                    // In case, BeginDataLoad is not called yet 
                    row = UpdatingAdd(values);
                    if (fAcceptChanges)
                        row.AcceptChanges();
                    return row; 
                }
            } 
            finally{ 
                Bid.ScopeLeave(ref hscp);
            } 
        }

        /// 
        ///    Finds and updates a specific row. If no matching 
        ///       row is found, a new row is created using the given values.
        ///  
        public DataRow LoadDataRow(object[] values, LoadOption loadOption) { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, loadOption=%d{ds.LoadOption}\n", ObjectID,  (int)loadOption); 
            try {
                Index indextoUse = null;
                if (this.primaryKey != null) {
                    if (loadOption == LoadOption.Upsert) { // CurrentVersion, and Deleted 
                        if (loadIndexwithCurrentDeleted == null) {
                            loadIndexwithCurrentDeleted = this.primaryKey.Key.GetSortIndex(DataViewRowState.CurrentRows |DataViewRowState.Deleted); 
                            Debug.Assert(loadIndexwithCurrentDeleted != null, "loadIndexwithCurrentDeleted should not be null" ); 
                            if (loadIndexwithCurrentDeleted != null) {
                                loadIndexwithCurrentDeleted.AddRef(); 
                            }
                        }
                        indextoUse = loadIndexwithCurrentDeleted;
                    } 
                    else {// CurrentVersion, and Deleted : OverwriteRow, PreserveCurrentValues
                        if (loadIndexwithOriginalAdded == null) { 
                            loadIndexwithOriginalAdded  = this.primaryKey.Key.GetSortIndex(DataViewRowState.OriginalRows |DataViewRowState.Added); 
                            Debug.Assert(loadIndexwithOriginalAdded != null, "loadIndexwithOriginalAdded should not be null");
                            if (loadIndexwithOriginalAdded != null) { 
                                loadIndexwithOriginalAdded.AddRef();
                            }
                        }
                        indextoUse = loadIndexwithOriginalAdded; 
                    }
                    // not expecting LiveIndexes to clear the index we use between calls to LoadDataRow 
                    Debug.Assert(2 <= indextoUse.RefCount, "bad indextoUse.RefCount"); 
                }
                if(inDataLoad && !AreIndexEventsSuspended) { // we do not want to fire any listchanged in new Load/Fill 
                    SuspendIndexEvents();// so suspend events here(not suspended == table already has some rows initially)
                }

                DataRow dataRow = LoadRow(values, loadOption, indextoUse);// if indextoUse == null, it means we dont have PK, 
                                                                          // so LoadRow will take care of just adding the row to end
 
                return dataRow; 
            }
            finally { 
                Bid.ScopeLeave(ref hscp);
            }
        }
 
        internal DataRow UpdatingAdd(object[] values) {
            Index index = null; 
            if (this.primaryKey != null) { 
                index = this.primaryKey.Key.GetSortIndex(DataViewRowState.OriginalRows);
            } 

            if (index != null) {
                int record = NewRecordFromArray(values);
                int result = index.FindRecord(record); 
                if (result != -1) {
                    int resultRecord = index.GetRecord(result); 
                    DataRow row = this.recordManager[resultRecord]; 
                    Debug.Assert (row != null, "Row can't be null for index record");
                    row.RejectChanges(); 
                    this.SetNewRecord(row, record);
                    return row;
                }
                DataRow row2 = NewRow(record); 
                Rows.Add(row2);
                return row2; 
            } 

            return Rows.Add(values); 
        }

        internal bool UpdatingCurrent(DataRow row, DataRowAction action) {
            return(action == DataRowAction.Add || action == DataRowAction.Change || 
                   action == DataRowAction.Rollback || action == DataRowAction.ChangeOriginal ||
                   action == DataRowAction.ChangeCurrentAndOriginal); 
//                (action == DataRowAction.Rollback && row.tempRecord != -1)); 
}
 
        internal DataColumn AddUniqueKey(int position) {
            if (_colUnique != null)
                return _colUnique;
 
            // check to see if we can use already existant PrimaryKey
            DataColumn[] pkey = PrimaryKey; 
            if (pkey.Length == 1) 
                // We have one-column primary key, so we can use it in our heirarchical relation
                return pkey[0]; 

            // add Unique, but not primaryKey to the table

            string keyName = XMLSchema.GenUniqueColumnName(TableName + "_Id", this); 
            DataColumn key = new DataColumn(keyName, typeof(Int32), null, MappingType.Hidden);
            key.Prefix = tablePrefix; 
            key.AutoIncrement = true; 
            key.AllowDBNull = false;
            key.Unique = true; 

            if (position == -1)
                Columns.Add(key);
            else { // we do have a problem and Imy idea is it is bug. Ask Enzo while Code review. Why we do not set ordinal when we call AddAt? 
                for(int i = Columns.Count -1; i >= position; i--) {
                    this.Columns[i].SetOrdinalInternal(i+1); 
                } 
                Columns.AddAt(position, key);
                key.SetOrdinalInternal(position); 
            }

            if (pkey.Length == 0)
                PrimaryKey = new DataColumn[] { 
                    key
                }; 
 
            _colUnique = key;
            return _colUnique; 
        }

        internal DataColumn AddUniqueKey() {
            return AddUniqueKey(-1); 
        }
 
        internal DataColumn AddForeignKey(DataColumn parentKey) { 
            Debug.Assert(parentKey != null, "AddForeignKey: Invalid paramter.. related primary key is null");
 
            string      keyName = XMLSchema.GenUniqueColumnName(parentKey.ColumnName, this);
            DataColumn  foreignKey = new DataColumn(keyName, parentKey.DataType, null, MappingType.Hidden);
            Columns.Add(foreignKey);
 
            return foreignKey;
        } 
 
        internal void UpdatePropertyDescriptorCollectionCache() {
            propertyDescriptorCollectionCache = null; 
        }

        /// 
        ///     Retrieves an array of properties that the given component instance 
        ///     provides.  This may differ from the set of properties the class
        ///     provides.  If the component is sited, the site may add or remove 
        ///     additional properties.  The returned array of properties will be 
        ///     filtered by the given set of attributes.
        ///  
        internal PropertyDescriptorCollection GetPropertyDescriptorCollection(Attribute[] attributes) {
            if (propertyDescriptorCollectionCache == null) {
                int columnsCount   = Columns.Count;
                int relationsCount = ChildRelations.Count; 
                PropertyDescriptor[] props = new PropertyDescriptor[columnsCount + relationsCount]; {
                    for (int i = 0; i < columnsCount; i++) { 
                        props[i] = new DataColumnPropertyDescriptor(Columns[i]); 
                    }
                    for (int i = 0; i < relationsCount; i++) { 
                        props[columnsCount + i] = new DataRelationPropertyDescriptor(ChildRelations[i]);
                    }
                }
                propertyDescriptorCollectionCache = new PropertyDescriptorCollection(props); 
            }
            return propertyDescriptorCollectionCache; 
        } 

        internal XmlQualifiedName TypeName { 
            get {
                return ((typeName == null) ? XmlQualifiedName.Empty : (XmlQualifiedName)typeName);
            }
            set { 
                typeName = value;
            } 
        } 

        public void Merge(DataTable table) 
        {
            Merge(table, false, MissingSchemaAction.Add);
        }
 
        public void Merge(DataTable table, bool preserveChanges)
        { 
            Merge(table, preserveChanges, MissingSchemaAction.Add); 
        }
 
        public void Merge(DataTable table, bool preserveChanges, MissingSchemaAction missingSchemaAction)
        {
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, table=%d, preserveChanges=%d{bool}, missingSchemaAction=%d{ds.MissingSchemaAction}\n", ObjectID, (table != null) ? table.ObjectID : 0, preserveChanges, (int)missingSchemaAction); 
            try{
                if (table == null) 
                    throw ExceptionBuilder.ArgumentNull("table"); 

                switch(missingSchemaAction) { // @perfnote: Enum.IsDefined 
                case MissingSchemaAction.Add:
                case MissingSchemaAction.Ignore:
                case MissingSchemaAction.Error:
                case MissingSchemaAction.AddWithKey: 
                    Merger merger = new Merger(this, preserveChanges, missingSchemaAction);
                    merger.MergeTable(table); 
                    break; 
                default:
                    throw Common.ADP.InvalidMissingSchemaAction(missingSchemaAction); 
                }
            }
            finally{
                Bid.ScopeLeave(ref hscp); 
            }
        } 
 
        public void Load (IDataReader reader){
            Load(reader, LoadOption.PreserveChanges, null); 
        }

        public void Load (IDataReader reader, LoadOption loadOption) {
            Load(reader, loadOption, null); 
        }
 
        public virtual void Load (IDataReader reader, LoadOption loadOption, FillErrorEventHandler errorHandler){ 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, loadOption=%d{ds.LoadOption}\n", ObjectID, (int)loadOption); 
            try {
                if (this.PrimaryKey.Length == 0) {
                    DataTableReader dtReader = reader as DataTableReader;
                    if (dtReader != null && dtReader.CurrentDataTable == this) 
                        return; // if not return, it will go to infinite loop
                } 
                Common.LoadAdapter adapter = new Common.LoadAdapter(); 
                adapter.FillLoadOption = loadOption;
                adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey; 
                if (null != errorHandler) {
                    adapter.FillError += errorHandler;
                }
                adapter.FillFromReader(new DataTable[] { this }, reader, 0, 0); 

                if (!reader.IsClosed && !reader.NextResult()) { // 
                    reader.Close(); 
                }
            } 
            finally {
                Bid.ScopeLeave(ref hscp);
            }
        } 

        private DataRow LoadRow(object[] values, LoadOption loadOption, Index searchIndex) { 
            int recordNo; 
            DataRow dataRow = null;
 
            if (searchIndex != null) {
                int[] primaryKeyIndex = new int[0];
                if (this.primaryKey != null) { // I do check above for PK, but in case if someone else gives me some index unrelated to PK
                    primaryKeyIndex = new int[this.primaryKey.ColumnsReference.Length]; 
                    for(int i = 0; i < this.primaryKey.ColumnsReference.Length; i++) {
                        primaryKeyIndex[i] = this.primaryKey.ColumnsReference[i].Ordinal; 
                    } 
                }
 
                object[] keys = new object[primaryKeyIndex.Length];
                for(int i = 0; i < primaryKeyIndex.Length; i++) {
                    keys[i] = values[primaryKeyIndex[i]];
                } 

                Range result = searchIndex.FindRecords(keys); 
 
                if (!result.IsNull) {
                    int deletedRowUpsertCount = 0; 
                    for(int i = result.Min; i <= result.Max; i++) {
                        int resultRecord = searchIndex.GetRecord(i);
                        dataRow = this.recordManager[resultRecord];
                        recordNo = NewRecordFromArray(values); 

                        //SQLBU DT 33648 
                        // values array is being reused by DataAdapter, do not modify the values array 
                        for(int count = 0; count < values.Length; count++) {
                            if (null == values[count]) { 
                                columnCollection[count].Copy(resultRecord, recordNo);
                            }
                        }
                        for(int count = values.Length; count < columnCollection.Count ; count++) { 
                            columnCollection[count].Copy(resultRecord, recordNo); // if there are missing values
                        } 
 
                        if (loadOption != LoadOption.Upsert || dataRow.RowState != DataRowState.Deleted) {
                            SetDataRowWithLoadOption(dataRow , recordNo, loadOption, true); 
                        }
                        else {
                            deletedRowUpsertCount++;
                        } 
                    }
                    if (0 == deletedRowUpsertCount) { 
                        return dataRow; 
                    }
                } 
            }

            recordNo = NewRecordFromArray(values);
            dataRow = NewRow(recordNo); 
            // fire rowChanging event here
            DataRowAction action; 
            DataRowChangeEventArgs drcevent = null; 
            switch(loadOption) {
                case LoadOption.OverwriteChanges: 
                case LoadOption.PreserveChanges:
                    action = DataRowAction.ChangeCurrentAndOriginal;
                    break;
                case LoadOption.Upsert: 
                    action = DataRowAction.Add;
                    break; 
                default: 
                    throw ExceptionBuilder.ArgumentOutOfRange("LoadOption");
            } 

            drcevent = RaiseRowChanging(null, dataRow, action);

            this.InsertRow (dataRow, -1, -1, false); 
            switch(loadOption) {
                case LoadOption.OverwriteChanges: 
                case LoadOption.PreserveChanges: 
                    this.SetOldRecord(dataRow,  recordNo);
                    break; 
                case LoadOption.Upsert:
                    break;
                default:
                    throw ExceptionBuilder.ArgumentOutOfRange("LoadOption"); 
            }
            RaiseRowChanged(drcevent, dataRow, action); 
 
            return dataRow;
        } 

        private void SetDataRowWithLoadOption (DataRow dataRow, int recordNo, LoadOption loadOption, bool checkReadOnly) {
            bool hasError = false;
            if (checkReadOnly) { 
                foreach(DataColumn dc in this.Columns) {
                    if (dc.ReadOnly && !dc.Computed) { 
                        switch(loadOption) { 
                            case LoadOption.OverwriteChanges:
                                if ((dataRow[dc, DataRowVersion.Current] != dc[recordNo]) ||(dataRow[dc, DataRowVersion.Original] != dc[recordNo])) 
                                    hasError = true;
                                break;
                            case LoadOption.Upsert:
                                if (dataRow[dc, DataRowVersion.Current] != dc[recordNo]) 
                                    hasError = true;
                                break; 
                            case LoadOption.PreserveChanges: 
                                if (dataRow[dc, DataRowVersion.Original] != dc[recordNo])
                                    hasError = true; 
                                break;
                        }
                    }
                } 
            } // No Event should be fired  in SenNewRecord and SetOldRecord
            // fire rowChanging event here 
 
            DataRowChangeEventArgs drcevent = null;
            DataRowAction action = DataRowAction.Nothing; 
            int cacheTempRecord = dataRow.tempRecord;
            dataRow.tempRecord = recordNo;

            switch(loadOption) { 
                case LoadOption.OverwriteChanges:
                    action = DataRowAction.ChangeCurrentAndOriginal; 
                    break; 
                case LoadOption.Upsert:
                    switch(dataRow.RowState) { 
                        case DataRowState.Unchanged:
                            // let see if the incomming value has the same values as existing row, so compare records
                            foreach(DataColumn dc in dataRow.Table.Columns) {
                                if (0 != dc.Compare(dataRow.newRecord, recordNo)) { 
                                    action = DataRowAction.Change;
                                    break; 
                                } 
                            }
                            break; 
                        case DataRowState.Deleted:
                            Debug.Assert(false, "LoadOption.Upsert with deleted row, should not be here");
                            break;
                        default : 
                            action = DataRowAction.Change;
                            break; 
                    } 
                    break;
                case LoadOption.PreserveChanges: 
                    switch(dataRow.RowState) {
                        case DataRowState.Unchanged:
                            action = DataRowAction.ChangeCurrentAndOriginal;
                            break; 
                        default:
                            action = DataRowAction.ChangeOriginal; 
                            break; 
                    }
                    break; 
                default:
                    throw ExceptionBuilder.ArgumentOutOfRange("LoadOption");
            }
 
            try {
                drcevent = RaiseRowChanging(null, dataRow, action); 
                if (action == DataRowAction.Nothing) { // RaiseRowChanging does not fire for DataRowAction.Nothing 
                    dataRow.inChangingEvent = true;
                    try { 
                        drcevent = OnRowChanging(drcevent, dataRow, action);
                    }
                    finally {
                        dataRow.inChangingEvent = false; 
                    }
                } 
            } 
            finally {
                Debug.Assert(dataRow.tempRecord == recordNo, "tempRecord has been changed in event handler"); 
                if (DataRowState.Detached == dataRow.RowState) {
                    // 'row.Table.Remove(row);'
                    if (-1 != cacheTempRecord) {
                        FreeRecord(ref cacheTempRecord); 
                    }
                } 
                else { 
                    if (dataRow.tempRecord != recordNo) {
                        // 'row.EndEdit(); row.BeginEdit(); ' 
                        if (-1 != cacheTempRecord) {
                            FreeRecord(ref cacheTempRecord);
                        }
                        if (-1 != recordNo) { 
                            FreeRecord(ref recordNo);
                        } 
                        recordNo = dataRow.tempRecord; 
                    }
                    else { 
                        dataRow.tempRecord = cacheTempRecord;
                    }
                }
            } 
            if (dataRow.tempRecord != -1) {
                dataRow.CancelEdit(); 
            } 

            switch(loadOption) { 
                case LoadOption.OverwriteChanges:
                     this.SetNewRecord(dataRow,  recordNo, DataRowAction.Change, false, false);
                     this.SetOldRecord(dataRow,  recordNo);
                     break; 
                case LoadOption.Upsert:
                     if (dataRow.RowState == DataRowState.Unchanged) { 
                         this.SetNewRecord(dataRow,  recordNo, DataRowAction.Change, false, false); 
                         if (!dataRow.HasChanges()) {
                             this.SetOldRecord(dataRow, recordNo); 
                         }
                     }
                     else {
                         if (dataRow.RowState == DataRowState.Deleted) 
                             dataRow.RejectChanges();
                         this.SetNewRecord(dataRow,  recordNo, DataRowAction.Change, false, false); 
                     } 
                     break;
                case LoadOption.PreserveChanges: 
                     if (dataRow.RowState == DataRowState.Unchanged) {
                         // SQLBU 500706: DataTable internal index is corrupted: '8'
                         // if ListChanged event deletes dataRow
                         this.SetOldRecord(dataRow,  recordNo); // do not fire event 
                         this.SetNewRecord(dataRow, recordNo, DataRowAction.Change, false, false);
                     } 
                     else { // if modified/ added / deleted we want this operation to fire event (just for LoadOption.PreserveCurrentValues) 
                        this.SetOldRecord(dataRow,  recordNo);
                     } 
                     break;
                default:
                    throw ExceptionBuilder.ArgumentOutOfRange("LoadOption");
            } 

            if (hasError) { 
                string error = Res.GetString(Res.Load_ReadOnlyDataModified); 
                if (dataRow.RowError.Length == 0) { // WebData 112272, append the row error
                    dataRow.RowError = error; 
                }
                else {
                    dataRow.RowError += " ]:[ " + error ;
                } 

                foreach(DataColumn dc in this.Columns) { 
                    if (dc.ReadOnly && !dc.Computed) 
                        dataRow.SetColumnError(dc, error);
                } 
            }

            drcevent = RaiseRowChanged(drcevent, dataRow, action);
            if (action == DataRowAction.Nothing) { // RaiseRowChanged does not fire for DataRowAction.Nothing 
                dataRow.inChangingEvent = true;
                try { 
                    OnRowChanged(drcevent, dataRow, action); 
                }
                finally { 
                    dataRow.inChangingEvent = false;
                }
            }
 
        }
 
        public  DataTableReader CreateDataReader() { 
            return new DataTableReader(this);
        } 


        public void WriteXml(Stream stream)
        { 
            WriteXml(stream, XmlWriteMode.IgnoreSchema, false);
        } 
 
        public void WriteXml(Stream stream, bool writeHierarchy)
        { 
            WriteXml(stream, XmlWriteMode.IgnoreSchema, writeHierarchy);
        }

        public void WriteXml(TextWriter writer) 
        {
            WriteXml(writer, XmlWriteMode.IgnoreSchema, false); 
        } 

        public void WriteXml(TextWriter writer, bool writeHierarchy) 
        {
            WriteXml(writer, XmlWriteMode.IgnoreSchema, writeHierarchy);
        }
 
        public void WriteXml(XmlWriter writer)
        { 
            WriteXml(writer, XmlWriteMode.IgnoreSchema, false); 
        }
 
        public void WriteXml(XmlWriter writer, bool writeHierarchy)
        {
            WriteXml(writer, XmlWriteMode.IgnoreSchema, writeHierarchy);
        } 

        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)] 
        public void WriteXml(String fileName)
        { 
            WriteXml(fileName, XmlWriteMode.IgnoreSchema, false);
        }

        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)]
        public void WriteXml(String fileName, bool writeHierarchy) 
        { 
            WriteXml(fileName, XmlWriteMode.IgnoreSchema, writeHierarchy);
        } 

        public void WriteXml(Stream stream, XmlWriteMode mode)
        {
            WriteXml(stream, mode, false); 
        }
 
        public void WriteXml(Stream stream, XmlWriteMode mode, bool writeHierarchy) 
        {
            if (stream != null) { 
                XmlTextWriter w =  new XmlTextWriter(stream, null) ;
                w.Formatting = Formatting.Indented;

                WriteXml( w, mode, writeHierarchy); 
            }
        } 
 
        public void WriteXml(TextWriter writer, XmlWriteMode mode)
        { 
            WriteXml(writer, mode, false);
        }

        public void WriteXml(TextWriter writer, XmlWriteMode mode, bool writeHierarchy) 
        {
            if (writer != null) { 
                XmlTextWriter w =  new XmlTextWriter(writer) ; 
                w.Formatting = Formatting.Indented;
 
                WriteXml(w, mode, writeHierarchy);
            }
        }
 
        public void WriteXml(XmlWriter writer, XmlWriteMode mode)
        { 
            WriteXml(writer, mode, false); 
        }
        public void WriteXml(XmlWriter writer, XmlWriteMode mode, bool writeHierarchy) 
        {
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, mode=%d{ds.XmlWriteMode}\n", ObjectID,  (int)mode);
            try{ 
                if (this.tableName.Length == 0) {
                    throw ExceptionBuilder.CanNotSerializeDataTableWithEmptyName(); 
                } 
                // Generate SchemaTree and write it out
                if (writer != null) { 

                    if (mode == XmlWriteMode.DiffGram) { // FIX THIS
                        // Create and save the updates
                        new NewDiffgramGen(this, writeHierarchy).Save(writer, this); 
                    }
                    else { 
                        // Create and save xml data 
                        if (mode == XmlWriteMode.WriteSchema) {
                            DataSet ds = null; 
                            string tablenamespace = this.tableNamespace;
                            if (null == this.DataSet) {
                                ds = new DataSet();
                                // if user set values on DataTable, it isn't necessary 
                                // to set them on the DataSet because they won't be inherited
                                // but it is simpler to set them in both places 
 
                                // if user did not set values on DataTable, it is required
                                // to set them on the DataSet so the table will inherit 
                                // the value already on the Datatable
                                ds.SetLocaleValue(_culture, _cultureUserSet);
                                ds.CaseSensitive = this.CaseSensitive;
                                ds.Namespace = this.Namespace; 
                                ds.RemotingFormat = this.RemotingFormat;
                                ds.Tables.Add(this); 
                            } 

                            if (writer != null) { 
                                XmlDataTreeWriter xmldataWriter = new XmlDataTreeWriter(this, writeHierarchy);
                                xmldataWriter.Save(writer, /*mode == XmlWriteMode.WriteSchema*/true);
                            }
                            if (null != ds) { 
                                ds.Tables.Remove(this);
                                this.tableNamespace = tablenamespace; 
                            } 
                        }
                        else { 
                            XmlDataTreeWriter xmldataWriter = new XmlDataTreeWriter(this, writeHierarchy);
                            xmldataWriter.Save(writer,/*mode == XmlWriteMode.WriteSchema*/ false);
                        }
                    } 
                }
            } 
            finally { 
                Bid.ScopeLeave(ref hscp);
            } 
        }

        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public void WriteXml(String fileName, XmlWriteMode mode)
        { 
            WriteXml(fileName, mode, false); 
        }
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public void WriteXml(String fileName, XmlWriteMode mode, bool writeHierarchy)
        { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, fileName='%ls', mode=%d{ds.XmlWriteMode}\n", ObjectID, fileName, (int)mode); 
            try { 
                using(XmlTextWriter xw = new XmlTextWriter( fileName, null )) {
                    xw.Formatting = Formatting.Indented; 
                    xw.WriteStartDocument(true);

                    WriteXml(xw, mode, writeHierarchy);
 
                    xw.WriteEndDocument();
                } 
            } 
            finally {
                Bid.ScopeLeave(ref hscp); 
            }
        }

        public void WriteXmlSchema(Stream stream) { 
            WriteXmlSchema(stream, false);
        } 
 
        public void WriteXmlSchema(Stream stream, bool writeHierarchy)
        { 
            if (stream == null)
                return;

            XmlTextWriter w =  new XmlTextWriter(stream, null) ; 
            w.Formatting = Formatting.Indented;
 
            WriteXmlSchema( w, writeHierarchy ); 
        }
 
        public void WriteXmlSchema( TextWriter writer ) {
            WriteXmlSchema( writer, false );
        }
 
        public void WriteXmlSchema( TextWriter writer, bool writeHierarchy )
        { 
 
            if (writer == null)
                return; 

            XmlTextWriter w =  new XmlTextWriter(writer);
            w.Formatting = Formatting.Indented;
 
            WriteXmlSchema( w, writeHierarchy );
        } 
 
        private  bool CheckForClosureOnExpressions(DataTable dt, bool writeHierarchy) {
            List tableList = new List(); 
            tableList.Add(dt);
            if (writeHierarchy) { // WebData 112161
                CreateTableList(dt, tableList);
            } 
            return CheckForClosureOnExpressionTables(tableList);
        } 
 
        private bool CheckForClosureOnExpressionTables(List tableList) {
            Debug.Assert(tableList != null, "tableList shouldnot be null"); 

            foreach(DataTable datatable in tableList) {
                foreach(DataColumn dc in datatable.Columns) {
                    if (dc.Expression.Length != 0)  { 
                        DataColumn[] dependency = dc.DataExpression.GetDependency();
                        for (int j = 0; j < dependency.Length; j++) { 
                            if (!(tableList.Contains(dependency[j].Table))) { 
                                return false;
                            } 
                        }
                    }
                }
            } 
            return true;
        } 
 

        public void WriteXmlSchema(XmlWriter writer) { 
            WriteXmlSchema(writer, false);
        }

        public void WriteXmlSchema(XmlWriter writer, bool writeHierarchy) 
        {
            IntPtr hscp; 
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); 
            try{
                if (this.tableName.Length == 0) { 
                    throw ExceptionBuilder.CanNotSerializeDataTableWithEmptyName();
                }

                if (!CheckForClosureOnExpressions(this, writeHierarchy)) { 
                    throw ExceptionBuilder.CanNotSerializeDataTableHierarchy();
                } 
 
                DataSet ds = null;
                string tablenamespace = this.tableNamespace;//SQL BU Defect Tracking 286968 

                // Generate SchemaTree and write it out
                if (null == this.DataSet) {
                    ds = new DataSet(); 
                    // if user set values on DataTable, it isn't necessary
                    // to set them on the DataSet because they won't be inherited 
                    // but it is simpler to set them in both places 

                    // if user did not set values on DataTable, it is required 
                    // to set them on the DataSet so the table will inherit
                    // the value already on the Datatable
                    ds.SetLocaleValue(_culture, _cultureUserSet);
                    ds.CaseSensitive = this.CaseSensitive; 
                    ds.Namespace = this.Namespace;
                    ds.RemotingFormat = this.RemotingFormat; 
                    ds.Tables.Add(this); 
                }
 
                if (writer != null) {
                    XmlTreeGen treeGen = new XmlTreeGen(SchemaFormat.Public);
                    treeGen.Save(null, this, writer, writeHierarchy);
                } 
                if (null != ds) {
                    ds.Tables.Remove(this); 
                    this.tableNamespace = tablenamespace; 
                }
            } 
            finally {
                Bid.ScopeLeave(ref hscp);
            }
        } 

        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)] 
        public void WriteXmlSchema(String fileName) {
            WriteXmlSchema(fileName, false); 
        }

        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public void WriteXmlSchema(String fileName, bool writeHierarchy)
        { 
            XmlTextWriter xw = new XmlTextWriter( fileName, null ); 
            try {
                xw.Formatting = Formatting.Indented; 
                xw.WriteStartDocument(true);
                WriteXmlSchema(xw, writeHierarchy);
                xw.WriteEndDocument();
            } 
            finally {
                xw.Close(); 
            } 
        }
 
        public XmlReadMode ReadXml(Stream stream)
        {
            if (stream == null)
                return XmlReadMode.Auto; 

            return ReadXml( new XmlTextReader(stream), false); 
        } 

        public XmlReadMode ReadXml(TextReader reader) 
        {
            if (reader == null)
                return XmlReadMode.Auto;
 
            return ReadXml( new XmlTextReader(reader), false);
        } 
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public XmlReadMode ReadXml(string fileName)
        {
            XmlTextReader xr = new XmlTextReader(fileName);
            try { 
                return ReadXml( xr , false);
            } 
            finally { 
                xr.Close();
            } 
        }

        public XmlReadMode ReadXml(XmlReader reader)
        { 
            return ReadXml(reader, false);
        } 
 
        private void RestoreConstraint(bool originalEnforceConstraint) {
            if (this.DataSet != null) { 
                this.DataSet.EnforceConstraints = originalEnforceConstraint;
            }
            else {
                this.EnforceConstraints = originalEnforceConstraint; 
            }
        } 
 
        private bool IsEmptyXml(XmlReader reader) {
            if (reader.IsEmptyElement) { 
                if (reader.AttributeCount == 0 || (reader.LocalName == Keywords.DIFFGRAM && reader.NamespaceURI == Keywords.DFFNS)) {
                    return true;
                }
                if (reader.AttributeCount == 1) { 
                    reader.MoveToAttribute(0);
                    if ((this.Namespace == reader.Value) && 
                        (this.Prefix == reader.LocalName) && 
                        (reader.Prefix == Keywords.XMLNS) &&
                        (reader.NamespaceURI == Keywords.XSD_XMLNS_NS)) 
                    return true;
                }
            }
            return false; 
        }
 
        internal XmlReadMode ReadXml(XmlReader reader, bool denyResolving) 
        {
            IntPtr hscp; 
            Bid.ScopeEnter(out hscp, " %d#, denyResolving=%d{bool}\n", ObjectID, denyResolving);
            try {
              try {
                bool fDataFound = false; 
                bool fSchemaFound = false;
                bool fDiffsFound = false; 
                bool fIsXdr = false; 
                int iCurrentDepth = -1;
                XmlReadMode ret = XmlReadMode.Auto; 

                // clear the hashtable to avoid conflicts between diffgrams, SqlHotFix 782
                Debug.Assert(null == rowDiffId, "wasn't previously cleared");
                rowDiffId = null; 

                if (reader == null) 
                    return ret; 
                bool originalEnforceConstraint = false;
                if (this.DataSet != null) { 
                    originalEnforceConstraint = this.DataSet.EnforceConstraints;
                    this.DataSet.EnforceConstraints = false;
                }
                else { 
                    originalEnforceConstraint = this.EnforceConstraints;
                    this.EnforceConstraints = false; 
                } 

                if (reader is XmlTextReader) 
                    ((XmlTextReader) reader).WhitespaceHandling = WhitespaceHandling.Significant;

                XmlDocument xdoc = new XmlDocument(); // we may need this to infer the schema
                XmlDataLoader xmlload = null; 

 
                reader.MoveToContent(); 
                if (Columns.Count == 0) {
                    if (IsEmptyXml(reader)) { 
                        reader.Read();
                        return ret;
                    }
                } 

                if (reader.NodeType == XmlNodeType.Element) { 
                    iCurrentDepth = reader.Depth; 

                    if ((reader.LocalName == Keywords.DIFFGRAM) && (reader.NamespaceURI == Keywords.DFFNS)) { 
                        if (Columns.Count == 0) {
                            if (reader.IsEmptyElement) {
                                reader.Read();
                                return XmlReadMode.DiffGram; 
                            }
                            throw ExceptionBuilder.DataTableInferenceNotSupported(); 
                        } 
                        this.ReadXmlDiffgram(reader);
                        // read the closing tag of the current element 
                        ReadEndElement(reader);

                        RestoreConstraint(originalEnforceConstraint);
                        return XmlReadMode.DiffGram; 
                    }
 
                    // if reader points to the schema load it 
                    if (reader.LocalName == Keywords.XDR_SCHEMA && reader.NamespaceURI==Keywords.XDRNS) {
                        // load XDR schema and exit 
                        ReadXDRSchema(reader);

                        RestoreConstraint(originalEnforceConstraint);
                        return XmlReadMode.ReadSchema; //since the top level element is a schema return 
                    }
 
                    if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI==Keywords.XSDNS) { 
                        // load XSD schema and exit
                        ReadXmlSchema(reader, denyResolving); 
                        RestoreConstraint(originalEnforceConstraint);
                        return XmlReadMode.ReadSchema; //since the top level element is a schema return
                    }
 
                    if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI.StartsWith(Keywords.XSD_NS_START, StringComparison.Ordinal)) {
                        if (this.DataSet != null) { // we should not throw for constraint, we already will throw for unsupported schema, so restore enforce cost, but not via property 
                            this.DataSet.RestoreEnforceConstraints(originalEnforceConstraint); 
                        }
                        else { 
                            this.enforceConstraints = originalEnforceConstraint;
                        }

                        throw ExceptionBuilder.DataSetUnsupportedSchema(Keywords.XSDNS); 
                    }
 
                    // now either the top level node is a table and we load it through dataReader... 

                    // ... or backup the top node and all its attributes because we may need to InferSchema 
                    XmlElement topNode = xdoc.CreateElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
                    if (reader.HasAttributes) {
                        int attrCount = reader.AttributeCount;
                        for (int i=0;i depth) { 
                reader.Read();
            }
            return (reader.NodeType == XmlNodeType.Element);
        } 
        private void ReadXmlDiffgram(XmlReader reader) { // fill correctly
            int d = reader.Depth; 
            bool fEnforce = this.EnforceConstraints; 
            this.EnforceConstraints =false;
            DataTable newDt; 
            bool isEmpty;

            if (this.Rows.Count == 0) {
                isEmpty = true; 
                newDt = this;
            } 
            else { 
                isEmpty = false;
                newDt = this.Clone(); 
                newDt.EnforceConstraints = false;
            }

            newDt.Rows.nullInList = 0; 

            reader.MoveToContent(); 
 
            if ((reader.LocalName != Keywords.DIFFGRAM) && (reader.NamespaceURI != Keywords.DFFNS))
                return; 
            reader.Read();
            if (reader.NodeType == XmlNodeType.Whitespace) {
                MoveToElement(reader, reader.Depth - 1 /*iCurrentDepth*/); // skip over whitespaces.
            } 

            newDt.fInLoadDiffgram = true; 
 
            if (reader.Depth > d) {
                if ((reader.NamespaceURI != Keywords.DFFNS) && (reader.NamespaceURI != Keywords.MSDNS)) { 
                    //we should be inside the dataset part
                    XmlDocument xdoc = new XmlDocument();
                    XmlElement node = xdoc.CreateElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
                    reader.Read(); 
                    if (reader.Depth-1 > d) {
                        XmlDataLoader xmlload = new XmlDataLoader(newDt, false, node, false); 
                        xmlload.isDiffgram = true; // turn on the special processing 
                        xmlload.LoadData(reader);
                    } 
                    ReadEndElement(reader);
                }
                if (((reader.LocalName == Keywords.SQL_BEFORE) && (reader.NamespaceURI == Keywords.DFFNS)) ||
                    ((reader.LocalName == Keywords.MSD_ERRORS) && (reader.NamespaceURI == Keywords.DFFNS))) 

                { 
                    //this will consume the changes and the errors part 
                    XMLDiffLoader diffLoader = new XMLDiffLoader();
                    diffLoader.LoadDiffGram(newDt, reader); 
                }

                // get to the closing diff tag
                while(reader.Depth > d) { 
                    reader.Read();
                } 
                // read the closing tag 
                ReadEndElement(reader);
            } 

            if (newDt.Rows.nullInList > 0)
                throw ExceptionBuilder.RowInsertMissing(newDt.TableName);
 

            newDt.fInLoadDiffgram = false; 
            List tableList = new List(); 
            tableList.Add(this);
            CreateTableList(this, tableList); 

// this is terrible, optimize it
            for (int i = 0; i < tableList.Count ; i++) {
                DataRelation[] relations = tableList[i].NestedParentRelations; 
                foreach(DataRelation rel in relations) {
                    if (rel != null && rel.ParentTable == tableList[i]) { 
                        foreach (DataRow r in tableList[i].Rows) { 
                            foreach (DataRelation rel2 in relations) {
                                r.CheckForLoops(rel2); 
                            }
                        }
                    }
                } 
            }
 
            if (!isEmpty) { 
                this.Merge(newDt);
            } 
            this.EnforceConstraints = fEnforce;
        }

        internal void ReadXSDSchema(XmlReader reader, bool denyResolving) { 
            XmlSchemaSet sSet = new XmlSchemaSet();
            while (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI==Keywords.XSDNS) { 
                XmlSchema s = XmlSchema.Read(reader, null); 
                sSet.Add(s);
                //read the end tag 
                ReadEndElement(reader);
            }
            sSet.Compile();
 
            XSDSchema schema = new XSDSchema();
            schema.LoadSchema(sSet, this); 
        } 

 
        public void ReadXmlSchema(Stream stream)
        {
            if (stream == null)
                return; 

            ReadXmlSchema( new XmlTextReader( stream ), false ); 
        } 

        public void ReadXmlSchema(TextReader reader) 
        {
            if (reader == null)
                return;
 
            ReadXmlSchema( new XmlTextReader( reader ), false );
        } 
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public void ReadXmlSchema(String fileName)
        {
            XmlTextReader xr = new XmlTextReader(fileName);
            try { 
                ReadXmlSchema( xr, false );
            } 
            finally { 
                xr.Close();
            } 
        }

        public void ReadXmlSchema(XmlReader reader)
        { 
            ReadXmlSchema(reader, false);
        } 
 
        internal void ReadXmlSchema(XmlReader reader, bool denyResolving)
        { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, denyResolving=%d{bool}\n", ObjectID, denyResolving);
            try{
                DataSet ds = new DataSet(); 
                SerializationFormat cachedRemotingFormat = this.RemotingFormat;
                // fxcop: ReadXmlSchema will provide the CaseSensitive, Locale, Namespace information 
                ds.ReadXmlSchema(reader, denyResolving); 

                string CurrentTableFullName = ds.MainTableName; 

                if (Common.ADP.IsEmpty(this.tableName) && Common.ADP.IsEmpty(CurrentTableFullName))
                    return;
 
                DataTable currentTable = null;
 
                if (!Common.ADP.IsEmpty(this.tableName)) { 
                    if (!Common.ADP.IsEmpty(this.Namespace)) {
                        currentTable = ds.Tables[this.tableName, this.Namespace]; 
                    }
                    else {//SQL BU defect tracking 240293
                        int tableIndex = ds.Tables.InternalIndexOf(this.tableName);
                        if (tableIndex  > -1) { 
                            currentTable = ds.Tables[tableIndex];
                        } 
                    } 
                }
                else{  //!Common.ADP.IsEmpty(CurrentTableFullName) 
                    string CurrentTableNamespace = "";
                    int nsSeperator = CurrentTableFullName.IndexOf(':');
                    if (nsSeperator > -1) {
                        CurrentTableNamespace = CurrentTableFullName.Substring(0, nsSeperator); 
                    }
                    string CurrentTableName = CurrentTableFullName.Substring(nsSeperator + 1, CurrentTableFullName.Length - nsSeperator -1); 
 
                    currentTable = ds.Tables[CurrentTableName, CurrentTableNamespace];
                } 

                if (currentTable == null) { // bug fix :99186
                    string qTableName = string.Empty;
                    if (!Common.ADP.IsEmpty(this.tableName)) { 
                        qTableName = (this.Namespace.Length > 0)? (this.Namespace + ":" + this.tableName):this.tableName;
                    } 
                    else { 
                        qTableName = CurrentTableFullName ;
                    } 
                    throw ExceptionBuilder.TableNotFound(qTableName);
                }

                currentTable._remotingFormat = cachedRemotingFormat; 

                List tableList = new List(); 
                tableList.Add(currentTable); 
                CreateTableList(currentTable, tableList);
                List relationList = new List(); 
                CreateRelationList(tableList, relationList);

                if (relationList.Count == 0) {
                    if (this.Columns.Count == 0) { 
                        DataTable tempTable = currentTable;
                        if (tempTable != null) 
                            tempTable.CloneTo(this, null, false); // we may have issue Amir 
                        if (this.DataSet == null && this.tableNamespace == null) { // webdata 105506
// for standalone table, clone wont get these correctly, since they may come with inheritance 
                            this.tableNamespace =  tempTable.Namespace;
                        }
                    }
                    return; 
                }
                else { 
                    if (Common.ADP.IsEmpty(this.TableName)) { 
                        this.TableName = currentTable.TableName;
                        if (!Common.ADP.IsEmpty(currentTable.Namespace)) { 
                            this.Namespace = currentTable.Namespace;
                        }
                    }
                    if (this.DataSet == null) { 
                        DataSet dataset = new DataSet(ds.DataSetName);
// webdata 105506 
                        // if user set values on DataTable, it isn't necessary 
                        // to set them on the DataSet because they won't be inherited
                        // but it is simpler to set them in both places 

                        // if user did not set values on DataTable, it is required
                        // to set them on the DataSet so the table will inherit
                        // the value already on the Datatable 
                        dataset.SetLocaleValue(ds.Locale, ds.ShouldSerializeLocale());
                        dataset.CaseSensitive = ds.CaseSensitive; 
                        dataset.Namespace = ds.Namespace; 
                        dataset.mainTableName = ds.mainTableName;
                        dataset.RemotingFormat = ds.RemotingFormat; 

                        dataset.Tables.Add(this);
                    }
 
                    DataTable targetTable = CloneHierarchy(currentTable, this.DataSet, null);
 
                    foreach(DataTable tempTable in tableList) { 
                        DataTable destinationTable = this.DataSet.Tables[tempTable.tableName, tempTable.Namespace];
                        DataTable sourceTable = ds.Tables[tempTable.tableName, tempTable.Namespace]; 
                        foreach(Constraint tempConstrain in sourceTable.Constraints) {
                            ForeignKeyConstraint fkc = tempConstrain as ForeignKeyConstraint;  // we have already cloned the UKC when cloning the datatable
                            if (fkc != null) {
                                if (fkc.Table != fkc.RelatedTable)  { 
                                    if (tableList.Contains(fkc.Table) && tableList.Contains(fkc.RelatedTable)) {
                                        ForeignKeyConstraint newFKC = (ForeignKeyConstraint)fkc.Clone(destinationTable.DataSet); 
                                        if (!destinationTable.Constraints.Contains(newFKC.ConstraintName)) 
                                            destinationTable.Constraints.Add(newFKC); // we know that the dest table is already in the table
                                    } 
                                }
                           }
                        }
                    } 
                    foreach(DataRelation rel in relationList) {
                        if (!this.DataSet.Relations.Contains(rel.RelationName)) 
                            this.DataSet.Relations.Add(rel.Clone(this.DataSet)); 
                    }
 
                    bool hasExternaldependency = false;

                    foreach(DataTable tempTable in tableList) {
                        foreach(DataColumn dc in tempTable.Columns) { 
                            hasExternaldependency = false;
                            if (dc.Expression.Length  != 0) { 
                                DataColumn[] dependency = dc.DataExpression.GetDependency(); 
                                for (int j = 0; j < dependency.Length; j++) {
                                    if (!tableList.Contains(dependency[j].Table)) { 
                                        hasExternaldependency = true;
                                        break;
                                    }
                                } 
                            }
                            if (!hasExternaldependency) { 
                                this.DataSet.Tables[tempTable.TableName, tempTable.Namespace].Columns[dc.ColumnName].Expression = dc.Expression; 
                            }
                        } 
                        hasExternaldependency = false;
                    }

                } 
            }
            finally{ 
                Bid.ScopeLeave(ref hscp); 
            }
        } 

        private void CreateTableList(DataTable currentTable, List tableList) {
            foreach( DataRelation r in currentTable.ChildRelations ) {
                if (! tableList.Contains(r.ChildTable)) { 
                    tableList.Add(r.ChildTable);
                    CreateTableList(r.ChildTable, tableList); 
                } 
            }
        } 
        private void CreateRelationList(List tableList,  List relationList) {
            foreach(DataTable table in tableList) {
                foreach( DataRelation r in table.ChildRelations) {
                    if (tableList.Contains(r.ChildTable) && tableList.Contains(r.ParentTable)) { 
                        relationList.Add(r);
                    } 
                } 
            }
        } 

        /*************************************************************************
        The V2.0 (no V1.0 or V1.1) WSDL for Untyped DataTable being returned as a result (no parameters)
         
            
             
         
        
             
                
                    
                        
                             
                                
                                 
                             
                        
                     
                
            
        
 
        Typed DataTable is not supported in WSDL (SQLBU 444636)
 
        either fails because xsd generates its typed DataTable with an internal parameterless ctor 

        or System.NullReferenceException: Object reference not set to an instance of an object.   (if namespace of StronglyTyped DataTable is not set) 
           at System.Data.XmlTreeGen.FindTargetNamespace(DataTable table)

        or System.InvalidOperationException: Schema Id is missing. The schema returned from WebServiceDataSetServer.Service+StudentsDataTable.GetSchema() must have an Id.
           at System.Xml.Serialization.SerializableMapping.RetrieveSerializableSchema() 
        *****************************************************************************/
        public static XmlSchemaComplexType GetDataTableSchema(XmlSchemaSet schemaSet) { 
            XmlSchemaComplexType type = new XmlSchemaComplexType(); 
            XmlSchemaSequence sequence = new XmlSchemaSequence();
            XmlSchemaAny any = new XmlSchemaAny(); 
            any.Namespace = XmlSchema.Namespace;
            any.MinOccurs = 0;
            any.MaxOccurs = Decimal.MaxValue;
            any.ProcessContents = XmlSchemaContentProcessing.Lax; 
            sequence.Items.Add(any);
 
            any = new XmlSchemaAny(); 
            any.Namespace = Keywords.DFFNS;
            any.MinOccurs = 1; // when recognizing WSDL - MinOccurs="0" denotes DataSet, a MinOccurs="1" for DataTable 
            any.ProcessContents = XmlSchemaContentProcessing.Lax;
            sequence.Items.Add(any);

            type.Particle = sequence; 

            return type; 
        } 

        XmlSchema IXmlSerializable.GetSchema() { 
            return GetSchema();
        }

        protected virtual XmlSchema GetSchema() { 
            if (GetType() == typeof(DataTable)) {
                return null; 
            } 
            MemoryStream stream = new MemoryStream();
 
            XmlWriter writer = new XmlTextWriter(stream, null);
            if (writer != null) {
                 (new XmlTreeGen(SchemaFormat.WebService)).Save(this, writer);
            } 
            stream.Position = 0;
            return XmlSchema.Read(new XmlTextReader(stream), null); 
        } 

        void IXmlSerializable.ReadXml(XmlReader reader) { 
            IXmlTextParser textReader = reader as IXmlTextParser;
            bool fNormalization = true;
            if (textReader != null) {
                fNormalization = textReader.Normalized; 
                textReader.Normalized = false;
            } 
            ReadXmlSerializable(reader); 

            if (textReader != null) { 
                textReader.Normalized = fNormalization;
            }
        }
 
        void IXmlSerializable.WriteXml(XmlWriter writer) {
            WriteXmlSchema(writer, false); 
            WriteXml(writer, XmlWriteMode.DiffGram, false); 
        }
 
         protected virtual void ReadXmlSerializable(XmlReader reader) {
            ReadXml(reader, XmlReadMode.DiffGram, true);
        }
 
/*
        [ 
        DefaultValue(false), 
        ResCategoryAttribute(Res.DataCategory_Data),
        ResDescriptionAttribute(Res.DataTableSerializeHierarchy) 
        ]
        public bool SerializeHierarchy {
            get {
                return this.serializeHierarchy; 
            }
            set { 
                this.serializeHierarchy = value; 
            }
        } 
*/

        internal Hashtable RowDiffId {
            get { 
                if (rowDiffId == null)
                    rowDiffId = new Hashtable(); 
                return rowDiffId; 
            }
        } 

        internal int ObjectID {
            get {
                return _objectID; 
            }
        } 
 
        internal void AddDependentColumn(DataColumn expressionColumn) {
            if (dependentColumns == null) 
                dependentColumns = new List();

            if (!dependentColumns.Contains(expressionColumn)) {
                // only remember unique columns but expect non-unique columns to be added 
                dependentColumns.Add(expressionColumn);
            } 
        } 

        internal void RemoveDependentColumn(DataColumn expressionColumn) { 
            if (dependentColumns != null && dependentColumns.Contains(expressionColumn)) {
                dependentColumns.Remove(expressionColumn);
            }
        } 

        internal void EvaluateExpressions() { 
            //evaluates all expressions for all rows in table 
            // SQLBU 414992: Serious performance issue when calling Merge
            // this improves performance by only computing expressions when they are present 
            // and iterating over the rows instead of computing their position multiple times
            if ((null != dependentColumns) && (0 < dependentColumns.Count)) {
                foreach(DataRow row in Rows) {
                    // only evaluate original values if different from current. 
                    if (row.oldRecord != -1 && row.oldRecord != row.newRecord) {
                        EvaluateDependentExpressions(dependentColumns, row, DataRowVersion.Original, null); 
                    } 
                    if (row.newRecord != -1) {
                        EvaluateDependentExpressions(dependentColumns, row, DataRowVersion.Current, null); 
                    }
                    if (row.tempRecord != -1) {
                        EvaluateDependentExpressions(dependentColumns, row, DataRowVersion.Proposed, null);
                    } 
                }
            } 
        } 

        internal void EvaluateExpressions(DataRow row, DataRowAction action, List cachedRows) { 
            // evaluate all expressions for specified row
            if (action == DataRowAction.Add ||
                action == DataRowAction.Change||
                action == DataRowAction.Rollback) { 
                 // only evaluate original values if different from current.
                if (row.oldRecord != -1 && row.oldRecord != row.newRecord) { 
                    EvaluateDependentExpressions(dependentColumns, row, DataRowVersion.Original, cachedRows); 
                }
                if (row.newRecord != -1) { 
                    EvaluateDependentExpressions(dependentColumns, row, DataRowVersion.Current, cachedRows);
                }
                if (row.tempRecord != -1) {
                    EvaluateDependentExpressions(dependentColumns, row, DataRowVersion.Proposed, cachedRows); 
                }
            } 
            else if (action == DataRowAction.Delete && dependentColumns != null) { 
                foreach(DataColumn col in dependentColumns) {
                    if (col.DataExpression != null && col.DataExpression.HasLocalAggregate() && col.Table == this) { 
                        for (int j = 0; j < Rows.Count; j++) {
                            DataRow tableRow = Rows[j];

                            if (tableRow.oldRecord != -1 && tableRow.oldRecord != tableRow.newRecord) { 
                                EvaluateDependentExpressions(dependentColumns, tableRow, DataRowVersion.Original, null);
                            } 
                            if (tableRow.newRecord != -1) { 
                                EvaluateDependentExpressions(dependentColumns, tableRow, DataRowVersion.Current, null);
                            } 
                            if (tableRow.tempRecord != -1) {
                                EvaluateDependentExpressions(dependentColumns, tableRow, DataRowVersion.Proposed, null);
                            }
                        } 
                        break;
                    } 
                } 

                foreach (DataRow relatedRow in cachedRows) { 
                    if (relatedRow.oldRecord != -1 && relatedRow.oldRecord != relatedRow.newRecord) {
                        relatedRow.Table.EvaluateDependentExpressions(relatedRow.Table.dependentColumns, relatedRow, DataRowVersion.Original, null);
                    }
                    if (relatedRow.newRecord != -1) { 
                        relatedRow.Table.EvaluateDependentExpressions(relatedRow.Table.dependentColumns, relatedRow, DataRowVersion.Current, null);
                    } 
                    if (relatedRow.tempRecord != -1) { 
                        relatedRow.Table.EvaluateDependentExpressions(relatedRow.Table.dependentColumns, relatedRow, DataRowVersion.Proposed, null);
                    } 
                }
            }
        }
 
        internal void EvaluateExpressions(DataColumn column) {
            // evaluates all rows for expression from specified column 
            Debug.Assert(column.Computed, "Only computed columns should be re-evaluated."); 
            int count = column.table.Rows.Count;
            if (column.DataExpression.IsTableAggregate() && count > 0) { 
                // this value is a constant across the table.
                object aggCurrent = column.DataExpression.Evaluate();
                for (int j = 0; j < count; j++) {
                    DataRow row = column.table.Rows[j]; 
                    // only evaluate original values if different from current.
                    if (row.oldRecord != -1 && row.oldRecord != row.newRecord) { 
                        column[row.oldRecord] = aggCurrent; 
                    }
                    if (row.newRecord != -1) { 
                        column[row.newRecord] = aggCurrent;
                    }
                    if (row.tempRecord != -1) {
                        column[row.tempRecord] = aggCurrent; 
                    }
                } 
            } 
            else {
                for (int j = 0; j < count; j++) { 
                    DataRow row = column.table.Rows[j];

                    if (row.oldRecord != -1 && row.oldRecord != row.newRecord) {
                        column[row.oldRecord] = column.DataExpression.Evaluate(row, DataRowVersion.Original); 
                    }
                    if (row.newRecord != -1) { 
                        column[row.newRecord] = column.DataExpression.Evaluate(row, DataRowVersion.Current); 
                    }
                    if (row.tempRecord != -1) { 
                        column[row.tempRecord] = column.DataExpression.Evaluate(row, DataRowVersion.Proposed);
                    }
                }
            } 

            // SQLBU 501916 - DataTable internal index is corrupted:'5' 
            column.Table.ResetInternalIndexes(column); 
            EvaluateDependentExpressions(column);
        } 

        internal void EvaluateDependentExpressions(DataColumn column) {
            // DataTable.Clear(), DataRowCollection.Clear() & DataColumn.set_Expression
            if (column.dependentColumns != null) { 
                foreach (DataColumn dc in column.dependentColumns) {
                    if ((dc.table != null) && !Object.ReferenceEquals(column, dc)) { // SQLBU 502736 
                        EvaluateExpressions(dc); 
                    }
                } 
            }
        }

        internal void EvaluateDependentExpressions(List columns, DataRow row, DataRowVersion version, List cachedRows) { 
            if (columns == null)
                return; 
            //Expression evaluation is done first over same table expressions. 
            int count = columns.Count;
            for(int i = 0; i < count; i++) { 
                if (columns[i].Table == this) {// if this column is in my table
                    DataColumn dc = columns[i];
                    if (dc.DataExpression != null && dc.DataExpression.HasLocalAggregate()) {
                    // if column expression references a local Table aggregate we need to recalc it for the each row in the local table 
                        DataRowVersion expressionVersion  = (version == DataRowVersion.Proposed) ? DataRowVersion.Default : version;
                        bool isConst = dc.DataExpression.IsTableAggregate(); //is expression constant for entire table? 
                        object newValue = null; 
                        if (isConst) {  //if new value, just compute once
                            newValue = dc.DataExpression.Evaluate(row, expressionVersion); 
                        }
                        for (int j = 0; j < Rows.Count; j++) { //evaluate for all rows in the table
                            DataRow dr = Rows[j];
                            if (dr.RowState == DataRowState.Deleted) { 
                                continue;
                            } 
                            else if (expressionVersion == DataRowVersion.Original && (dr.oldRecord == -1 || dr.oldRecord == dr.newRecord)) { 
                                continue;
                            } 

                            if (!isConst) {
                                newValue = dc.DataExpression.Evaluate(dr, expressionVersion);
                            } 
                            SilentlySetValue(dr, dc, expressionVersion, newValue);
                        } 
                    } 
                    else {
                        if (row.RowState == DataRowState.Deleted) { 
                            continue;
                        }
                        else if (version == DataRowVersion.Original && (row.oldRecord == -1 || row.oldRecord == row.newRecord)) {
                            continue; 
                        }
                        SilentlySetValue(row, dc, version, dc.DataExpression == null ? dc.DefaultValue : dc.DataExpression.Evaluate(row, version)); 
                    } 
                }
            } 
            // now do expression evaluation for expression columns other tables.
            count = columns.Count;
            for(int i = 0; i < count; i++) {
                DataColumn dc = columns[i]; 
                // if this column is NOT in my table or it is in the table and is not a local aggregate (self refs)
                if (dc.Table != this || (dc.DataExpression != null && !dc.DataExpression.HasLocalAggregate())) { 
                    DataRowVersion foreignVer = (version == DataRowVersion.Proposed) ? DataRowVersion.Default : version; 

                    // first - evaluate expressions for cachedRows (deletes & updates) 
                    if (cachedRows != null) {
                        foreach (DataRow cachedRow in cachedRows) {
                            if (cachedRow.Table != dc.Table)
                                continue; 
                             // don't update original version if child row doesn't have an oldRecord.
                            if (foreignVer == DataRowVersion.Original && cachedRow.newRecord == cachedRow.oldRecord) 
                                 continue; 
                            if (cachedRow != null && ((cachedRow.RowState != DataRowState.Deleted) && (version != DataRowVersion.Original || cachedRow.oldRecord != -1))) {// if deleted GetRecordFromVersion will throw
                                object newValue = dc.DataExpression.Evaluate(cachedRow, foreignVer); 
                                SilentlySetValue(cachedRow, dc, foreignVer, newValue);
                            }
                        }
                    } 

                    // next check parent relations 
                    for (int j = 0; j < ParentRelations.Count; j++) { 
                        DataRelation relation = ParentRelations[j];
                        if (relation.ParentTable != dc.Table) 
                            continue;
                        foreach (DataRow parentRow in row.GetParentRows(relation, version)) {
                            if (cachedRows != null && cachedRows.Contains(parentRow))
                                continue; 
                             // don't update original version if child row doesn't have an oldRecord.
                            if (foreignVer == DataRowVersion.Original && parentRow.newRecord == parentRow.oldRecord) 
                                 continue; 
                            if (parentRow != null && ((parentRow.RowState != DataRowState.Deleted) && (version != DataRowVersion.Original || parentRow.oldRecord != -1))) {// if deleted GetRecordFromVersion will throw
                                object newValue = dc.DataExpression.Evaluate(parentRow, foreignVer); 
                                SilentlySetValue(parentRow, dc, foreignVer, newValue);
                            }
                        }
                    } 
                    // next check child relations
                    for (int j = 0; j < ChildRelations.Count; j++) { 
                        DataRelation relation = ChildRelations[j]; 
                        if (relation.ChildTable != dc.Table)
                            continue; 
                        foreach (DataRow childRow in row.GetChildRows(relation, version)) {
                            // don't update original version if child row doesn't have an oldRecord.
                            if (cachedRows != null && cachedRows.Contains(childRow))
                                continue; 
                            if (foreignVer == DataRowVersion.Original && childRow.newRecord == childRow.oldRecord)
                                continue; 
                            if (childRow != null && ((childRow.RowState != DataRowState.Deleted) && (version != DataRowVersion.Original || childRow.oldRecord != -1))) { // if deleted GetRecordFromVersion will throw 
                                object newValue = dc.DataExpression.Evaluate(childRow, foreignVer);
                                SilentlySetValue(childRow, dc, foreignVer, newValue); 
                            }
                        }
                    }
                } 
            }
        } 
    } 
}
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
//----------------------------------------------------------------------------- 
 
namespace System.Data {
    using System; 
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Diagnostics; 
    using System.Globalization;
    using System.IO; 
    using System.Runtime.Serialization; 
    using System.Text;
    using System.Threading; 
    using System.Xml;
    using System.Xml.Schema;
    using System.Xml.Serialization;
    using System.Data.Common; 
    using System.Runtime.Versioning;
 
    ///  
    ///    Represents one table of in-memory data.
    ///  
    [
    ToolboxItem(false),
    DesignTimeVisible(false),
    DefaultProperty("TableName"), 
    Editor("Microsoft.VSDesigner.Data.Design.DataTableEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing),
    DefaultEvent("RowChanging"), 
    XmlSchemaProvider("GetDataTableSchema"), 
    Serializable
    ] 
    public class DataTable : MarshalByValueComponent, System.ComponentModel.IListSource, ISupportInitializeNotification, ISerializable, IXmlSerializable{
        private DataSet dataSet;
        private DataView defaultView = null;
 
        // rows
        ///  
        /// Monotonically increasing number representing the order  have been added to . 
        /// 
        /// This limits  to  operations. 
        internal long nextRowID;
        internal readonly DataRowCollection rowCollection;

        // columns 
        internal readonly DataColumnCollection columnCollection;
 
        // constraints 
        private readonly ConstraintCollection constraintCollection;
 
        //SimpleContent implementation
        private int elementColumnCount = 0;

        // relations 
        internal DataRelationCollection parentRelationsCollection;
        internal DataRelationCollection childRelationsCollection; 
 
        // RecordManager
        internal readonly RecordManager recordManager; 

        // index mgmt
        internal readonly List indexes;
 
        private List shadowIndexes;
        private int shadowCount; 
 
        // props
        internal PropertyCollection extendedProperties = null; 
        private string tableName = "";
        internal string tableNamespace = null;
        private string tablePrefix = "";
        internal DataExpression displayExpression; 
        internal bool fNestedInDataset = true;
 
        // globalization stuff 
        private CultureInfo _culture;
        private bool _cultureUserSet; 
        private CompareInfo _compareInfo;
        private CompareOptions _compareFlags = CompareOptions.IgnoreCase | CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth;
        private IFormatProvider _formatProvider;
        private StringComparer _hashCodeProvider; 
        private bool _caseSensitive;
        private bool _caseSensitiveUserSet; 
 
        // XML properties
        internal string encodedTableName;           // For XmlDataDocument only 
        internal DataColumn xmlText;            // text values of a complex xml element
        internal DataColumn _colUnique;
        internal bool textOnly = false;         // the table has only text value with possible attributes
        internal decimal minOccurs = 1;    // default = 1 
        internal decimal maxOccurs = 1;    // default = 1
        internal bool repeatableElement = false; 
        private object typeName = null; 

        // primary key info 
        private readonly static Int32[] zeroIntegers = new Int32[0];
        internal readonly static DataColumn[] zeroColumns = new DataColumn[0];
        internal readonly static DataRow[] zeroRows = new DataRow[0];
        internal UniqueConstraint primaryKey; 
        internal readonly static IndexField[] zeroIndexField = new IndexField[0];
        internal IndexField[] _primaryIndex = zeroIndexField; 
        private DataColumn[] delayedSetPrimaryKey = null; 

        // Loading Schema and/or Data related optimization 
        private Index loadIndex;
        private Index loadIndexwithOriginalAdded = null;
        private Index loadIndexwithCurrentDeleted = null;
        private int _suspendIndexEvents; 

        private bool savedEnforceConstraints = false; 
        private bool inDataLoad = false; 
        private bool initialLoad;
        private bool schemaLoading = false; 
        private bool enforceConstraints = true;
        internal bool _suspendEnforceConstraints = false;

        protected internal bool fInitInProgress = false; 
        private bool inLoad = false;
        internal bool fInLoadDiffgram = false; 
 
        private byte _isTypedDataTable; // 0 == unknown, 1 = yes, 2 = No
        private DataRow[] EmptyDataRowArray; 


        // Property Descriptor Cache for DataBinding
        private PropertyDescriptorCollection propertyDescriptorCollectionCache = null; 

        // Cache for relation that has this table as nested child table. 
        private static readonly DataRelation[] EmptyArrayDataRelation = new DataRelation[0]; 
        private DataRelation[] _nestedParentRelations = EmptyArrayDataRelation;
 
        // Dependent column list for expression evaluation
        internal List dependentColumns = null;

        // events 
        private bool mergingData = false;
        private DataRowChangeEventHandler onRowChangedDelegate; 
        private DataRowChangeEventHandler onRowChangingDelegate; 
        private DataRowChangeEventHandler onRowDeletingDelegate;
        private DataRowChangeEventHandler onRowDeletedDelegate; 
        private DataColumnChangeEventHandler onColumnChangedDelegate;
        private DataColumnChangeEventHandler onColumnChangingDelegate;

        private DataTableClearEventHandler onTableClearingDelegate; 
        private DataTableClearEventHandler onTableClearedDelegate;
        private DataTableNewRowEventHandler onTableNewRowDelegate; 
 
        private PropertyChangedEventHandler onPropertyChangingDelegate;
 
        private System.EventHandler  onInitialized;


        // misc 
        private readonly DataRowBuilder rowBuilder;
        private const String KEY_XMLSCHEMA = "XmlSchema"; 
        private const String KEY_XMLDIFFGRAM = "XmlDiffGram"; 
        private const String KEY_NAME = "TableName";
 
        internal readonly List delayedViews = new List();
        private readonly List _dataViewListeners = new List();

//        private bool serializeHierarchy = false; 
        internal Hashtable rowDiffId = null;
        internal readonly ReaderWriterLock indexesLock = new ReaderWriterLock(); 
        internal int ukColumnPositionForInference= -1; 

        // default remoting format is Xml 
        private SerializationFormat _remotingFormat = SerializationFormat.Xml;

        private static int _objectTypeCount; // Bid counter
        private readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount); 

        ///  
        /// Initializes a new instance of the  class with no arguments. 
        /// 
        public DataTable() { 
            GC.SuppressFinalize(this);
            Bid.Trace(" %d#\n", ObjectID);
            nextRowID = 1;
            recordManager = new RecordManager(this); 

            _culture = CultureInfo.CurrentCulture; 
            this.columnCollection = new DataColumnCollection(this); 
            this.constraintCollection = new ConstraintCollection(this);
            this.rowCollection = new DataRowCollection(this); 
            this.indexes = new List();

            rowBuilder = new DataRowBuilder(this, -1);
        } 

        ///  
        /// Intitalizes a new instance of the  class with the specified table 
        ///    name.
        ///  
        public DataTable(string tableName) : this() {
            this.tableName = tableName == null ? "" : tableName;
        }
 
        public DataTable(string tableName, string tableNamespace) : this(tableName) {
            this.Namespace = tableNamespace; 
        } 

//        Deserialize the table from binary/xml stream. 
        protected DataTable(SerializationInfo info, StreamingContext context) : this()
        {
            bool isSingleTable = context.Context != null ? Convert.ToBoolean(context.Context, CultureInfo.InvariantCulture) : true;
            SerializationFormat remotingFormat = SerializationFormat.Xml; 
            SerializationInfoEnumerator e = info.GetEnumerator();
            while (e.MoveNext()) { 
                switch(e.Name) { 
                    case "DataTable.RemotingFormat" : //DataTable.RemotingFormat does not exist in V1/V1.1 versions
                    remotingFormat = (SerializationFormat)e.Value; 
                    break;
                }
            }
 
            DeserializeDataTable(info, context, isSingleTable, remotingFormat);
        } 
 
        [System.Security.Permissions.SecurityPermissionAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Flags=System.Security.Permissions.SecurityPermissionFlag.SerializationFormatter)]
        public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { 
            SerializationFormat remotingFormat = RemotingFormat;
            bool isSingleTable = context.Context != null ? Convert.ToBoolean(context.Context, CultureInfo.InvariantCulture) : true;
            SerializeDataTable(info, context, isSingleTable, remotingFormat);
        } 

//        Serialize the table schema and data. 
        private void SerializeDataTable(SerializationInfo info, StreamingContext context, bool isSingleTable, SerializationFormat remotingFormat) { 
            info.AddValue("DataTable.RemotingVersion", new Version(2, 0));
 
            // SqlHotFix 299, SerializationFormat enumeration types don't exist in V1.1 SP1
            if (SerializationFormat.Xml != remotingFormat) {
                info.AddValue("DataTable.RemotingFormat", remotingFormat);
            } 

            if (remotingFormat != SerializationFormat.Xml) {//Binary 
                SerializeTableSchema(info, context, isSingleTable); 
                if (isSingleTable) {
                    SerializeTableData(info, context, 0); 
                }
            } else {//XML/V1.0/V1.1
                string tempDSNamespace = "";
                Boolean fCreatedDataSet = false; 

                if (dataSet == null) { 
                    DataSet ds = new DataSet("tmpDataSet"); 
                    // if user set values on DataTable, it isn't necessary
                    // to set them on the DataSet because they won't be inherited 
                    // but it is simpler to set them in both places

                    // if user did not set values on DataTable, it is required
                    // to set them on the DataSet so the table will inherit 
                    // the value already on the Datatable
                    ds.SetLocaleValue(_culture, _cultureUserSet); 
                    ds.CaseSensitive = this.CaseSensitive; 
                    ds.namespaceURI  = this.Namespace;
                    Debug.Assert(ds.RemotingFormat == SerializationFormat.Xml, "RemotingFormat must be SerializationFormat.Xml"); 
                    ds.Tables.Add(this);
                    fCreatedDataSet = true;
                } else {
                    tempDSNamespace = this.DataSet.Namespace; 
                    this.DataSet.namespaceURI = this.Namespace; //this.DataSet.Namespace = this.Namespace; ??
                } 
 
                info.AddValue(KEY_XMLSCHEMA, dataSet.GetXmlSchemaForRemoting(this));
                info.AddValue(KEY_XMLDIFFGRAM, dataSet.GetRemotingDiffGram(this)); 

                if (fCreatedDataSet) {
                    dataSet.Tables.Remove(this);
                } 
                else{
                    dataSet.namespaceURI  = tempDSNamespace; 
                } 
            }
        } 

//        Deserialize the table schema and data.
        internal void DeserializeDataTable(SerializationInfo info, StreamingContext context, bool isSingleTable, SerializationFormat remotingFormat) {
            if (remotingFormat != SerializationFormat.Xml) {//Binary 
                DeserializeTableSchema(info, context, isSingleTable);
                if (isSingleTable) { 
                    DeserializeTableData(info, context, 0); 
                    this.ResetIndexes();
                } 
            } else {//XML/V1.0/V1.1
                string strSchema = (String)info.GetValue(KEY_XMLSCHEMA, typeof(System.String));
                string strData = (String)info.GetValue(KEY_XMLDIFFGRAM, typeof(System.String));
 
                if (strSchema != null) {
                    DataSet ds = new DataSet(); 
                    // fxcop: ReadXmlSchema will provide the CaseSensitive, Locale, Namespace information 
                    ds.ReadXmlSchema(new XmlTextReader( new StringReader( strSchema ) ) );
 
                    Debug.Assert(ds.Tables.Count == 1, "There should be exactly 1 table here");
                    DataTable table = ds.Tables[0];
                    table.CloneTo(this, null, false);// WebData 111656
                    //this is to avoid the cascading rules in the namespace 
                    this.Namespace = table.Namespace;
 
                    if (strData != null) { 
                        ds.Tables.Remove(ds.Tables[0]);
                        ds.Tables.Add(this); 
                        ds.ReadXml(new XmlTextReader( new StringReader( strData ) ), XmlReadMode.DiffGram);
                        ds.Tables.Remove(this);
                    }
                } 
            }
        } 
 
//        Serialize the columns
        internal void SerializeTableSchema(SerializationInfo info, StreamingContext context, bool isSingleTable) { 
            //DataTable basic  properties
            info.AddValue("DataTable.TableName", TableName);
            info.AddValue("DataTable.Namespace", Namespace);
            info.AddValue("DataTable.Prefix", Prefix); 
            info.AddValue("DataTable.CaseSensitive", _caseSensitive);
            info.AddValue("DataTable.caseSensitiveAmbient", !_caseSensitiveUserSet); 
            info.AddValue("DataTable.LocaleLCID", Locale.LCID); 
            info.AddValue("DataTable.MinimumCapacity", recordManager.MinimumCapacity);
            //info.AddValue("DataTable.DisplayExpression", DisplayExpression); 

            //DataTable state internal properties
            info.AddValue("DataTable.NestedInDataSet", fNestedInDataset);
            info.AddValue("DataTable.TypeName", TypeName.ToString()); 
            info.AddValue("DataTable.RepeatableElement", repeatableElement);
 
 
            //ExtendedProperties
            info.AddValue("DataTable.ExtendedProperties", ExtendedProperties); 

            //Columns
            info.AddValue("DataTable.Columns.Count", Columns.Count);
 
            //Check for closure of expression in case of single table.
            if (isSingleTable) { 
                List list = new List(); 
                list.Add(this);
                if (!CheckForClosureOnExpressionTables(list)) 
                    throw ExceptionBuilder.CanNotRemoteDataTable();
            }

            IFormatProvider formatProvider = CultureInfo.InvariantCulture; 
            for (int i = 0; i < Columns.Count; i++) {
                //DataColumn basic properties 
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.ColumnName", i), Columns[i].ColumnName); 
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.Namespace", i), Columns[i]._columnUri);
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.Prefix", i), Columns[i].Prefix); 
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.ColumnMapping", i), Columns[i].ColumnMapping);
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.AllowDBNull", i), Columns[i].AllowDBNull);
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.AutoIncrement", i), Columns[i].AutoIncrement);
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.AutoIncrementStep", i), Columns[i].AutoIncrementStep); 
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.AutoIncrementSeed", i), Columns[i].AutoIncrementSeed);
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.Caption", i), Columns[i].Caption); 
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.DefaultValue", i), Columns[i].DefaultValue); 
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.ReadOnly", i), Columns[i].ReadOnly);
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.MaxLength", i), Columns[i].MaxLength); 
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.DataType", i), Columns[i].DataType);

                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.XmlDataType", i), Columns[i].XmlDataType);
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.SimpleType", i), Columns[i].SimpleType); 

                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.DateTimeMode", i), Columns[i].DateTimeMode); 
 
                //DataColumn internal state properties
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.AutoIncrementCurrent", i), Columns[i].AutoIncrementCurrent); 

                //Expression
                if (isSingleTable) {
                    info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.Expression", i), Columns[i].Expression); 
                }
 
                //ExtendedProperties 
                info.AddValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.ExtendedProperties", i), Columns[i].extendedProperties);
            } 

            //Constraints
            if (isSingleTable) {
                SerializeConstraints(info, context, 0, false); 
            }
        } 
 
//        Deserialize all the Columns
        internal void DeserializeTableSchema(SerializationInfo info, StreamingContext context, bool isSingleTable) { 
            //DataTable basic properties
            tableName = info.GetString("DataTable.TableName");
            tableNamespace = info.GetString("DataTable.Namespace");
            tablePrefix = info.GetString("DataTable.Prefix"); 

            bool caseSensitive = info.GetBoolean("DataTable.CaseSensitive"); 
            SetCaseSensitiveValue(caseSensitive, true, false); 
            _caseSensitiveUserSet = !info.GetBoolean("DataTable.caseSensitiveAmbient");
 
            int lcid = (int)info.GetValue("DataTable.LocaleLCID", typeof(int));
            CultureInfo culture = new CultureInfo(lcid);
            SetLocaleValue(culture, true, false);
            _cultureUserSet = true; 

 
            MinimumCapacity = info.GetInt32("DataTable.MinimumCapacity"); 
            //DisplayExpression = info.GetString("DataTable.DisplayExpression");
 
            //DataTable state internal properties
            fNestedInDataset = (bool) info.GetBoolean("DataTable.NestedInDataSet");
            string tName = info.GetString("DataTable.TypeName");
            typeName =  new XmlQualifiedName(tName); 
            repeatableElement = info.GetBoolean("DataTable.RepeatableElement");
 
            //ExtendedProperties 
            extendedProperties = (PropertyCollection) info.GetValue("DataTable.ExtendedProperties", typeof(PropertyCollection));
 
            //Columns
            int colCount = info.GetInt32("DataTable.Columns.Count");
            string [] expressions = new string[colCount];
            Debug.Assert(Columns.Count == 0, "There is column in Table"); 

            IFormatProvider formatProvider = CultureInfo.InvariantCulture; 
            for (int i = 0; i < colCount; i++) { 
                DataColumn dc = new DataColumn();
 
                //DataColumn public state properties
                dc.ColumnName = info.GetString(String.Format(formatProvider, "DataTable.DataColumn_{0}.ColumnName", i));
                dc._columnUri = info.GetString(String.Format(formatProvider, "DataTable.DataColumn_{0}.Namespace", i));
                dc.Prefix = info.GetString(String.Format(formatProvider, "DataTable.DataColumn_{0}.Prefix", i)); 

                dc.DataType = (Type) info.GetValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.DataType", i), typeof(Type)); 
                dc.XmlDataType = (string) info.GetValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.XmlDataType", i), typeof(string)); 
                dc.SimpleType = (SimpleType) info.GetValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.SimpleType", i), typeof(SimpleType));
 
                dc.ColumnMapping = (MappingType) info.GetValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.ColumnMapping", i), typeof(MappingType));
                dc.DateTimeMode = (DataSetDateTime) info.GetValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.DateTimeMode", i), typeof(DataSetDateTime));

                dc.AllowDBNull = info.GetBoolean(String.Format(formatProvider, "DataTable.DataColumn_{0}.AllowDBNull", i)); 
                dc.AutoIncrement = info.GetBoolean(String.Format(formatProvider, "DataTable.DataColumn_{0}.AutoIncrement", i));
                dc.AutoIncrementStep = info.GetInt64(String.Format(formatProvider, "DataTable.DataColumn_{0}.AutoIncrementStep", i)); 
                dc.AutoIncrementSeed = info.GetInt64(String.Format(formatProvider, "DataTable.DataColumn_{0}.AutoIncrementSeed", i)); 
                dc.Caption = info.GetString(String.Format(formatProvider, "DataTable.DataColumn_{0}.Caption", i));
                dc.DefaultValue = info.GetValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.DefaultValue", i), typeof(object)); 
                dc.ReadOnly = info.GetBoolean(String.Format(formatProvider, "DataTable.DataColumn_{0}.ReadOnly", i));
                dc.MaxLength= info.GetInt32(String.Format(formatProvider, "DataTable.DataColumn_{0}.MaxLength", i));

                //DataColumn internal state properties 
                dc.AutoIncrementCurrent = info.GetValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.AutoIncrementCurrent", i), typeof(object));
 
                //Expression 
                if (isSingleTable) {
                    expressions[i] = info.GetString(String.Format(formatProvider, "DataTable.DataColumn_{0}.Expression", i)); 
                }

                //ExtendedProperties
                dc.extendedProperties = (PropertyCollection) info.GetValue(String.Format(formatProvider, "DataTable.DataColumn_{0}.ExtendedProperties", i), typeof(PropertyCollection)); 
                Columns.Add(dc);
            } 
            if (isSingleTable) { 
                for(int i = 0; i < colCount; i++) {
                    if (expressions[i] != null) { 
                        Columns[i].Expression = expressions[i];
                    }
                }
            } 

            //Constraints 
            if (isSingleTable) { 
                DeserializeConstraints(info, context, /*table index */ 0, /* serialize all constraints */false);// since single table, send table index as 0, meanwhile passing
                // false for 'allConstraints' means, handle all the constraint related to the table 
            }
        }

/* 
        Serialize constraints availabe on the table - note this function is marked internal because it is called by the DataSet deserializer.
        ***Schema for Serializing ArrayList of Constraints*** 
        Unique Constraint - ["U"]->[constraintName]->[columnIndexes]->[IsPrimaryKey]->[extendedProperties] 
        Foriegn Key Constraint - ["F"]->[constraintName]->[parentTableIndex, parentcolumnIndexes]->[childTableIndex, childColumnIndexes]->[AcceptRejectRule, UpdateRule, DeleteRule]->[extendedProperties]
*/ 
        internal void SerializeConstraints(SerializationInfo info, StreamingContext context, int serIndex, bool allConstraints) {
            if (allConstraints) {
                Debug.Assert(DataSet != null);
            } 

            ArrayList constraintList = new ArrayList(); 
 
            for (int i = 0; i < Constraints.Count; i++) {
                Constraint c = Constraints[i]; 

                UniqueConstraint uc = c as UniqueConstraint;
                if (uc != null) {
                    int[] colInfo = new int[uc.Columns.Length]; 
                    for (int j = 0; j < colInfo.Length; j++) {
                        colInfo[j] = uc.Columns[j].Ordinal; 
                    } 

                    ArrayList list = new ArrayList(); 
                    list.Add("U");
                    list.Add(uc.ConstraintName);
                    list.Add(colInfo);
                    list.Add(uc.IsPrimaryKey); 
                    list.Add(uc.ExtendedProperties);
 
                    constraintList.Add(list); 
                } else {
                    ForeignKeyConstraint fk = c as ForeignKeyConstraint; 
                    Debug.Assert(fk != null);
                    bool shouldSerialize = (allConstraints == true) || (fk.Table == this && fk.RelatedTable == this);

                    if (shouldSerialize) { 
                        int[] parentInfo = new int[fk.RelatedColumns.Length + 1];
                        parentInfo[0] = allConstraints ? this.DataSet.Tables.IndexOf(fk.RelatedTable) : 0; 
                        for (int j = 1; j < parentInfo.Length; j++) { 
                            parentInfo[j] = fk.RelatedColumns[j - 1].Ordinal;
                        } 

                        int[] childInfo = new int[fk.Columns.Length + 1];
                        childInfo[0] = allConstraints ? this.DataSet.Tables.IndexOf(fk.Table) : 0 ;   //Since the constraint is on the current table, this is the child table.
                        for (int j = 1; j < childInfo.Length; j++) { 
                            childInfo[j] = fk.Columns[j - 1].Ordinal;
                        } 
 
                        ArrayList list = new ArrayList();
                        list.Add("F"); 
                        list.Add(fk.ConstraintName);
                        list.Add(parentInfo);
                        list.Add(childInfo);
                        list.Add(new int[] { (int) fk.AcceptRejectRule, (int) fk.UpdateRule, (int) fk.DeleteRule }); 
                        list.Add(fk.ExtendedProperties);
 
                        constraintList.Add(list); 
                    }
                } 
            }
            info.AddValue(String.Format(CultureInfo.InvariantCulture, "DataTable_{0}.Constraints", serIndex), constraintList);
        }
 
/*
        Deserialize the constraints on the table. 
        ***Schema for Serializing ArrayList of Constraints*** 
        Unique Constraint - ["U"]->[constraintName]->[columnIndexes]->[IsPrimaryKey]->[extendedProperties]
        Foriegn Key Constraint - ["F"]->[constraintName]->[parentTableIndex, parentcolumnIndexes]->[childTableIndex, childColumnIndexes]->[AcceptRejectRule, UpdateRule, DeleteRule]->[extendedProperties] 
*/
        internal void DeserializeConstraints(SerializationInfo info, StreamingContext context, int serIndex, bool allConstraints) {
            ArrayList constraintList = (ArrayList) info.GetValue(String.Format(CultureInfo.InvariantCulture, "DataTable_{0}.Constraints", serIndex), typeof(ArrayList));
 
            foreach (ArrayList list in constraintList) {
                string con = (string) list[0]; 
 
                if (con.Equals("U")) { //Unique Constraints
                    string constraintName = (string) list[1]; 

                    int[] keyColumnIndexes = (int[]) list[2];
                    bool isPrimaryKey = (bool) list[3];
                    PropertyCollection extendedProperties = (PropertyCollection) list[4]; 

                    DataColumn[] keyColumns = new DataColumn[keyColumnIndexes.Length]; 
                    for (int i = 0; i < keyColumnIndexes.Length; i++) { 
                        keyColumns[i] = Columns[keyColumnIndexes[i]];
                    } 

                    //Create the constraint.
                    UniqueConstraint uc = new UniqueConstraint(constraintName, keyColumns, isPrimaryKey);
                    uc.extendedProperties = extendedProperties; 

                    //Add the unique constraint and it will in turn set the primary keys also if needed. 
                    Constraints.Add(uc); 
                } else { //ForeignKeyConstraints
                    Debug.Assert(con.Equals("F")); 

                    string constraintName = (string) list[1];
                    int[] parentInfo = (int[]) list[2];
                    int[] childInfo = (int[]) list[3]; 
                    int[] rules = (int[]) list[4];
                    PropertyCollection extendedProperties = (PropertyCollection) list[5]; 
 
                    //ParentKey Columns.
                    DataTable parentTable = (allConstraints == false) ? this : this.DataSet.Tables[parentInfo[0]]; 
                    DataColumn[] parentkeyColumns = new DataColumn[parentInfo.Length - 1];
                    for (int i = 0; i < parentkeyColumns.Length; i++) {
                        parentkeyColumns[i] = parentTable.Columns[parentInfo[i + 1]];
                    } 

                    //ChildKey Columns. 
                    DataTable childTable = (allConstraints == false) ? this : this.DataSet.Tables[childInfo[0]]; 
                    DataColumn[] childkeyColumns = new DataColumn[childInfo.Length - 1];
                    for (int i = 0; i < childkeyColumns.Length; i++) { 
                        childkeyColumns[i] = childTable.Columns[childInfo[i + 1]];
                    }

                    //Create the Constraint. 
                    ForeignKeyConstraint fk = new ForeignKeyConstraint(constraintName, parentkeyColumns, childkeyColumns);
                    fk.AcceptRejectRule = (AcceptRejectRule) rules[0]; 
                    fk.UpdateRule = (Rule) rules[1]; 
                    fk.DeleteRule = (Rule) rules[2];
                    fk.extendedProperties = extendedProperties; 

                    //Add just the foreign key constraint without creating unique constraint.
                    Constraints.Add(fk, false);
                } 
            }
        } 
 
//        Serialize the expressions on the table - Marked internal so that DataSet deserializer can call into this
        internal void SerializeExpressionColumns(SerializationInfo info, StreamingContext context, int serIndex) { 
            int colCount = Columns.Count;
            for (int i = 0; i < colCount; i++) {
                info.AddValue(String.Format(CultureInfo.InvariantCulture, "DataTable_{0}.DataColumn_{1}.Expression", serIndex, i), Columns[i].Expression);
            } 
        }
 
//        Deserialize the expressions on the table - Marked internal so that DataSet deserializer can call into this 
        internal void DeserializeExpressionColumns(SerializationInfo info, StreamingContext context, int serIndex) {
            int colCount = Columns.Count; 
            for (int i = 0; i < colCount; i++) {
                string expr = info.GetString(String.Format(CultureInfo.InvariantCulture, "DataTable_{0}.DataColumn_{1}.Expression", serIndex, i));
                if (0 != expr.Length) {
                    Columns[i].Expression = expr; 
                }
            } 
        } 

//        Serialize all the Rows. 
        internal void SerializeTableData(SerializationInfo info, StreamingContext context, int serIndex) {
            //Cache all the column count, row count
            int colCount = Columns.Count;
            int rowCount = Rows.Count; 
            int modifiedRowCount = 0;
            int editRowCount = 0; 
 
            //Compute row states and assign the bits accordingly - 00[Unchanged], 01[Added], 10[Modifed], 11[Deleted]
            BitArray rowStates = new BitArray(rowCount * 3, false); //All bit flags are set to false on initialization of the BitArray. 
            for (int i = 0; i < rowCount; i++) {
                int bitIndex = i * 3;
                DataRow row = Rows[i];
                DataRowState rowState = row.RowState; 
                switch (rowState) {
                    case DataRowState.Unchanged: 
                        //rowStates[bitIndex] = false; 
                        //rowStates[bitIndex + 1] = false;
                        break; 
                    case DataRowState.Added:
                        //rowStates[bitIndex] = false;
                        rowStates[bitIndex + 1] = true;
                        break; 
                    case DataRowState.Modified:
                        rowStates[bitIndex] = true; 
                        //rowStates[bitIndex + 1] = false; 
                        modifiedRowCount++;
                        break; 
                    case DataRowState.Deleted:
                        rowStates[bitIndex] = true;
                        rowStates[bitIndex + 1] = true;
                        break; 
                    default:
                        throw ExceptionBuilder.InvalidRowState(rowState); 
                } 
                if (-1 != row.tempRecord) {
                    rowStates[bitIndex + 2] = true; 
                    editRowCount++;
                }
            }
 
            //Compute the actual storage records that need to be created.
            int recordCount = rowCount + modifiedRowCount + editRowCount; 
 
            //Create column storages.
            ArrayList storeList = new ArrayList(); 
            ArrayList nullbitList = new ArrayList();
            if (recordCount > 0) { //Create the storage only if have records.
                for (int i = 0; i < colCount; i++) {
                    object store = Columns[i].GetEmptyColumnStore(recordCount); 
                    storeList.Add(store);
                    BitArray nullbits = new BitArray(recordCount); 
                    nullbitList.Add(nullbits); 
                }
            } 

            //Copy values into column storages
            int recordsConsumed = 0;
            Hashtable rowErrors = new Hashtable(); 
            Hashtable colErrors = new Hashtable();
            for (int i = 0; i < rowCount; i++) { 
                int recordsPerRow = Rows[i].CopyValuesIntoStore(storeList, nullbitList, recordsConsumed); 
                GetRowAndColumnErrors(i, rowErrors, colErrors);
                recordsConsumed += recordsPerRow; 
            }

            IFormatProvider formatProvider = CultureInfo.InvariantCulture;
            //Serialize all the computed values. 
            info.AddValue(String.Format(formatProvider, "DataTable_{0}.Rows.Count", serIndex), rowCount);
            info.AddValue(String.Format(formatProvider, "DataTable_{0}.Records.Count", serIndex), recordCount); 
            info.AddValue(String.Format(formatProvider, "DataTable_{0}.RowStates", serIndex), rowStates); 
            info.AddValue(String.Format(formatProvider, "DataTable_{0}.Records", serIndex), storeList);
            info.AddValue(String.Format(formatProvider, "DataTable_{0}.NullBits", serIndex), nullbitList); 
            info.AddValue(String.Format(formatProvider, "DataTable_{0}.RowErrors", serIndex), rowErrors);
            info.AddValue(String.Format(formatProvider, "DataTable_{0}.ColumnErrors", serIndex), colErrors);
        }
 
//        Deserialize all the Rows.
        internal void DeserializeTableData(SerializationInfo info, StreamingContext context, int serIndex) { 
            bool enforceConstraintsOrg = enforceConstraints; 
            bool inDataLoadOrg = inDataLoad;
 

            try {
                enforceConstraints = false;
                inDataLoad = true; 
                IFormatProvider formatProvider = CultureInfo.InvariantCulture;
                int rowCount = info.GetInt32(String.Format(formatProvider, "DataTable_{0}.Rows.Count", serIndex)); 
                int recordCount = info.GetInt32(String.Format(formatProvider, "DataTable_{0}.Records.Count", serIndex)); 
                BitArray rowStates = (BitArray) info.GetValue(String.Format(formatProvider, "DataTable_{0}.RowStates", serIndex), typeof(BitArray));
                ArrayList storeList = (ArrayList) info.GetValue(String.Format(formatProvider, "DataTable_{0}.Records", serIndex), typeof(ArrayList)); 
                ArrayList nullbitList = (ArrayList) info.GetValue(String.Format(formatProvider, "DataTable_{0}.NullBits", serIndex), typeof(ArrayList));
                Hashtable rowErrors = (Hashtable) info.GetValue(String.Format(formatProvider, "DataTable_{0}.RowErrors", serIndex), typeof(Hashtable));
                rowErrors.OnDeserialization(this);//OnDeSerialization must be called since the hashtable gets deserialized after the whole graph gets deserialized
                Hashtable colErrors = (Hashtable) info.GetValue(String.Format(formatProvider, "DataTable_{0}.ColumnErrors", serIndex), typeof(Hashtable)); 
                colErrors.OnDeserialization(this);//OnDeSerialization must be called since the hashtable gets deserialized after the whole graph gets deserialized
 
 
                if (recordCount <= 0) { //No need for deserialization of the storage and errors if there are no records.
                    return; 
                }

                //Point the record manager storage to the deserialized values.
                for (int i = 0; i < Columns.Count; i++) { 
                    Columns[i].SetStorage(storeList[i], (BitArray) nullbitList[i]);
                } 
 
                //Create rows and set the records appropriately.
                int recordIndex = 0; 
                DataRow[] rowArr = new DataRow[recordCount];
                for (int i = 0; i < rowCount; i++) {
                    //Create a new row which sets old and new records to -1.
                    DataRow row = NewEmptyRow(); 
                    rowArr[recordIndex] = row;
                    int bitIndex = i * 3; 
                    switch (ConvertToRowState(rowStates, bitIndex)) { 
                        case DataRowState.Unchanged:
                            row.oldRecord = recordIndex; 
                            row.newRecord = recordIndex;
                            recordIndex += 1;
                            break;
                        case DataRowState.Added: 
                            row.oldRecord = -1;
                            row.newRecord = recordIndex; 
                            recordIndex += 1; 
                            break;
                        case DataRowState.Modified: 
                            row.oldRecord = recordIndex;
                            row.newRecord = recordIndex + 1;
                            rowArr[recordIndex + 1] = row;
                            recordIndex += 2; 
                            break;
                        case DataRowState.Deleted: 
                            row.oldRecord = recordIndex; 
                            row.newRecord = -1;
                            recordIndex += 1; 
                            break;
                    }
                    if (rowStates[bitIndex + 2]) {
                        row.tempRecord = recordIndex; 
                        rowArr[recordIndex] = row;
                        recordIndex += 1; 
                    } else { 
                        row.tempRecord = -1;
                    } 
                    Rows.ArrayAdd(row);
                    row.rowID = nextRowID;
                    nextRowID++;
                    ConvertToRowError(i, rowErrors, colErrors); 
                }
                recordManager.SetRowCache(rowArr); 
                ResetIndexes(); 
            } finally {
                enforceConstraints = enforceConstraintsOrg; 
                inDataLoad = inDataLoadOrg;
            }
        }
 
//        Constructs the RowState from the two bits in the bitarray.
        private DataRowState ConvertToRowState(BitArray bitStates, int bitIndex) { 
            Debug.Assert(bitStates != null); 
            Debug.Assert(bitStates.Length > bitIndex);
 
            bool b1 = bitStates[bitIndex];
            bool b2 = bitStates[bitIndex + 1];

            if (!b1 && !b2) { 
                return DataRowState.Unchanged;
            } else if (!b1 && b2) { 
                return DataRowState.Added; 
            } else if (b1 && !b2) {
                return DataRowState.Modified; 
            } else if (b1 && b2) {
                return DataRowState.Deleted;
            } else {
                throw ExceptionBuilder.InvalidRowBitPattern(); 
            }
        } 
 
//        Get the error on the row and columns - Marked internal so that DataSet deserializer can call into this
        internal void GetRowAndColumnErrors(int rowIndex, Hashtable rowErrors, Hashtable colErrors) { 
            Debug.Assert(Rows.Count > rowIndex);
            Debug.Assert(rowErrors != null);
            Debug.Assert(colErrors != null);
 
            DataRow row = Rows[rowIndex];
 
            if (row.HasErrors) { 
                rowErrors.Add(rowIndex, row.RowError);
                DataColumn[] dcArr = row.GetColumnsInError(); 
                if (dcArr.Length > 0) {
                    int[] columnsInError = new int[dcArr.Length];
                    string[] columnErrors = new string[dcArr.Length];
                    for (int i = 0; i < dcArr.Length; i++) { 
                        columnsInError[i] = dcArr[i].Ordinal;
                        columnErrors[i] = row.GetColumnError(dcArr[i]); 
                    } 
                    ArrayList list = new ArrayList();
                    list.Add(columnsInError); 
                    list.Add(columnErrors);
                    colErrors.Add(rowIndex, list);
                }
            } 
        }
 
//        Set the row and columns in error.. 
        private void ConvertToRowError(int rowIndex, Hashtable rowErrors, Hashtable colErrors) {
            Debug.Assert(Rows.Count > rowIndex); 
            Debug.Assert(rowErrors != null);
            Debug.Assert(colErrors != null);

            DataRow row = Rows[rowIndex]; 

            if (rowErrors.ContainsKey(rowIndex)) { 
                row.RowError = (string) rowErrors[rowIndex]; 
            }
            if (colErrors.ContainsKey(rowIndex)) { 
                ArrayList list = (ArrayList) colErrors[rowIndex];
                int[] columnsInError = (int[]) list[0];
                string[] columnErrors = (string[]) list[1];
                Debug.Assert(columnsInError.Length == columnErrors.Length); 
                for (int i = 0; i < columnsInError.Length; i++) {
                    row.SetColumnError(columnsInError[i], columnErrors[i]); 
                } 
            }
        } 

        /// 
        ///    Indicates whether string comparisons within the table are case-sensitive.
        ///  
        [ResDescriptionAttribute(Res.DataTableCaseSensitiveDescr)]
        public bool CaseSensitive { 
            get { 
                //The following assert is valid except when calling DataSet.set_CaseSensitive which Validates constraints and failing here
                //Debug.Assert(_caseSensitiveUserSet || (null == dataSet) || (dataSet.CaseSensitive == _caseSensitive), "CaseSensitive mismatch"); 
                return _caseSensitive;
            }
            set {
                if (_caseSensitive != value) { 
                    bool oldValue = _caseSensitive;
                    bool oldUserSet = _caseSensitiveUserSet; 
                    _caseSensitive = value; 
                    _caseSensitiveUserSet = true;
 
                    if (DataSet != null && !DataSet.ValidateCaseConstraint()) {
                        _caseSensitive = oldValue;
                        _caseSensitiveUserSet = oldUserSet;
                        throw ExceptionBuilder.CannotChangeCaseLocale(); 
                    }
                    SetCaseSensitiveValue(value, true, true); 
                } 
                _caseSensitiveUserSet = true;
            } 
        }

        internal bool AreIndexEventsSuspended {
            get { return (0 < _suspendIndexEvents); } 
        }
 
        internal void RestoreIndexEvents(bool forceReset) { 
            Bid.Trace(" %d#, %d\n", ObjectID, _suspendIndexEvents);
            if (0 < _suspendIndexEvents) { 
                _suspendIndexEvents--;
                if (0 == _suspendIndexEvents) {
                    Exception first = null;
                    SetShadowIndexes(); 
                    try{
                    // the length of shadowIndexes will not change 
                    // but the array instance may change during 
                    // events during Index.Reset
                        int numIndexes = shadowIndexes.Count; 
                        for (int i = 0; i < numIndexes; i++) {
                            Index ndx = shadowIndexes[i];// shadowindexes may change, see ShadowIndexCopy()
                            try {
                                if (forceReset || ndx.HasRemoteAggregate) { 
                                    ndx.Reset(); // resets & fires
                                } 
                                else { 
                                    ndx.FireResetEvent(); // fire the Reset event we were firing
                                } 
                            }
                            catch(Exception e) {
                                if (!ADP.IsCatchableExceptionType (e)) {
                                    throw; 
                                }
                                ExceptionBuilder.TraceExceptionWithoutRethrow(e); 
                                if (null == first) { 
                                    first = e;
                                } 
                            }
                        }
                        if (null != first) {
                            throw first; 
                        }
                    } 
                   finally { 
                       RestoreShadowIndexes();
                   } 
                }
            }
        }
 
        internal void SuspendIndexEvents() {
            Bid.Trace(" %d#, %d\n", ObjectID, _suspendIndexEvents); 
            _suspendIndexEvents++; 
        }
 
        [Browsable(false)]
        public bool IsInitialized {
            get {
                return !fInitInProgress; 
            }
        } 
 
        private bool IsTypedDataTable {
            get { 
                switch (_isTypedDataTable) {
                case 0:
                    _isTypedDataTable = (byte)((this.GetType() != typeof(DataTable))? 1 : 2);
                    return (1 == _isTypedDataTable); 
                case 1:
                    return true; 
                default: 
                    return false;
                } 
            }
        }

        internal bool SetCaseSensitiveValue(bool isCaseSensitive, bool userSet, bool resetIndexes) { 
            if (userSet || (!_caseSensitiveUserSet && (_caseSensitive != isCaseSensitive))) {
                _caseSensitive = isCaseSensitive; 
                if (isCaseSensitive) { 
                    _compareFlags = CompareOptions.None;
                } 
                else {
                    _compareFlags = CompareOptions.IgnoreCase | CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth;
                }
                if (resetIndexes) { 
                    ResetIndexes();
                    foreach (Constraint constraint in Constraints) { 
                       constraint.CheckConstraint(); 
                    }
                } 
                return true;
            }
            return false;
        } 

 
        private void ResetCaseSensitive() { 
            // this method is used design-time scenarios via reflection
            //   by the property grid context menu to show the Reset option or not 
            SetCaseSensitiveValue((null != dataSet) && dataSet.CaseSensitive, true, true);
            _caseSensitiveUserSet = false;
        }
 
        internal bool ShouldSerializeCaseSensitive() {
            // this method is used design-time scenarios via reflection 
            //   by the property grid to show the CaseSensitive property in bold or not 
            //   by the code dom for persisting the CaseSensitive property or not
            return _caseSensitiveUserSet; 
        }

        internal bool SelfNested {
            get { 
                // Is this correct? if ((top[i].nestedParentRelation!= null) && (top[i].nestedParentRelation.ParentTable == top[i]))
                foreach(DataRelation rel in ParentRelations) { 
                    if (rel.Nested && rel.ParentTable == this) { 
                        return true;
                    } 
                }
                return false;
            }
        } 
/*        internal bool SelfNestedWithOneRelation {
            get { 
                return (this.ParentRelations.Count == 1 && (this.ParentRelations[0].ParentTable == this)); 
            }
        } 
*/

        [DebuggerBrowsable(DebuggerBrowsableState.Never)] // don't have debugger view expand this
        internal List LiveIndexes { 
            get {
                if (!AreIndexEventsSuspended) { 
                    for (int i = indexes.Count-1; 0 <= i; --i) { 
                        Index index = indexes[i];
                        if (index.RefCount <= 1) { 
                            index.RemoveRef();
                        }
                    }
                } 
                return indexes;
            } 
        } 

        [ 
        DefaultValue(SerializationFormat.Xml)
        ]
        public SerializationFormat RemotingFormat {
            get { 
                return _remotingFormat;
            } 
            set { 
                if (value != SerializationFormat.Binary && value != SerializationFormat.Xml) {
                    throw ExceptionBuilder.InvalidRemotingFormat(value); 
                }
                // table can not have different format than its dataset, unless it is stand alone datatable
                if (this.DataSet != null && value != this.DataSet.RemotingFormat) {
                    throw ExceptionBuilder.CanNotSetRemotingFormat(); 
                }
                _remotingFormat = value; 
            } 
        }
 
// used to keep temporary state of unique Key posiotion to be added for inference only
        internal int UKColumnPositionForInference {
            get {
                return ukColumnPositionForInference; 
            }
            set{ 
                ukColumnPositionForInference= value; 
            }
        } 

        /// 
        /// Gets the collection of child relations for this .
        ///  
        [
        Browsable(false), 
        ResDescriptionAttribute(Res.DataTableChildRelationsDescr), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ] 
        public DataRelationCollection ChildRelations {
            get {
                if (childRelationsCollection == null)
                    childRelationsCollection = new DataRelationCollection.DataTableRelationCollection(this, false); 
                return childRelationsCollection;
            } 
        } 

        ///  
        ///    Gets the collection of columns that belong to this table.
        /// 
        [
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
        ResCategoryAttribute(Res.DataCategory_Data),
        ResDescriptionAttribute(Res.DataTableColumnsDescr) 
        ] 
        public DataColumnCollection Columns {
            get { 
                return columnCollection;
            }
        }
 
        private void ResetColumns() {
            // this method is used design-time scenarios via reflection 
            //   by the property grid context menu to show the Reset option or not 
            Columns.Clear();
        } 

        private CompareInfo CompareInfo {
            get {
                if (null == _compareInfo) { 
                    _compareInfo = Locale.CompareInfo;
                } 
                return _compareInfo; 
            }
        } 

        /// 
        ///    Gets the collection of constraints maintained by this table.
        ///  
        [
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
        ResCategoryAttribute(Res.DataCategory_Data), 
        ResDescriptionAttribute(Res.DataTableConstraintsDescr)
        ] 
        public ConstraintCollection Constraints {
            get {
                return constraintCollection;
            } 
        }
 
        ///  
        ///    
        ///       Resets the  property to its default state. 
        ///    
        /// 
        private void ResetConstraints() {
            Constraints.Clear(); 
        }
 
        ///  
        /// Gets the  that this table belongs to.
        ///  
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false), ResDescriptionAttribute(Res.DataTableDataSetDescr)]
        public DataSet DataSet {
            get {
                return dataSet; 
            }
        } 
 
        /// 
        /// Internal method for setting the DataSet pointer. 
        /// 
        internal void SetDataSet(DataSet dataSet) {
            if (this.dataSet != dataSet) {
                this.dataSet = dataSet; 

                // Inform all the columns of the dataset being set. 
                DataColumnCollection   cols = Columns; 
                for (int i = 0; i < cols.Count; i++)
                    cols[i].OnSetDataSet(); 

                if (this.DataSet != null) {
                    defaultView = null;
                } 
                //Set the remoting format variable directly
                if (dataSet != null) { 
                    _remotingFormat = dataSet.RemotingFormat; 
                }
            } 
        }

        /// 
        ///    Gets a customized view of the table which may include a 
        ///       filtered view, or a cursor position.
        ///  
        [Browsable(false), ResDescriptionAttribute(Res.DataTableDefaultViewDescr)] 
        public DataView DefaultView {
            get { 
                DataView view = defaultView;
                if (null == view) {
                    if (null != dataSet) {
                        view = dataSet.DefaultViewManager.CreateDataView(this); 
                    }
                    else { 
                        view = new DataView(this, true); 
                        view.SetIndex2("", DataViewRowState.CurrentRows, null, true);
                    } 
                    // avoid HostProtectionAttribute(Synchronization=true) by not calling virtual methods from inside a lock
                    view = Interlocked.CompareExchange(ref defaultView, view, null);
                    if (null == view) {
                        view = defaultView; 
                    }
                } 
                return view; 
            }
        } 

        /// 
        ///    Gets or sets the expression that will return a value used to represent
        ///       this table in UI. 
        /// 
        [ 
        DefaultValue(""), 
        ResCategoryAttribute(Res.DataCategory_Data),
        ResDescriptionAttribute(Res.DataTableDisplayExpressionDescr) 
        ]
        public string DisplayExpression {
            get {
                return DisplayExpressionInternal; 
            }
            set { 
                if (value != null && value.Length > 0) { 
                    this.displayExpression = new DataExpression(this, value);
                } 
                else {
                    this.displayExpression = null;
                }
            } 
        }
        internal string DisplayExpressionInternal { 
            get { 
                return(displayExpression != null ? displayExpression.Expression : "");
            } 
        }

        internal bool EnforceConstraints {
            get { 
                if (SuspendEnforceConstraints) {
                    return false; 
                } 
                if (dataSet != null)
                    return dataSet.EnforceConstraints; 

                return this.enforceConstraints;
            }
            set { 
                if (dataSet == null && this.enforceConstraints != value) {
                    if (value) 
                        EnableConstraints(); 

                    this.enforceConstraints = value; 
                }
            }
        }
 
        internal bool SuspendEnforceConstraints {
            get { 
                return _suspendEnforceConstraints ; 
            }
            set { 
                _suspendEnforceConstraints = value;
            }
        }
 
        internal void EnableConstraints()
        { 
            bool errors = false; 
            foreach (Constraint constr in Constraints)
            { 
                if (constr is UniqueConstraint)
                    errors |= constr.IsConstraintViolated();
            }
 
            foreach (DataColumn column in Columns) {
                if (!column.AllowDBNull) { 
                    errors |= column.IsNotAllowDBNullViolated(); 
                }
                if (column.MaxLength >= 0) { 
                    errors |= column.IsMaxLengthViolated();
                }
            }
 
            if (errors) {
                this.EnforceConstraints = false; 
                throw ExceptionBuilder.EnforceConstraint(); 
            }
        } 

        /// 
        ///    Gets the collection of customized user information.
        ///  
        [
        ResCategoryAttribute(Res.DataCategory_Data), 
        Browsable(false), 
        ResDescriptionAttribute(Res.ExtendedPropertiesDescr)
        ] 
        public PropertyCollection ExtendedProperties {
            get {
                if (extendedProperties == null) {
                    extendedProperties = new PropertyCollection(); 
                }
                return extendedProperties; 
            } 
        }
 
        internal IFormatProvider FormatProvider {
            get {
                // used for Formating/Parsing
                // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemglobalizationcultureinfoclassisneutralculturetopic.asp 
                if (null == _formatProvider) {
                    CultureInfo culture = Locale; 
                    if (culture.IsNeutralCulture) { 
                        culture = CultureInfo.InvariantCulture;
                    } 
                    _formatProvider = (IFormatProvider)culture;
                }
                return _formatProvider;
            } 
        }
 
        ///  
        ///    Gets a value indicating whether there are errors in any of the rows in any of
        ///       the tables of the  to which the table belongs. 
        /// 
        [Browsable(false), ResDescriptionAttribute(Res.DataTableHasErrorsDescr)]
        public bool HasErrors {
            get { 
                for (int i = 0; i < Rows.Count; i++) {
                    if (Rows[i].HasErrors) { 
                        return true; 
                    }
                } 
                return false;
            }
        }
 
        /// 
        ///    Gets or sets the locale information used to compare strings within the table. 
        ///    Also used for locale sensitive, case,kana,width insensitive column name lookups 
        ///    Also used for converting values to and from string
        ///  
        [ResDescriptionAttribute(Res.DataTableLocaleDescr)]
        public CultureInfo Locale {
            get {
                // used for Comparing not Formatting/Parsing 
                Debug.Assert(null != _culture, "null culture");
                Debug.Assert(_cultureUserSet || (null == dataSet) || _culture.Equals(dataSet.Locale), "Locale mismatch"); 
                return _culture; 
            }
            set { 
                IntPtr hscp;
                Bid.ScopeEnter(out hscp, " %d#\n", ObjectID);
                try {
                    bool userSet = true; 
                    if (null == value)  {
                        // reset Locale to inherit from DataSet 
                        userSet = false; 
                        value = (null != dataSet) ? dataSet.Locale : _culture;
                    } 
                    if (_culture != value && !_culture.Equals(value)) {
                        bool flag = false;
                        bool exceptionThrown = false;
                        CultureInfo oldLocale = _culture; 
                        bool oldUserSet = _cultureUserSet;
                        try { 
                            _cultureUserSet = true; 
                            SetLocaleValue(value, true, false);
                            if ((null == DataSet) || DataSet.ValidateLocaleConstraint()) { 
                                flag = false;
                                SetLocaleValue(value, true, true);
                                flag = true;
                            } 
                        }
                        catch { 
                            exceptionThrown = true; 
                            throw;
                        } 
                        finally {
                            if (!flag) { // reset old locale if ValidationFailed or exception thrown
                                try {
                                    SetLocaleValue(oldLocale, true, true); 
                                }
                                catch(Exception e) { // failed to reset all indexes for all constraints 
                                    if (!Common.ADP.IsCatchableExceptionType(e)) { 
                                        throw;
                                    } 
                                    Common.ADP.TraceExceptionWithoutRethrow(e);
                                }
                                _cultureUserSet = oldUserSet;
                                if (!exceptionThrown) { 
                                    throw ExceptionBuilder.CannotChangeCaseLocale(null);
                                } 
                            } 
                        }
                        SetLocaleValue(value, true, true); 
                    }
                    _cultureUserSet = userSet;
                }
                finally{ 
                    Bid.ScopeLeave(ref hscp);
                } 
            } 
        }
 
        internal bool SetLocaleValue(CultureInfo culture, bool userSet, bool resetIndexes) {
            Debug.Assert(null != culture, "SetLocaleValue: no locale");
            if (userSet || resetIndexes || (!_cultureUserSet && !_culture.Equals(culture))) {
                _culture = culture; 
                _compareInfo = null;
                _formatProvider = null; 
                _hashCodeProvider = null; 

                foreach(DataColumn column in Columns) { 
                    column._hashCode = GetSpecialHashCode(column.ColumnName);
                }
                if (resetIndexes) {
                    ResetIndexes(); 
                    foreach (Constraint constraint in Constraints) {
                        constraint.CheckConstraint(); 
                    } 
                }
                return true; 
            }
            return false;
        }
 
        internal bool ShouldSerializeLocale() {
            // this method is used design-time scenarios via reflection 
            //   by the property grid to show the Locale property in bold or not 
            //   by the code dom for persisting the Locale property or not
 
            // we always want the locale persisted if set by user or different the current thread if standalone table
            // but that logic should by performed by the serializion code
            return _cultureUserSet;
        } 

        ///  
        ///    Gets or sets the initial starting size for this table. 
        /// 
        [ 
        DefaultValue(50),
        ResCategoryAttribute(Res.DataCategory_Data),
        ResDescriptionAttribute(Res.DataTableMinimumCapacityDescr)
        ] 
        public int MinimumCapacity {
            get { 
                return recordManager.MinimumCapacity; 
            }
            set { 
                if (value != recordManager.MinimumCapacity) {
                    recordManager.MinimumCapacity = value;
                }
            } 
        }
 
        internal int RecordCapacity { 
            get {
                return recordManager.RecordCapacity; 
            }
        }

 
        internal int ElementColumnCount {
            get { 
                return elementColumnCount; 
            }
            set { 
                if ((value > 0) && (xmlText != null))
                    throw ExceptionBuilder.TableCannotAddToSimpleContent();
                else elementColumnCount = value;
            } 
        }
 
        ///  
        /// Gets the collection of parent relations for this .
        ///  
        [
        Browsable(false),
        ResDescriptionAttribute(Res.DataTableParentRelationsDescr),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) 
        ]
        public DataRelationCollection ParentRelations { 
            get { 
                if (parentRelationsCollection == null)
                    parentRelationsCollection = new DataRelationCollection.DataTableRelationCollection(this, true); 
                return parentRelationsCollection;
            }
        }
 
        internal bool MergingData {
            get { 
                return mergingData; 
            }
            set { 
                mergingData = value;
            }
        }
 
        internal DataRelation[] NestedParentRelations {
            get { 
#if DEBUG 
                DataRelation[] nRel = FindNestedParentRelations();
                Debug.Assert(nRel.Length == _nestedParentRelations.Length, "nestedParent cache is broken"); 
                for(int i = 0; i < nRel.Length; i++) {
                    Debug.Assert(null != nRel[i], "null relation");
                    Debug.Assert(null != _nestedParentRelations[i], "null relation");
                    Debug.Assert(nRel[i] == _nestedParentRelations[i], "unequal relations"); 
                }
#endif 
                return _nestedParentRelations; 
            }
        } 

        internal bool SchemaLoading {
            get {
                return schemaLoading; 
            }
        } 
 

        internal void CacheNestedParent() { 
            _nestedParentRelations = FindNestedParentRelations();
        }

        private DataRelation[] FindNestedParentRelations() { 
            List nestedParents = null;
            foreach(DataRelation relation in this.ParentRelations) { 
                if(relation.Nested) { 
                    if (null == nestedParents) {
                        nestedParents = new List(); 
                    }
                    nestedParents.Add(relation);
                }
            } 
            if ((null == nestedParents) || (nestedParents.Count == 0)) {
                return EmptyArrayDataRelation; 
            } 
            return nestedParents.ToArray();
        } 


        internal int NestedParentsCount {
            get { 
                int count = 0;
                foreach(DataRelation relation in this.ParentRelations) { 
                    if(relation.Nested) 
                        count++;
                } 
                return count;
            }
        }
 
        /// 
        ///    Gets or sets an array of columns that function as primary keys for the data 
        ///       table. 
        /// 
        [ 
        TypeConverter(typeof(PrimaryKeyTypeConverter)),
        ResDescriptionAttribute(Res.DataTablePrimaryKeyDescr),
        ResCategoryAttribute(Res.DataCategory_Data),
        Editor("Microsoft.VSDesigner.Data.Design.PrimaryKeyEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing) 
        ]
        public DataColumn[] PrimaryKey { 
            get { 
                UniqueConstraint primayKeyConstraint = primaryKey;
                if (null != primayKeyConstraint) { 
                    Debug.Assert(2 <= primaryKey.ConstraintIndex.RefCount, "bad primaryKey index RefCount");
                    return primayKeyConstraint.Key.ToArray();
                }
                return zeroColumns; 
            }
            set { 
                UniqueConstraint key = null; 
                UniqueConstraint existingKey = null;
 
                // Loading with persisted property
                if (fInitInProgress && value != null) {
                    delayedSetPrimaryKey = value;
                    return; 
                }
 
                if ((value != null) && (value.Length != 0)) { 
                    int count = 0;
                    for (int i = 0; i < value.Length; i++) { 
                        if (value[i] != null)
                            count++;
                        else
                            break; 
                    }
 
                    if (count != 0) { 
                        DataColumn[] newValue = value;
                        if (count != value.Length) { 
                            newValue = new DataColumn[count];
                            for (int i = 0; i < count; i++)
                                newValue[i] = value[i];
                        } 
                        key = new UniqueConstraint(newValue);
                        if (key.Table != this) 
                            throw ExceptionBuilder.TableForeignPrimaryKey(); 
                    }
                } 

                if (key == primaryKey || (key != null && key.Equals(primaryKey)))
                    return;
 
                // Use an existing UniqueConstraint that matches if one exists
                if ((existingKey = (UniqueConstraint)Constraints.FindConstraint(key)) != null) { 
                    key.ColumnsReference.CopyTo(existingKey.Key.ColumnsReference, 0); 
                    key = existingKey;
                } 

                UniqueConstraint oldKey = primaryKey;
                primaryKey = null;
                if (oldKey != null) { 
                    oldKey.ConstraintIndex.RemoveRef();
 
                    // SQLBU 429176: if PrimaryKey is removed, reset LoadDataRow indexes 
                    if (null != loadIndex) {
                        loadIndex.RemoveRef(); 
                        loadIndex = null;
                    }
                    if (null != loadIndexwithOriginalAdded) {
                        loadIndexwithOriginalAdded.RemoveRef(); 
                        loadIndexwithOriginalAdded = null;
                    } 
                    if (null != loadIndexwithCurrentDeleted) { 
                        loadIndexwithCurrentDeleted.RemoveRef();
                        loadIndexwithCurrentDeleted = null; 
                    }
                    Constraints.Remove(oldKey);
                }
 
                // Add the key if there isnt an existing matching key in collection
                if (key != null && existingKey == null) 
                    Constraints.Add(key); 

                primaryKey = key; 

                Debug.Assert(Constraints.FindConstraint(primaryKey) == primaryKey, "PrimaryKey is not in ConstraintCollection");
                _primaryIndex = (key != null) ? key.Key.GetIndexDesc() : zeroIndexField;
 
                if (primaryKey != null) {
                    // must set index for DataView.Sort before setting AllowDBNull which can fail 
                    key.ConstraintIndex.AddRef(); 

                    for (int i = 0; i < key.ColumnsReference.Length; i++) 
                        key.ColumnsReference[i].AllowDBNull = false;
                }
            }
        } 

        ///  
        ///     
        ///       Indicates whether the  property should be persisted.
        ///     
        /// 
        private bool ShouldSerializePrimaryKey() {
            return(primaryKey != null);
        } 

        ///  
        ///     
        ///       Resets the  property to its default state.
        ///     
        /// 
        private void ResetPrimaryKey() {
            PrimaryKey = null;
        } 

        ///  
        ///    Gets the collection of rows that belong to this table. 
        /// 
        [Browsable(false), ResDescriptionAttribute(Res.DataTableRowsDescr)] 
        public DataRowCollection Rows {
            get {
                return rowCollection;
            } 
        }
 
        ///  
        ///    Gets or sets the name of the table.
        ///  
        [
        RefreshProperties(RefreshProperties.All),
        DefaultValue(""),
        ResCategoryAttribute(Res.DataCategory_Data), 
        ResDescriptionAttribute(Res.DataTableTableNameDescr)
        ] 
        public string TableName { 
            get {
                return tableName; 
            }
            set {
                IntPtr hscp;
                Bid.ScopeEnter(out hscp, " %d#, value='%ls'\n", ObjectID, value); 
                try {
                    if (value == null) { 
                        value = ""; 
                    }
                    CultureInfo currentLocale = this.Locale; 
                    if (String.Compare(tableName, value, true, currentLocale) != 0) {
                        if (dataSet != null) {
                            if (value.Length == 0)
                                throw ExceptionBuilder.NoTableName(); 
                            if ((0 == String.Compare(value, dataSet.DataSetName, true, dataSet.Locale)) && !fNestedInDataset)
                               throw ExceptionBuilder.DatasetConflictingName(dataSet.DataSetName); 
 
                            DataRelation[] nestedRelations = NestedParentRelations;
                            if (nestedRelations.Length == 0) { 
                                dataSet.Tables.RegisterName(value, this.Namespace);
                            }
                            else {
                                foreach(DataRelation rel in nestedRelations) { 
                                    if (!rel.ParentTable.Columns.CanRegisterName(value)) {
                                        throw ExceptionBuilder.CannotAddDuplicate2(value); 
                                    } 
                                }
                                // if it cannot register the following line will throw exception 
                                dataSet.Tables.RegisterName(value, this.Namespace);

                                foreach(DataRelation rel in nestedRelations) {
                                    rel.ParentTable.Columns.RegisterColumnName(value, (DataColumn)null, this); 
                                    rel.ParentTable.Columns.UnregisterName(this.TableName);
                                } 
                            } 

                            if (tableName.Length != 0) { 
                                dataSet.Tables.UnregisterName(tableName);
                            }
                        }
                        RaisePropertyChanging("TableName"); 
                        tableName = value;
                        encodedTableName = null; 
                    } 
                    else if (String.Compare(tableName, value, false, currentLocale) != 0) {
                        RaisePropertyChanging("TableName"); 
                        tableName = value;
                        encodedTableName = null;
                    }
                } 
                finally {
                    Bid.ScopeLeave(ref hscp); 
                } 
            }
        } 


        internal string EncodedTableName {
            get { 
                string encodedTblName = this.encodedTableName;
                if (null == encodedTblName) { 
                    encodedTblName = XmlConvert.EncodeLocalName( this.TableName ); 
                    this.encodedTableName = encodedTblName;
                } 
                return encodedTblName;
            }
        }
        private string GetInheritedNamespace(List visitedTables){ 
            // if there is nested relation: ie: this table is nested child of a another table and
            // if it is not self nested, return parent tables NS: Meanwhile make sure SQLBUDT 240219 is FIXED 
            DataRelation[] nestedRelations = NestedParentRelations; 
            if (nestedRelations.Length > 0) {
                for(int i =0; i < nestedRelations.Length; i++) { 
                    DataRelation rel = nestedRelations[i];
                    if (rel.ParentTable.tableNamespace != null) {
                        return rel.ParentTable.tableNamespace; // if parent table has a non-null NS, return it
                    } 
                }
                // Assumption, in hierarchy of multiple nested relation, a child table with no NS, has DataRelation 
                // only and only with parent DataTable witin the same namespace 
                int j = 0;
                while(j < nestedRelations.Length &&((nestedRelations[j].ParentTable == this)||(visitedTables.Contains(nestedRelations[j].ParentTable)))) { 
                    j++;
                }
                if (j < nestedRelations.Length) {
                    DataTable parentTable = nestedRelations[j].ParentTable; 
                    if (!visitedTables.Contains(parentTable))
                        visitedTables.Add(parentTable); 
                        return parentTable.GetInheritedNamespace(visitedTables);// this is the same as return parentTable.Namespace 
                }
            } // dont put else 
            if (DataSet != null) { // if it cant return from parent tables, return NS from dataset, if exists
                return  DataSet.Namespace;
            }
            else { 
                return string.Empty;
            } 
 
        }
 
        /// 
        ///    
        ///       Gets or sets the namespace for the .
        ///     
        /// 
        [ 
        ResCategoryAttribute(Res.DataCategory_Data), 
        ResDescriptionAttribute(Res.DataTableNamespaceDescr)
        ] 
        public string Namespace {
            get {
                if (tableNamespace == null) {
                    return GetInheritedNamespace(new List()); 
                }
                return tableNamespace; 
            } 
            set {
                IntPtr hscp; 
                Bid.ScopeEnter(out hscp, " %d#, value='%ls'\n", ObjectID, value);
                try {
                    if(value != tableNamespace) {
                        if (dataSet != null) { 
                            string realNamespace = (value == null ? GetInheritedNamespace(new List()) : value);
                            if (realNamespace != Namespace) { 
                                // do this extra check only if the namespace is really going to change 
                                // inheritance-wise.
                                if (dataSet.Tables.Contains( this.TableName, realNamespace, true, true)) 
                                    throw ExceptionBuilder.DuplicateTableName2(this.TableName, realNamespace);

                                CheckCascadingNamespaceConflict(realNamespace);
                            } 
                        }
                        CheckNamespaceValidityForNestedRelations(value); 
                        DoRaiseNamespaceChange(); 
                    }
                    tableNamespace = value; 
                }
                finally{
                    Bid.ScopeLeave(ref hscp);
                } 
            }
        } 
        internal bool IsNamespaceInherited() { 
            return (null == tableNamespace);
        } 

        internal void CheckCascadingNamespaceConflict(string realNamespace){
            foreach (DataRelation rel in ChildRelations)
                if ((rel.Nested) && (rel.ChildTable != this) && (rel.ChildTable.tableNamespace == null)) { 
                    DataTable childTable = rel.ChildTable;
                    if (dataSet.Tables.Contains( childTable.TableName, realNamespace, false, true)) 
                        throw ExceptionBuilder.DuplicateTableName2(this.TableName, realNamespace); 

                    childTable.CheckCascadingNamespaceConflict(realNamespace); 
                }

        }
 
        internal void CheckNamespaceValidityForNestedRelations(string realNamespace){
            foreach(DataRelation rel in ChildRelations) { 
                if (rel.Nested) { 
                    if (realNamespace != null) {
                        rel.ChildTable.CheckNamespaceValidityForNestedParentRelations(realNamespace, this); 
                    }
                    else{
                        rel.ChildTable.CheckNamespaceValidityForNestedParentRelations(GetInheritedNamespace(new List()), this);
                    } 
                }
            } 
            if (realNamespace == null) { // this will affect this table if it has parent relations 
                this.CheckNamespaceValidityForNestedParentRelations(GetInheritedNamespace(new List()), this);
            } 

        }
        internal void CheckNamespaceValidityForNestedParentRelations(string ns, DataTable parentTable) {
            foreach(DataRelation rel in ParentRelations){ 
                if (rel.Nested) {
                    if (rel.ParentTable != parentTable && rel.ParentTable.Namespace != ns) { 
                        throw ExceptionBuilder.InValidNestedRelation(this.TableName); 
                    }
                } 
            }

        }
 
        internal void DoRaiseNamespaceChange(){
            RaisePropertyChanging("Namespace"); 
            // raise column Namespace change 

            foreach (DataColumn col in Columns) 
                if (col._columnUri == null)
                    col.RaisePropertyChanging("Namespace");

            foreach (DataRelation rel in ChildRelations) 
                if ((rel.Nested) && (rel.ChildTable != this)) {
                    DataTable childTable = rel.ChildTable; 
 
                    rel.ChildTable.DoRaiseNamespaceChange();
                } 
        }
        /// 
        ///    
        ///       Indicates whether the  property should be persisted. 
        ///    
        ///  
        private bool ShouldSerializeNamespace() { 
            return(tableNamespace != null);
        } 

        /// 
        ///    
        ///       Resets the  property to its default state. 
        ///    
        ///  
        private void ResetNamespace() { 
            this.Namespace = null;
        } 

        /// 
        ///    [To be supplied.]
        ///  
        virtual public void BeginInit() {
            fInitInProgress = true; 
        } 

        ///  
        ///    [To be supplied.]
        /// 
        virtual public void EndInit() {
            if (dataSet == null || !dataSet.fInitInProgress) { 
                Columns.FinishInitCollection();
                Constraints.FinishInitConstraints(); 
                foreach(DataColumn dc in Columns){ 
                    if (dc.Computed) {
                        dc.Expression = dc.Expression; 
                    }
                }
            }
            fInitInProgress = false; // [....] : 77890. It is must that we set off this flag after calling FinishInitxxx(); 
            if (delayedSetPrimaryKey != null) {
                PrimaryKey = delayedSetPrimaryKey; 
                delayedSetPrimaryKey = null; 
            }
            if (delayedViews.Count > 0) { 
                foreach(DataView dv in delayedViews) {
                    dv.EndInit();
                }
                delayedViews.Clear(); 
            }
            OnInitialized(); 
        } 

        ///  
        ///    [To be supplied.]
        /// 
        [
        DefaultValue(""), 
        ResCategoryAttribute(Res.DataCategory_Data),
        ResDescriptionAttribute(Res.DataTablePrefixDescr) 
        ] 
        public string Prefix {
            get { return tablePrefix;} 
            set {
                if (value == null) {
                    value = "";
                } 
                Bid.Trace(" %d#, value='%ls'\n", ObjectID, value);
                if ((XmlConvert.DecodeName(value) == value) && 
                    (XmlConvert.EncodeName(value) != value)) 
                    throw ExceptionBuilder.InvalidPrefix(value);
 

                tablePrefix = value;
            }
        } 

        internal DataColumn XmlText { 
            get { 
                return xmlText;
            } 
            set {
                if (xmlText != value) {
                    if (xmlText != null) {
                        if (value != null) { 
                            throw ExceptionBuilder.MultipleTextOnlyColumns();
                        } 
                        Columns.Remove(xmlText); 
                    }
                    else { 
                        Debug.Assert(value != null, "Value shoud not be null ??");
                        Debug.Assert(value.ColumnMapping == MappingType.SimpleContent, "should be text node here");
                        if (value != Columns[value.ColumnName])
                            Columns.Add(value); 
                    }
                    xmlText = value; 
                } 
            }
        } 

        internal decimal MaxOccurs {
            get {
                return maxOccurs; 
            }
            set { 
                maxOccurs = value; 
            }
        } 

        internal decimal MinOccurs {
            get {
                return minOccurs; 
            }
            set { 
                minOccurs = value; 
            }
        } 

        internal void SetKeyValues(DataKey key, object[] keyValues, int record) {
            for (int i = 0; i < keyValues.Length; i++) {
                key.ColumnsReference[i][record] = keyValues[i]; 
            }
        } 
 
        internal DataRow FindByIndex(Index ndx, object[] key) {
            Range range = ndx.FindRecords(key); 
            if (range.IsNull) {
                return null;
            }
            return this.recordManager[ndx.GetRecord(range.Min)]; 
        }
 
        internal DataRow FindMergeTarget(DataRow row, DataKey key, Index ndx) { 
            DataRow targetRow = null;
 
            // Primary key match
            if (key.HasValue) {
                Debug.Assert(ndx != null);
                int   findRecord = (row.oldRecord == -1) ? row.newRecord : row.oldRecord; 
                object[] values = key.GetKeyValues(findRecord);
                targetRow = FindByIndex(ndx, values); 
            } 
            return targetRow;
        } 

        private void SetMergeRecords(DataRow row, int newRecord, int oldRecord, DataRowAction action) {
            if (newRecord != -1) {
                SetNewRecord(row, newRecord, action, true, true); 
                SetOldRecord(row, oldRecord);
            } 
            else { 
                SetOldRecord(row, oldRecord);
                if (row.newRecord != -1) { 
                    Debug.Assert(action == DataRowAction.Delete, "Unexpected SetNewRecord action in merge function.");
                    SetNewRecord(row, newRecord, action, true, true);
                }
            } 
        }
 
        internal DataRow MergeRow(DataRow row, DataRow targetRow, bool preserveChanges, Index idxSearch) { 
             if (targetRow == null) {
                targetRow = this.NewEmptyRow(); 
                targetRow.oldRecord = recordManager.ImportRecord(row.Table, row.oldRecord);
                targetRow.newRecord = targetRow.oldRecord;
                if(row.oldRecord != row.newRecord) {
                    targetRow.newRecord = recordManager.ImportRecord(row.Table, row.newRecord); 
                }
                InsertRow(targetRow, -1); 
            } 
            else {
                // SQLBU 500789: Record Manager corruption during Merge when target row in edit state 
                // the newRecord would be freed and overwrite tempRecord (which became the newRecord)
                // this would leave the DataRow referencing a freed record and leaking memory for the now lost record
                int proposedRecord = targetRow.tempRecord; // by saving off the tempRecord, EndEdit won't free newRecord
                targetRow.tempRecord = -1; 
                try {
                    DataRowState saveRowState = targetRow.RowState; 
                    int saveIdxRecord = (saveRowState == DataRowState.Added) ? targetRow.newRecord : saveIdxRecord = targetRow.oldRecord; 
                     int newRecord;
                     int oldRecord; 
                    if (targetRow.RowState == DataRowState.Unchanged && row.RowState == DataRowState.Unchanged) {
                        // unchanged row merging with unchanged row
                        oldRecord = targetRow.oldRecord;
                        newRecord = (preserveChanges) ? recordManager.CopyRecord(this, oldRecord, -1) : targetRow.newRecord; 
                        oldRecord = recordManager.CopyRecord(row.Table, row.oldRecord, targetRow.oldRecord);
                        SetMergeRecords(targetRow, newRecord, oldRecord, DataRowAction.Change); 
                    } 
                    else if (row.newRecord == -1) {
                        // Incoming row is deleted 
                        oldRecord = targetRow.oldRecord;
                        if (preserveChanges) {
                          newRecord = (targetRow.RowState == DataRowState.Unchanged)? recordManager.CopyRecord(this, oldRecord, -1) : targetRow.newRecord;
                        } 
                        else
                            newRecord = -1; 
                        oldRecord = recordManager.CopyRecord(row.Table, row.oldRecord, oldRecord); 

                        // Change index record, need to update index 
                        if (saveIdxRecord != ((saveRowState == DataRowState.Added) ? newRecord : oldRecord)) {
                            SetMergeRecords(targetRow, newRecord, oldRecord, (newRecord == -1) ? DataRowAction.Delete : DataRowAction.Change);
                            idxSearch.Reset();
                            saveIdxRecord = ((saveRowState == DataRowState.Added) ? newRecord : oldRecord); 
                        } else {
                            SetMergeRecords(targetRow, newRecord, oldRecord, (newRecord == -1) ? DataRowAction.Delete : DataRowAction.Change); 
                        } 
                    }
                    else { 
                        // incoming row is added, modified or unchanged (targetRow is not unchanged)
                        oldRecord = targetRow.oldRecord;
                        newRecord = targetRow.newRecord;
                        if (targetRow.RowState == DataRowState.Unchanged) { 
                            newRecord = recordManager.CopyRecord(this, oldRecord, -1);
                        } 
                        oldRecord = recordManager.CopyRecord(row.Table, row.oldRecord, oldRecord); 

                        if (!preserveChanges) { 
                            newRecord = recordManager.CopyRecord(row.Table, row.newRecord, newRecord);
                        }
                        SetMergeRecords(targetRow, newRecord, oldRecord, DataRowAction.Change);
                    } 

                    if (saveRowState == DataRowState.Added && targetRow.oldRecord != -1) 
                        idxSearch.Reset(); 
                    Debug.Assert(saveIdxRecord == ((saveRowState == DataRowState.Added) ? targetRow.newRecord : targetRow.oldRecord), "oops, you change index record without noticing it");
                } 
                finally {
                    targetRow.tempRecord = proposedRecord;
                }
            } 

            // Merge all errors 
            if (row.HasErrors) { 
                if (targetRow.RowError.Length == 0) {
                    targetRow.RowError = row.RowError; 
                } else {
                    targetRow.RowError += " ]:[ " + row.RowError;
                }
                DataColumn[] cols = row.GetColumnsInError(); 

                for (int i = 0; i < cols.Length; i++) { 
                    DataColumn col = targetRow.Table.Columns[cols[i].ColumnName]; 
                    targetRow.SetColumnError(col, row.GetColumnError(cols[i]));
                } 
            }else {
                if (!preserveChanges) {
                    targetRow.ClearErrors();
                } 
            }
 
            return targetRow; 
        }
 
        /// 
        /// Commits all the changes made to this table since the last time  was called.
        /// 
        public void AcceptChanges() { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); 
            try { 
                DataRow[] oldRows = new DataRow[Rows.Count];
                Rows.CopyTo(oldRows, 0); 

                // delay updating of indexes until after all
                // AcceptChange calls have been completed
                SuspendIndexEvents(); 
                try {
                    for (int i = 0; i < oldRows.Length; ++i) { 
                        if (oldRows[i].rowID != -1) { 
                            oldRows[i].AcceptChanges();
                        } 
                    }
                }
                finally {
                    RestoreIndexEvents(false); 
                }
            } 
            finally{ 
                Bid.ScopeLeave(ref hscp);
             } 
        }

    protected virtual DataTable CreateInstance() {
        return (DataTable) Activator.CreateInstance(this.GetType(), true); 
    }
 
        public virtual DataTable Clone() { 
            return Clone(null);
        } 

        internal DataTable Clone(DataSet cloneDS) {
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, cloneDS=%d\n", ObjectID, (cloneDS != null) ? cloneDS.ObjectID : 0); 
            try {
                DataTable clone = CreateInstance(); 
                if (clone.Columns.Count > 0) // [....] : To clean up all the schema in strong typed dataset. 
                    clone.Reset();
                return CloneTo(clone, cloneDS, false); 
            }
            finally {
                Bid.ScopeLeave(ref hscp);
            } 
        }
 
 
        private DataTable IncrementalCloneTo (DataTable sourceTable, DataTable targetTable) {
            foreach(DataColumn dc in sourceTable.Columns) { 
                if (targetTable.Columns[dc.ColumnName] == null) {
                    targetTable.Columns.Add(dc.Clone());
                }
            } 

            return targetTable; 
        } 

        private DataTable CloneHierarchy (DataTable sourceTable, DataSet ds, Hashtable visitedMap) { 
            if (visitedMap == null)
                visitedMap = new Hashtable();
            if (visitedMap.Contains(sourceTable))
                return ((DataTable)visitedMap[sourceTable]); 

 
            DataTable destinationTable = ds.Tables[sourceTable.TableName, sourceTable.Namespace]; 

            if ((destinationTable != null && destinationTable.Columns.Count > 0)) { 
                destinationTable = IncrementalCloneTo(sourceTable,destinationTable);
                   // get extra columns from source into destination , increamental read
            }
            else { 
                if (destinationTable == null) {
                    destinationTable = new DataTable(); 
                    // fxcop: new DataTable values for CaseSensitive, Locale, Namespace will come from CloneTo 
                    ds.Tables.Add(destinationTable);
                } 
                destinationTable = sourceTable.CloneTo(destinationTable, ds, true);
            }
            visitedMap[sourceTable] = destinationTable;
 

            // start cloning relation 
            foreach( DataRelation r in sourceTable.ChildRelations ) { 
                DataTable childTable = CloneHierarchy((DataTable)r.ChildTable, ds, visitedMap);
             } 

            return destinationTable;
         }
 

        private DataTable CloneTo(DataTable clone, DataSet cloneDS, bool skipExpressionColumns) { 
// we do clone datatables while we do readxmlschema, so we do not want to clone columnexpressions if we call this from ReadXmlSchema 
// it will cause exception to be thrown in cae expression refers to a table that is not in hirerachy or not created yet
            Debug.Assert(clone != null, "The table passed in has to be newly created empty DataTable."); 

            // set All properties
            clone.tableName = tableName;
 
            clone.tableNamespace = tableNamespace;
            clone.tablePrefix = tablePrefix; 
            clone.fNestedInDataset = fNestedInDataset; 

            clone._culture = _culture; 
            clone._cultureUserSet = _cultureUserSet;
            clone._compareInfo = _compareInfo;
            clone._compareFlags = _compareFlags;
            clone._formatProvider = _formatProvider; 
            clone._hashCodeProvider = _hashCodeProvider;
            clone._caseSensitive = _caseSensitive; 
            clone._caseSensitiveUserSet = _caseSensitiveUserSet; 

            clone.displayExpression = displayExpression; 
            clone.typeName = typeName; //[....]
            clone.repeatableElement = repeatableElement; //[....]
            clone.MinimumCapacity = MinimumCapacity;
            clone.RemotingFormat = RemotingFormat; 
//            clone.SerializeHierarchy = SerializeHierarchy;
 
            // add all columns 
            DataColumnCollection clmns = this.Columns;
            for (int i = 0; i < clmns.Count; i++) { 
                clone.Columns.Add(clmns[i].Clone());
            }

            // add all expressions if Clone is invoked only on DataTable otherwise DataSet.Clone will assign expressions after creating all relationships. 
            if (!skipExpressionColumns && cloneDS == null) {
                for (int i = 0; i < clmns.Count; i++) { 
                    clone.Columns[clmns[i].ColumnName].Expression = clmns[i].Expression; 
                }
            } 

            // Create PrimaryKey
            DataColumn[] pkey = PrimaryKey;
            if (pkey.Length > 0) { 
                DataColumn[] key = new DataColumn[pkey.Length];
                for (int i = 0; i < pkey.Length; i++) { 
                    key[i] = clone.Columns[pkey[i].Ordinal]; 
                }
                clone.PrimaryKey = key; 
            }

            // now clone all unique constraints
            // Rename first 
            for (int j = 0; j < Constraints.Count; j++)  {
                ForeignKeyConstraint foreign = Constraints[j] as ForeignKeyConstraint; 
                UniqueConstraint unique = Constraints[j] as UniqueConstraint; 
                if (foreign  != null) {
                    if (foreign.Table == foreign.RelatedTable) { 
                        ForeignKeyConstraint clonedConstraint = foreign.Clone(clone);
                        Constraint oldConstraint = clone.Constraints.FindConstraint(clonedConstraint);
                        if (oldConstraint != null) {
                            oldConstraint.ConstraintName = Constraints[j].ConstraintName; 
                        }
                    } 
                } 
                else if (unique != null) {
                    UniqueConstraint clonedConstraint = unique.Clone(clone); 
                    Constraint oldConstraint = clone.Constraints.FindConstraint(clonedConstraint);
                    if (oldConstraint != null) {
                        oldConstraint.ConstraintName = Constraints[j].ConstraintName;
                        foreach (Object key in clonedConstraint.ExtendedProperties.Keys) { 
                            oldConstraint.ExtendedProperties[key] = clonedConstraint.ExtendedProperties[key];
                        } 
                    } 
                }
            } 

            // then add
            for (int j = 0; j < Constraints.Count; j++)  {
                if (! clone.Constraints.Contains(Constraints[j].ConstraintName, true)) { 
                    ForeignKeyConstraint foreign = Constraints[j] as ForeignKeyConstraint;
                    UniqueConstraint unique = Constraints[j] as UniqueConstraint; 
                    if (foreign  != null) { 
                        if (foreign.Table == foreign.RelatedTable) {
                            ForeignKeyConstraint newforeign = foreign.Clone(clone); 
                            if (newforeign != null) { // we cant make sure that we recieve a cloned FKC,since it depends if table and relatedtable be the same
                                clone.Constraints.Add(newforeign);
                            }
                        } 
                    }
                    else if (unique != null) { 
                        clone.Constraints.Add(unique.Clone(clone)); 
                    }
                 } 
            }

            // ...Extended Properties...
 
            if (this.extendedProperties != null) {
                foreach(Object key in this.extendedProperties.Keys) { 
                    clone.ExtendedProperties[key]=this.extendedProperties[key]; 
                }
            } 

            return clone;
        }
 

        public DataTable Copy(){ 
            IntPtr hscp; 
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID);
            try { 
                DataTable destTable = this.Clone();

                foreach (DataRow row in Rows)
                    CopyRow(destTable, row); 

                return destTable; 
            } 
            finally {
                Bid.ScopeLeave(ref hscp); 
            }
        }

        ///  
        ///    Occurs when a value has been submitted for this column.
        ///  
        [ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.DataTableColumnChangingDescr)] 
        public event DataColumnChangeEventHandler ColumnChanging {
            add { 
                Bid.Trace(" %d#\n", ObjectID);
                onColumnChangingDelegate += value;
            }
            remove { 
                Bid.Trace(" %d#\n", ObjectID);
                onColumnChangingDelegate -= value; 
            } 
        }
 
        /// 
        ///    [To be supplied.]
        /// 
        [ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.DataTableColumnChangedDescr)] 
        public event DataColumnChangeEventHandler ColumnChanged {
            add  { 
                Bid.Trace(" %d#\n", ObjectID); 
                onColumnChangedDelegate += value;
            } 
            remove {
                Bid.Trace(" %d#\n", ObjectID);
                onColumnChangedDelegate -= value;
            } 
        }
 
        [ 
            ResCategoryAttribute(Res.DataCategory_Action),
            ResDescriptionAttribute(Res.DataSetInitializedDescr) 
        ]
        public event System.EventHandler  Initialized {
            add {
                onInitialized += value; 
            }
            remove { 
                onInitialized -= value; 
            }
        } 

        internal event PropertyChangedEventHandler PropertyChanging {
            add {
                Bid.Trace(" %d#\n", ObjectID); 
                onPropertyChangingDelegate += value;
            } 
            remove { 
                Bid.Trace(" %d#\n", ObjectID);
                onPropertyChangingDelegate -= value; 
            }
        }

        ///  
        ///    
        ///       Occurs after a row in the table has been successfully edited. 
        ///     
        /// 
        [ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.DataTableRowChangedDescr)] 
        public event DataRowChangeEventHandler RowChanged {
            add {
                Bid.Trace(" %d#\n", ObjectID);
                onRowChangedDelegate += value; 
            }
            remove { 
                Bid.Trace(" %d#\n", ObjectID); 
                onRowChangedDelegate -= value;
            } 
        }

        /// 
        ///     
        ///       Occurs when the  is changing.
        ///     
        ///  
        [ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.DataTableRowChangingDescr)]
        public event DataRowChangeEventHandler RowChanging { 
            add {
                Bid.Trace(" %d#\n", ObjectID);
                onRowChangingDelegate += value;
            } 
            remove {
                Bid.Trace(" %d#\n", ObjectID); 
                onRowChangingDelegate -= value; 
            }
        } 

        /// 
        ///    
        ///       Occurs before a row in the table is 
        ///       about to be deleted.
        ///     
        ///  
        [ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.DataTableRowDeletingDescr)]
        public event DataRowChangeEventHandler RowDeleting { 
            add {
                Bid.Trace(" %d#\n", ObjectID);
                onRowDeletingDelegate += value;
            } 
            remove {
                Bid.Trace(" %d#\n", ObjectID); 
                onRowDeletingDelegate -= value; 
            }
        } 

        /// 
        ///    
        ///       Occurs after a row in the 
        ///       table has been deleted.
        ///     
        ///  
        [ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.DataTableRowDeletedDescr)]
        public event DataRowChangeEventHandler RowDeleted { 
            add {
                Bid.Trace(" %d#\n", ObjectID);
                onRowDeletedDelegate += value;
            } 
            remove {
                Bid.Trace(" %d#\n", ObjectID); 
                onRowDeletedDelegate -= value; 
            }
        } 

        [ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.DataTableRowsClearingDescr)]
        public event DataTableClearEventHandler TableClearing {
            add { 
                Bid.Trace(" %d#\n", ObjectID);
                onTableClearingDelegate += value; 
            } 
            remove {
                Bid.Trace(" %d#\n", ObjectID); 
                onTableClearingDelegate -= value;
            }
        }
 
        [ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.DataTableRowsClearedDescr)]
        public event DataTableClearEventHandler TableCleared { 
            add { 
                Bid.Trace(" %d#\n", ObjectID);
                onTableClearedDelegate += value; 
            }
            remove {
                Bid.Trace(" %d#\n", ObjectID);
                onTableClearedDelegate -= value; 
            }
        } 
 
        [ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.DataTableRowsNewRowDescr)]
        public event DataTableNewRowEventHandler TableNewRow { 
            add {
                onTableNewRowDelegate += value;
            }
            remove { 
                onTableNewRowDelegate -= value;
            } 
        } 

        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        public override ISite Site {
            get {
                return base.Site;
            } 
            set {
                ISite oldSite = Site; 
                if (value == null && oldSite != null) { 
                    IContainer cont = oldSite.Container;
 
                    if (cont != null) {
                        for (int i = 0; i < Columns.Count; i++) {
                            if (Columns[i].Site != null) {
                                cont.Remove(Columns[i]); 
                            }
                        } 
                    } 
                }
                base.Site = value; 
            }
        }

        internal DataRow AddRecords(int oldRecord, int newRecord) { 
            DataRow row;
            if (oldRecord == -1 && newRecord == -1) 
            { 
                row = NewRow(-1);
                AddRow(row); 
            }
            else
            {
                row = NewEmptyRow(); 
                row.oldRecord = oldRecord;
                row.newRecord = newRecord; 
                InsertRow(row, -1); 
            }
            return row; 
        }

        internal void AddRow(DataRow row) {
            AddRow(row, -1); 
        }
 
        internal void AddRow(DataRow row, int proposedID) { 
            InsertRow(row, proposedID, -1);
        } 

        internal void InsertRow(DataRow row, int proposedID, int pos) {
            InsertRow(row, proposedID, pos, /*fireEvent*/true);
        } 

        internal void InsertRow(DataRow row, long proposedID, int pos, bool fireEvent) { 
            Exception deferredException = null; 

            if (row == null) { 
                throw ExceptionBuilder.ArgumentNull("row");
            }
            if (row.Table != this) {
                throw ExceptionBuilder.RowAlreadyInOtherCollection(); 
            }
            if (row.rowID != -1) { 
                throw ExceptionBuilder.RowAlreadyInTheCollection(); 
            }
            row.BeginEdit(); // ensure something's there. 

            int record = row.tempRecord;
            row.tempRecord = -1;
 
            if (proposedID == -1) {
                proposedID = this.nextRowID; 
            } 

            bool rollbackOnException; 
            if (rollbackOnException = (nextRowID <= proposedID)) { // WebData 109005
                nextRowID = checked(proposedID + 1);
            }
 
            try {
                try { 
                    row.rowID = proposedID; 
                    // this method may cause DataView.OnListChanged in which another row may be added
                    SetNewRecordWorker(row, record, DataRowAction.Add, false, false, pos, fireEvent, out deferredException); // now we do add the row to collection before OnRowChanged (RaiseRowChanged) 
                }
                catch {
                    if (rollbackOnException && (nextRowID == proposedID+1)) {
                        nextRowID = proposedID; 
                    }
                    row.rowID = -1; 
                    row.tempRecord = record; 
                    throw;
                } 

                // since expression evaluation occurred in SetNewRecordWorker, there may have been a problem that
                // was deferred to this point.  If so, throw now since row has already been added.
                if (deferredException != null) 
                    throw deferredException;
 
                if (EnforceConstraints && !inLoad ) { // if we are evaluating expression, we need to validate constraints 
                    int columnCount = columnCollection.Count;
                    for (int i = 0; i < columnCount; ++i) { 
                        DataColumn column = columnCollection[i];
                        if (column.Computed) {
                            column.CheckColumnConstraint(row, DataRowAction.Add);
                        } 
                    }
                } 
            } 
            finally {
                row.ResetLastChangedColumn();// if expression is evaluated while adding, before  return, we want to clear it 
            }
        }

        internal void CheckNotModifying(DataRow row) { 
            if (row.tempRecord != -1) {
                row.EndEdit(); 
                //throw ExceptionBuilder.ModifyingRow(); 
            }
        } 

        /// 
        ///    
        ///       Clears the table of all data. 
        /// 
 
        public void Clear() { 
            Clear(true);
        } 
        internal void Clear(bool clearAll) {
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, clearAll=%d{bool}\n", ObjectID, clearAll);
 
            try {
                Debug.Assert(null == rowDiffId, "wasn't previously cleared"); 
                rowDiffId = null; 

                if (dataSet != null) 
                    dataSet.OnClearFunctionCalled(this);
                bool shouldFireClearEvents = (this.Rows.Count != 0); // if Rows is already empty, this is noop

                DataTableClearEventArgs e = null; 
                if (shouldFireClearEvents) {
                    e = new DataTableClearEventArgs (this); 
                    OnTableClearing(e); 
                }
 
                if (dataSet != null && dataSet.EnforceConstraints) {

                    for (ParentForeignKeyConstraintEnumerator constraints = new ParentForeignKeyConstraintEnumerator(dataSet, this); constraints.GetNext();) {
                        ForeignKeyConstraint constraint = constraints.GetForeignKeyConstraint(); 
                        constraint.CheckCanClearParentTable(this);
                    } 
                } 

                recordManager.Clear(clearAll); 

                // SQLBU 415729: Serious performance issue when calling Clear()
                // this improves performance by iterating over rows instead of computing by index
                foreach(DataRow row in Rows) { 
                    row.oldRecord = -1;
                    row.newRecord = -1; 
                    row.tempRecord = -1; 
                    row.rowID = -1;
                    row.RBTreeNodeId = 0; 
                }
                Rows.ArrayClear();

                ResetIndexes(); 

                if (shouldFireClearEvents) { 
                    OnTableCleared(e); 
                }
 
                // SQLBU 501916 - DataTable internal index is corrupted:'5'
                foreach(DataColumn column in Columns) {
                    EvaluateDependentExpressions(column);
                } 
            }
            finally { 
                Bid.ScopeLeave(ref hscp); 
            }
        } 

        internal void CascadeAll(DataRow row, DataRowAction action) {
            if (DataSet != null && DataSet.fEnableCascading) {
                for (ParentForeignKeyConstraintEnumerator constraints = new ParentForeignKeyConstraintEnumerator(dataSet, this); constraints.GetNext();) { 
                    constraints.GetForeignKeyConstraint().CheckCascade(row, action);
                } 
            } 
        }
 
        internal void CommitRow(DataRow row) {
            // Fire Changing event
            DataRowChangeEventArgs drcevent = OnRowChanging(null, row, DataRowAction.Commit);
 
            if (!inDataLoad)
                CascadeAll(row, DataRowAction.Commit); 
 
            SetOldRecord(row, row.newRecord);
 
            OnRowChanged(drcevent, row, DataRowAction.Commit);
        }

        internal int Compare(string s1, string s2) { 
            object obj1 = s1;
            object obj2 = s2; 
            if (obj1 == obj2) 
                return 0;
            if (obj1 == null) 
                return -1;
            if (obj2 == null)
                return 1;
 
            int leng1 = s1.Length;
            int leng2 = s2.Length; 
 
            for (; leng1 > 0; leng1--) {
                if (s1[leng1-1] != 0x20 && s1[leng1-1] != 0x3000) // 0x3000 is Ideographic Whitespace 
                    break;
            }
            for (; leng2 > 0; leng2--) {
                if (s2[leng2-1] != 0x20 && s2[leng2-1] != 0x3000) 
                    break;
            } 
 
            return CompareInfo.Compare(s1, 0, leng1, s2, 0, leng2, _compareFlags);
        } 

        internal int IndexOf(string s1, string s2) {
            return CompareInfo.IndexOf(s1, s2, _compareFlags);
        } 

        internal bool IsSuffix(string s1, string s2) { 
            return CompareInfo.IsSuffix(s1, s2, _compareFlags); 
        }
 
        /// 
        ///    Computes the given expression on the current rows that pass the filter criteria.
        /// 
        public object Compute(string expression, string filter) { 
            DataRow[] rows = Select(filter, "", DataViewRowState.CurrentRows);
            DataExpression expr = new DataExpression(this, expression); 
            return expr.Evaluate(rows); 
        }
 
        bool System.ComponentModel.IListSource.ContainsListCollection {
            get {
                return false;
            } 
        }
 
        internal void CopyRow(DataTable table, DataRow row) 
        {
            int oldRecord = -1, newRecord = -1; 

            if (row == null)
                return;
 
            if (row.oldRecord != -1) {
                oldRecord = table.recordManager.ImportRecord(row.Table, row.oldRecord); 
            } 
            if (row.newRecord != -1) {
                if (row.newRecord != row.oldRecord) { 
                    newRecord = table.recordManager.ImportRecord(row.Table, row.newRecord);
                }
                else
                    newRecord = oldRecord; 
            }
 
            DataRow targetRow = table.AddRecords(oldRecord, newRecord); 

            if (row.HasErrors) { 
                targetRow.RowError = row.RowError;

                DataColumn[] cols = row.GetColumnsInError();
 
                for (int i = 0; i < cols.Length; i++) {
                    DataColumn col = targetRow.Table.Columns[cols[i].ColumnName]; 
                    targetRow.SetColumnError(col, row.GetColumnError(cols[i])); 
                }
            } 

       }

 
        internal void DeleteRow(DataRow row) {
            if (row.newRecord == -1) { 
                throw ExceptionBuilder.RowAlreadyDeleted(); 
            }
 
            // Store.PrepareForDelete(row);
            SetNewRecord(row, -1, DataRowAction.Delete, false, true);
        }
 
        private void CheckPrimaryKey() {
            if (primaryKey == null) throw ExceptionBuilder.TableMissingPrimaryKey(); 
        } 

        internal DataRow FindByPrimaryKey(object[] values) { 
            CheckPrimaryKey();
            return FindRow(primaryKey.Key, values);
        }
 
        internal DataRow FindByPrimaryKey(object value) {
            CheckPrimaryKey(); 
            return FindRow(primaryKey.Key, value); 
        }
 
        private DataRow FindRow(DataKey key, object[] values) {
            Index index = GetIndex(NewIndexDesc(key));
            Range range = index.FindRecords(values);
            if (range.IsNull) 
                return null;
            return recordManager[index.GetRecord(range.Min)]; 
        } 

        private DataRow FindRow(DataKey key, object value) { 
            Index index = GetIndex(NewIndexDesc(key));
            Range range = index.FindRecords(value);
            if (range.IsNull)
                return null; 
            return recordManager[index.GetRecord(range.Min)];
        } 
 
        internal string FormatSortString(IndexField[] indexDesc) {
            StringBuilder builder = new StringBuilder(); 
            foreach (IndexField field in indexDesc) {
                if (0 < builder.Length) {
                    builder.Append(", ");
                } 
                builder.Append(field.Column.ColumnName);
                if (field.IsDescending) { 
                    builder.Append(" DESC"); 
                }
            } 
            return builder.ToString();
        }

        internal void FreeRecord(ref int record) { 
            recordManager.FreeRecord(ref record);
        } 
 
        public DataTable GetChanges() {
            IntPtr hscp; 
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID);
            try {
                DataTable dtChanges = this.Clone();
                DataRow row = null; 

                for (int i = 0; i < Rows.Count; i++) { 
                    row = Rows[i]; 
                    if (row.oldRecord != row.newRecord)
                        dtChanges.ImportRow(row); 
                }

                if (dtChanges.Rows.Count == 0)
                    return null; 

                return dtChanges; 
            } 
            finally {
                Bid.ScopeLeave(ref hscp); 
            }
        }

        public DataTable GetChanges(DataRowState rowStates) 
        {
            IntPtr hscp; 
            Bid.ScopeEnter(out hscp, " %d#, rowStates=%d{ds.DataRowState}\n", ObjectID, (int)rowStates); 
            try {
                DataTable dtChanges = this.Clone(); 
                DataRow row = null;

                // check that rowStates is valid DataRowState
                Debug.Assert(Enum.GetUnderlyingType(typeof(DataRowState)) == typeof(Int32), "Invalid DataRowState type"); 

                for (int i = 0; i < Rows.Count; i++) { 
                    row = Rows[i]; 
                    if ((row.RowState & rowStates) != 0)
                        dtChanges.ImportRow(row); 
                }

                if (dtChanges.Rows.Count == 0)
                    return null; 

                return dtChanges; 
            } 
            finally {
                Bid.ScopeLeave(ref hscp); 
            }
        }

        ///  
        /// Returns an array of  objects that contain errors.
        ///  
        public DataRow[] GetErrors() { 
            List errorList = new List();
 
            for (int i = 0; i < Rows.Count; i++) {
                DataRow row = Rows[i];
                if (row.HasErrors) {
                    errorList.Add(row); 
                }
            } 
            DataRow[] temp = NewRowArray(errorList.Count); 
            errorList.CopyTo(temp);
            return temp; 
        }

        internal Index GetIndex(IndexField[] indexDesc) {
            return GetIndex(indexDesc, DataViewRowState.CurrentRows, (IFilter)null); 
        }
 
        internal Index GetIndex(string sort, DataViewRowState recordStates, IFilter rowFilter) { 
            return GetIndex(ParseSortString(sort), recordStates, rowFilter);
        } 

        internal Index GetIndex(IndexField[] indexDesc, DataViewRowState recordStates, IFilter rowFilter) {
            indexesLock.AcquireReaderLock(-1);
            try { 
                for (int i = 0; i < indexes.Count; i++) {
                    Index index = indexes[i]; 
                    if (index != null) { 
                        if (index.Equal(indexDesc, recordStates, rowFilter)) {
                            return index; 
                        }
                    }
                }
            } 
            finally {
                indexesLock.ReleaseReaderLock(); 
            } 
            Index ndx = new Index(this, indexDesc, recordStates, rowFilter);
            ndx.AddRef(); 
            return ndx;
        }

        IList System.ComponentModel.IListSource.GetList() { 
            return DefaultView;
        } 
 

        internal List GetListeners() { 
            return _dataViewListeners;
        }

        // We need a HashCodeProvider for Case, Kana and Width insensitive 
        internal int GetSpecialHashCode(string name) {
            int i; 
            for (i = 0; (i < name.Length) && (0x3000 > name[i]); ++i); 

            if (name.Length == i) { 
                if (null == _hashCodeProvider) {
                    // it should use the CaseSensitive property, but V1 shipped this way
                    _hashCodeProvider = StringComparer.Create(Locale, true);
                } 
                return _hashCodeProvider.GetHashCode(name);
            } 
            else { 
                return 0;
            } 
        }

        public void ImportRow(DataRow row)
        { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); 
            try { 
                int oldRecord = -1, newRecord = -1;
 
                if (row == null)
                    return;

                if (row.oldRecord != -1) { 
                    oldRecord = recordManager.ImportRecord(row.Table, row.oldRecord);
                } 
                if (row.newRecord != -1) {  // row not deleted 
                    if (row.RowState != DataRowState.Unchanged) { // not unchanged, it means Added or modified
                        newRecord = recordManager.ImportRecord(row.Table, row.newRecord); 
                    }
                    else
                        newRecord = oldRecord;
                } 

                if (oldRecord != -1 || newRecord != -1) { 
                    DataRow targetRow = AddRecords(oldRecord, newRecord); 

                    if (row.HasErrors) { 
                        targetRow.RowError = row.RowError;

                        DataColumn[] cols = row.GetColumnsInError();
 
                        for (int i = 0; i < cols.Length; i++) {
                            DataColumn col = targetRow.Table.Columns[cols[i].ColumnName]; 
                            targetRow.SetColumnError(col, row.GetColumnError(cols[i])); 
                        }
                    } 
                }
            }
            finally {
                Bid.ScopeLeave(ref hscp); 
            }
 
       } 

        internal void InsertRow(DataRow row, long proposedID) { 
            IntPtr hscp;

            Bid.ScopeEnter(out hscp, " %d#, row=%d\n", ObjectID, row.ObjectID);
            try { 
                if (row.Table != this) {
                    throw ExceptionBuilder.RowAlreadyInOtherCollection(); 
                } 
                if (row.rowID != -1) {
                    throw ExceptionBuilder.RowAlreadyInTheCollection(); 
                }
                if (row.oldRecord == -1 && row.newRecord == -1) {
                    throw ExceptionBuilder.RowEmpty();
                } 

                if (proposedID == -1) 
                    proposedID = nextRowID; 

                row.rowID = proposedID; 
                if (nextRowID <= proposedID)
                    nextRowID = checked(proposedID + 1);

                DataRowChangeEventArgs drcevent = null; 

 
                if (row.newRecord != -1) { 
                    row.tempRecord = row.newRecord;
                    row.newRecord = -1; 

                    try {
                        drcevent = RaiseRowChanging(null, row, DataRowAction.Add, true);
                    } 
                    catch {
                        row.tempRecord = -1; 
                        throw; 
                    }
 
                    row.newRecord = row.tempRecord;
                    row.tempRecord = -1;
                }
 
                if (row.oldRecord != -1)
                    recordManager[row.oldRecord] = row; 
 
                if (row.newRecord != -1)
                    recordManager[row.newRecord] = row; 

                Rows.ArrayAdd(row); // SQL BU Defect Tracking 247738, 323482 row should be in the
                                    // collection when maintaining the indexes
 
                if (row.RowState == DataRowState.Unchanged){ //  how about row.oldRecord == row.newRecord both == -1
                    RecordStateChanged(row.oldRecord, DataViewRowState.None, DataViewRowState.Unchanged); 
                } 
                else {
                    RecordStateChanged(row.oldRecord, DataViewRowState.None, row.GetRecordState(row.oldRecord), 
                                       row.newRecord, DataViewRowState.None, row.GetRecordState(row.newRecord));
                }

                if (dependentColumns != null && dependentColumns.Count > 0) 
                    EvaluateExpressions(row, DataRowAction.Add, null);
 
                RaiseRowChanged(drcevent, row, DataRowAction.Add); 
            }
            finally { 
                Bid.ScopeLeave(ref hscp);
            }
        }
 
        private IndexField [] NewIndexDesc(DataKey key) {
            Debug.Assert(key.HasValue); 
            IndexField[] indexDesc = key.GetIndexDesc(); 
            IndexField[] newIndexDesc = new IndexField[indexDesc.Length];
            Array.Copy(indexDesc, 0, newIndexDesc, 0, indexDesc.Length); 
            return newIndexDesc;
        }

        internal int NewRecord() { 
            return NewRecord(-1);
        } 
 
        internal int NewUninitializedRecord() {
            return recordManager.NewRecordBase(); 
        }

        internal int NewRecordFromArray(object[] value) {
            int colCount = columnCollection.Count; // Perf: use the readonly columnCollection field directly 
            if (colCount < value.Length) {
                throw ExceptionBuilder.ValueArrayLength(); 
            } 
            int record = recordManager.NewRecordBase();
            try { 
                for (int i = 0; i < value.Length; i++) {
                    if (null != value[i]) {
                        columnCollection[i][record] = value[i];
                    } 
                    else {
                        columnCollection[i].Init(record);  // Increase AutoIncrementCurrent 
                    } 
                }
                for (int i = value.Length; i < colCount; i++) { 
                    columnCollection[i].Init(record);
                }
                return record;
            } 
            catch (Exception e) {
                // 
                if (Common.ADP.IsCatchableOrSecurityExceptionType (e)) { 
                    FreeRecord(ref record); // WebData 104246
                } 
                throw;
            }
        }
 
        internal int NewRecord(int sourceRecord) {
            int record = recordManager.NewRecordBase(); 
 
            int count = columnCollection.Count;
            if (-1 == sourceRecord) { 
                for (int i = 0; i < count; ++i) {
                    columnCollection[i].Init(record);
                }
            } 
            else {
                for (int i = 0; i < count; ++i) { 
                    columnCollection[i].Copy(sourceRecord, record); 
                }
            } 
            return record;
        }

        internal DataRow NewEmptyRow() { 
            rowBuilder._record = -1;
            DataRow dr = NewRowFromBuilder( rowBuilder ); 
            if (dataSet != null) { 
                DataSet.OnDataRowCreated( dr );
            } 
            return dr;
        }

        private DataRow NewUninitializedRow() { 
            DataRow dr = NewRow(NewUninitializedRecord());
            return dr; 
        } 

        ///  
        /// Creates a new 
        /// with the same schema as the table.
        /// 
        public DataRow NewRow() { 
            DataRow dr = NewRow(-1);
            NewRowCreated(dr); // this is the only API we want this event to be fired 
            return dr; 
        }
 
        // Only initialize DataRelation mapping columns (approximately hidden columns)
        internal DataRow CreateEmptyRow() {
            DataRow row = this.NewUninitializedRow();
 
            foreach( DataColumn c in this.Columns ) {
                if (!XmlToDatasetMap.IsMappedColumn(c)) { 
                    if (!c.AutoIncrement) { 
                        if (c.AllowDBNull) {
                            row[c] = DBNull.Value; 
                        }
                        else if(c.DefaultValue!=null){
                            row[c] = c.DefaultValue;
                        } 
                    }
                    else { 
                        c.Init(row.tempRecord); 
                    }
                } 
            }
            return row;
        }
 
        private void NewRowCreated(DataRow row) {
            if (null != onTableNewRowDelegate) { 
                DataTableNewRowEventArgs eventArg =  new DataTableNewRowEventArgs(row); 
                OnTableNewRow(eventArg);
            } 
        }

        internal DataRow NewRow(int record) {
            if (-1 == record) { 
                record = NewRecord(-1);
            } 
 
            rowBuilder._record = record;
            DataRow row = NewRowFromBuilder( rowBuilder ); 
            recordManager[record] = row;

            if (dataSet != null)
                DataSet.OnDataRowCreated( row ); 

            return row; 
        } 

        // This is what a subclassed dataSet overrides to create a new row. 
        protected virtual DataRow NewRowFromBuilder(DataRowBuilder builder) {
            return new DataRow(builder);
        }
 
        /// 
        ///    Gets the row type. 
        ///  
        protected virtual Type GetRowType() {
            return typeof(DataRow); 
        }

        protected internal DataRow[] NewRowArray(int size) {
            if (IsTypedDataTable) { 
                if (0 == size) {
                    if (null == EmptyDataRowArray) { 
                        EmptyDataRowArray = (DataRow[]) Array.CreateInstance(GetRowType(), 0); 
                    }
                    return EmptyDataRowArray; 
                }
                return (DataRow[]) Array.CreateInstance(GetRowType(), size);
            }
            else { 
                return ((0 == size) ? DataTable.zeroRows : new DataRow[size]);
            } 
        } 

        internal bool NeedColumnChangeEvents { 
            get {
                return (IsTypedDataTable || (null != onColumnChangingDelegate) || (null != onColumnChangedDelegate));
            }
        } 

        protected internal virtual void OnColumnChanging(DataColumnChangeEventArgs e) { 
            // intentionally allow exceptions to bubble up.  We haven't committed anything yet. 
            Debug.Assert(e != null, "e should not be null");
            if (onColumnChangingDelegate != null) { 
                Bid.Trace(" %d#\n", ObjectID);
                onColumnChangingDelegate(this, e);
            }
        } 

        protected internal virtual void OnColumnChanged(DataColumnChangeEventArgs e) { 
            Debug.Assert(e != null, "e should not be null"); 
            if (onColumnChangedDelegate != null) {
                Bid.Trace(" %d#\n", ObjectID); 
                onColumnChangedDelegate(this, e);
            }
        }
 
        protected virtual void OnPropertyChanging(PropertyChangedEventArgs pcevent) {
            if (onPropertyChangingDelegate != null) { 
                Bid.Trace(" %d#\n", ObjectID); 
                onPropertyChangingDelegate(this, pcevent);
            } 
        }

        internal void OnRemoveColumnInternal(DataColumn column) {
            OnRemoveColumn(column); 
        }
 
        ///  
        /// Notifies the  that a  is
        ///    being removed. 
        /// 
        protected virtual void OnRemoveColumn(DataColumn column) {
        }
 
        private DataRowChangeEventArgs OnRowChanged(DataRowChangeEventArgs args, DataRow eRow, DataRowAction eAction) {
            if ((null != onRowChangedDelegate) || IsTypedDataTable) { 
                if (null == args) { 
                    args = new DataRowChangeEventArgs(eRow, eAction);
                } 
                OnRowChanged(args);
            }
            return args;
        } 

        private DataRowChangeEventArgs OnRowChanging(DataRowChangeEventArgs args, DataRow eRow, DataRowAction eAction) { 
            if ((null != onRowChangingDelegate) || IsTypedDataTable) { 
                if (null == args) {
                    args = new DataRowChangeEventArgs(eRow, eAction); 
                }
                OnRowChanging(args);
            }
            return args; 
        }
 
        ///  
        ///    
        ///       Raises the  event. 
        ///    
        /// 
        protected virtual void OnRowChanged(DataRowChangeEventArgs e) {
            Debug.Assert((null != e) && ((null != onRowChangedDelegate) || IsTypedDataTable), "OnRowChanged arguments"); 
            if (onRowChangedDelegate != null) {
                Bid.Trace(" %d#\n", ObjectID); 
                onRowChangedDelegate(this, e); 
            }
        } 

        /// 
        ///    
        ///       Raises the  event. 
        ///    
        ///  
        protected virtual void OnRowChanging(DataRowChangeEventArgs e) { 
            Debug.Assert((null != e) && ((null != onRowChangingDelegate) || IsTypedDataTable), "OnRowChanging arguments");
            if (onRowChangingDelegate != null) { 
                Bid.Trace(" %d#\n", ObjectID);
                onRowChangingDelegate(this, e);
           }
        } 

        ///  
        ///     
        ///       Raises the  event.
        ///     
        /// 
        protected virtual void OnRowDeleting(DataRowChangeEventArgs e) {
            Debug.Assert((null != e) && ((null != onRowDeletingDelegate) || IsTypedDataTable), "OnRowDeleting arguments");
            if (onRowDeletingDelegate != null) { 
                Bid.Trace(" %d#\n", ObjectID);
                onRowDeletingDelegate(this, e); 
            } 
        }
 
        /// 
        ///    
        ///       Raises the  event.
        ///     
        /// 
        protected virtual void OnRowDeleted(DataRowChangeEventArgs e) { 
            Debug.Assert((null != e) && ((null != onRowDeletedDelegate) || IsTypedDataTable), "OnRowDeleted arguments"); 
            if (onRowDeletedDelegate != null) {
                Bid.Trace(" %d#\n", ObjectID); 
                onRowDeletedDelegate(this, e);
            }
        }
 
        protected virtual void OnTableCleared(DataTableClearEventArgs e) {
            if (onTableClearedDelegate != null) { 
                Bid.Trace(" %d#\n", ObjectID); 
                onTableClearedDelegate(this, e);
            } 
        }

        protected virtual void OnTableClearing(DataTableClearEventArgs e) {
            if (onTableClearingDelegate != null) { 
                Bid.Trace(" %d#\n", ObjectID);
                onTableClearingDelegate(this, e); 
            } 
        }
 
        protected virtual void OnTableNewRow(DataTableNewRowEventArgs  e) {
            if (onTableNewRowDelegate != null) {
                Bid.Trace(" %d#\n", ObjectID);
                onTableNewRowDelegate(this, e); 
            }
        } 
 
        private void OnInitialized() {
            if (onInitialized != null) { 
                Bid.Trace(" %d#\n", ObjectID);
                onInitialized(this, EventArgs.Empty);
            }
        } 

 
        internal IndexField[] ParseSortString(string sortString) { 
            IndexField[] indexDesc = zeroIndexField;
            if ((null != sortString) && (0 < sortString.Length)) { 
                string[] split = sortString.Split(new char[] { ','});
                indexDesc = new IndexField[split.Length];

                for (int i = 0; i < split.Length; i++) { 
                    string current = split[i].Trim();
 
                    // handle ASC and DESC. 
                    int length = current.Length;
                    bool descending = false; 
                    if (length >= 5 && String.Compare(current, length - 4, " ASC", 0, 4, StringComparison.OrdinalIgnoreCase) == 0) {
                        current = current.Substring(0, length - 4).Trim();
                    }
                    else if (length >= 6 && String.Compare(current, length - 5, " DESC", 0, 5, StringComparison.OrdinalIgnoreCase) == 0) { 
                        descending = true;
                        current = current.Substring(0, length - 5).Trim(); 
                    } 

                    // handle brackets. 
                    if (current.StartsWith("[", StringComparison.Ordinal)) {
                        if (current.EndsWith("]", StringComparison.Ordinal)) {
                            current = current.Substring(1, current.Length - 2);
                        } 
                        else {
                            throw ExceptionBuilder.InvalidSortString(split[i]); 
                        } 
                    }
 
                    // find the column.
                    DataColumn column = Columns[current];
                    if(column == null) {
                        throw ExceptionBuilder.ColumnOutOfRange(current); 
                    }
                    indexDesc[i] = new IndexField(column, descending); 
                } 
            }
            return indexDesc; 
        }

        internal void RaisePropertyChanging(string name) {
            OnPropertyChanging(new PropertyChangedEventArgs(name)); 
        }
 
        // Notify all indexes that record changed. 
        // Only called when Error was changed.
        internal void RecordChanged(int record) { 
            Debug.Assert (record != -1, "Record number must be given");
            SetShadowIndexes(); // how about new assert?
            try {
                int numIndexes = shadowIndexes.Count; 
                for (int i = 0; i < numIndexes; i++) {
                    Index ndx = shadowIndexes[i];// shadowindexes may change, see ShadowIndexCopy() 
                    if (0 < ndx.RefCount) { 
                        ndx.RecordChanged(record);
                    } 
                }
            }
            finally{
                RestoreShadowIndexes(); 
            }
        } 
 
// for each index in liveindexes invok RecordChanged
// oldIndex and newIndex keeps  position of record before delete and after insert in each index in order 
// LiveIndexes[n-m] will have its information in oldIndex[n-m] and  newIndex[n-m]
        internal void RecordChanged(int[] oldIndex, int[] newIndex) {
            SetShadowIndexes();
            Debug.Assert (oldIndex.Length == newIndex.Length,  "Size oldIndexes and newIndexes should be the same"); 
            Debug.Assert (oldIndex.Length == shadowIndexes.Count, "Size of OldIndexes should be the same as size of Live indexes");
            try{ 
                int numIndexes = shadowIndexes.Count; 
                for (int i = 0; i < numIndexes; i++) {
                    Index ndx = shadowIndexes[i];// shadowindexes may change, see ShadowIndexCopy() 
                    if (0 < ndx.RefCount) {
                        ndx.RecordChanged(oldIndex[i], newIndex[i]);
                    }
                } 

            } 
            finally{ 
                RestoreShadowIndexes();
            } 
        }

        internal void RecordStateChanged(int record, DataViewRowState oldState, DataViewRowState newState) {
            SetShadowIndexes(); 
            try{
                int numIndexes = shadowIndexes.Count; 
                for (int i = 0; i < numIndexes; i++) { 
                    Index ndx = shadowIndexes[i];// shadowindexes may change, see ShadowIndexCopy()
                    if (0 < ndx.RefCount) { 
                        ndx.RecordStateChanged(record, oldState, newState);
                    }
                }
            } 
            finally{
                RestoreShadowIndexes(); 
            } 
            // System.Data.XML.Store.Store.OnROMChanged(record, oldState, newState);
        } 


        internal void RecordStateChanged(int record1, DataViewRowState oldState1, DataViewRowState newState1,
                                         int record2, DataViewRowState oldState2, DataViewRowState newState2) { 
            SetShadowIndexes();
            try{ 
                int numIndexes = shadowIndexes.Count; 
                for (int i = 0; i < numIndexes; i++) {
                    Index ndx = shadowIndexes[i];// shadowindexes may change, see ShadowIndexCopy() 
                    if (0 < ndx.RefCount) {
                        if (record1 != -1 && record2 != -1)
                            ndx.RecordStateChanged(record1, oldState1, newState1,
                                                   record2, oldState2, newState2); 
                        else if (record1 != -1)
                            ndx.RecordStateChanged(record1, oldState1, newState1); 
                        else if (record2 != -1) 
                            ndx.RecordStateChanged(record2, oldState2, newState2);
                    } 
                }
            }
            finally {
                RestoreShadowIndexes(); 
            }
            // System.Data.XML.Store.Store.OnROMChanged(record1, oldState1, newState1, record2, oldState2, newState2); 
        } 

 
// RemoveRecordFromIndexes removes the given record (using row and version) from all indexes and it  stores and returns the position of deleted
// record from each index
// IT SHOULD NOT CAUSE ANY EVENT TO BE FIRED
        internal int[] RemoveRecordFromIndexes(DataRow row, DataRowVersion  version) { 
            int    indexCount          =  LiveIndexes.Count;
            int [] positionIndexes =  new int[indexCount]; 
 
            int recordNo = row.GetRecordFromVersion(version);
            DataViewRowState states = row.GetRecordState(recordNo); 

            while (--indexCount >= 0) {
                if (row.HasVersion(version) && ((states & indexes[indexCount].RecordStates) != DataViewRowState.None)) {
                    int index = indexes[indexCount].GetIndex(recordNo); 
                    if (index > -1) {
                        positionIndexes [indexCount] = index; 
                        indexes[indexCount].DeleteRecordFromIndex(index); // this will delete the record from index and MUSt not fire event 
                    }
                    else { 
                        positionIndexes [indexCount] = -1; // this means record was not in index
                    }
                }
                else { 
                    positionIndexes [indexCount] = -1; // this means record was not in index
                } 
            } 
            return positionIndexes;
        } 

// InsertRecordToIndexes inserts the given record (using row and version) to all indexes and it  stores and returns the position of inserted
// record to each index
// IT SHOULD NOT CAUSE ANY EVENT TO BE FIRED 
        internal int[] InsertRecordToIndexes(DataRow row, DataRowVersion  version) {
            int    indexCount          =  LiveIndexes.Count; 
            int [] positionIndexes =  new int[indexCount]; 

            int recordNo = row.GetRecordFromVersion(version); 
            DataViewRowState states = row.GetRecordState(recordNo);

            while (--indexCount >= 0) {
                if (row.HasVersion(version)) { 
                    if ((states & indexes[indexCount].RecordStates) != DataViewRowState.None) {
                        positionIndexes [indexCount] = indexes[indexCount].InsertRecordToIndex(recordNo); 
                    } 
                    else {
                        positionIndexes [indexCount] = -1; 
                    }
                }
            }
            return positionIndexes; 
        }
 
        internal void SilentlySetValue(DataRow dr, DataColumn dc, DataRowVersion version, object newValue) { 
            // get record for version
            int record = dr.GetRecordFromVersion(version); 

            bool equalValues = false;
            if (DataStorage.IsTypeCustomType(dc.DataType) && newValue != dc[record]) {
                // if UDT storage, need to check if reference changed. See bug 385182 
                equalValues = false;
            } 
            else { 
                equalValues = dc.CompareValueTo(record, newValue, true);
            } 

            // if expression has changed
            if (!equalValues) {
                int[] oldIndex = dr.Table.RemoveRecordFromIndexes(dr, version);// conditional, if it exists it will try to remove with no event fired 
                dc.SetValue(record, newValue);
                int[] newIndex = dr.Table.InsertRecordToIndexes(dr, version);// conditional, it will insert if it qualifies, no event will be fired 
                if (dr.HasVersion(version)) { 
                    if (version != DataRowVersion.Original) {
                        dr.Table.RecordChanged(oldIndex, newIndex); 
                    }
                    if (dc.dependentColumns != null) {
                        //BugBug - passing in null for cachedRows.  This means expression columns as keys does not work when key changes.
                        dc.Table.EvaluateDependentExpressions(dc.dependentColumns, dr, version, null); 
                    }
                } 
             } 
             dr.ResetLastChangedColumn();
        } 

        /// 
        ///    Rolls back all changes that have been made to the table
        ///       since it was loaded, or the last time  was called. 
        /// 
        public void RejectChanges() { 
            IntPtr hscp; 
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID);
            try{ 
                DataRow[] oldRows = new DataRow[Rows.Count];
                Rows.CopyTo(oldRows, 0);

                for (int i = 0; i < oldRows.Length; i++) { 
                    RollbackRow(oldRows[i]);
                } 
            } 
            finally{
                Bid.ScopeLeave(ref hscp); 
            }

        }
 
        internal void RemoveRow(DataRow row, bool check) {
            if (row.rowID == -1) { 
                throw ExceptionBuilder.RowAlreadyRemoved(); 
            }
 
            if (check && dataSet != null) {
                for (ParentForeignKeyConstraintEnumerator constraints = new ParentForeignKeyConstraintEnumerator(dataSet, this); constraints.GetNext();) {
                    constraints.GetForeignKeyConstraint().CheckCanRemoveParentRow(row);
                } 
            }
 
            int oldRecord = row.oldRecord; 
            int newRecord = row.newRecord;
 
            DataViewRowState oldRecordStatePre = row.GetRecordState(oldRecord);
            DataViewRowState newRecordStatePre = row.GetRecordState(newRecord);

            row.oldRecord = -1; 
            row.newRecord = -1;
 
            if (oldRecord == newRecord) { 
                oldRecord = -1;
            } 

            RecordStateChanged(oldRecord, oldRecordStatePre, DataViewRowState.None,
                               newRecord, newRecordStatePre, DataViewRowState.None);
 
            FreeRecord(ref oldRecord);
            FreeRecord(ref newRecord); 
 
            row.rowID = -1;
            Rows.ArrayRemove(row); 
        }

        // Resets the table back to its original state.
        public virtual void Reset() { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); 
            try { 
                Clear();
                ResetConstraints(); 

                DataRelationCollection dr = this.ParentRelations;
                int count = dr.Count;
                  while (count > 0) { 
                   count--;
                   dr.RemoveAt(count); 
                } 

                dr = this.ChildRelations; 
                count = dr.Count;
                  while (count > 0) {
                   count--;
                   dr.RemoveAt(count); 
                }
 
                Columns.Clear(); 
                indexes.Clear();
            } 
            finally{
                Bid.ScopeLeave(ref hscp);
            }
        } 

        internal void ResetIndexes() { 
            ResetInternalIndexes(null); 
        }
 
        internal void ResetInternalIndexes(DataColumn column) {
            Debug.Assert(null != indexes, "unexpected null indexes");
            SetShadowIndexes();
            try{ 
                // the length of shadowIndexes will not change
                // but the array instance may change during 
                // events during Index.Reset 
                int numIndexes = shadowIndexes.Count;
                for (int i = 0; i < numIndexes; i++) { 
                    Index ndx = shadowIndexes[i];// shadowindexes may change, see ShadowIndexCopy()
                    if (0 < ndx.RefCount) {
                        if (null == column) {
                            ndx.Reset(); 
                        }
                        else { 
                            // SQLBU 501916: DataTable internal index is corrupted:'5' 
                            bool found = false;
                            foreach(IndexField field in ndx.IndexFields) { 
                                if (Object.ReferenceEquals(column, field.Column)) {
                                    found = true;
                                    break;
 
                                }
                            } 
                            if (found) { 
                                ndx.Reset();
                            } 
                        }
                    }
                }
            } 
            finally {
                RestoreShadowIndexes(); 
            } 
        }
 
        internal void RollbackRow(DataRow row) {
            row.CancelEdit();
            SetNewRecord(row, row.oldRecord, DataRowAction.Rollback, false, true);
        } 

        private DataRowChangeEventArgs RaiseRowChanged(DataRowChangeEventArgs args, DataRow eRow, DataRowAction eAction) { 
            try { 
                if (UpdatingCurrent(eRow, eAction) && (IsTypedDataTable || (null != onRowChangedDelegate))) {
                    args = OnRowChanged(args, eRow, eAction); 
                }
                // check if we deleting good row
                else if (DataRowAction.Delete == eAction && eRow.newRecord == -1 && (IsTypedDataTable || (null != onRowDeletedDelegate))) {
                    if (null == args) { 
                        args = new DataRowChangeEventArgs(eRow, eAction);
                    } 
                    OnRowDeleted(args); 
                }
            } 
            catch (Exception f) {
               //
               if (!Common.ADP.IsCatchableExceptionType(f)) {
                 throw; 
               }
               ExceptionBuilder.TraceExceptionWithoutRethrow(f); 
               // ignore the exception 
            }
            return args; 
        }

        private DataRowChangeEventArgs RaiseRowChanging(DataRowChangeEventArgs args, DataRow eRow, DataRowAction eAction) {
            if (UpdatingCurrent(eRow, eAction) && (IsTypedDataTable || (null != onRowChangingDelegate))) { 
                eRow.inChangingEvent = true;
 
                // don't catch 
                try {
                    args = OnRowChanging(args, eRow, eAction); 
                }
                finally {
                    eRow.inChangingEvent = false;
                } 
            }
            // check if we deleting good row 
            else if (DataRowAction.Delete == eAction && eRow.newRecord != -1 && (IsTypedDataTable || (null != onRowDeletingDelegate))) { 
                eRow.inDeletingEvent = true;
                // don't catch 
                try {
                    if (null == args) {
                        args = new DataRowChangeEventArgs(eRow, eAction);
                    } 
                    OnRowDeleting(args);
                } 
                finally { 
                    eRow.inDeletingEvent = false;
                } 
            }
            return args;
        }
 
        private DataRowChangeEventArgs RaiseRowChanging(DataRowChangeEventArgs args, DataRow eRow, DataRowAction eAction, bool fireEvent) {
 
            // check all constraints 
            if (EnforceConstraints && !inLoad ) {
                int columnCount = columnCollection.Count; 
                for(int i = 0; i < columnCount; ++i) {
                    DataColumn column = columnCollection[i];
                    if (!column.Computed || eAction != DataRowAction.Add) {
                        column.CheckColumnConstraint(eRow, eAction); 
                    }
                } 
 
                int constraintCount = constraintCollection.Count;
                for(int i = 0; i < constraintCount; ++i) { 
                    constraintCollection[i].CheckConstraint(eRow, eAction);
                }
            }
 
            // $$anandra.  Check this event out. May be an issue.
            if (fireEvent) { 
                args = RaiseRowChanging(args, eRow, eAction); 
            }
 
            if (!inDataLoad) {
                // cascade things...
                if (!MergingData && eAction != DataRowAction.Nothing && eAction != DataRowAction.ChangeOriginal) {
                    CascadeAll(eRow, eAction); 
                }
            } 
            return args; 
        }
 
        /// 
        /// Returns an array of all  objects.
        /// 
        public DataRow[] Select() { 
            Bid.Trace(" %d#\n", ObjectID);
            return new Select(this, "", "", DataViewRowState.CurrentRows).SelectRows(); 
        } 

        ///  
        /// Returns an array of all  objects that match the filter criteria in order of
        ///    primary key (or lacking one, order of addition.)
        /// 
        public DataRow[] Select(string filterExpression) { 
            Bid.Trace(" %d#, filterExpression='%ls'\n", ObjectID, filterExpression);
            return new Select(this, filterExpression, "", DataViewRowState.CurrentRows).SelectRows(); 
        } 

        ///  
        /// Returns an array of all  objects that match the filter criteria, in the the
        ///    specified sort order.
        /// 
        public DataRow[] Select(string filterExpression, string sort) { 
            Bid.Trace(" %d#, filterExpression='%ls', sort='%ls'\n", ObjectID, filterExpression, sort);
            return new Select(this, filterExpression, sort, DataViewRowState.CurrentRows).SelectRows(); 
        } 

        ///  
        /// Returns an array of all  objects that match the filter in the order of the
        ///    sort, that match the specified state.
        /// 
        public DataRow[] Select(string filterExpression, string sort, DataViewRowState recordStates) { 
            Bid.Trace(" %d#, filterExpression='%ls', sort='%ls', recordStates=%d{ds.DataViewRowState}\n", ObjectID, filterExpression, sort, (int)recordStates);
            return new Select(this, filterExpression, sort, recordStates).SelectRows(); 
        } 

        internal void SetNewRecord(DataRow row, int proposedRecord, DataRowAction action = DataRowAction.Change, bool isInMerge = false, bool fireEvent = true, bool suppressEnsurePropertyChanged = false) { 
            Exception deferredException = null;
            SetNewRecordWorker(row, proposedRecord, action, isInMerge, suppressEnsurePropertyChanged, -1, fireEvent, out deferredException); // we are going to call below overload from insert
            if (deferredException != null) {
                throw deferredException; 
            }
        } 
 
        private void SetNewRecordWorker(DataRow row, int proposedRecord, DataRowAction action, bool isInMerge, bool suppressEnsurePropertyChanged,
            int position, bool fireEvent, out Exception deferredException) { 

            // this is the event workhorse... it will throw the changing/changed events
            // and update the indexes. Used by change, add, delete, revert.
 
            // order of execution is as follows
            // 
            // 1) set temp record 
            // 2) Check constraints for non-expression columns
            // 3) Raise RowChanging/RowDeleting with temp record 
            // 4) set the new record in storage
            // 5) Update indexes with recordStateChanges - this will fire ListChanged & PropertyChanged events on associated views
            // 6) Evaluate all Expressions (exceptions are deferred)- this will fire ListChanged & PropertyChanged events on associated views
            // 7) Raise RowChanged/ RowDeleted 
            // 8) Check constraints for expression columns
 
            Debug.Assert(row != null, "Row can't be null."); 
            deferredException = null;
 
            if (row.tempRecord != proposedRecord) {
                // $HACK: for performance reasons, EndUpdate calls SetNewRecord with tempRecord == proposedRecord
                if (!inDataLoad) {
                    row.CheckInTable(); 
                    CheckNotModifying(row);
                } 
                if (proposedRecord == row.newRecord) { 
                    if (isInMerge) {
                        Debug.Assert(fireEvent, "SetNewRecord is called with wrong parameter"); 
                        RaiseRowChanged(null, row, action);
                    }
                    return;
                } 

                Debug.Assert(!row.inChangingEvent, "How can this row be in an infinite loop?"); 
 
                row.tempRecord = proposedRecord;
            } 
            DataRowChangeEventArgs drcevent = null;

            try {
                row._action = action; 
                drcevent = RaiseRowChanging(null, row, action, fireEvent);
            } 
            catch { 
                row.tempRecord = -1;
                throw; 
            }
            finally {
                row._action = DataRowAction.Nothing;
            } 

            row.tempRecord = -1; 
 
            int currentRecord = row.newRecord;
 
            // if we're deleting, then the oldRecord value will change, so need to track that if it's distinct from the newRecord.
            int secondRecord = (proposedRecord != -1 ?
                                proposedRecord :
                                (row.RowState != DataRowState.Unchanged ? 
                                 row.oldRecord :
                                 -1)); 
 
            if (action == DataRowAction.Add) { //if we come here from insert we do insert the row to collection
                if (position == -1) 
                    Rows.ArrayAdd(row);
                else
                    Rows.ArrayInsert(row, position);
            } 

            List cachedRows = null; 
            if ((action == DataRowAction.Delete || action == DataRowAction.Change) 
                && dependentColumns != null && dependentColumns.Count > 0) {
                // if there are expression columns, need to cache related rows for deletes and updates (key changes) 
                // before indexes are modified.
                cachedRows = new List();
                for (int j = 0; j < ParentRelations.Count; j++) {
                    DataRelation relation = ParentRelations[j]; 
                    if (relation.ChildTable != row.Table) {
                        continue; 
                    } 
                    cachedRows.InsertRange(cachedRows.Count, row.GetParentRows(relation));
                } 

                for (int j = 0; j < ChildRelations.Count; j++) {
                    DataRelation relation = ChildRelations[j];
                    if (relation.ParentTable != row.Table) { 
                        continue;
                    } 
                    cachedRows.InsertRange(cachedRows.Count, row.GetChildRows(relation)); 
                }
            } 

            // Dev10 Bug 688779: DataRowView.PropertyChanged are not raised on RejectChanges
            // if the newRecord is changing, the propertychanged event should be allowed to triggered for ListChangedType.Changed or .Moved
            // unless the specific condition is known that no data has changed, like DataRow.SetModified() 
            if (!suppressEnsurePropertyChanged && !row.HasPropertyChanged && (row.newRecord != proposedRecord)
                && (-1 != proposedRecord) // explictly not fixing Dev10 Bug 692044: DataRowView.PropertyChanged are not raised on DataTable.Delete when mixing current and original records in RowStateFilter 
                && (-1 != row.newRecord)) // explictly not fixing parts of Dev10 Bug 697909: when mixing current and original records in RowStateFilter 
            {
                // DataRow will believe multiple edits occured and 
                // DataView.ListChanged event w/ ListChangedType.ItemChanged will raise DataRowView.PropertyChanged event and
                // PropertyChangedEventArgs.PropertyName will now be empty string so
                // WPF will refresh the entire row
                row.LastChangedColumn = null; 
                row.LastChangedColumn = null;
            } 
 
                // Check whether we need to update indexes
                if (LiveIndexes.Count != 0) { 

                    // Dev10 bug #463087: DataTable internal index is currupted: '5'
                    if ((-1 == currentRecord) && (-1 != proposedRecord) && (-1 != row.oldRecord) && (proposedRecord != row.oldRecord)) {
                        // the transition from DataRowState.Deleted -> DataRowState.Modified 
                        // with same orginal record but new current record
                        // needs to raise an ItemChanged or ItemMoved instead of ItemAdded in the ListChanged event. 
                        // for indexes/views listening for both DataViewRowState.Deleted | DataViewRowState.ModifiedCurrent 
                        currentRecord = row.oldRecord;
                    } 

                    DataViewRowState currentRecordStatePre = row.GetRecordState(currentRecord);
                    DataViewRowState secondRecordStatePre = row.GetRecordState(secondRecord);
 
                    row.newRecord = proposedRecord;
                    if (proposedRecord != -1) 
                        this.recordManager[proposedRecord] = row; 

                    DataViewRowState currentRecordStatePost = row.GetRecordState(currentRecord); 
                    DataViewRowState secondRecordStatePost = row.GetRecordState(secondRecord);

                    // may raise DataView.ListChanged event
                    RecordStateChanged(currentRecord, currentRecordStatePre, currentRecordStatePost, 
                        secondRecord, secondRecordStatePre, secondRecordStatePost);
                } 
                else { 
                    row.newRecord = proposedRecord;
                    if (proposedRecord != -1) 
                        this.recordManager[proposedRecord] = row;
                }

                // Dev10 Bug 461199 - reset the last changed column here, after all 
                // DataViews have raised their DataRowView.PropertyChanged event
                row.ResetLastChangedColumn(); 
 
                // SQLBU 278737: Record manager corruption when reentrant write operations
                // free the 'currentRecord' only after all the indexes have been updated. 
                // Corruption! { if (currentRecord != row.oldRecord) { FreeRecord(ref currentRecord); } }
                // RecordStateChanged raises ListChanged event at which time user may do work
                if (-1 != currentRecord) {
                    if (currentRecord != row.oldRecord) 
                    {
                        if ((currentRecord != row.tempRecord) &&   // Delete, AcceptChanges, BeginEdit 
                            (currentRecord != row.newRecord) &&    // RejectChanges & SetAdded 
                            (row == recordManager[currentRecord])) // AcceptChanges, NewRow
                        { 
                            FreeRecord(ref currentRecord);
                        }
                    }
                } 

            if (row.RowState == DataRowState.Detached && row.rowID != -1) { 
                RemoveRow(row, false); 
            }
 
            if (dependentColumns != null && dependentColumns.Count > 0) {
                try {
                    EvaluateExpressions(row, action, cachedRows);
                } 
                catch (Exception exc) {
                    // For DataRows being added, throwing of exception from expression evaluation is 
                    // deferred until after the row has been completely added. 
                    if (action != DataRowAction.Add) {
                        throw exc; 
                    }
                    else {
                        deferredException = exc;
                    } 
                }
            } 
 
            try {
                if (fireEvent) { 
                    RaiseRowChanged(drcevent, row, action);
                }
            }
            catch (Exception e) { 
                //
                if (!Common.ADP.IsCatchableExceptionType(e)) { 
                    throw; 
                }
                ExceptionBuilder.TraceExceptionWithoutRethrow(e); 
                // ignore the exception
            }
        }
 
        // this is the event workhorse... it will throw the changing/changed events
        // and update the indexes. 
        internal void SetOldRecord(DataRow row, int proposedRecord) { 
            if (!inDataLoad) {
                row.CheckInTable(); 
                CheckNotModifying(row);
            }

            if (proposedRecord == row.oldRecord) { 
                return;
            } 
 
            int originalRecord = row.oldRecord; // cache old record after potential RowChanging event
            try { 
                // Check whether we need to update indexes
                if (LiveIndexes.Count != 0) {

                    // Dev10 bug #463087: DataTable internal index is currupted: '5' 
                    if ((-1 == originalRecord) && (-1 != proposedRecord) && (-1 != row.newRecord) && (proposedRecord != row.newRecord)) {
                        // the transition from DataRowState.Added -> DataRowState.Modified 
                        // with same current record but new original record 
                        // needs to raise an ItemChanged or ItemMoved instead of ItemAdded in the ListChanged event.
                        // for indexes/views listening for both DataViewRowState.Added | DataViewRowState.ModifiedOriginal 
                        originalRecord = row.newRecord;
                    }

                    DataViewRowState originalRecordStatePre = row.GetRecordState(originalRecord); 
                    DataViewRowState proposedRecordStatePre = row.GetRecordState(proposedRecord);
 
                    row.oldRecord = proposedRecord; 
                    if (proposedRecord != -1)
                        this.recordManager[proposedRecord] = row; 

                    DataViewRowState originalRecordStatePost = row.GetRecordState(originalRecord);
                    DataViewRowState proposedRecordStatePost = row.GetRecordState(proposedRecord);
 
                    RecordStateChanged(originalRecord, originalRecordStatePre, originalRecordStatePost,
                                       proposedRecord, proposedRecordStatePre, proposedRecordStatePost); 
                } 
                else {
                    row.oldRecord = proposedRecord; 
                    if (proposedRecord != -1)
                        this.recordManager[proposedRecord] = row;
                }
            } 
            finally {
                if ((originalRecord != -1) && (originalRecord != row.tempRecord) && 
                    (originalRecord != row.oldRecord) && (originalRecord != row.newRecord)) { 

                    FreeRecord(ref originalRecord); 
                }
                // else during an event 'row.AcceptChanges(); row.BeginEdit(); row.EndEdit();'

                if (row.RowState == DataRowState.Detached && row.rowID != -1) { 
                    RemoveRow(row, false);
                } 
            } 
        }
 
        private void RestoreShadowIndexes() {
            Debug.Assert(1 <= shadowCount, "unexpected negative shadow count");
            shadowCount--;
            if (0 == shadowCount) { 
                shadowIndexes = null;
            } 
        } 

        private void SetShadowIndexes() { 
            if (null == shadowIndexes) {
                Debug.Assert(0 == shadowCount, "unexpected count");
                shadowIndexes = LiveIndexes;
                shadowCount = 1; 
            }
            else { 
                Debug.Assert(1 <= shadowCount, "unexpected negative shadow count"); 
                shadowCount++;
            } 
        }

        internal void ShadowIndexCopy(){
            if (shadowIndexes == indexes) { 
                Debug.Assert(0 < indexes.Count, "unexpected");
                shadowIndexes = new List(indexes); 
            } 
        }
 
        /// 
        /// Returns the  and , if there is one as a concatenated string.
        /// 
        public override string ToString() { 
            if (this.displayExpression == null)
                return this.TableName; 
            else 
                return this.TableName + " + " + this.DisplayExpressionInternal;
        } 

        /// 
        ///    [To be supplied.]
        ///  
        public void BeginLoadData() {
            IntPtr hscp; 
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); 
            try {
                if (inDataLoad) 
                    return;

                inDataLoad = true;
                Debug.Assert(null == loadIndex, "loadIndex should already be null"); 
                loadIndex  = null;
                // LoadDataRow may have been called before BeginLoadData and already 
                // initialized loadIndexwithOriginalAdded & loadIndexwithCurrentDeleted 

                initialLoad = (Rows.Count == 0); 
                if(initialLoad) {
                    SuspendIndexEvents();
                } else {
                    if (primaryKey != null) { 
                        loadIndex = primaryKey.Key.GetSortIndex(DataViewRowState.OriginalRows);
                    } 
                    if(loadIndex != null) { 
                        loadIndex.AddRef();
                    } 
                }

                if (DataSet != null) {
                    savedEnforceConstraints = DataSet.EnforceConstraints; 
                    DataSet.EnforceConstraints = false;
                } 
                else { 
                    this.EnforceConstraints = false;
                } 
            }
            finally{
                Bid.ScopeLeave(ref hscp);
            } 
        }
 
        ///  
        ///    [To be supplied.]
        ///  
        public void EndLoadData() {
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID);
            try { 
                if (!inDataLoad)
                    return; 
 
                if(loadIndex != null) {
                    loadIndex.RemoveRef(); 
                }
                if (loadIndexwithOriginalAdded  != null) {
                    loadIndexwithOriginalAdded.RemoveRef();
                } 
                if (loadIndexwithCurrentDeleted  != null) {
                    loadIndexwithCurrentDeleted.RemoveRef(); 
                } 

                loadIndex  = null; 
                loadIndexwithOriginalAdded = null;
                loadIndexwithCurrentDeleted = null;

                inDataLoad = false; 

                RestoreIndexEvents(false); 
 
                if (DataSet != null)
                    DataSet.EnforceConstraints = savedEnforceConstraints; 
                else
                    this.EnforceConstraints = true;
            }
            finally{ 
                Bid.ScopeLeave(ref hscp);
            } 
        } 

        ///  
        ///    Finds and updates a specific row. If no matching
        ///       row is found, a new row is created using the given values.
        /// 
        public DataRow LoadDataRow(object[] values, bool fAcceptChanges) { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, fAcceptChanges=%d{bool}\n", ObjectID, fAcceptChanges); 
            try { 
                DataRow row;
                if (inDataLoad) { 
                    int record = NewRecordFromArray(values);
                    if (loadIndex != null) {
                        // not expecting LiveIndexes to clear the index we use between calls to LoadDataRow
                        Debug.Assert(2 <= loadIndex.RefCount, "bad loadIndex.RefCount"); 

                        int result = loadIndex.FindRecord(record); 
                        if (result != -1) { 
                            int resultRecord = loadIndex.GetRecord(result);
                            row = recordManager[resultRecord]; 
                            Debug.Assert (row != null, "Row can't be null for index record");
                            row.CancelEdit();
                            if (row.RowState == DataRowState.Deleted)
                                SetNewRecord(row, row.oldRecord, DataRowAction.Rollback, false, true); 
                            SetNewRecord(row, record, DataRowAction.Change, false, true);
                            if (fAcceptChanges) 
                                row.AcceptChanges(); 
                            return row;
                        } 
                    }
                    row = NewRow(record);
                    AddRow(row);
                    if (fAcceptChanges) 
                        row.AcceptChanges();
                    return row; 
                } 
                else {
                    // In case, BeginDataLoad is not called yet 
                    row = UpdatingAdd(values);
                    if (fAcceptChanges)
                        row.AcceptChanges();
                    return row; 
                }
            } 
            finally{ 
                Bid.ScopeLeave(ref hscp);
            } 
        }

        /// 
        ///    Finds and updates a specific row. If no matching 
        ///       row is found, a new row is created using the given values.
        ///  
        public DataRow LoadDataRow(object[] values, LoadOption loadOption) { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, loadOption=%d{ds.LoadOption}\n", ObjectID,  (int)loadOption); 
            try {
                Index indextoUse = null;
                if (this.primaryKey != null) {
                    if (loadOption == LoadOption.Upsert) { // CurrentVersion, and Deleted 
                        if (loadIndexwithCurrentDeleted == null) {
                            loadIndexwithCurrentDeleted = this.primaryKey.Key.GetSortIndex(DataViewRowState.CurrentRows |DataViewRowState.Deleted); 
                            Debug.Assert(loadIndexwithCurrentDeleted != null, "loadIndexwithCurrentDeleted should not be null" ); 
                            if (loadIndexwithCurrentDeleted != null) {
                                loadIndexwithCurrentDeleted.AddRef(); 
                            }
                        }
                        indextoUse = loadIndexwithCurrentDeleted;
                    } 
                    else {// CurrentVersion, and Deleted : OverwriteRow, PreserveCurrentValues
                        if (loadIndexwithOriginalAdded == null) { 
                            loadIndexwithOriginalAdded  = this.primaryKey.Key.GetSortIndex(DataViewRowState.OriginalRows |DataViewRowState.Added); 
                            Debug.Assert(loadIndexwithOriginalAdded != null, "loadIndexwithOriginalAdded should not be null");
                            if (loadIndexwithOriginalAdded != null) { 
                                loadIndexwithOriginalAdded.AddRef();
                            }
                        }
                        indextoUse = loadIndexwithOriginalAdded; 
                    }
                    // not expecting LiveIndexes to clear the index we use between calls to LoadDataRow 
                    Debug.Assert(2 <= indextoUse.RefCount, "bad indextoUse.RefCount"); 
                }
                if(inDataLoad && !AreIndexEventsSuspended) { // we do not want to fire any listchanged in new Load/Fill 
                    SuspendIndexEvents();// so suspend events here(not suspended == table already has some rows initially)
                }

                DataRow dataRow = LoadRow(values, loadOption, indextoUse);// if indextoUse == null, it means we dont have PK, 
                                                                          // so LoadRow will take care of just adding the row to end
 
                return dataRow; 
            }
            finally { 
                Bid.ScopeLeave(ref hscp);
            }
        }
 
        internal DataRow UpdatingAdd(object[] values) {
            Index index = null; 
            if (this.primaryKey != null) { 
                index = this.primaryKey.Key.GetSortIndex(DataViewRowState.OriginalRows);
            } 

            if (index != null) {
                int record = NewRecordFromArray(values);
                int result = index.FindRecord(record); 
                if (result != -1) {
                    int resultRecord = index.GetRecord(result); 
                    DataRow row = this.recordManager[resultRecord]; 
                    Debug.Assert (row != null, "Row can't be null for index record");
                    row.RejectChanges(); 
                    this.SetNewRecord(row, record);
                    return row;
                }
                DataRow row2 = NewRow(record); 
                Rows.Add(row2);
                return row2; 
            } 

            return Rows.Add(values); 
        }

        internal bool UpdatingCurrent(DataRow row, DataRowAction action) {
            return(action == DataRowAction.Add || action == DataRowAction.Change || 
                   action == DataRowAction.Rollback || action == DataRowAction.ChangeOriginal ||
                   action == DataRowAction.ChangeCurrentAndOriginal); 
//                (action == DataRowAction.Rollback && row.tempRecord != -1)); 
}
 
        internal DataColumn AddUniqueKey(int position) {
            if (_colUnique != null)
                return _colUnique;
 
            // check to see if we can use already existant PrimaryKey
            DataColumn[] pkey = PrimaryKey; 
            if (pkey.Length == 1) 
                // We have one-column primary key, so we can use it in our heirarchical relation
                return pkey[0]; 

            // add Unique, but not primaryKey to the table

            string keyName = XMLSchema.GenUniqueColumnName(TableName + "_Id", this); 
            DataColumn key = new DataColumn(keyName, typeof(Int32), null, MappingType.Hidden);
            key.Prefix = tablePrefix; 
            key.AutoIncrement = true; 
            key.AllowDBNull = false;
            key.Unique = true; 

            if (position == -1)
                Columns.Add(key);
            else { // we do have a problem and Imy idea is it is bug. Ask Enzo while Code review. Why we do not set ordinal when we call AddAt? 
                for(int i = Columns.Count -1; i >= position; i--) {
                    this.Columns[i].SetOrdinalInternal(i+1); 
                } 
                Columns.AddAt(position, key);
                key.SetOrdinalInternal(position); 
            }

            if (pkey.Length == 0)
                PrimaryKey = new DataColumn[] { 
                    key
                }; 
 
            _colUnique = key;
            return _colUnique; 
        }

        internal DataColumn AddUniqueKey() {
            return AddUniqueKey(-1); 
        }
 
        internal DataColumn AddForeignKey(DataColumn parentKey) { 
            Debug.Assert(parentKey != null, "AddForeignKey: Invalid paramter.. related primary key is null");
 
            string      keyName = XMLSchema.GenUniqueColumnName(parentKey.ColumnName, this);
            DataColumn  foreignKey = new DataColumn(keyName, parentKey.DataType, null, MappingType.Hidden);
            Columns.Add(foreignKey);
 
            return foreignKey;
        } 
 
        internal void UpdatePropertyDescriptorCollectionCache() {
            propertyDescriptorCollectionCache = null; 
        }

        /// 
        ///     Retrieves an array of properties that the given component instance 
        ///     provides.  This may differ from the set of properties the class
        ///     provides.  If the component is sited, the site may add or remove 
        ///     additional properties.  The returned array of properties will be 
        ///     filtered by the given set of attributes.
        ///  
        internal PropertyDescriptorCollection GetPropertyDescriptorCollection(Attribute[] attributes) {
            if (propertyDescriptorCollectionCache == null) {
                int columnsCount   = Columns.Count;
                int relationsCount = ChildRelations.Count; 
                PropertyDescriptor[] props = new PropertyDescriptor[columnsCount + relationsCount]; {
                    for (int i = 0; i < columnsCount; i++) { 
                        props[i] = new DataColumnPropertyDescriptor(Columns[i]); 
                    }
                    for (int i = 0; i < relationsCount; i++) { 
                        props[columnsCount + i] = new DataRelationPropertyDescriptor(ChildRelations[i]);
                    }
                }
                propertyDescriptorCollectionCache = new PropertyDescriptorCollection(props); 
            }
            return propertyDescriptorCollectionCache; 
        } 

        internal XmlQualifiedName TypeName { 
            get {
                return ((typeName == null) ? XmlQualifiedName.Empty : (XmlQualifiedName)typeName);
            }
            set { 
                typeName = value;
            } 
        } 

        public void Merge(DataTable table) 
        {
            Merge(table, false, MissingSchemaAction.Add);
        }
 
        public void Merge(DataTable table, bool preserveChanges)
        { 
            Merge(table, preserveChanges, MissingSchemaAction.Add); 
        }
 
        public void Merge(DataTable table, bool preserveChanges, MissingSchemaAction missingSchemaAction)
        {
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, table=%d, preserveChanges=%d{bool}, missingSchemaAction=%d{ds.MissingSchemaAction}\n", ObjectID, (table != null) ? table.ObjectID : 0, preserveChanges, (int)missingSchemaAction); 
            try{
                if (table == null) 
                    throw ExceptionBuilder.ArgumentNull("table"); 

                switch(missingSchemaAction) { // @perfnote: Enum.IsDefined 
                case MissingSchemaAction.Add:
                case MissingSchemaAction.Ignore:
                case MissingSchemaAction.Error:
                case MissingSchemaAction.AddWithKey: 
                    Merger merger = new Merger(this, preserveChanges, missingSchemaAction);
                    merger.MergeTable(table); 
                    break; 
                default:
                    throw Common.ADP.InvalidMissingSchemaAction(missingSchemaAction); 
                }
            }
            finally{
                Bid.ScopeLeave(ref hscp); 
            }
        } 
 
        public void Load (IDataReader reader){
            Load(reader, LoadOption.PreserveChanges, null); 
        }

        public void Load (IDataReader reader, LoadOption loadOption) {
            Load(reader, loadOption, null); 
        }
 
        public virtual void Load (IDataReader reader, LoadOption loadOption, FillErrorEventHandler errorHandler){ 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, loadOption=%d{ds.LoadOption}\n", ObjectID, (int)loadOption); 
            try {
                if (this.PrimaryKey.Length == 0) {
                    DataTableReader dtReader = reader as DataTableReader;
                    if (dtReader != null && dtReader.CurrentDataTable == this) 
                        return; // if not return, it will go to infinite loop
                } 
                Common.LoadAdapter adapter = new Common.LoadAdapter(); 
                adapter.FillLoadOption = loadOption;
                adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey; 
                if (null != errorHandler) {
                    adapter.FillError += errorHandler;
                }
                adapter.FillFromReader(new DataTable[] { this }, reader, 0, 0); 

                if (!reader.IsClosed && !reader.NextResult()) { // 
                    reader.Close(); 
                }
            } 
            finally {
                Bid.ScopeLeave(ref hscp);
            }
        } 

        private DataRow LoadRow(object[] values, LoadOption loadOption, Index searchIndex) { 
            int recordNo; 
            DataRow dataRow = null;
 
            if (searchIndex != null) {
                int[] primaryKeyIndex = new int[0];
                if (this.primaryKey != null) { // I do check above for PK, but in case if someone else gives me some index unrelated to PK
                    primaryKeyIndex = new int[this.primaryKey.ColumnsReference.Length]; 
                    for(int i = 0; i < this.primaryKey.ColumnsReference.Length; i++) {
                        primaryKeyIndex[i] = this.primaryKey.ColumnsReference[i].Ordinal; 
                    } 
                }
 
                object[] keys = new object[primaryKeyIndex.Length];
                for(int i = 0; i < primaryKeyIndex.Length; i++) {
                    keys[i] = values[primaryKeyIndex[i]];
                } 

                Range result = searchIndex.FindRecords(keys); 
 
                if (!result.IsNull) {
                    int deletedRowUpsertCount = 0; 
                    for(int i = result.Min; i <= result.Max; i++) {
                        int resultRecord = searchIndex.GetRecord(i);
                        dataRow = this.recordManager[resultRecord];
                        recordNo = NewRecordFromArray(values); 

                        //SQLBU DT 33648 
                        // values array is being reused by DataAdapter, do not modify the values array 
                        for(int count = 0; count < values.Length; count++) {
                            if (null == values[count]) { 
                                columnCollection[count].Copy(resultRecord, recordNo);
                            }
                        }
                        for(int count = values.Length; count < columnCollection.Count ; count++) { 
                            columnCollection[count].Copy(resultRecord, recordNo); // if there are missing values
                        } 
 
                        if (loadOption != LoadOption.Upsert || dataRow.RowState != DataRowState.Deleted) {
                            SetDataRowWithLoadOption(dataRow , recordNo, loadOption, true); 
                        }
                        else {
                            deletedRowUpsertCount++;
                        } 
                    }
                    if (0 == deletedRowUpsertCount) { 
                        return dataRow; 
                    }
                } 
            }

            recordNo = NewRecordFromArray(values);
            dataRow = NewRow(recordNo); 
            // fire rowChanging event here
            DataRowAction action; 
            DataRowChangeEventArgs drcevent = null; 
            switch(loadOption) {
                case LoadOption.OverwriteChanges: 
                case LoadOption.PreserveChanges:
                    action = DataRowAction.ChangeCurrentAndOriginal;
                    break;
                case LoadOption.Upsert: 
                    action = DataRowAction.Add;
                    break; 
                default: 
                    throw ExceptionBuilder.ArgumentOutOfRange("LoadOption");
            } 

            drcevent = RaiseRowChanging(null, dataRow, action);

            this.InsertRow (dataRow, -1, -1, false); 
            switch(loadOption) {
                case LoadOption.OverwriteChanges: 
                case LoadOption.PreserveChanges: 
                    this.SetOldRecord(dataRow,  recordNo);
                    break; 
                case LoadOption.Upsert:
                    break;
                default:
                    throw ExceptionBuilder.ArgumentOutOfRange("LoadOption"); 
            }
            RaiseRowChanged(drcevent, dataRow, action); 
 
            return dataRow;
        } 

        private void SetDataRowWithLoadOption (DataRow dataRow, int recordNo, LoadOption loadOption, bool checkReadOnly) {
            bool hasError = false;
            if (checkReadOnly) { 
                foreach(DataColumn dc in this.Columns) {
                    if (dc.ReadOnly && !dc.Computed) { 
                        switch(loadOption) { 
                            case LoadOption.OverwriteChanges:
                                if ((dataRow[dc, DataRowVersion.Current] != dc[recordNo]) ||(dataRow[dc, DataRowVersion.Original] != dc[recordNo])) 
                                    hasError = true;
                                break;
                            case LoadOption.Upsert:
                                if (dataRow[dc, DataRowVersion.Current] != dc[recordNo]) 
                                    hasError = true;
                                break; 
                            case LoadOption.PreserveChanges: 
                                if (dataRow[dc, DataRowVersion.Original] != dc[recordNo])
                                    hasError = true; 
                                break;
                        }
                    }
                } 
            } // No Event should be fired  in SenNewRecord and SetOldRecord
            // fire rowChanging event here 
 
            DataRowChangeEventArgs drcevent = null;
            DataRowAction action = DataRowAction.Nothing; 
            int cacheTempRecord = dataRow.tempRecord;
            dataRow.tempRecord = recordNo;

            switch(loadOption) { 
                case LoadOption.OverwriteChanges:
                    action = DataRowAction.ChangeCurrentAndOriginal; 
                    break; 
                case LoadOption.Upsert:
                    switch(dataRow.RowState) { 
                        case DataRowState.Unchanged:
                            // let see if the incomming value has the same values as existing row, so compare records
                            foreach(DataColumn dc in dataRow.Table.Columns) {
                                if (0 != dc.Compare(dataRow.newRecord, recordNo)) { 
                                    action = DataRowAction.Change;
                                    break; 
                                } 
                            }
                            break; 
                        case DataRowState.Deleted:
                            Debug.Assert(false, "LoadOption.Upsert with deleted row, should not be here");
                            break;
                        default : 
                            action = DataRowAction.Change;
                            break; 
                    } 
                    break;
                case LoadOption.PreserveChanges: 
                    switch(dataRow.RowState) {
                        case DataRowState.Unchanged:
                            action = DataRowAction.ChangeCurrentAndOriginal;
                            break; 
                        default:
                            action = DataRowAction.ChangeOriginal; 
                            break; 
                    }
                    break; 
                default:
                    throw ExceptionBuilder.ArgumentOutOfRange("LoadOption");
            }
 
            try {
                drcevent = RaiseRowChanging(null, dataRow, action); 
                if (action == DataRowAction.Nothing) { // RaiseRowChanging does not fire for DataRowAction.Nothing 
                    dataRow.inChangingEvent = true;
                    try { 
                        drcevent = OnRowChanging(drcevent, dataRow, action);
                    }
                    finally {
                        dataRow.inChangingEvent = false; 
                    }
                } 
            } 
            finally {
                Debug.Assert(dataRow.tempRecord == recordNo, "tempRecord has been changed in event handler"); 
                if (DataRowState.Detached == dataRow.RowState) {
                    // 'row.Table.Remove(row);'
                    if (-1 != cacheTempRecord) {
                        FreeRecord(ref cacheTempRecord); 
                    }
                } 
                else { 
                    if (dataRow.tempRecord != recordNo) {
                        // 'row.EndEdit(); row.BeginEdit(); ' 
                        if (-1 != cacheTempRecord) {
                            FreeRecord(ref cacheTempRecord);
                        }
                        if (-1 != recordNo) { 
                            FreeRecord(ref recordNo);
                        } 
                        recordNo = dataRow.tempRecord; 
                    }
                    else { 
                        dataRow.tempRecord = cacheTempRecord;
                    }
                }
            } 
            if (dataRow.tempRecord != -1) {
                dataRow.CancelEdit(); 
            } 

            switch(loadOption) { 
                case LoadOption.OverwriteChanges:
                     this.SetNewRecord(dataRow,  recordNo, DataRowAction.Change, false, false);
                     this.SetOldRecord(dataRow,  recordNo);
                     break; 
                case LoadOption.Upsert:
                     if (dataRow.RowState == DataRowState.Unchanged) { 
                         this.SetNewRecord(dataRow,  recordNo, DataRowAction.Change, false, false); 
                         if (!dataRow.HasChanges()) {
                             this.SetOldRecord(dataRow, recordNo); 
                         }
                     }
                     else {
                         if (dataRow.RowState == DataRowState.Deleted) 
                             dataRow.RejectChanges();
                         this.SetNewRecord(dataRow,  recordNo, DataRowAction.Change, false, false); 
                     } 
                     break;
                case LoadOption.PreserveChanges: 
                     if (dataRow.RowState == DataRowState.Unchanged) {
                         // SQLBU 500706: DataTable internal index is corrupted: '8'
                         // if ListChanged event deletes dataRow
                         this.SetOldRecord(dataRow,  recordNo); // do not fire event 
                         this.SetNewRecord(dataRow, recordNo, DataRowAction.Change, false, false);
                     } 
                     else { // if modified/ added / deleted we want this operation to fire event (just for LoadOption.PreserveCurrentValues) 
                        this.SetOldRecord(dataRow,  recordNo);
                     } 
                     break;
                default:
                    throw ExceptionBuilder.ArgumentOutOfRange("LoadOption");
            } 

            if (hasError) { 
                string error = Res.GetString(Res.Load_ReadOnlyDataModified); 
                if (dataRow.RowError.Length == 0) { // WebData 112272, append the row error
                    dataRow.RowError = error; 
                }
                else {
                    dataRow.RowError += " ]:[ " + error ;
                } 

                foreach(DataColumn dc in this.Columns) { 
                    if (dc.ReadOnly && !dc.Computed) 
                        dataRow.SetColumnError(dc, error);
                } 
            }

            drcevent = RaiseRowChanged(drcevent, dataRow, action);
            if (action == DataRowAction.Nothing) { // RaiseRowChanged does not fire for DataRowAction.Nothing 
                dataRow.inChangingEvent = true;
                try { 
                    OnRowChanged(drcevent, dataRow, action); 
                }
                finally { 
                    dataRow.inChangingEvent = false;
                }
            }
 
        }
 
        public  DataTableReader CreateDataReader() { 
            return new DataTableReader(this);
        } 


        public void WriteXml(Stream stream)
        { 
            WriteXml(stream, XmlWriteMode.IgnoreSchema, false);
        } 
 
        public void WriteXml(Stream stream, bool writeHierarchy)
        { 
            WriteXml(stream, XmlWriteMode.IgnoreSchema, writeHierarchy);
        }

        public void WriteXml(TextWriter writer) 
        {
            WriteXml(writer, XmlWriteMode.IgnoreSchema, false); 
        } 

        public void WriteXml(TextWriter writer, bool writeHierarchy) 
        {
            WriteXml(writer, XmlWriteMode.IgnoreSchema, writeHierarchy);
        }
 
        public void WriteXml(XmlWriter writer)
        { 
            WriteXml(writer, XmlWriteMode.IgnoreSchema, false); 
        }
 
        public void WriteXml(XmlWriter writer, bool writeHierarchy)
        {
            WriteXml(writer, XmlWriteMode.IgnoreSchema, writeHierarchy);
        } 

        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)] 
        public void WriteXml(String fileName)
        { 
            WriteXml(fileName, XmlWriteMode.IgnoreSchema, false);
        }

        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)]
        public void WriteXml(String fileName, bool writeHierarchy) 
        { 
            WriteXml(fileName, XmlWriteMode.IgnoreSchema, writeHierarchy);
        } 

        public void WriteXml(Stream stream, XmlWriteMode mode)
        {
            WriteXml(stream, mode, false); 
        }
 
        public void WriteXml(Stream stream, XmlWriteMode mode, bool writeHierarchy) 
        {
            if (stream != null) { 
                XmlTextWriter w =  new XmlTextWriter(stream, null) ;
                w.Formatting = Formatting.Indented;

                WriteXml( w, mode, writeHierarchy); 
            }
        } 
 
        public void WriteXml(TextWriter writer, XmlWriteMode mode)
        { 
            WriteXml(writer, mode, false);
        }

        public void WriteXml(TextWriter writer, XmlWriteMode mode, bool writeHierarchy) 
        {
            if (writer != null) { 
                XmlTextWriter w =  new XmlTextWriter(writer) ; 
                w.Formatting = Formatting.Indented;
 
                WriteXml(w, mode, writeHierarchy);
            }
        }
 
        public void WriteXml(XmlWriter writer, XmlWriteMode mode)
        { 
            WriteXml(writer, mode, false); 
        }
        public void WriteXml(XmlWriter writer, XmlWriteMode mode, bool writeHierarchy) 
        {
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, mode=%d{ds.XmlWriteMode}\n", ObjectID,  (int)mode);
            try{ 
                if (this.tableName.Length == 0) {
                    throw ExceptionBuilder.CanNotSerializeDataTableWithEmptyName(); 
                } 
                // Generate SchemaTree and write it out
                if (writer != null) { 

                    if (mode == XmlWriteMode.DiffGram) { // FIX THIS
                        // Create and save the updates
                        new NewDiffgramGen(this, writeHierarchy).Save(writer, this); 
                    }
                    else { 
                        // Create and save xml data 
                        if (mode == XmlWriteMode.WriteSchema) {
                            DataSet ds = null; 
                            string tablenamespace = this.tableNamespace;
                            if (null == this.DataSet) {
                                ds = new DataSet();
                                // if user set values on DataTable, it isn't necessary 
                                // to set them on the DataSet because they won't be inherited
                                // but it is simpler to set them in both places 
 
                                // if user did not set values on DataTable, it is required
                                // to set them on the DataSet so the table will inherit 
                                // the value already on the Datatable
                                ds.SetLocaleValue(_culture, _cultureUserSet);
                                ds.CaseSensitive = this.CaseSensitive;
                                ds.Namespace = this.Namespace; 
                                ds.RemotingFormat = this.RemotingFormat;
                                ds.Tables.Add(this); 
                            } 

                            if (writer != null) { 
                                XmlDataTreeWriter xmldataWriter = new XmlDataTreeWriter(this, writeHierarchy);
                                xmldataWriter.Save(writer, /*mode == XmlWriteMode.WriteSchema*/true);
                            }
                            if (null != ds) { 
                                ds.Tables.Remove(this);
                                this.tableNamespace = tablenamespace; 
                            } 
                        }
                        else { 
                            XmlDataTreeWriter xmldataWriter = new XmlDataTreeWriter(this, writeHierarchy);
                            xmldataWriter.Save(writer,/*mode == XmlWriteMode.WriteSchema*/ false);
                        }
                    } 
                }
            } 
            finally { 
                Bid.ScopeLeave(ref hscp);
            } 
        }

        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public void WriteXml(String fileName, XmlWriteMode mode)
        { 
            WriteXml(fileName, mode, false); 
        }
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)]
        public void WriteXml(String fileName, XmlWriteMode mode, bool writeHierarchy)
        { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, fileName='%ls', mode=%d{ds.XmlWriteMode}\n", ObjectID, fileName, (int)mode); 
            try { 
                using(XmlTextWriter xw = new XmlTextWriter( fileName, null )) {
                    xw.Formatting = Formatting.Indented; 
                    xw.WriteStartDocument(true);

                    WriteXml(xw, mode, writeHierarchy);
 
                    xw.WriteEndDocument();
                } 
            } 
            finally {
                Bid.ScopeLeave(ref hscp); 
            }
        }

        public void WriteXmlSchema(Stream stream) { 
            WriteXmlSchema(stream, false);
        } 
 
        public void WriteXmlSchema(Stream stream, bool writeHierarchy)
        { 
            if (stream == null)
                return;

            XmlTextWriter w =  new XmlTextWriter(stream, null) ; 
            w.Formatting = Formatting.Indented;
 
            WriteXmlSchema( w, writeHierarchy ); 
        }
 
        public void WriteXmlSchema( TextWriter writer ) {
            WriteXmlSchema( writer, false );
        }
 
        public void WriteXmlSchema( TextWriter writer, bool writeHierarchy )
        { 
 
            if (writer == null)
                return; 

            XmlTextWriter w =  new XmlTextWriter(writer);
            w.Formatting = Formatting.Indented;
 
            WriteXmlSchema( w, writeHierarchy );
        } 
 
        private  bool CheckForClosureOnExpressions(DataTable dt, bool writeHierarchy) {
            List tableList = new List(); 
            tableList.Add(dt);
            if (writeHierarchy) { // WebData 112161
                CreateTableList(dt, tableList);
            } 
            return CheckForClosureOnExpressionTables(tableList);
        } 
 
        private bool CheckForClosureOnExpressionTables(List tableList) {
            Debug.Assert(tableList != null, "tableList shouldnot be null"); 

            foreach(DataTable datatable in tableList) {
                foreach(DataColumn dc in datatable.Columns) {
                    if (dc.Expression.Length != 0)  { 
                        DataColumn[] dependency = dc.DataExpression.GetDependency();
                        for (int j = 0; j < dependency.Length; j++) { 
                            if (!(tableList.Contains(dependency[j].Table))) { 
                                return false;
                            } 
                        }
                    }
                }
            } 
            return true;
        } 
 

        public void WriteXmlSchema(XmlWriter writer) { 
            WriteXmlSchema(writer, false);
        }

        public void WriteXmlSchema(XmlWriter writer, bool writeHierarchy) 
        {
            IntPtr hscp; 
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); 
            try{
                if (this.tableName.Length == 0) { 
                    throw ExceptionBuilder.CanNotSerializeDataTableWithEmptyName();
                }

                if (!CheckForClosureOnExpressions(this, writeHierarchy)) { 
                    throw ExceptionBuilder.CanNotSerializeDataTableHierarchy();
                } 
 
                DataSet ds = null;
                string tablenamespace = this.tableNamespace;//SQL BU Defect Tracking 286968 

                // Generate SchemaTree and write it out
                if (null == this.DataSet) {
                    ds = new DataSet(); 
                    // if user set values on DataTable, it isn't necessary
                    // to set them on the DataSet because they won't be inherited 
                    // but it is simpler to set them in both places 

                    // if user did not set values on DataTable, it is required 
                    // to set them on the DataSet so the table will inherit
                    // the value already on the Datatable
                    ds.SetLocaleValue(_culture, _cultureUserSet);
                    ds.CaseSensitive = this.CaseSensitive; 
                    ds.Namespace = this.Namespace;
                    ds.RemotingFormat = this.RemotingFormat; 
                    ds.Tables.Add(this); 
                }
 
                if (writer != null) {
                    XmlTreeGen treeGen = new XmlTreeGen(SchemaFormat.Public);
                    treeGen.Save(null, this, writer, writeHierarchy);
                } 
                if (null != ds) {
                    ds.Tables.Remove(this); 
                    this.tableNamespace = tablenamespace; 
                }
            } 
            finally {
                Bid.ScopeLeave(ref hscp);
            }
        } 

        [ResourceExposure(ResourceScope.Machine)] 
        [ResourceConsumption(ResourceScope.Machine)] 
        public void WriteXmlSchema(String fileName) {
            WriteXmlSchema(fileName, false); 
        }

        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public void WriteXmlSchema(String fileName, bool writeHierarchy)
        { 
            XmlTextWriter xw = new XmlTextWriter( fileName, null ); 
            try {
                xw.Formatting = Formatting.Indented; 
                xw.WriteStartDocument(true);
                WriteXmlSchema(xw, writeHierarchy);
                xw.WriteEndDocument();
            } 
            finally {
                xw.Close(); 
            } 
        }
 
        public XmlReadMode ReadXml(Stream stream)
        {
            if (stream == null)
                return XmlReadMode.Auto; 

            return ReadXml( new XmlTextReader(stream), false); 
        } 

        public XmlReadMode ReadXml(TextReader reader) 
        {
            if (reader == null)
                return XmlReadMode.Auto;
 
            return ReadXml( new XmlTextReader(reader), false);
        } 
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public XmlReadMode ReadXml(string fileName)
        {
            XmlTextReader xr = new XmlTextReader(fileName);
            try { 
                return ReadXml( xr , false);
            } 
            finally { 
                xr.Close();
            } 
        }

        public XmlReadMode ReadXml(XmlReader reader)
        { 
            return ReadXml(reader, false);
        } 
 
        private void RestoreConstraint(bool originalEnforceConstraint) {
            if (this.DataSet != null) { 
                this.DataSet.EnforceConstraints = originalEnforceConstraint;
            }
            else {
                this.EnforceConstraints = originalEnforceConstraint; 
            }
        } 
 
        private bool IsEmptyXml(XmlReader reader) {
            if (reader.IsEmptyElement) { 
                if (reader.AttributeCount == 0 || (reader.LocalName == Keywords.DIFFGRAM && reader.NamespaceURI == Keywords.DFFNS)) {
                    return true;
                }
                if (reader.AttributeCount == 1) { 
                    reader.MoveToAttribute(0);
                    if ((this.Namespace == reader.Value) && 
                        (this.Prefix == reader.LocalName) && 
                        (reader.Prefix == Keywords.XMLNS) &&
                        (reader.NamespaceURI == Keywords.XSD_XMLNS_NS)) 
                    return true;
                }
            }
            return false; 
        }
 
        internal XmlReadMode ReadXml(XmlReader reader, bool denyResolving) 
        {
            IntPtr hscp; 
            Bid.ScopeEnter(out hscp, " %d#, denyResolving=%d{bool}\n", ObjectID, denyResolving);
            try {
              try {
                bool fDataFound = false; 
                bool fSchemaFound = false;
                bool fDiffsFound = false; 
                bool fIsXdr = false; 
                int iCurrentDepth = -1;
                XmlReadMode ret = XmlReadMode.Auto; 

                // clear the hashtable to avoid conflicts between diffgrams, SqlHotFix 782
                Debug.Assert(null == rowDiffId, "wasn't previously cleared");
                rowDiffId = null; 

                if (reader == null) 
                    return ret; 
                bool originalEnforceConstraint = false;
                if (this.DataSet != null) { 
                    originalEnforceConstraint = this.DataSet.EnforceConstraints;
                    this.DataSet.EnforceConstraints = false;
                }
                else { 
                    originalEnforceConstraint = this.EnforceConstraints;
                    this.EnforceConstraints = false; 
                } 

                if (reader is XmlTextReader) 
                    ((XmlTextReader) reader).WhitespaceHandling = WhitespaceHandling.Significant;

                XmlDocument xdoc = new XmlDocument(); // we may need this to infer the schema
                XmlDataLoader xmlload = null; 

 
                reader.MoveToContent(); 
                if (Columns.Count == 0) {
                    if (IsEmptyXml(reader)) { 
                        reader.Read();
                        return ret;
                    }
                } 

                if (reader.NodeType == XmlNodeType.Element) { 
                    iCurrentDepth = reader.Depth; 

                    if ((reader.LocalName == Keywords.DIFFGRAM) && (reader.NamespaceURI == Keywords.DFFNS)) { 
                        if (Columns.Count == 0) {
                            if (reader.IsEmptyElement) {
                                reader.Read();
                                return XmlReadMode.DiffGram; 
                            }
                            throw ExceptionBuilder.DataTableInferenceNotSupported(); 
                        } 
                        this.ReadXmlDiffgram(reader);
                        // read the closing tag of the current element 
                        ReadEndElement(reader);

                        RestoreConstraint(originalEnforceConstraint);
                        return XmlReadMode.DiffGram; 
                    }
 
                    // if reader points to the schema load it 
                    if (reader.LocalName == Keywords.XDR_SCHEMA && reader.NamespaceURI==Keywords.XDRNS) {
                        // load XDR schema and exit 
                        ReadXDRSchema(reader);

                        RestoreConstraint(originalEnforceConstraint);
                        return XmlReadMode.ReadSchema; //since the top level element is a schema return 
                    }
 
                    if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI==Keywords.XSDNS) { 
                        // load XSD schema and exit
                        ReadXmlSchema(reader, denyResolving); 
                        RestoreConstraint(originalEnforceConstraint);
                        return XmlReadMode.ReadSchema; //since the top level element is a schema return
                    }
 
                    if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI.StartsWith(Keywords.XSD_NS_START, StringComparison.Ordinal)) {
                        if (this.DataSet != null) { // we should not throw for constraint, we already will throw for unsupported schema, so restore enforce cost, but not via property 
                            this.DataSet.RestoreEnforceConstraints(originalEnforceConstraint); 
                        }
                        else { 
                            this.enforceConstraints = originalEnforceConstraint;
                        }

                        throw ExceptionBuilder.DataSetUnsupportedSchema(Keywords.XSDNS); 
                    }
 
                    // now either the top level node is a table and we load it through dataReader... 

                    // ... or backup the top node and all its attributes because we may need to InferSchema 
                    XmlElement topNode = xdoc.CreateElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
                    if (reader.HasAttributes) {
                        int attrCount = reader.AttributeCount;
                        for (int i=0;i depth) { 
                reader.Read();
            }
            return (reader.NodeType == XmlNodeType.Element);
        } 
        private void ReadXmlDiffgram(XmlReader reader) { // fill correctly
            int d = reader.Depth; 
            bool fEnforce = this.EnforceConstraints; 
            this.EnforceConstraints =false;
            DataTable newDt; 
            bool isEmpty;

            if (this.Rows.Count == 0) {
                isEmpty = true; 
                newDt = this;
            } 
            else { 
                isEmpty = false;
                newDt = this.Clone(); 
                newDt.EnforceConstraints = false;
            }

            newDt.Rows.nullInList = 0; 

            reader.MoveToContent(); 
 
            if ((reader.LocalName != Keywords.DIFFGRAM) && (reader.NamespaceURI != Keywords.DFFNS))
                return; 
            reader.Read();
            if (reader.NodeType == XmlNodeType.Whitespace) {
                MoveToElement(reader, reader.Depth - 1 /*iCurrentDepth*/); // skip over whitespaces.
            } 

            newDt.fInLoadDiffgram = true; 
 
            if (reader.Depth > d) {
                if ((reader.NamespaceURI != Keywords.DFFNS) && (reader.NamespaceURI != Keywords.MSDNS)) { 
                    //we should be inside the dataset part
                    XmlDocument xdoc = new XmlDocument();
                    XmlElement node = xdoc.CreateElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
                    reader.Read(); 
                    if (reader.Depth-1 > d) {
                        XmlDataLoader xmlload = new XmlDataLoader(newDt, false, node, false); 
                        xmlload.isDiffgram = true; // turn on the special processing 
                        xmlload.LoadData(reader);
                    } 
                    ReadEndElement(reader);
                }
                if (((reader.LocalName == Keywords.SQL_BEFORE) && (reader.NamespaceURI == Keywords.DFFNS)) ||
                    ((reader.LocalName == Keywords.MSD_ERRORS) && (reader.NamespaceURI == Keywords.DFFNS))) 

                { 
                    //this will consume the changes and the errors part 
                    XMLDiffLoader diffLoader = new XMLDiffLoader();
                    diffLoader.LoadDiffGram(newDt, reader); 
                }

                // get to the closing diff tag
                while(reader.Depth > d) { 
                    reader.Read();
                } 
                // read the closing tag 
                ReadEndElement(reader);
            } 

            if (newDt.Rows.nullInList > 0)
                throw ExceptionBuilder.RowInsertMissing(newDt.TableName);
 

            newDt.fInLoadDiffgram = false; 
            List tableList = new List(); 
            tableList.Add(this);
            CreateTableList(this, tableList); 

// this is terrible, optimize it
            for (int i = 0; i < tableList.Count ; i++) {
                DataRelation[] relations = tableList[i].NestedParentRelations; 
                foreach(DataRelation rel in relations) {
                    if (rel != null && rel.ParentTable == tableList[i]) { 
                        foreach (DataRow r in tableList[i].Rows) { 
                            foreach (DataRelation rel2 in relations) {
                                r.CheckForLoops(rel2); 
                            }
                        }
                    }
                } 
            }
 
            if (!isEmpty) { 
                this.Merge(newDt);
            } 
            this.EnforceConstraints = fEnforce;
        }

        internal void ReadXSDSchema(XmlReader reader, bool denyResolving) { 
            XmlSchemaSet sSet = new XmlSchemaSet();
            while (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI==Keywords.XSDNS) { 
                XmlSchema s = XmlSchema.Read(reader, null); 
                sSet.Add(s);
                //read the end tag 
                ReadEndElement(reader);
            }
            sSet.Compile();
 
            XSDSchema schema = new XSDSchema();
            schema.LoadSchema(sSet, this); 
        } 

 
        public void ReadXmlSchema(Stream stream)
        {
            if (stream == null)
                return; 

            ReadXmlSchema( new XmlTextReader( stream ), false ); 
        } 

        public void ReadXmlSchema(TextReader reader) 
        {
            if (reader == null)
                return;
 
            ReadXmlSchema( new XmlTextReader( reader ), false );
        } 
 
        [ResourceExposure(ResourceScope.Machine)]
        [ResourceConsumption(ResourceScope.Machine)] 
        public void ReadXmlSchema(String fileName)
        {
            XmlTextReader xr = new XmlTextReader(fileName);
            try { 
                ReadXmlSchema( xr, false );
            } 
            finally { 
                xr.Close();
            } 
        }

        public void ReadXmlSchema(XmlReader reader)
        { 
            ReadXmlSchema(reader, false);
        } 
 
        internal void ReadXmlSchema(XmlReader reader, bool denyResolving)
        { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, denyResolving=%d{bool}\n", ObjectID, denyResolving);
            try{
                DataSet ds = new DataSet(); 
                SerializationFormat cachedRemotingFormat = this.RemotingFormat;
                // fxcop: ReadXmlSchema will provide the CaseSensitive, Locale, Namespace information 
                ds.ReadXmlSchema(reader, denyResolving); 

                string CurrentTableFullName = ds.MainTableName; 

                if (Common.ADP.IsEmpty(this.tableName) && Common.ADP.IsEmpty(CurrentTableFullName))
                    return;
 
                DataTable currentTable = null;
 
                if (!Common.ADP.IsEmpty(this.tableName)) { 
                    if (!Common.ADP.IsEmpty(this.Namespace)) {
                        currentTable = ds.Tables[this.tableName, this.Namespace]; 
                    }
                    else {//SQL BU defect tracking 240293
                        int tableIndex = ds.Tables.InternalIndexOf(this.tableName);
                        if (tableIndex  > -1) { 
                            currentTable = ds.Tables[tableIndex];
                        } 
                    } 
                }
                else{  //!Common.ADP.IsEmpty(CurrentTableFullName) 
                    string CurrentTableNamespace = "";
                    int nsSeperator = CurrentTableFullName.IndexOf(':');
                    if (nsSeperator > -1) {
                        CurrentTableNamespace = CurrentTableFullName.Substring(0, nsSeperator); 
                    }
                    string CurrentTableName = CurrentTableFullName.Substring(nsSeperator + 1, CurrentTableFullName.Length - nsSeperator -1); 
 
                    currentTable = ds.Tables[CurrentTableName, CurrentTableNamespace];
                } 

                if (currentTable == null) { // bug fix :99186
                    string qTableName = string.Empty;
                    if (!Common.ADP.IsEmpty(this.tableName)) { 
                        qTableName = (this.Namespace.Length > 0)? (this.Namespace + ":" + this.tableName):this.tableName;
                    } 
                    else { 
                        qTableName = CurrentTableFullName ;
                    } 
                    throw ExceptionBuilder.TableNotFound(qTableName);
                }

                currentTable._remotingFormat = cachedRemotingFormat; 

                List tableList = new List(); 
                tableList.Add(currentTable); 
                CreateTableList(currentTable, tableList);
                List relationList = new List(); 
                CreateRelationList(tableList, relationList);

                if (relationList.Count == 0) {
                    if (this.Columns.Count == 0) { 
                        DataTable tempTable = currentTable;
                        if (tempTable != null) 
                            tempTable.CloneTo(this, null, false); // we may have issue Amir 
                        if (this.DataSet == null && this.tableNamespace == null) { // webdata 105506
// for standalone table, clone wont get these correctly, since they may come with inheritance 
                            this.tableNamespace =  tempTable.Namespace;
                        }
                    }
                    return; 
                }
                else { 
                    if (Common.ADP.IsEmpty(this.TableName)) { 
                        this.TableName = currentTable.TableName;
                        if (!Common.ADP.IsEmpty(currentTable.Namespace)) { 
                            this.Namespace = currentTable.Namespace;
                        }
                    }
                    if (this.DataSet == null) { 
                        DataSet dataset = new DataSet(ds.DataSetName);
// webdata 105506 
                        // if user set values on DataTable, it isn't necessary 
                        // to set them on the DataSet because they won't be inherited
                        // but it is simpler to set them in both places 

                        // if user did not set values on DataTable, it is required
                        // to set them on the DataSet so the table will inherit
                        // the value already on the Datatable 
                        dataset.SetLocaleValue(ds.Locale, ds.ShouldSerializeLocale());
                        dataset.CaseSensitive = ds.CaseSensitive; 
                        dataset.Namespace = ds.Namespace; 
                        dataset.mainTableName = ds.mainTableName;
                        dataset.RemotingFormat = ds.RemotingFormat; 

                        dataset.Tables.Add(this);
                    }
 
                    DataTable targetTable = CloneHierarchy(currentTable, this.DataSet, null);
 
                    foreach(DataTable tempTable in tableList) { 
                        DataTable destinationTable = this.DataSet.Tables[tempTable.tableName, tempTable.Namespace];
                        DataTable sourceTable = ds.Tables[tempTable.tableName, tempTable.Namespace]; 
                        foreach(Constraint tempConstrain in sourceTable.Constraints) {
                            ForeignKeyConstraint fkc = tempConstrain as ForeignKeyConstraint;  // we have already cloned the UKC when cloning the datatable
                            if (fkc != null) {
                                if (fkc.Table != fkc.RelatedTable)  { 
                                    if (tableList.Contains(fkc.Table) && tableList.Contains(fkc.RelatedTable)) {
                                        ForeignKeyConstraint newFKC = (ForeignKeyConstraint)fkc.Clone(destinationTable.DataSet); 
                                        if (!destinationTable.Constraints.Contains(newFKC.ConstraintName)) 
                                            destinationTable.Constraints.Add(newFKC); // we know that the dest table is already in the table
                                    } 
                                }
                           }
                        }
                    } 
                    foreach(DataRelation rel in relationList) {
                        if (!this.DataSet.Relations.Contains(rel.RelationName)) 
                            this.DataSet.Relations.Add(rel.Clone(this.DataSet)); 
                    }
 
                    bool hasExternaldependency = false;

                    foreach(DataTable tempTable in tableList) {
                        foreach(DataColumn dc in tempTable.Columns) { 
                            hasExternaldependency = false;
                            if (dc.Expression.Length  != 0) { 
                                DataColumn[] dependency = dc.DataExpression.GetDependency(); 
                                for (int j = 0; j < dependency.Length; j++) {
                                    if (!tableList.Contains(dependency[j].Table)) { 
                                        hasExternaldependency = true;
                                        break;
                                    }
                                } 
                            }
                            if (!hasExternaldependency) { 
                                this.DataSet.Tables[tempTable.TableName, tempTable.Namespace].Columns[dc.ColumnName].Expression = dc.Expression; 
                            }
                        } 
                        hasExternaldependency = false;
                    }

                } 
            }
            finally{ 
                Bid.ScopeLeave(ref hscp); 
            }
        } 

        private void CreateTableList(DataTable currentTable, List tableList) {
            foreach( DataRelation r in currentTable.ChildRelations ) {
                if (! tableList.Contains(r.ChildTable)) { 
                    tableList.Add(r.ChildTable);
                    CreateTableList(r.ChildTable, tableList); 
                } 
            }
        } 
        private void CreateRelationList(List tableList,  List relationList) {
            foreach(DataTable table in tableList) {
                foreach( DataRelation r in table.ChildRelations) {
                    if (tableList.Contains(r.ChildTable) && tableList.Contains(r.ParentTable)) { 
                        relationList.Add(r);
                    } 
                } 
            }
        } 

        /*************************************************************************
        The V2.0 (no V1.0 or V1.1) WSDL for Untyped DataTable being returned as a result (no parameters)
         
            
             
         
        
             
                
                    
                        
                             
                                
                                 
                             
                        
                     
                
            
        
 
        Typed DataTable is not supported in WSDL (SQLBU 444636)
 
        either fails because xsd generates its typed DataTable with an internal parameterless ctor 

        or System.NullReferenceException: Object reference not set to an instance of an object.   (if namespace of StronglyTyped DataTable is not set) 
           at System.Data.XmlTreeGen.FindTargetNamespace(DataTable table)

        or System.InvalidOperationException: Schema Id is missing. The schema returned from WebServiceDataSetServer.Service+StudentsDataTable.GetSchema() must have an Id.
           at System.Xml.Serialization.SerializableMapping.RetrieveSerializableSchema() 
        *****************************************************************************/
        public static XmlSchemaComplexType GetDataTableSchema(XmlSchemaSet schemaSet) { 
            XmlSchemaComplexType type = new XmlSchemaComplexType(); 
            XmlSchemaSequence sequence = new XmlSchemaSequence();
            XmlSchemaAny any = new XmlSchemaAny(); 
            any.Namespace = XmlSchema.Namespace;
            any.MinOccurs = 0;
            any.MaxOccurs = Decimal.MaxValue;
            any.ProcessContents = XmlSchemaContentProcessing.Lax; 
            sequence.Items.Add(any);
 
            any = new XmlSchemaAny(); 
            any.Namespace = Keywords.DFFNS;
            any.MinOccurs = 1; // when recognizing WSDL - MinOccurs="0" denotes DataSet, a MinOccurs="1" for DataTable 
            any.ProcessContents = XmlSchemaContentProcessing.Lax;
            sequence.Items.Add(any);

            type.Particle = sequence; 

            return type; 
        } 

        XmlSchema IXmlSerializable.GetSchema() { 
            return GetSchema();
        }

        protected virtual XmlSchema GetSchema() { 
            if (GetType() == typeof(DataTable)) {
                return null; 
            } 
            MemoryStream stream = new MemoryStream();
 
            XmlWriter writer = new XmlTextWriter(stream, null);
            if (writer != null) {
                 (new XmlTreeGen(SchemaFormat.WebService)).Save(this, writer);
            } 
            stream.Position = 0;
            return XmlSchema.Read(new XmlTextReader(stream), null); 
        } 

        void IXmlSerializable.ReadXml(XmlReader reader) { 
            IXmlTextParser textReader = reader as IXmlTextParser;
            bool fNormalization = true;
            if (textReader != null) {
                fNormalization = textReader.Normalized; 
                textReader.Normalized = false;
            } 
            ReadXmlSerializable(reader); 

            if (textReader != null) { 
                textReader.Normalized = fNormalization;
            }
        }
 
        void IXmlSerializable.WriteXml(XmlWriter writer) {
            WriteXmlSchema(writer, false); 
            WriteXml(writer, XmlWriteMode.DiffGram, false); 
        }
 
         protected virtual void ReadXmlSerializable(XmlReader reader) {
            ReadXml(reader, XmlReadMode.DiffGram, true);
        }
 
/*
        [ 
        DefaultValue(false), 
        ResCategoryAttribute(Res.DataCategory_Data),
        ResDescriptionAttribute(Res.DataTableSerializeHierarchy) 
        ]
        public bool SerializeHierarchy {
            get {
                return this.serializeHierarchy; 
            }
            set { 
                this.serializeHierarchy = value; 
            }
        } 
*/

        internal Hashtable RowDiffId {
            get { 
                if (rowDiffId == null)
                    rowDiffId = new Hashtable(); 
                return rowDiffId; 
            }
        } 

        internal int ObjectID {
            get {
                return _objectID; 
            }
        } 
 
        internal void AddDependentColumn(DataColumn expressionColumn) {
            if (dependentColumns == null) 
                dependentColumns = new List();

            if (!dependentColumns.Contains(expressionColumn)) {
                // only remember unique columns but expect non-unique columns to be added 
                dependentColumns.Add(expressionColumn);
            } 
        } 

        internal void RemoveDependentColumn(DataColumn expressionColumn) { 
            if (dependentColumns != null && dependentColumns.Contains(expressionColumn)) {
                dependentColumns.Remove(expressionColumn);
            }
        } 

        internal void EvaluateExpressions() { 
            //evaluates all expressions for all rows in table 
            // SQLBU 414992: Serious performance issue when calling Merge
            // this improves performance by only computing expressions when they are present 
            // and iterating over the rows instead of computing their position multiple times
            if ((null != dependentColumns) && (0 < dependentColumns.Count)) {
                foreach(DataRow row in Rows) {
                    // only evaluate original values if different from current. 
                    if (row.oldRecord != -1 && row.oldRecord != row.newRecord) {
                        EvaluateDependentExpressions(dependentColumns, row, DataRowVersion.Original, null); 
                    } 
                    if (row.newRecord != -1) {
                        EvaluateDependentExpressions(dependentColumns, row, DataRowVersion.Current, null); 
                    }
                    if (row.tempRecord != -1) {
                        EvaluateDependentExpressions(dependentColumns, row, DataRowVersion.Proposed, null);
                    } 
                }
            } 
        } 

        internal void EvaluateExpressions(DataRow row, DataRowAction action, List cachedRows) { 
            // evaluate all expressions for specified row
            if (action == DataRowAction.Add ||
                action == DataRowAction.Change||
                action == DataRowAction.Rollback) { 
                 // only evaluate original values if different from current.
                if (row.oldRecord != -1 && row.oldRecord != row.newRecord) { 
                    EvaluateDependentExpressions(dependentColumns, row, DataRowVersion.Original, cachedRows); 
                }
                if (row.newRecord != -1) { 
                    EvaluateDependentExpressions(dependentColumns, row, DataRowVersion.Current, cachedRows);
                }
                if (row.tempRecord != -1) {
                    EvaluateDependentExpressions(dependentColumns, row, DataRowVersion.Proposed, cachedRows); 
                }
            } 
            else if (action == DataRowAction.Delete && dependentColumns != null) { 
                foreach(DataColumn col in dependentColumns) {
                    if (col.DataExpression != null && col.DataExpression.HasLocalAggregate() && col.Table == this) { 
                        for (int j = 0; j < Rows.Count; j++) {
                            DataRow tableRow = Rows[j];

                            if (tableRow.oldRecord != -1 && tableRow.oldRecord != tableRow.newRecord) { 
                                EvaluateDependentExpressions(dependentColumns, tableRow, DataRowVersion.Original, null);
                            } 
                            if (tableRow.newRecord != -1) { 
                                EvaluateDependentExpressions(dependentColumns, tableRow, DataRowVersion.Current, null);
                            } 
                            if (tableRow.tempRecord != -1) {
                                EvaluateDependentExpressions(dependentColumns, tableRow, DataRowVersion.Proposed, null);
                            }
                        } 
                        break;
                    } 
                } 

                foreach (DataRow relatedRow in cachedRows) { 
                    if (relatedRow.oldRecord != -1 && relatedRow.oldRecord != relatedRow.newRecord) {
                        relatedRow.Table.EvaluateDependentExpressions(relatedRow.Table.dependentColumns, relatedRow, DataRowVersion.Original, null);
                    }
                    if (relatedRow.newRecord != -1) { 
                        relatedRow.Table.EvaluateDependentExpressions(relatedRow.Table.dependentColumns, relatedRow, DataRowVersion.Current, null);
                    } 
                    if (relatedRow.tempRecord != -1) { 
                        relatedRow.Table.EvaluateDependentExpressions(relatedRow.Table.dependentColumns, relatedRow, DataRowVersion.Proposed, null);
                    } 
                }
            }
        }
 
        internal void EvaluateExpressions(DataColumn column) {
            // evaluates all rows for expression from specified column 
            Debug.Assert(column.Computed, "Only computed columns should be re-evaluated."); 
            int count = column.table.Rows.Count;
            if (column.DataExpression.IsTableAggregate() && count > 0) { 
                // this value is a constant across the table.
                object aggCurrent = column.DataExpression.Evaluate();
                for (int j = 0; j < count; j++) {
                    DataRow row = column.table.Rows[j]; 
                    // only evaluate original values if different from current.
                    if (row.oldRecord != -1 && row.oldRecord != row.newRecord) { 
                        column[row.oldRecord] = aggCurrent; 
                    }
                    if (row.newRecord != -1) { 
                        column[row.newRecord] = aggCurrent;
                    }
                    if (row.tempRecord != -1) {
                        column[row.tempRecord] = aggCurrent; 
                    }
                } 
            } 
            else {
                for (int j = 0; j < count; j++) { 
                    DataRow row = column.table.Rows[j];

                    if (row.oldRecord != -1 && row.oldRecord != row.newRecord) {
                        column[row.oldRecord] = column.DataExpression.Evaluate(row, DataRowVersion.Original); 
                    }
                    if (row.newRecord != -1) { 
                        column[row.newRecord] = column.DataExpression.Evaluate(row, DataRowVersion.Current); 
                    }
                    if (row.tempRecord != -1) { 
                        column[row.tempRecord] = column.DataExpression.Evaluate(row, DataRowVersion.Proposed);
                    }
                }
            } 

            // SQLBU 501916 - DataTable internal index is corrupted:'5' 
            column.Table.ResetInternalIndexes(column); 
            EvaluateDependentExpressions(column);
        } 

        internal void EvaluateDependentExpressions(DataColumn column) {
            // DataTable.Clear(), DataRowCollection.Clear() & DataColumn.set_Expression
            if (column.dependentColumns != null) { 
                foreach (DataColumn dc in column.dependentColumns) {
                    if ((dc.table != null) && !Object.ReferenceEquals(column, dc)) { // SQLBU 502736 
                        EvaluateExpressions(dc); 
                    }
                } 
            }
        }

        internal void EvaluateDependentExpressions(List columns, DataRow row, DataRowVersion version, List cachedRows) { 
            if (columns == null)
                return; 
            //Expression evaluation is done first over same table expressions. 
            int count = columns.Count;
            for(int i = 0; i < count; i++) { 
                if (columns[i].Table == this) {// if this column is in my table
                    DataColumn dc = columns[i];
                    if (dc.DataExpression != null && dc.DataExpression.HasLocalAggregate()) {
                    // if column expression references a local Table aggregate we need to recalc it for the each row in the local table 
                        DataRowVersion expressionVersion  = (version == DataRowVersion.Proposed) ? DataRowVersion.Default : version;
                        bool isConst = dc.DataExpression.IsTableAggregate(); //is expression constant for entire table? 
                        object newValue = null; 
                        if (isConst) {  //if new value, just compute once
                            newValue = dc.DataExpression.Evaluate(row, expressionVersion); 
                        }
                        for (int j = 0; j < Rows.Count; j++) { //evaluate for all rows in the table
                            DataRow dr = Rows[j];
                            if (dr.RowState == DataRowState.Deleted) { 
                                continue;
                            } 
                            else if (expressionVersion == DataRowVersion.Original && (dr.oldRecord == -1 || dr.oldRecord == dr.newRecord)) { 
                                continue;
                            } 

                            if (!isConst) {
                                newValue = dc.DataExpression.Evaluate(dr, expressionVersion);
                            } 
                            SilentlySetValue(dr, dc, expressionVersion, newValue);
                        } 
                    } 
                    else {
                        if (row.RowState == DataRowState.Deleted) { 
                            continue;
                        }
                        else if (version == DataRowVersion.Original && (row.oldRecord == -1 || row.oldRecord == row.newRecord)) {
                            continue; 
                        }
                        SilentlySetValue(row, dc, version, dc.DataExpression == null ? dc.DefaultValue : dc.DataExpression.Evaluate(row, version)); 
                    } 
                }
            } 
            // now do expression evaluation for expression columns other tables.
            count = columns.Count;
            for(int i = 0; i < count; i++) {
                DataColumn dc = columns[i]; 
                // if this column is NOT in my table or it is in the table and is not a local aggregate (self refs)
                if (dc.Table != this || (dc.DataExpression != null && !dc.DataExpression.HasLocalAggregate())) { 
                    DataRowVersion foreignVer = (version == DataRowVersion.Proposed) ? DataRowVersion.Default : version; 

                    // first - evaluate expressions for cachedRows (deletes & updates) 
                    if (cachedRows != null) {
                        foreach (DataRow cachedRow in cachedRows) {
                            if (cachedRow.Table != dc.Table)
                                continue; 
                             // don't update original version if child row doesn't have an oldRecord.
                            if (foreignVer == DataRowVersion.Original && cachedRow.newRecord == cachedRow.oldRecord) 
                                 continue; 
                            if (cachedRow != null && ((cachedRow.RowState != DataRowState.Deleted) && (version != DataRowVersion.Original || cachedRow.oldRecord != -1))) {// if deleted GetRecordFromVersion will throw
                                object newValue = dc.DataExpression.Evaluate(cachedRow, foreignVer); 
                                SilentlySetValue(cachedRow, dc, foreignVer, newValue);
                            }
                        }
                    } 

                    // next check parent relations 
                    for (int j = 0; j < ParentRelations.Count; j++) { 
                        DataRelation relation = ParentRelations[j];
                        if (relation.ParentTable != dc.Table) 
                            continue;
                        foreach (DataRow parentRow in row.GetParentRows(relation, version)) {
                            if (cachedRows != null && cachedRows.Contains(parentRow))
                                continue; 
                             // don't update original version if child row doesn't have an oldRecord.
                            if (foreignVer == DataRowVersion.Original && parentRow.newRecord == parentRow.oldRecord) 
                                 continue; 
                            if (parentRow != null && ((parentRow.RowState != DataRowState.Deleted) && (version != DataRowVersion.Original || parentRow.oldRecord != -1))) {// if deleted GetRecordFromVersion will throw
                                object newValue = dc.DataExpression.Evaluate(parentRow, foreignVer); 
                                SilentlySetValue(parentRow, dc, foreignVer, newValue);
                            }
                        }
                    } 
                    // next check child relations
                    for (int j = 0; j < ChildRelations.Count; j++) { 
                        DataRelation relation = ChildRelations[j]; 
                        if (relation.ChildTable != dc.Table)
                            continue; 
                        foreach (DataRow childRow in row.GetChildRows(relation, version)) {
                            // don't update original version if child row doesn't have an oldRecord.
                            if (cachedRows != null && cachedRows.Contains(childRow))
                                continue; 
                            if (foreignVer == DataRowVersion.Original && childRow.newRecord == childRow.oldRecord)
                                continue; 
                            if (childRow != null && ((childRow.RowState != DataRowState.Deleted) && (version != DataRowVersion.Original || childRow.oldRecord != -1))) { // if deleted GetRecordFromVersion will throw 
                                object newValue = dc.DataExpression.Evaluate(childRow, foreignVer);
                                SilentlySetValue(childRow, dc, foreignVer, newValue); 
                            }
                        }
                    }
                } 
            }
        } 
    } 
}
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK