Merge pull request #4248 from Unity-Technologies/boehm-gc-alloc-fixed
[mono.git] / mcs / class / referencesource / System.Data / System / Data / DataSet.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="DataSet.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">[....]</owner>
6 // <owner current="true" primary="false">[....]</owner>
7 //------------------------------------------------------------------------------
8
9 namespace System.Data {
10     using System;
11     using System.Text;
12     using System.Runtime.Serialization;
13     using System.ComponentModel;
14     using System.Diagnostics;
15     using System.Globalization;
16     using System.IO;
17     using System.Collections;
18     using System.Collections.Generic;
19     using System.Collections.Specialized;
20     using System.Xml;
21     using System.Xml.Serialization;
22 #if !NO_CONFIGURATION
23     using System.Xml.Serialization.Advanced;
24 #endif
25     using System.Xml.Schema;
26     using System.Runtime.Serialization.Formatters.Binary; //Binary Formatter
27     using System.CodeDom;
28     using System.CodeDom.Compiler;
29     using System.Configuration;
30     using System.Data.Common;
31     using System.Runtime.Versioning;
32     using System.Runtime.CompilerServices;
33
34 #if !COREFX
35     /// <devdoc>
36     ///    <para>
37     ///       Represents an in-memory cache of data.
38     ///    </para>
39     /// </devdoc>
40     [
41     ResDescriptionAttribute(Res.DataSetDescr),
42     DefaultProperty("DataSetName"),
43     ToolboxItem("Microsoft.VSDesigner.Data.VS.DataSetToolboxItem, " + AssemblyRef.MicrosoftVSDesigner),
44     Designer("Microsoft.VSDesigner.Data.VS.DataSetDesigner, " + AssemblyRef.MicrosoftVSDesigner),
45     Serializable,
46     XmlSchemaProvider("GetDataSetSchema"),
47     XmlRoot("DataSet")
48     ]
49  public class DataSet : MarshalByValueComponent, System.ComponentModel.IListSource, IXmlSerializable, ISupportInitializeNotification, ISerializable {
50
51         private DataViewManager defaultViewManager;
52
53         // Public Collections
54         private readonly DataTableCollection tableCollection;
55         private readonly DataRelationCollection relationCollection;
56         internal PropertyCollection extendedProperties = null;
57         private string dataSetName = "NewDataSet";
58         private string _datasetPrefix = String.Empty;
59         internal string namespaceURI = string.Empty;
60         private bool enforceConstraints = true;
61         private const String KEY_XMLSCHEMA = "XmlSchema";
62         private const String KEY_XMLDIFFGRAM = "XmlDiffGram";
63
64         // globalization stuff
65         private bool _caseSensitive;
66         private CultureInfo _culture;
67         private bool _cultureUserSet;
68
69         // Internal definitions
70         internal bool fInReadXml = false;
71         internal bool fInLoadDiffgram = false;
72         internal bool fTopLevelTable = false;
73         internal bool fInitInProgress = false;
74         internal bool fEnableCascading = true;
75         internal bool fIsSchemaLoading = false;
76         private bool fBoundToDocument;        // for XmlDataDocument
77
78         // Events
79         private PropertyChangedEventHandler onPropertyChangingDelegate;
80         private MergeFailedEventHandler onMergeFailed;
81         private DataRowCreatedEventHandler onDataRowCreated;   // Internal for XmlDataDocument only
82         private DataSetClearEventhandler onClearFunctionCalled;   // Internal for XmlDataDocument only
83         private System.EventHandler onInitialized;
84
85
86         internal readonly static DataTable[] zeroTables = new DataTable[0];
87         internal string mainTableName = "";
88
89         //default remoting format is XML
90         private SerializationFormat _remotingFormat = SerializationFormat.Xml;
91
92         private object _defaultViewManagerLock = new Object();
93
94         private static int _objectTypeCount; // Bid counter
95         private readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);
96         private static XmlSchemaComplexType schemaTypeForWSDL = null;
97
98         internal bool UseDataSetSchemaOnly; // UseDataSetSchemaOnly  , for YUKON
99         internal bool UdtIsWrapped; // if UDT is wrapped , for YUKON
100
101         /// <devdoc>
102         /// <para>Initializes a new instance of the <see cref='System.Data.DataSet'/> class.</para>
103         /// </devdoc>
104         public DataSet() {
105             GC.SuppressFinalize(this);
106             Bid.Trace("<ds.DataSet.DataSet|API> %d#\n", ObjectID); // others will call this constr
107             // Set default locale
108             this.tableCollection = new DataTableCollection(this);
109             this.relationCollection = new DataRelationCollection.DataSetRelationCollection(this);
110             _culture = CultureInfo.CurrentCulture; // Set default locale
111         }
112
113         /// <devdoc>
114         /// <para>Initializes a new instance of a <see cref='System.Data.DataSet'/>
115         /// class with the given name.</para>
116         /// </devdoc>
117         public DataSet(string dataSetName) 
118             : this()
119         {
120             this.DataSetName = dataSetName;
121         }
122
123         [
124         DefaultValue(SerializationFormat.Xml)
125         ]
126         public SerializationFormat RemotingFormat {
127             get {
128                 return _remotingFormat;
129             }
130             set {
131                 if (value != SerializationFormat.Binary && value != SerializationFormat.Xml) {
132                     throw ExceptionBuilder.InvalidRemotingFormat(value);
133                 }
134                 _remotingFormat = value;
135                 // this property is inherited to DataTable from DataSet.So we set this value to DataTable also
136                 for (int i = 0; i < Tables.Count; i++) {
137                     Tables[i].RemotingFormat = value;
138                 }
139             }
140         }
141
142         [BrowsableAttribute(false)]
143         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
144         public virtual SchemaSerializationMode SchemaSerializationMode { //Typed DataSet calls into this
145             get {
146                 return SchemaSerializationMode.IncludeSchema;
147             }
148             set {
149                 if (value != SchemaSerializationMode.IncludeSchema) {
150                     throw ExceptionBuilder.CannotChangeSchemaSerializationMode();
151                 }
152             }
153         }
154
155         //      Check whether the stream is binary serialized.
156         // 'static' function that consumes SerializationInfo
157         protected bool IsBinarySerialized(SerializationInfo info, StreamingContext context) {// mainly for typed DS
158             // our default remoting format is XML
159             SerializationFormat remotingFormat = SerializationFormat.Xml;
160             SerializationInfoEnumerator e = info.GetEnumerator();
161
162             while (e.MoveNext()) {
163                 if (e.Name == "DataSet.RemotingFormat") {//DataSet.RemotingFormat does not exist in V1/V1.1 versions
164                     remotingFormat = (SerializationFormat)e.Value;
165                     break;
166                 }
167             }
168             return (remotingFormat == SerializationFormat.Binary);
169         }
170
171         //      Should Schema be included during Serialization
172         // 'static' function that consumes SerializationInfo
173         protected SchemaSerializationMode DetermineSchemaSerializationMode(SerializationInfo info, StreamingContext context) { //Typed DataSet calls into this
174             SchemaSerializationMode schemaSerializationMode = SchemaSerializationMode.IncludeSchema;
175             SerializationInfoEnumerator e = info.GetEnumerator();
176
177             while (e.MoveNext()) {
178                 if (e.Name == "SchemaSerializationMode.DataSet") { //SchemaSerializationMode.DataSet does not exist in V1/V1.1 versions
179                     schemaSerializationMode = (SchemaSerializationMode)e.Value;
180                     break;
181                 }
182             }
183             return schemaSerializationMode;
184         }
185
186         protected SchemaSerializationMode DetermineSchemaSerializationMode(XmlReader reader) { //Typed DataSet calls into this
187             SchemaSerializationMode schemaSerializationMode = SchemaSerializationMode.IncludeSchema;
188             reader.MoveToContent();
189             if (reader.NodeType == XmlNodeType.Element) {
190                 if (reader.HasAttributes) {
191                     string attribValue = reader.GetAttribute(Keywords.MSD_SCHEMASERIALIZATIONMODE, Keywords.MSDNS);
192                     if ((String.Compare(attribValue, Keywords.MSD_EXCLUDESCHEMA, StringComparison.OrdinalIgnoreCase) == 0)) {
193                         schemaSerializationMode = SchemaSerializationMode.ExcludeSchema;
194                     }
195                     else if ((String.Compare(attribValue, Keywords.MSD_INCLUDESCHEMA, StringComparison.OrdinalIgnoreCase) == 0)) {
196                         schemaSerializationMode = SchemaSerializationMode.IncludeSchema;
197                     }
198                     else if (attribValue != null) { // if attrib does not exist, then don't throw
199                         throw ExceptionBuilder.InvalidSchemaSerializationMode(typeof(SchemaSerializationMode), attribValue);
200                     }
201                 }
202             }
203             return schemaSerializationMode;
204         }
205
206
207         //      Deserialize all the tables data of the dataset from binary/xml stream.
208         // 'instance' method that consumes SerializationInfo
209         protected void GetSerializationData(SerializationInfo info, StreamingContext context) {// mainly for typed DS
210             SerializationFormat remotingFormat = SerializationFormat.Xml;
211             SerializationInfoEnumerator e = info.GetEnumerator();
212
213             while (e.MoveNext()) {
214                 if (e.Name == "DataSet.RemotingFormat") { //DataSet.RemotingFormat does not exist in V1/V1.1 versions
215                     remotingFormat = (SerializationFormat)e.Value;
216                     break;
217                 }
218             }
219             DeserializeDataSetData(info, context, remotingFormat);
220         }
221
222
223         //      Deserialize all the tables schema and data of the dataset from binary/xml stream.
224         protected DataSet(SerializationInfo info, StreamingContext context)
225             : this(info, context, true) {
226         }
227         protected DataSet(SerializationInfo info, StreamingContext context, bool ConstructSchema)
228             : this() {
229             SerializationFormat remotingFormat = SerializationFormat.Xml;
230             SchemaSerializationMode schemaSerializationMode = SchemaSerializationMode.IncludeSchema;
231             SerializationInfoEnumerator e = info.GetEnumerator();
232
233             while (e.MoveNext()) {
234                 switch (e.Name) {
235                     case "DataSet.RemotingFormat": //DataSet.RemotingFormat does not exist in V1/V1.1 versions
236                         remotingFormat = (SerializationFormat)e.Value;
237                         break;
238                     case "SchemaSerializationMode.DataSet": //SchemaSerializationMode.DataSet does not exist in V1/V1.1 versions
239                         schemaSerializationMode = (SchemaSerializationMode)e.Value;
240                         break;
241                 }
242             }
243
244             if (schemaSerializationMode == SchemaSerializationMode.ExcludeSchema) {
245                 InitializeDerivedDataSet();
246             }
247
248             // adding back this check will fix typed dataset XML remoting, but we have to fix case that 
249             // a class inherits from DataSet and just relies on DataSet to deserialize (see SQL BU DT 374717)
250             // to fix that case also, we need to add a flag and add it to below check so return (no-op) will be 
251             // conditional (flag needs to be set in TypedDataSet
252             if (remotingFormat == SerializationFormat.Xml && !ConstructSchema /* && this.GetType() != typeof(DataSet)*/) {
253                 return; //For typed dataset xml remoting, this is a no-op
254             }
255             DeserializeDataSet(info, context, remotingFormat, schemaSerializationMode);
256         }
257
258
259
260         [System.Security.Permissions.SecurityPermissionAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Flags = System.Security.Permissions.SecurityPermissionFlag.SerializationFormatter)]
261         public virtual void GetObjectData(SerializationInfo info, StreamingContext context) {
262             SerializationFormat remotingFormat = RemotingFormat;
263             SerializeDataSet(info, context, remotingFormat);
264         }
265
266         //      Deserialize all the tables data of the dataset from binary/xml stream.
267         protected virtual void InitializeDerivedDataSet() {
268             return;
269         }
270
271         //      Serialize all the tables.
272         private void SerializeDataSet(SerializationInfo info, StreamingContext context, SerializationFormat remotingFormat) {
273             Debug.Assert(info != null);
274             info.AddValue("DataSet.RemotingVersion", new Version(2, 0));
275
276             // SqlHotFix 299, SerializationFormat enumeration types don't exist in V1.1 SP1
277             if (SerializationFormat.Xml != remotingFormat) {
278                 info.AddValue("DataSet.RemotingFormat", remotingFormat);
279             }
280
281             // SqlHotFix 299, SchemaSerializationMode enumeration types don't exist in V1.1 SP1
282             if (SchemaSerializationMode.IncludeSchema != SchemaSerializationMode) {
283                 //SkipSchemaDuringSerialization
284                 info.AddValue("SchemaSerializationMode.DataSet", SchemaSerializationMode);
285             }
286
287             if (remotingFormat != SerializationFormat.Xml) {
288                 if (SchemaSerializationMode == SchemaSerializationMode.IncludeSchema) {
289
290                     //DataSet public state properties
291                     SerializeDataSetProperties(info, context);
292
293                     //Tables Count
294                     info.AddValue("DataSet.Tables.Count", Tables.Count);
295
296                     //Tables, Columns, Rows
297                     for (int i = 0; i < Tables.Count; i++) {
298                         BinaryFormatter bf = new BinaryFormatter(null, new StreamingContext(context.State, false));
299                         MemoryStream memStream = new MemoryStream();
300                         bf.Serialize(memStream, Tables[i]);
301                         memStream.Position = 0;
302                         info.AddValue(String.Format(CultureInfo.InvariantCulture, "DataSet.Tables_{0}", i), memStream.GetBuffer());
303                     }
304
305                     //Constraints
306                     for (int i = 0; i < Tables.Count; i++) {
307                         Tables[i].SerializeConstraints(info, context, i, true);
308                     }
309
310                     //Relations
311                     SerializeRelations(info, context);
312
313                     //Expression Columns
314                     for (int i = 0; i < Tables.Count; i++) {
315                         Tables[i].SerializeExpressionColumns(info, context, i);
316                     }
317                 }
318                 else {
319                     //Serialize  DataSet public properties.
320                     SerializeDataSetProperties(info, context);
321                 }
322                 //Rows
323                 for (int i = 0; i < Tables.Count; i++) {
324                     Tables[i].SerializeTableData(info, context, i);
325                 }
326             } else { // old behaviour
327
328                 String strSchema = this.GetXmlSchemaForRemoting(null);
329
330                 String strData = null;
331                 info.AddValue(KEY_XMLSCHEMA, strSchema);
332
333                 StringBuilder strBuilder;
334                 strBuilder = new StringBuilder(EstimatedXmlStringSize() * 2);
335                 StringWriter strWriter = new StringWriter(strBuilder, CultureInfo.InvariantCulture);
336                 XmlTextWriter w = new XmlTextWriter(strWriter);
337                 WriteXml(w, XmlWriteMode.DiffGram);
338                 strData = strWriter.ToString();
339                 info.AddValue(KEY_XMLDIFFGRAM, strData);
340             }
341         }
342
343         //      Deserialize all the tables - marked internal so that DataTable can call into this
344         internal void DeserializeDataSet(SerializationInfo info, StreamingContext context, SerializationFormat remotingFormat, SchemaSerializationMode schemaSerializationMode) {
345             // deserialize schema
346             DeserializeDataSetSchema(info, context, remotingFormat, schemaSerializationMode);
347             // deserialize data
348             DeserializeDataSetData(info, context, remotingFormat);
349         }
350
351         //      Deserialize schema.
352         private void DeserializeDataSetSchema(SerializationInfo info, StreamingContext context, SerializationFormat remotingFormat, SchemaSerializationMode schemaSerializationMode) {
353             if (remotingFormat != SerializationFormat.Xml) {
354                 if (schemaSerializationMode == SchemaSerializationMode.IncludeSchema) {
355                     //DataSet public state properties
356                     DeserializeDataSetProperties(info, context);
357
358                     //Tables Count
359                     int tableCount = info.GetInt32("DataSet.Tables.Count");
360
361                     //Tables, Columns, Rows
362                     for (int i = 0; i < tableCount; i++) {
363                         Byte[] buffer = (Byte[])info.GetValue(String.Format(CultureInfo.InvariantCulture, "DataSet.Tables_{0}", i), typeof(Byte[]));
364                         MemoryStream memStream = new MemoryStream(buffer);
365                         memStream.Position = 0;
366                         BinaryFormatter bf = new BinaryFormatter(null, new StreamingContext(context.State, false));
367                         DataTable dt = (DataTable)bf.Deserialize(memStream);
368                         Tables.Add(dt);
369                     }
370
371                     //Constraints
372                     for (int i = 0; i < tableCount; i++) {
373                         Tables[i].DeserializeConstraints(info, context,  /* table index */i,  /* serialize all constraints */ true); //
374                     }
375
376                     //Relations
377                     DeserializeRelations(info, context);
378
379                     //Expression Columns
380                     for (int i = 0; i < tableCount; i++) {
381                         Tables[i].DeserializeExpressionColumns(info, context, i);
382                     }
383                 } else {
384                     //DeSerialize DataSet public properties.[Locale, CaseSensitive and EnforceConstraints]
385                     DeserializeDataSetProperties(info, context);
386                 }
387             } else {
388                 string strSchema = (String)info.GetValue(KEY_XMLSCHEMA, typeof(System.String));
389
390                 if (strSchema != null) {
391                     this.ReadXmlSchema(new XmlTextReader(new StringReader(strSchema)), true);
392                 }
393             }
394         }
395
396         //        Deserialize all  data.
397         private void DeserializeDataSetData(SerializationInfo info, StreamingContext context, SerializationFormat remotingFormat) {
398             if (remotingFormat != SerializationFormat.Xml) {
399                 for (int i = 0; i < Tables.Count; i++) {
400                     Tables[i].DeserializeTableData(info, context, i);
401                 }
402             }
403             else {
404                 string strData = (String)info.GetValue(KEY_XMLDIFFGRAM, typeof(System.String));
405
406                 if (strData != null) {
407                     this.ReadXml(new XmlTextReader(new StringReader(strData)), XmlReadMode.DiffGram);
408                 }
409             }
410         }
411
412         //        Serialize just the dataset properties
413         private void SerializeDataSetProperties(SerializationInfo info, StreamingContext context) {
414             //DataSet basic properties
415             info.AddValue("DataSet.DataSetName", DataSetName);
416             info.AddValue("DataSet.Namespace", Namespace);
417             info.AddValue("DataSet.Prefix", Prefix);
418             //DataSet runtime properties
419             info.AddValue("DataSet.CaseSensitive", CaseSensitive);
420             info.AddValue("DataSet.LocaleLCID", Locale.LCID);
421             info.AddValue("DataSet.EnforceConstraints", EnforceConstraints);
422
423             //ExtendedProperties
424             info.AddValue("DataSet.ExtendedProperties", ExtendedProperties);
425         }
426
427         //      DeSerialize dataset properties
428         private void DeserializeDataSetProperties(SerializationInfo info, StreamingContext context) {
429             //DataSet basic properties
430             dataSetName = info.GetString("DataSet.DataSetName");
431             namespaceURI = info.GetString("DataSet.Namespace");
432             _datasetPrefix = info.GetString("DataSet.Prefix");
433             //DataSet runtime properties
434             _caseSensitive = info.GetBoolean("DataSet.CaseSensitive");
435             int lcid = (int)info.GetValue("DataSet.LocaleLCID", typeof(int));
436             _culture = new CultureInfo(lcid);
437             _cultureUserSet = true;
438             enforceConstraints = info.GetBoolean("DataSet.EnforceConstraints");
439
440
441
442             //ExtendedProperties
443             extendedProperties = (PropertyCollection)info.GetValue("DataSet.ExtendedProperties", typeof(PropertyCollection));
444         }
445
446         //        Gets relation info from the dataset.
447         //        ***Schema for Serializing ArrayList of Relations***
448         //        Relations -> [relationName]->[parentTableIndex, parentcolumnIndexes]->[childTableIndex, childColumnIndexes]->[Nested]->[extendedProperties]
449         private void SerializeRelations(SerializationInfo info, StreamingContext context) {
450             ArrayList relationList = new ArrayList();
451
452             foreach (DataRelation rel in Relations) {
453                 int[] parentInfo = new int[rel.ParentColumns.Length + 1];
454
455                 parentInfo[0] = Tables.IndexOf(rel.ParentTable);
456                 for (int j = 1; j < parentInfo.Length; j++) {
457                     parentInfo[j] = rel.ParentColumns[j - 1].Ordinal;
458                 }
459
460                 int[] childInfo = new int[rel.ChildColumns.Length + 1];
461                 childInfo[0] = Tables.IndexOf(rel.ChildTable);
462                 for (int j = 1; j < childInfo.Length; j++) {
463                     childInfo[j] = rel.ChildColumns[j - 1].Ordinal;
464                 }
465
466                 ArrayList list = new ArrayList();
467                 list.Add(rel.RelationName);
468                 list.Add(parentInfo);
469                 list.Add(childInfo);
470                 list.Add(rel.Nested);
471                 list.Add(rel.extendedProperties);
472
473                 relationList.Add(list);
474             }
475             info.AddValue("DataSet.Relations", relationList);
476         }
477
478         /*
479                 Adds relations to the dataset.
480                 ***Schema for Serializing ArrayList of Relations***
481                 Relations -> [relationName]->[parentTableIndex, parentcolumnIndexes]->[childTableIndex, childColumnIndexes]->[Nested]->[extendedProperties]
482         */
483         private void DeserializeRelations(SerializationInfo info, StreamingContext context) {
484             ArrayList relationList = (ArrayList)info.GetValue("DataSet.Relations", typeof(ArrayList));
485
486             foreach (ArrayList list in relationList) {
487                 string relationName = (string)list[0];
488                 int[] parentInfo = (int[])list[1];
489                 int[] childInfo = (int[])list[2];
490                 bool isNested = (bool)list[3];
491                 PropertyCollection extendedProperties = (PropertyCollection)list[4];
492
493                 //ParentKey Columns.
494                 DataColumn[] parentkeyColumns = new DataColumn[parentInfo.Length - 1];
495                 for (int i = 0; i < parentkeyColumns.Length; i++) {
496                     parentkeyColumns[i] = Tables[parentInfo[0]].Columns[parentInfo[i + 1]];
497                 }
498
499                 //ChildKey Columns.
500                 DataColumn[] childkeyColumns = new DataColumn[childInfo.Length - 1];
501                 for (int i = 0; i < childkeyColumns.Length; i++) {
502                     childkeyColumns[i] = Tables[childInfo[0]].Columns[childInfo[i + 1]];
503                 }
504
505                 //Create the Relation, without any constraints[Assumption: The constraints are added earlier than the relations]
506                 DataRelation rel = new DataRelation(relationName, parentkeyColumns, childkeyColumns, false);
507                 rel.CheckMultipleNested = false; // disable the check for multiple nested parent
508                 rel.Nested = isNested;
509                 rel.extendedProperties = extendedProperties;
510
511                 Relations.Add(rel);
512                 rel.CheckMultipleNested = true; // enable the check for multiple nested parent
513             }
514         }
515
516         internal void FailedEnableConstraints() {
517             this.EnforceConstraints = false;
518             throw ExceptionBuilder.EnforceConstraint();
519         }
520
521         /// <devdoc>
522         ///    <para>
523         ///       Gets or sets a value indicating whether string
524         ///       comparisons within <see cref='System.Data.DataTable'/>
525         ///       objects are
526         ///       case-sensitive.
527         ///    </para>
528         /// </devdoc>
529         [
530         ResCategoryAttribute(Res.DataCategory_Data),
531         DefaultValue(false),
532         ResDescriptionAttribute(Res.DataSetCaseSensitiveDescr)
533         ]
534         public bool CaseSensitive {
535             get {
536                 return _caseSensitive;
537             }
538             set {
539                 if (_caseSensitive != value)
540                 {
541                     bool oldValue = _caseSensitive;
542                     _caseSensitive = value;
543
544                     if (!ValidateCaseConstraint()) {
545                         _caseSensitive = oldValue;
546                         throw ExceptionBuilder.CannotChangeCaseLocale();
547                     }
548
549                     foreach (DataTable table in Tables) {
550                         table.SetCaseSensitiveValue(value, false, true);
551                     }
552                 }
553             }
554         }
555
556         bool System.ComponentModel.IListSource.ContainsListCollection {
557             get {
558                 return true;
559             }
560         }
561
562         /// <devdoc>
563         /// <para>Gets a custom view of the data contained by the <see cref='System.Data.DataSet'/> , one
564         ///    that allows filtering, searching, and navigating through the custom data view.</para>
565         /// </devdoc>
566         [Browsable(false), ResDescriptionAttribute(Res.DataSetDefaultViewDescr)]
567         public DataViewManager DefaultViewManager {
568             get {
569                 if (defaultViewManager == null) {
570                     lock (_defaultViewManagerLock) {
571                         if (defaultViewManager == null) {
572                             defaultViewManager = new DataViewManager(this, true);
573                         }
574                     }
575                 }
576                 return defaultViewManager;
577             }
578         }
579
580         /// <devdoc>
581         ///    <para>Gets or sets a value indicating whether constraint rules are followed when
582         ///       attempting any update operation.</para>
583         /// </devdoc>
584         [DefaultValue(true), ResDescriptionAttribute(Res.DataSetEnforceConstraintsDescr)]
585         public bool EnforceConstraints {
586             get {
587                 return enforceConstraints;
588             }
589             set {
590                 IntPtr hscp;
591                 Bid.ScopeEnter(out hscp, "<ds.DataSet.set_EnforceConstraints|API> %d#, %d{bool}\n", ObjectID, value);
592                 try {
593                     if (this.enforceConstraints != value) {
594                         if (value)
595                             EnableConstraints();
596                         this.enforceConstraints = value;
597                     }
598                 }
599                 finally {
600                     Bid.ScopeLeave(ref hscp);
601                 }
602             }
603         }
604
605         internal void RestoreEnforceConstraints(bool value) {
606             this.enforceConstraints = value;
607         }
608
609         internal void EnableConstraints()
610         {
611             IntPtr hscp;
612             Bid.ScopeEnter(out hscp, "<ds.DataSet.EnableConstraints|INFO> %d#\n", ObjectID);
613             try {
614                 bool errors = false;
615                 for (ConstraintEnumerator constraints = new ConstraintEnumerator(this); constraints.GetNext(); ) {
616                     Constraint constraint = (Constraint)constraints.GetConstraint();
617                     errors |= constraint.IsConstraintViolated();
618                 }
619
620                 foreach (DataTable table in Tables) {
621                     foreach (DataColumn column in table.Columns) {
622                         if (!column.AllowDBNull) {
623                             errors |= column.IsNotAllowDBNullViolated();
624                         }
625                         if (column.MaxLength >= 0) {
626                             errors |= column.IsMaxLengthViolated();
627                         }
628                     }
629                 }
630
631                 if (errors)
632                     this.FailedEnableConstraints();
633             }
634             finally {
635                 Bid.ScopeLeave(ref hscp);
636             }
637         }
638
639         /// <devdoc>
640         ///    <para>Gets or
641         ///       sets the name of this <see cref='System.Data.DataSet'/> .</para>
642         /// </devdoc>
643         [
644         ResCategoryAttribute(Res.DataCategory_Data),
645         DefaultValue(""),
646         ResDescriptionAttribute(Res.DataSetDataSetNameDescr)
647         ]
648         public string DataSetName {
649             get {
650                 return dataSetName;
651             }
652             set {
653                 Bid.Trace("<ds.DataSet.set_DataSetName|API> %d#, '%ls'\n", ObjectID, value);
654                 if (value != dataSetName) {
655                     if (value == null || value.Length == 0)
656                         throw ExceptionBuilder.SetDataSetNameToEmpty();
657                     DataTable conflicting = Tables[value, Namespace];
658                     if ((conflicting != null) && (!conflicting.fNestedInDataset))
659                         throw ExceptionBuilder.SetDataSetNameConflicting(value);
660                     RaisePropertyChanging("DataSetName");
661                     this.dataSetName = value;
662                 }
663             }
664         }
665
666         /// <devdoc>
667         /// </devdoc>
668         [
669         DefaultValue(""),
670         ResCategoryAttribute(Res.DataCategory_Data),
671         ResDescriptionAttribute(Res.DataSetNamespaceDescr)
672         ]
673         public string Namespace {
674             get {
675                 return namespaceURI;
676             }
677             set {
678                 Bid.Trace("<ds.DataSet.set_Namespace|API> %d#, '%ls'\n", ObjectID, value);
679                 if (value == null)
680                     value = String.Empty;
681                 if (value != namespaceURI) {
682                     RaisePropertyChanging("Namespace");
683                     foreach (DataTable dt in Tables) {
684                         if (dt.tableNamespace != null)
685                             continue;
686                         if ((dt.NestedParentRelations.Length == 0) ||
687                             (dt.NestedParentRelations.Length == 1 && dt.NestedParentRelations[0].ChildTable == dt)) {
688                             //                            dt.SelfNestedWithOneRelation) { // this is wrong bug it was previous behavior
689                             if (Tables.Contains(dt.TableName, value, false, true))
690                                 throw ExceptionBuilder.DuplicateTableName2(dt.TableName, value);
691                             dt.CheckCascadingNamespaceConflict(value);
692                             dt.DoRaiseNamespaceChange();
693                         }
694                     }
695                     namespaceURI = value;
696
697
698                     if (Common.ADP.IsEmpty(value))
699                         _datasetPrefix = String.Empty;
700                 }
701             }
702         }
703
704         /// <devdoc>
705         ///    <para>[To be supplied.]</para>
706         /// </devdoc>
707         [
708         DefaultValue(""),
709         ResCategoryAttribute(Res.DataCategory_Data),
710         ResDescriptionAttribute(Res.DataSetPrefixDescr)
711         ]
712         public string Prefix {
713             get { return _datasetPrefix; }
714             set {
715                 if (value == null)
716                     value = String.Empty;
717
718                 if ((XmlConvert.DecodeName(value) == value) &&
719                     (XmlConvert.EncodeName(value) != value))
720                     throw ExceptionBuilder.InvalidPrefix(value);
721
722
723                 if (value != _datasetPrefix) {
724                     RaisePropertyChanging("Prefix");
725                     _datasetPrefix = value;
726                 }
727             }
728         }
729
730         /// <devdoc>
731         ///    <para>Gets the collection of custom user information.</para>
732         /// </devdoc>
733         [
734         ResCategoryAttribute(Res.DataCategory_Data),
735         Browsable(false),
736         ResDescriptionAttribute(Res.ExtendedPropertiesDescr)
737         ]
738         public PropertyCollection ExtendedProperties {
739             get {
740                 if (extendedProperties == null) {
741                     extendedProperties = new PropertyCollection();
742                 }
743                 return extendedProperties;
744             }
745         }
746
747         /// <devdoc>
748         ///    <para>
749         ///       Gets a value indicating whether there are errors in any
750         ///       of the rows in any of the tables of this <see cref='System.Data.DataSet'/> .
751         ///    </para>
752         /// </devdoc>
753         [Browsable(false), ResDescriptionAttribute(Res.DataSetHasErrorsDescr)]
754         public bool HasErrors {
755             get {
756                 for (int i = 0; i < Tables.Count; i++) {
757                     if (Tables[i].HasErrors)
758                         return true;
759                 }
760                 return false;
761             }
762         }
763
764         [Browsable(false)]
765         public bool IsInitialized {
766             get {
767                 return !fInitInProgress;
768             }
769         }
770
771         /// <devdoc>
772         ///    <para>
773         ///       Gets or sets the locale information used to compare strings within the table.
774         ///    </para>
775         /// </devdoc>
776         [
777         ResCategoryAttribute(Res.DataCategory_Data),
778         ResDescriptionAttribute(Res.DataSetLocaleDescr)
779         ]
780         public CultureInfo Locale {
781             get {
782                 // used for comparing not formating/parsing
783                 Debug.Assert(null != _culture, "DataSet.Locale: null culture");
784                 return _culture;
785             }
786             set {
787                 IntPtr hscp;
788                 Bid.ScopeEnter(out hscp, "<ds.DataSet.set_Locale|API> %d#\n", ObjectID);
789                 try {
790                     if (value != null) {
791                         if (!_culture.Equals(value)) {
792                             SetLocaleValue(value, true);
793                         }
794                         _cultureUserSet = true;
795                     }
796                 }
797                 finally {
798                     Bid.ScopeLeave(ref hscp);
799                 }
800             }
801         }
802
803         internal void SetLocaleValue(CultureInfo value, bool userSet) {
804             bool flag = false;
805             bool exceptionThrown = false;
806             int tableCount = 0;
807
808             CultureInfo oldLocale = _culture;
809             bool oldUserSet = _cultureUserSet;
810
811             try {
812                 _culture = value;
813                 _cultureUserSet = userSet;
814
815                 foreach (DataTable table in Tables) {
816                     if (!table.ShouldSerializeLocale()) {
817                         bool retchk = table.SetLocaleValue(value, false, false);
818                         //Debug.Assert(retchk == table.ShouldSerializeLocale(), "unexpected setting of table locale"); may fire with Deserialize
819                     }
820                 }
821
822                 flag = ValidateLocaleConstraint();
823                 if (flag) {
824                     flag = false;
825                     foreach (DataTable table in Tables) {
826                         tableCount++;
827                         if (!table.ShouldSerializeLocale()) {
828                             table.SetLocaleValue(value, false, true);
829                         }
830                     }
831                     flag = true;
832                 }
833             }
834             catch {
835                 exceptionThrown = true;
836                 throw;
837             }
838             finally {
839                 if (!flag) { // reset old locale if ValidationFailed or exception thrown
840                     _culture = oldLocale;
841                     _cultureUserSet = oldUserSet;
842                     foreach (DataTable table in Tables) {
843                         if (!table.ShouldSerializeLocale()) {
844                             table.SetLocaleValue(oldLocale, false, false);
845                         }
846                     }
847                     try {
848                         for (int i = 0; i < tableCount; ++i) {
849                             if (!Tables[i].ShouldSerializeLocale()) {
850                                 Tables[i].SetLocaleValue(oldLocale, false, true);
851                             }
852                         }
853                     }
854                     catch (Exception e) {
855                         if (!Common.ADP.IsCatchableExceptionType(e)) {
856                             throw;
857                         }
858                         Common.ADP.TraceExceptionWithoutRethrow(e);
859                     }
860                     if (!exceptionThrown) {
861                         throw ExceptionBuilder.CannotChangeCaseLocale(null);
862                     }
863                 }
864             }
865         }
866
867         internal bool ShouldSerializeLocale() {
868             // this method is used design-time scenarios via reflection
869             //   by the property grid to show the Locale property in bold or not
870             //   by the code dom for persisting the Locale property or not
871
872             // we always want the locale persisted if set by user or different the current thread
873             // but that logic should by performed by the serializion code
874             return _cultureUserSet;
875         }
876
877         /// <devdoc>
878         ///    <para>[To be supplied.]</para>
879         /// </devdoc>
880         [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
881         public override ISite Site {
882             get {
883                 return base.Site;
884             }
885             set {
886                 ISite oldSite = Site;
887                 if (value == null && oldSite != null) {
888                     IContainer cont = oldSite.Container;
889
890                     if (cont != null) {
891                         for (int i = 0; i < Tables.Count; i++) {
892                             if (Tables[i].Site != null) {
893                                 cont.Remove(Tables[i]);
894                             }
895                         }
896                     }
897                 }
898                 base.Site = value;
899             }
900         }
901
902
903
904         /// <devdoc>
905         ///    <para>
906         ///       Get the collection of relations that link tables and
907         ///       allow navigation from parent tables to child tables.
908         ///    </para>
909         /// </devdoc>
910         [
911         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
912         ResCategoryAttribute(Res.DataCategory_Data),
913         ResDescriptionAttribute(Res.DataSetRelationsDescr)
914         ]
915         public DataRelationCollection Relations {
916             get {
917                 return relationCollection;
918             }
919         }
920
921         /// <devdoc>
922         ///    <para>
923         ///       Indicates whether <see cref='Relations'/> property should be persisted.
924         ///    </para>
925         /// </devdoc>
926         protected virtual bool ShouldSerializeRelations() {
927             return true; /*Relations.Count > 0;*/ // VS7 300569
928         }
929
930         /// <devdoc>
931         ///    <para>
932         ///       Resets the <see cref='System.Data.DataSet.Relations'/> property to its default state.
933         ///    </para>
934         /// </devdoc>
935         private void ResetRelations()
936         {
937             Relations.Clear();
938         }
939
940         /// <devdoc>
941         /// <para>Gets the collection of tables contained in the <see cref='System.Data.DataSet'/>.</para>
942         /// </devdoc>
943         [
944         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
945         ResCategoryAttribute(Res.DataCategory_Data),
946         ResDescriptionAttribute(Res.DataSetTablesDescr)
947         ]
948         public DataTableCollection Tables {
949             get {
950                 return tableCollection;
951             }
952         }
953
954         /// <devdoc>
955         ///    <para>
956         ///       Indicates whether <see cref='System.Data.DataSet.Tables'/> property should be persisted.
957         ///    </para>
958         /// </devdoc>
959         protected virtual bool ShouldSerializeTables() {
960             return true;/*(Tables.Count > 0);*/ // VS7 300569
961         }
962
963         /// <devdoc>
964         ///    <para>
965         ///       Resets the <see cref='System.Data.DataSet.Tables'/> property to its default state.
966         ///    </para>
967         /// </devdoc>
968         private void ResetTables()
969         {
970             Tables.Clear();
971         }
972
973         internal bool FBoundToDocument {
974             get {
975                 return fBoundToDocument;
976             }
977             set {
978                 fBoundToDocument = value;
979             }
980         }
981
982         /// <devdoc>
983         ///    <para>
984         ///       Commits all the changes made to this <see cref='System.Data.DataSet'/> since it was loaded or the last
985         ///       time <see cref='System.Data.DataSet.AcceptChanges'/> was called.
986         ///    </para>
987         /// </devdoc>
988         public void AcceptChanges()
989         {
990             IntPtr hscp;
991             Bid.ScopeEnter(out hscp, "<ds.DataSet.AcceptChanges|API> %d#\n", ObjectID);
992             try {
993                 for (int i = 0; i < Tables.Count; i++)
994                     Tables[i].AcceptChanges();
995             }
996             finally {
997                 Bid.ScopeLeave(ref hscp);
998             }
999         }
1000
1001         internal event PropertyChangedEventHandler PropertyChanging {
1002             add {
1003                 onPropertyChangingDelegate += value;
1004             }
1005             remove {
1006                 onPropertyChangingDelegate -= value;
1007             }
1008         }
1009
1010         /// <devdoc>
1011         ///    <para>Occurs when attempting to merge schemas for two tables with the same
1012         ///       name.</para>
1013         /// </devdoc>
1014         [
1015          ResCategoryAttribute(Res.DataCategory_Action),
1016          ResDescriptionAttribute(Res.DataSetMergeFailedDescr)
1017         ]
1018         public event MergeFailedEventHandler MergeFailed {
1019             add {
1020                 onMergeFailed += value;
1021             }
1022             remove {
1023                 onMergeFailed -= value;
1024             }
1025         }
1026
1027         internal event DataRowCreatedEventHandler DataRowCreated {
1028             add {
1029                 onDataRowCreated += value;
1030             }
1031             remove {
1032                 onDataRowCreated -= value;
1033             }
1034         }
1035
1036         internal event DataSetClearEventhandler ClearFunctionCalled {
1037             add {
1038                 onClearFunctionCalled += value;
1039             }
1040             remove {
1041                 onClearFunctionCalled -= value;
1042             }
1043         }
1044
1045         [
1046          ResCategoryAttribute(Res.DataCategory_Action),
1047          ResDescriptionAttribute(Res.DataSetInitializedDescr)
1048         ]
1049         public event System.EventHandler Initialized {
1050             add {
1051                 onInitialized += value;
1052             }
1053             remove {
1054                 onInitialized -= value;
1055             }
1056         }
1057
1058         public void BeginInit() {
1059             fInitInProgress = true;
1060         }
1061
1062         public void EndInit() {
1063             Tables.FinishInitCollection();
1064             for (int i = 0; i < Tables.Count; i++) {
1065                 Tables[i].Columns.FinishInitCollection();
1066             }
1067
1068             for (int i = 0; i < Tables.Count; i++) {
1069                 Tables[i].Constraints.FinishInitConstraints();
1070             }
1071
1072             ((DataRelationCollection.DataSetRelationCollection)Relations).FinishInitRelations();
1073
1074             fInitInProgress = false;
1075             OnInitialized();
1076         }
1077
1078         /// <devdoc>
1079         /// <para>Clears the <see cref='System.Data.DataSet'/> of any data by removing all rows in all tables.</para>
1080         /// </devdoc>
1081         public void Clear()
1082         {
1083             IntPtr hscp;
1084             Bid.ScopeEnter(out hscp, "<ds.DataSet.Clear|API> %d#\n", ObjectID);
1085             try {
1086                 OnClearFunctionCalled(null);
1087                 bool fEnforce = EnforceConstraints;
1088                 EnforceConstraints = false;
1089                 for (int i = 0; i < Tables.Count; i++)
1090                     Tables[i].Clear();
1091                 EnforceConstraints = fEnforce;
1092             }
1093             finally {
1094                 Bid.ScopeLeave(ref hscp);
1095             }
1096         }
1097
1098         /// <devdoc>
1099         /// <para>Clones the structure of the <see cref='System.Data.DataSet'/>, including all <see cref='System.Data.DataTable'/> schemas, relations, and
1100         ///    constraints.</para>
1101         /// </devdoc>
1102         // Prevent inlining so that reflection calls are not moved to caller that may be in a different assembly that may have a different grant set.
1103         [MethodImpl(MethodImplOptions.NoInlining)] 
1104         public virtual DataSet Clone() {
1105             IntPtr hscp;
1106             Bid.ScopeEnter(out hscp, "<ds.DataSet.Clone|API> %d#\n", ObjectID);
1107             try {
1108                 DataSet ds = (DataSet)Activator.CreateInstance(this.GetType(), true);
1109
1110                 if (ds.Tables.Count > 0)  // [....] : To clean up all the schema in strong typed dataset.
1111                     ds.Reset();
1112
1113                 //copy some original dataset properties
1114                 ds.DataSetName = DataSetName;
1115                 ds.CaseSensitive = CaseSensitive;
1116                 ds._culture = _culture;
1117                 ds._cultureUserSet = _cultureUserSet;
1118                 ds.EnforceConstraints = EnforceConstraints;
1119                 ds.Namespace = Namespace;
1120                 ds.Prefix = Prefix;
1121                 ds.RemotingFormat = RemotingFormat;
1122                 ds.fIsSchemaLoading = true; //delay expression evaluation
1123
1124
1125                 // ...Tables...
1126                 DataTableCollection tbls = Tables;
1127                 for (int i = 0; i < tbls.Count; i++) {
1128                     DataTable dt = tbls[i].Clone(ds);
1129                     dt.tableNamespace = tbls[i].Namespace; // hardcode the namespace for a second to not mess up
1130                     // DataRelation cloning.
1131                     ds.Tables.Add(dt);
1132                 }
1133
1134                 // ...Constraints...
1135                 for (int i = 0; i < tbls.Count; i++) {
1136                     ConstraintCollection constraints = tbls[i].Constraints;
1137                     for (int j = 0; j < constraints.Count; j++) {
1138                         if (constraints[j] is UniqueConstraint)
1139                             continue;
1140                         ForeignKeyConstraint foreign = constraints[j] as ForeignKeyConstraint;
1141                         if (foreign.Table == foreign.RelatedTable)
1142                             continue;// we have already added this foreign key in while cloning the datatable
1143                         ds.Tables[i].Constraints.Add(constraints[j].Clone(ds));
1144                     }
1145                 }
1146
1147                 // ...Relations...
1148                 DataRelationCollection rels = Relations;
1149                 for (int i = 0; i < rels.Count; i++) {
1150                     DataRelation rel = rels[i].Clone(ds);
1151                     rel.CheckMultipleNested = false; // disable the check for multiple nested parent
1152                     ds.Relations.Add(rel);
1153                     rel.CheckMultipleNested = true; // enable the check for multiple nested parent
1154                 }
1155
1156                 // ...Extended Properties...
1157                 if (this.extendedProperties != null) {
1158                     foreach (Object key in this.extendedProperties.Keys) {
1159                         ds.ExtendedProperties[key] = this.extendedProperties[key];
1160                     }
1161                 }
1162
1163                 foreach (DataTable table in Tables)
1164                     foreach (DataColumn col in table.Columns)
1165                         if (col.Expression.Length != 0)
1166                             ds.Tables[table.TableName, table.Namespace].Columns[col.ColumnName].Expression = col.Expression;
1167
1168                 for (int i = 0; i < tbls.Count; i++) {
1169                     ds.Tables[i].tableNamespace = tbls[i].tableNamespace; // undo the hardcoding of the namespace
1170                 }
1171
1172                 ds.fIsSchemaLoading = false; //reactivate column computations
1173
1174                 return ds;
1175             }
1176             finally {
1177                 Bid.ScopeLeave(ref hscp);
1178             }
1179         }
1180
1181         /// <devdoc>
1182         /// <para>Copies both the structure and data for this <see cref='System.Data.DataSet'/>.</para>
1183         /// </devdoc>
1184         public DataSet Copy()
1185         {
1186             IntPtr hscp;
1187             Bid.ScopeEnter(out hscp, "<ds.DataSet.Copy|API> %d#\n", ObjectID);
1188             try {
1189                 DataSet dsNew = Clone();
1190                 bool fEnforceConstraints = dsNew.EnforceConstraints;
1191                 dsNew.EnforceConstraints = false;
1192                 foreach (DataTable table in this.Tables)
1193                 {
1194                     DataTable destTable = dsNew.Tables[table.TableName, table.Namespace];
1195
1196                     foreach (DataRow row in table.Rows)
1197                         table.CopyRow(destTable, row);
1198                 }
1199
1200                 dsNew.EnforceConstraints = fEnforceConstraints;
1201
1202                 return dsNew;
1203             }
1204             finally {
1205                 Bid.ScopeLeave(ref hscp);
1206             }
1207         }
1208
1209         internal Int32 EstimatedXmlStringSize()
1210         {
1211             Int32 bytes = 100;
1212             for (int i = 0; i < Tables.Count; i++) {
1213                 Int32 rowBytes = (Tables[i].TableName.Length + 4) << 2;
1214                 DataTable table = Tables[i];
1215                 for (int j = 0; j < table.Columns.Count; j++) {
1216                     rowBytes += ((table.Columns[j].ColumnName.Length + 4) << 2);
1217                     rowBytes += 20;
1218                 }
1219                 bytes += table.Rows.Count * rowBytes;
1220             }
1221
1222             return bytes;
1223         }
1224
1225         /// <devdoc>
1226         /// <para>Returns a copy of the <see cref='System.Data.DataSet'/> that contains all changes made to
1227         ///    it since it was loaded or <see cref='System.Data.DataSet.AcceptChanges'/>
1228         ///    was last called.</para>
1229         /// </devdoc>
1230         public DataSet GetChanges()
1231         {
1232             return GetChanges(DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
1233         }
1234
1235         private struct TableChanges {
1236             private BitArray _rowChanges;
1237             private int _hasChanges;
1238
1239             internal TableChanges(int rowCount) {
1240                 _rowChanges = new BitArray(rowCount);
1241                 _hasChanges = 0;
1242             }
1243             internal int HasChanges {
1244                 get { return _hasChanges; }
1245                 set { _hasChanges = value; }
1246             }
1247             internal bool this[int index] {
1248                 get { return _rowChanges[index]; }
1249                 set {
1250                     Debug.Assert(value && !_rowChanges[index], "setting twice or to false");
1251                     _rowChanges[index] = value;
1252                     _hasChanges++;
1253                 }
1254             }
1255         }
1256
1257         public DataSet GetChanges(DataRowState rowStates)
1258         {
1259             IntPtr hscp;
1260             Bid.ScopeEnter(out hscp, "<ds.DataSet.GetChanges|API> %d#, rowStates=%d{ds.DataRowState}\n", ObjectID, (int)rowStates);
1261             try {
1262                 DataSet dsNew = null;
1263                 bool fEnforceConstraints = false;
1264                 if (0 != (rowStates & ~(DataRowState.Added | DataRowState.Deleted | DataRowState.Modified | DataRowState.Unchanged))) {
1265                     throw ExceptionBuilder.InvalidRowState(rowStates);
1266                 }
1267
1268                 // Initialize all the individual table bitmaps.
1269                 TableChanges[] bitMatrix = new TableChanges[Tables.Count];
1270                 for (int i = 0; i < bitMatrix.Length; ++i) {
1271                     bitMatrix[i] = new TableChanges(Tables[i].Rows.Count);
1272                 }
1273
1274                 // find all the modified rows and their parents
1275                 MarkModifiedRows(bitMatrix, rowStates);
1276
1277                 // copy the changes to a cloned table
1278                 for (int i = 0; i < bitMatrix.Length; ++i) {
1279                     Debug.Assert(0 <= bitMatrix[i].HasChanges, "negative change count");
1280                     if (0 < bitMatrix[i].HasChanges) {
1281                         if (null == dsNew) {
1282                             dsNew = this.Clone();
1283                             fEnforceConstraints = dsNew.EnforceConstraints;
1284                             dsNew.EnforceConstraints = false;
1285                         }
1286
1287                         DataTable table = this.Tables[i];
1288                         DataTable destTable = dsNew.Tables[table.TableName, table.Namespace];
1289                         Debug.Assert(bitMatrix[i].HasChanges <= table.Rows.Count, "to many changes");
1290
1291                         for (int j = 0; 0 < bitMatrix[i].HasChanges; ++j) { // Loop through the rows.
1292                             if (bitMatrix[i][j]) {
1293                                 table.CopyRow(destTable, table.Rows[j]);
1294                                 bitMatrix[i].HasChanges--;
1295                             }
1296                         }
1297                     }
1298                 }
1299
1300                 if (null != dsNew) {
1301                     dsNew.EnforceConstraints = fEnforceConstraints;
1302                 }
1303                 return dsNew;
1304             }
1305             finally {
1306                 Bid.ScopeLeave(ref hscp);
1307             }
1308         }
1309
1310         private void MarkModifiedRows(TableChanges[] bitMatrix, DataRowState rowStates) {
1311             // for every table, every row & every relation find the modified rows and for non-deleted rows, their parents
1312             for (int tableIndex = 0; tableIndex < bitMatrix.Length; ++tableIndex) {
1313                 DataRowCollection rows = Tables[tableIndex].Rows;
1314                 int rowCount = rows.Count;
1315
1316                 for (int rowIndex = 0; rowIndex < rowCount; ++rowIndex) {
1317                     DataRow row = rows[rowIndex];
1318                     DataRowState rowState = row.RowState;
1319                     Debug.Assert(DataRowState.Added == rowState ||
1320                                  DataRowState.Deleted == rowState ||
1321                                  DataRowState.Modified == rowState ||
1322                                  DataRowState.Unchanged == rowState,
1323                                  "unexpected DataRowState");
1324
1325                     // if bit not already set and row is modified
1326                     if ((0 != (rowStates & rowState)) && !bitMatrix[tableIndex][rowIndex]) {
1327                         bitMatrix[tableIndex][rowIndex] = true;
1328
1329                         if (DataRowState.Deleted != rowState) {
1330                             MarkRelatedRowsAsModified(bitMatrix, row);
1331                         }
1332                     }
1333                 }
1334             }
1335         }
1336
1337         private void MarkRelatedRowsAsModified(TableChanges[] bitMatrix, DataRow row) {
1338             DataRelationCollection relations = row.Table.ParentRelations;
1339             int relationCount = relations.Count;
1340             for (int relatedIndex = 0; relatedIndex < relationCount; ++relatedIndex) {
1341                 DataRow[] relatedRows = row.GetParentRows(relations[relatedIndex], DataRowVersion.Current);
1342
1343                 foreach (DataRow relatedRow in relatedRows) {
1344                     int relatedTableIndex = this.Tables.IndexOf(relatedRow.Table);
1345                     int relatedRowIndex = relatedRow.Table.Rows.IndexOf(relatedRow);
1346
1347                     if (!bitMatrix[relatedTableIndex][relatedRowIndex]) {
1348                         bitMatrix[relatedTableIndex][relatedRowIndex] = true;
1349
1350                         if (DataRowState.Deleted != relatedRow.RowState) {
1351                             // recurse into related rows
1352                             MarkRelatedRowsAsModified(bitMatrix, relatedRow);
1353                         }
1354                     }
1355                 }
1356             }
1357         }
1358
1359         IList System.ComponentModel.IListSource.GetList() {
1360             return DefaultViewManager;
1361         }
1362
1363         internal string GetRemotingDiffGram(DataTable table)
1364         {
1365             StringWriter strWriter = new StringWriter(CultureInfo.InvariantCulture);
1366             XmlTextWriter writer = new XmlTextWriter(strWriter);
1367             writer.Formatting = Formatting.Indented;
1368             if (strWriter != null) {
1369                 // Create and save the updates
1370                 new NewDiffgramGen(table, false).Save(writer, table);
1371             }
1372
1373             return strWriter.ToString();
1374         }
1375
1376         public string GetXml()
1377         {
1378             IntPtr hscp;
1379             Bid.ScopeEnter(out hscp, "<ds.DataSet.GetXml|API> %d#\n", ObjectID);
1380             try {
1381
1382                 // StringBuilder strBuilder = new StringBuilder(EstimatedXmlStringSize());
1383                 // StringWriter strWriter = new StringWriter(strBuilder);
1384                 StringWriter strWriter = new StringWriter(CultureInfo.InvariantCulture);
1385                 if (strWriter != null) {
1386                     XmlTextWriter w = new XmlTextWriter(strWriter);
1387                     w.Formatting = Formatting.Indented;
1388                     new XmlDataTreeWriter(this).Save(w, false);
1389                 }
1390                 return strWriter.ToString();
1391             }
1392             finally {
1393                 Bid.ScopeLeave(ref hscp);
1394             }
1395         }
1396
1397         public string GetXmlSchema()
1398         {
1399             IntPtr hscp;
1400             Bid.ScopeEnter(out hscp, "<ds.DataSet.GetXmlSchema|API> %d#\n", ObjectID);
1401             try {
1402                 StringWriter strWriter = new StringWriter(CultureInfo.InvariantCulture);
1403                 XmlTextWriter writer = new XmlTextWriter(strWriter);
1404                 writer.Formatting = Formatting.Indented;
1405                 if (strWriter != null) {
1406                     (new XmlTreeGen(SchemaFormat.Public)).Save(this, writer);
1407                 }
1408
1409                 return strWriter.ToString();
1410             }
1411             finally {
1412                 Bid.ScopeLeave(ref hscp);
1413             }
1414         }
1415
1416         internal string GetXmlSchemaForRemoting(DataTable table)
1417         {
1418             StringWriter strWriter = new StringWriter(CultureInfo.InvariantCulture);
1419             XmlTextWriter writer = new XmlTextWriter(strWriter);
1420             writer.Formatting = Formatting.Indented;
1421             if (strWriter != null) {
1422                 if (table == null) {
1423                     if (this.SchemaSerializationMode == SchemaSerializationMode.ExcludeSchema)
1424                         (new XmlTreeGen(SchemaFormat.RemotingSkipSchema)).Save(this, writer);
1425                     else
1426                         (new XmlTreeGen(SchemaFormat.Remoting)).Save(this, writer);
1427                 }
1428                 else { // no skip schema support for typed datatable
1429                     (new XmlTreeGen(SchemaFormat.Remoting)).Save(table, writer);
1430                 }
1431             }
1432
1433             return strWriter.ToString();
1434         }
1435
1436
1437         /// <devdoc>
1438         /// <para>Gets a value indicating whether the <see cref='System.Data.DataSet'/> has changes, including new,
1439         ///    deleted, or modified rows.</para>
1440         /// </devdoc>
1441         public bool HasChanges()
1442         {
1443             return HasChanges(DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
1444         }
1445
1446         /// <devdoc>
1447         /// <para>Gets a value indicating whether the <see cref='System.Data.DataSet'/> has changes, including new,
1448         ///    deleted, or modified rows, filtered by <see cref='System.Data.DataRowState'/>.</para>
1449         /// </devdoc>
1450         public bool HasChanges(DataRowState rowStates)
1451         {
1452             IntPtr hscp;
1453             Bid.ScopeEnter(out hscp, "<ds.DataSet.HasChanges|API> %d#, rowStates=%d{ds.DataRowState}\n", ObjectID, (int)rowStates);
1454
1455             try {
1456                 const DataRowState allRowStates = DataRowState.Detached | DataRowState.Unchanged | DataRowState.Added | DataRowState.Deleted | DataRowState.Modified;
1457
1458                 if ((rowStates & (~allRowStates)) != 0) {
1459                     throw ExceptionBuilder.ArgumentOutOfRange("rowState");
1460                 }
1461
1462                 for (int i = 0; i < Tables.Count; i++) {
1463                     DataTable table = Tables[i];
1464
1465                     for (int j = 0; j < table.Rows.Count; j++) {
1466                         DataRow row = table.Rows[j];
1467                         if ((row.RowState & rowStates) != 0) {
1468                             return true;
1469                         }
1470                     }
1471                 }
1472                 return false;
1473             }
1474             finally {
1475                 Bid.ScopeLeave(ref hscp);
1476             }
1477         }
1478
1479         /// <devdoc>
1480         /// <para>Infer the XML schema from the specified <see cref='System.IO.TextReader'/> into the <see cref='System.Data.DataSet'/>.</para>
1481         /// </devdoc>
1482         public void InferXmlSchema(XmlReader reader, string[] nsArray)
1483         {
1484             IntPtr hscp;
1485             Bid.ScopeEnter(out hscp, "<ds.DataSet.InferXmlSchema|API> %d#\n", ObjectID);
1486             try {
1487                 if (reader == null)
1488                     return;
1489
1490                 XmlDocument xdoc = new XmlDocument();
1491                 if (reader.NodeType == XmlNodeType.Element) {
1492                     XmlNode node = xdoc.ReadNode(reader);
1493                     xdoc.AppendChild(node);
1494                 }
1495                 else
1496                     xdoc.Load(reader);
1497                 if (xdoc.DocumentElement == null)
1498                     return;
1499
1500                 InferSchema(xdoc, nsArray, XmlReadMode.InferSchema);
1501             }
1502             finally {
1503                 Bid.ScopeLeave(ref hscp);
1504             }
1505         }
1506
1507         /// <devdoc>
1508         /// <para>Infer the XML schema from the specified <see cref='System.IO.TextReader'/> into the <see cref='System.Data.DataSet'/>.</para>
1509         /// </devdoc>
1510         public void InferXmlSchema(Stream stream, string[] nsArray)
1511         {
1512             if (stream == null)
1513                 return;
1514
1515             InferXmlSchema(new XmlTextReader(stream), nsArray);
1516         }
1517
1518         /// <devdoc>
1519         /// <para>Infer the XML schema from the specified <see cref='System.IO.TextReader'/> into the <see cref='System.Data.DataSet'/>.</para>
1520         /// </devdoc>
1521         public void InferXmlSchema(TextReader reader, string[] nsArray)
1522         {
1523             if (reader == null)
1524                 return;
1525
1526             InferXmlSchema(new XmlTextReader(reader), nsArray);
1527         }
1528
1529         /// <devdoc>
1530         /// <para>Infer the XML schema from the specified file into the <see cref='System.Data.DataSet'/>.</para>
1531         /// </devdoc>
1532         [ResourceExposure(ResourceScope.Machine)]
1533         [ResourceConsumption(ResourceScope.Machine)]
1534         public void InferXmlSchema(String fileName, string[] nsArray)
1535         {
1536             XmlTextReader xr = new XmlTextReader(fileName);
1537             try {
1538                 InferXmlSchema(xr, nsArray);
1539             }
1540             finally {
1541                 xr.Close();
1542             }
1543         }
1544
1545         /// <devdoc>
1546         /// <para>Reads the XML schema from the specified <see cref='T:System.Xml.XMLReader'/> into the <see cref='System.Data.DataSet'/>
1547         /// .</para>
1548         /// </devdoc>
1549         public void ReadXmlSchema(XmlReader reader)
1550         {
1551             ReadXmlSchema(reader, false);
1552         }
1553
1554         internal void ReadXmlSchema(XmlReader reader, bool denyResolving)
1555         {
1556             IntPtr hscp;
1557             Bid.ScopeEnter(out hscp, "<ds.DataSet.ReadXmlSchema|INFO> %d#, reader, denyResolving=%d{bool}\n", ObjectID, denyResolving);
1558             try {
1559                 int iCurrentDepth = -1;
1560
1561                 if (reader == null)
1562                     return;
1563
1564                 if (reader is XmlTextReader)
1565                     ((XmlTextReader)reader).WhitespaceHandling = WhitespaceHandling.None;
1566
1567                 XmlDocument xdoc = new XmlDocument(); // we may need this to infer the schema
1568
1569                 if (reader.NodeType == XmlNodeType.Element)
1570                     iCurrentDepth = reader.Depth;
1571
1572                 reader.MoveToContent();
1573
1574                 if (reader.NodeType == XmlNodeType.Element) {
1575                     // if reader points to the schema load it...
1576
1577                     if (reader.LocalName == Keywords.XDR_SCHEMA && reader.NamespaceURI == Keywords.XDRNS) {
1578                         // load XDR schema and exit
1579                         ReadXDRSchema(reader);
1580                         return;
1581                     }
1582
1583                     if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI == Keywords.XSDNS) {
1584                         // load XSD schema and exit
1585                         ReadXSDSchema(reader, denyResolving);
1586                         return;
1587                     }
1588
1589                     if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI.StartsWith(Keywords.XSD_NS_START, StringComparison.Ordinal))
1590                         throw ExceptionBuilder.DataSetUnsupportedSchema(Keywords.XSDNS);
1591
1592                     // ... otherwise backup the top node and all its attributes
1593                     XmlElement topNode = xdoc.CreateElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
1594                     if (reader.HasAttributes) {
1595                         int attrCount = reader.AttributeCount;
1596                         for (int i = 0; i < attrCount; i++) {
1597                             reader.MoveToAttribute(i);
1598                             if (reader.NamespaceURI.Equals(Keywords.XSD_XMLNS_NS))
1599                                 topNode.SetAttribute(reader.Name, reader.GetAttribute(i));
1600                             else {
1601                                 XmlAttribute attr = topNode.SetAttributeNode(reader.LocalName, reader.NamespaceURI);
1602                                 attr.Prefix = reader.Prefix;
1603                                 attr.Value = reader.GetAttribute(i);
1604                             }
1605                         }
1606                     }
1607                     reader.Read();
1608
1609                     while (MoveToElement(reader, iCurrentDepth)) {
1610
1611                         // if reader points to the schema load it...
1612                         if (reader.LocalName == Keywords.XDR_SCHEMA && reader.NamespaceURI == Keywords.XDRNS) {
1613                             // load XDR schema and exit
1614                             ReadXDRSchema(reader);
1615                             return;
1616                         }
1617
1618                         if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI == Keywords.XSDNS) {
1619                             // load XSD schema and exit
1620                             ReadXSDSchema(reader, denyResolving);
1621                             return;
1622                         }
1623
1624                         if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI.StartsWith(Keywords.XSD_NS_START, StringComparison.Ordinal))
1625                             throw ExceptionBuilder.DataSetUnsupportedSchema(Keywords.XSDNS);
1626
1627
1628                         XmlNode node = xdoc.ReadNode(reader);
1629                         topNode.AppendChild(node);
1630
1631                     }
1632
1633                     // read the closing tag of the current element
1634                     ReadEndElement(reader);
1635
1636                     // if we are here no schema has been found
1637                     xdoc.AppendChild(topNode);
1638
1639                     // so we InferSchema
1640                     InferSchema(xdoc, null, XmlReadMode.Auto);
1641                 }
1642             }
1643             finally {
1644                 Bid.ScopeLeave(ref hscp);
1645             }
1646         }
1647
1648         internal bool MoveToElement(XmlReader reader, int depth) {
1649             while (!reader.EOF && reader.NodeType != XmlNodeType.EndElement && reader.NodeType != XmlNodeType.Element && reader.Depth > depth) {
1650                 reader.Read();
1651             }
1652             return (reader.NodeType == XmlNodeType.Element);
1653         }
1654
1655         private static void MoveToElement(XmlReader reader) {
1656             while (!reader.EOF && reader.NodeType != XmlNodeType.EndElement && reader.NodeType != XmlNodeType.Element) {
1657                 reader.Read();
1658             }
1659         }
1660         internal void ReadEndElement(XmlReader reader) {
1661             while (reader.NodeType == XmlNodeType.Whitespace) {
1662                 reader.Skip();
1663             }
1664             if (reader.NodeType == XmlNodeType.None) {
1665                 reader.Skip();
1666             }
1667             else if (reader.NodeType == XmlNodeType.EndElement) {
1668                 reader.ReadEndElement();
1669             }
1670         }
1671
1672         internal void ReadXSDSchema(XmlReader reader, bool denyResolving) {
1673             XmlSchemaSet sSet = new XmlSchemaSet();
1674
1675             int schemaFragmentCount = 1;
1676             //read from current schmema element
1677             if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI == Keywords.XSDNS) {
1678                 if (reader.HasAttributes) {
1679                     string attribValue = reader.GetAttribute(Keywords.MSD_FRAGMENTCOUNT, Keywords.MSDNS); // this must not move the position
1680                     if (!Common.ADP.IsEmpty(attribValue)) {
1681                         schemaFragmentCount = int.Parse(attribValue, null);
1682                     }
1683                 }
1684             }
1685
1686             while (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI == Keywords.XSDNS) {
1687                 XmlSchema s = XmlSchema.Read(reader, null);
1688                 sSet.Add(s);
1689                 //read the end tag
1690                 ReadEndElement(reader);
1691
1692                 if (--schemaFragmentCount > 0) {
1693                     MoveToElement(reader);
1694                 }
1695                 while (reader.NodeType == XmlNodeType.Whitespace) {
1696                     reader.Skip();
1697                 }
1698             }
1699             sSet.Compile();
1700             XSDSchema schema = new XSDSchema();
1701             schema.LoadSchema(sSet, this);
1702         }
1703
1704         internal void ReadXDRSchema(XmlReader reader) {
1705             XmlDocument xdoc = new XmlDocument(); // we may need this to infer the schema
1706             XmlNode schNode = xdoc.ReadNode(reader);
1707             xdoc.AppendChild(schNode);
1708             XDRSchema schema = new XDRSchema(this, false);
1709             this.DataSetName = xdoc.DocumentElement.LocalName;
1710             schema.LoadSchema((XmlElement)schNode, this);
1711         }
1712
1713         /// <devdoc>
1714         /// <para>Reads the XML schema from the specified <see cref='System.IO.Stream'/> into the
1715         /// <see cref='System.Data.DataSet'/>.</para>
1716         /// </devdoc>
1717         public void ReadXmlSchema(Stream stream)
1718         {
1719             if (stream == null)
1720                 return;
1721
1722             ReadXmlSchema(new XmlTextReader(stream), false);
1723         }
1724
1725         /// <devdoc>
1726         /// <para>Reads the XML schema from the specified <see cref='System.IO.TextReader'/> into the <see cref='System.Data.DataSet'/>.</para>
1727         /// </devdoc>
1728         public void ReadXmlSchema(TextReader reader)
1729         {
1730             if (reader == null)
1731                 return;
1732
1733             ReadXmlSchema(new XmlTextReader(reader), false);
1734         }
1735
1736         /// <devdoc>
1737         /// <para>Reads the XML schema from the specified file into the <see cref='System.Data.DataSet'/>.</para>
1738         /// </devdoc>
1739         [ResourceExposure(ResourceScope.Machine)]
1740         [ResourceConsumption(ResourceScope.Machine)]
1741         public void ReadXmlSchema(String fileName)
1742         {
1743             XmlTextReader xr = new XmlTextReader(fileName);
1744             try {
1745                 ReadXmlSchema(xr, false);
1746             }
1747             finally {
1748                 xr.Close();
1749             }
1750         }
1751
1752         #region WriteXmlSchema
1753         /// <summary>Writes the <see cref='DataSet'/> structure as an XML schema to using the specified <see cref='Stream'/> object.</summary>
1754         /// <param name="stream">A <see cref='Stream'/> object used to write to a file.</param>
1755         public void WriteXmlSchema(Stream stream)
1756         {
1757             this.WriteXmlSchema(stream, SchemaFormat.Public, (Converter<Type, string>)null);
1758         }
1759
1760         /// <summary>Writes the <see cref='DataSet'/> structure as an XML schema to using the specified <see cref='Stream'/> object.</summary>
1761         /// <param name="stream">A <see cref='Stream'/> object used to write to a file.</param>
1762         /// <param name="multipleTargetConverter">A delegate used to convert <see cref='Type'/> into string.</param>
1763         public void WriteXmlSchema(Stream stream, Converter<Type, string> multipleTargetConverter)
1764         {
1765             ADP.CheckArgumentNull(multipleTargetConverter, "multipleTargetConverter");
1766             this.WriteXmlSchema(stream, SchemaFormat.Public, multipleTargetConverter);
1767         }
1768
1769         /// <summary>Writes the <see cref='DataSet'/> structure as an XML schema to a file.</summary>
1770         /// <param name="fileName">The file name (including the path) to which to write.</param>
1771         [ResourceExposure(ResourceScope.Machine)]
1772         [ResourceConsumption(ResourceScope.Machine)]
1773         public void WriteXmlSchema(String fileName)
1774         {
1775             this.WriteXmlSchema(fileName, SchemaFormat.Public, (Converter<Type, string>)null);
1776         }
1777
1778         /// <summary>Writes the <see cref='DataSet'/> structure as an XML schema to a file.</summary>
1779         /// <param name="fileName">The file name (including the path) to which to write.</param>
1780         /// <param name="multipleTargetConverter">A delegate used to convert <see cref='Type'/> into string.</param>
1781         [ResourceExposure(ResourceScope.Machine)]
1782         [ResourceConsumption(ResourceScope.Machine)]
1783         public void WriteXmlSchema(String fileName, Converter<Type, string> multipleTargetConverter)
1784         {
1785             ADP.CheckArgumentNull(multipleTargetConverter, "multipleTargetConverter");
1786             this.WriteXmlSchema(fileName, SchemaFormat.Public, multipleTargetConverter);
1787         }
1788
1789         /// <summary>Writes the <see cref='DataSet'/> structure as an XML schema to a <see cref='TextWriter'/> object.</summary>
1790         /// <param name="writer">The <see cref='TextWriter'/> object with which to write.</param>
1791         public void WriteXmlSchema(TextWriter writer)
1792         {
1793             this.WriteXmlSchema(writer, SchemaFormat.Public, (Converter<Type, string>)null);
1794         }
1795
1796         /// <summary>Writes the <see cref='DataSet'/> structure as an XML schema to a <see cref='TextWriter'/> object.</summary>
1797         /// <param name="writer">The <see cref='TextWriter'/> object with which to write.</param>
1798         /// <param name="multipleTargetConverter">A delegate used to convert <see cref='Type'/> into string.</param>
1799         public void WriteXmlSchema(TextWriter writer, Converter<Type, string> multipleTargetConverter)
1800         {
1801             ADP.CheckArgumentNull(multipleTargetConverter, "multipleTargetConverter");
1802             this.WriteXmlSchema(writer, SchemaFormat.Public, multipleTargetConverter);
1803         }
1804
1805         /// <summary>Writes the <see cref='DataSet'/> structure as an XML schema to an <see cref='XmlWriter'/> object.</summary>
1806         /// <param name="writer">The <see cref='XmlWriter'/> object with which to write.</param>
1807         public void WriteXmlSchema(XmlWriter writer)
1808         {
1809             this.WriteXmlSchema(writer, SchemaFormat.Public, (Converter<Type, string>)null);
1810         }
1811
1812         /// <summary>Writes the <see cref='DataSet'/> structure as an XML schema to an <see cref='XmlWriter'/> object.</summary>
1813         /// <param name="writer">The <see cref='XmlWriter'/> object with which to write.</param>
1814         /// <param name="multipleTargetConverter">A delegate used to convert <see cref='Type'/> into string.</param>
1815         public void WriteXmlSchema(XmlWriter writer, Converter<Type, string> multipleTargetConverter)
1816         {
1817             ADP.CheckArgumentNull(multipleTargetConverter, "multipleTargetConverter");
1818             this.WriteXmlSchema(writer, SchemaFormat.Public, multipleTargetConverter);
1819         }
1820
1821         [ResourceExposure(ResourceScope.Machine)]
1822         [ResourceConsumption(ResourceScope.Machine)]
1823         private void WriteXmlSchema(String fileName, SchemaFormat schemaFormat, Converter<Type, string> multipleTargetConverter)
1824         {
1825             XmlTextWriter xw = new XmlTextWriter( fileName, null );
1826             try {
1827                 xw.Formatting = Formatting.Indented;
1828                 xw.WriteStartDocument(true);
1829                 this.WriteXmlSchema(xw, schemaFormat, multipleTargetConverter);
1830                 xw.WriteEndDocument();
1831             }
1832             finally {
1833                 xw.Close();
1834             }
1835         }
1836
1837         private void WriteXmlSchema(Stream stream, SchemaFormat schemaFormat, Converter<Type, string> multipleTargetConverter)
1838         {
1839             if (stream == null)
1840                 return;
1841
1842             XmlTextWriter w = new XmlTextWriter(stream, null);
1843             w.Formatting = Formatting.Indented;
1844
1845             this.WriteXmlSchema(w, schemaFormat, multipleTargetConverter);
1846         }
1847
1848         private void WriteXmlSchema(TextWriter writer, SchemaFormat schemaFormat, Converter<Type, string> multipleTargetConverter)
1849         {
1850             if (writer == null)
1851                 return;
1852
1853             XmlTextWriter w = new XmlTextWriter(writer);
1854             w.Formatting = Formatting.Indented;
1855
1856             this.WriteXmlSchema(w, schemaFormat, multipleTargetConverter);
1857         }
1858
1859         private void WriteXmlSchema(XmlWriter writer, SchemaFormat schemaFormat, Converter<Type, string> multipleTargetConverter)
1860         {
1861             IntPtr hscp;
1862             Bid.ScopeEnter(out hscp, "<ds.DataSet.WriteXmlSchema|INFO> %d#, schemaFormat=%d{ds.SchemaFormat}\n", ObjectID, (int)schemaFormat);
1863             try {
1864                 // Generate SchemaTree and write it out
1865                 if (writer != null) {
1866                     XmlTreeGen treeGen = null;
1867                     if (schemaFormat == SchemaFormat.WebService &&
1868                         SchemaSerializationMode == SchemaSerializationMode.ExcludeSchema &&
1869                         writer.WriteState == WriteState.Element) {
1870                         treeGen = new XmlTreeGen(SchemaFormat.WebServiceSkipSchema);
1871                     }
1872                     else {
1873                         treeGen = new XmlTreeGen(schemaFormat);
1874                     }
1875
1876                     treeGen.Save(this, (DataTable)null, writer, false, multipleTargetConverter);
1877                 }
1878             }
1879             finally {
1880                 Bid.ScopeLeave(ref hscp);
1881             }
1882         }
1883         #endregion
1884
1885         /// <devdoc>
1886         /// </devdoc>
1887         public XmlReadMode ReadXml(XmlReader reader)
1888         {
1889             return ReadXml(reader, false);
1890         }
1891
1892
1893         internal XmlReadMode ReadXml(XmlReader reader, bool denyResolving)
1894         {
1895             IntPtr hscp;
1896             Bid.ScopeEnter(out hscp, "<ds.DataSet.ReadXml|INFO> %d#, denyResolving=%d{bool}\n", ObjectID, denyResolving);
1897             try {
1898                 
1899                 DataTable.DSRowDiffIdUsageSection rowDiffIdUsage = new DataTable.DSRowDiffIdUsageSection();
1900                 try {
1901                     bool fDataFound = false;
1902                     bool fSchemaFound = false;
1903                     bool fDiffsFound = false;
1904                     bool fIsXdr = false;
1905                     int iCurrentDepth = -1;
1906                     XmlReadMode ret = XmlReadMode.Auto;
1907                     bool isEmptyDataSet = false;
1908                     bool topNodeIsProcessed = false; // we chanche topnode and there is just one case that we miss to process it
1909                     // it is : <elem attrib1="Attrib">txt</elem>
1910
1911                     // clear the hashtable to avoid conflicts between diffgrams, SqlHotFix 782
1912                     rowDiffIdUsage.Prepare(this);
1913
1914                     if (reader == null)
1915                         return ret;
1916
1917                     if (Tables.Count == 0) {
1918                         isEmptyDataSet = true;
1919                     }
1920
1921                     if (reader is XmlTextReader)
1922                         ((XmlTextReader)reader).WhitespaceHandling = WhitespaceHandling.Significant;
1923
1924                     XmlDocument xdoc = new XmlDocument(); // we may need this to infer the schema
1925                     XmlDataLoader xmlload = null;
1926
1927
1928                     reader.MoveToContent();
1929
1930                     if (reader.NodeType == XmlNodeType.Element)
1931                         iCurrentDepth = reader.Depth;
1932
1933                     if (reader.NodeType == XmlNodeType.Element) {
1934                         if ((reader.LocalName == Keywords.DIFFGRAM) && (reader.NamespaceURI == Keywords.DFFNS)) {
1935                             this.ReadXmlDiffgram(reader);
1936                             // read the closing tag of the current element
1937                             ReadEndElement(reader);
1938                             return XmlReadMode.DiffGram;
1939                         }
1940
1941                         // if reader points to the schema load it
1942                         if (reader.LocalName == Keywords.XDR_SCHEMA && reader.NamespaceURI == Keywords.XDRNS) {
1943                             // load XDR schema and exit
1944                             ReadXDRSchema(reader);
1945                             return XmlReadMode.ReadSchema; //since the top level element is a schema return
1946                         }
1947
1948                         if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI == Keywords.XSDNS) {
1949                             // load XSD schema and exit
1950                             ReadXSDSchema(reader, denyResolving);
1951                             return XmlReadMode.ReadSchema; //since the top level element is a schema return
1952                         }
1953
1954                         if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI.StartsWith(Keywords.XSD_NS_START, StringComparison.Ordinal))
1955                             throw ExceptionBuilder.DataSetUnsupportedSchema(Keywords.XSDNS);
1956
1957                         // now either the top level node is a table and we load it through dataReader...
1958
1959                         // ... or backup the top node and all its attributes because we may need to InferSchema
1960                         XmlElement topNode = xdoc.CreateElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
1961                         if (reader.HasAttributes) {
1962                             int attrCount = reader.AttributeCount;
1963                             for (int i = 0; i < attrCount; i++) {
1964                                 reader.MoveToAttribute(i);
1965                                 if (reader.NamespaceURI.Equals(Keywords.XSD_XMLNS_NS))
1966                                     topNode.SetAttribute(reader.Name, reader.GetAttribute(i));
1967                                 else {
1968                                     XmlAttribute attr = topNode.SetAttributeNode(reader.LocalName, reader.NamespaceURI);
1969                                     attr.Prefix = reader.Prefix;
1970                                     attr.Value = reader.GetAttribute(i);
1971                                 }
1972                             }
1973                         }
1974                         reader.Read();
1975                         string rootNodeSimpleContent = reader.Value;
1976
1977                         while (MoveToElement(reader, iCurrentDepth)) {
1978
1979                             if ((reader.LocalName == Keywords.DIFFGRAM) && (reader.NamespaceURI == Keywords.DFFNS)) {
1980                                 this.ReadXmlDiffgram(reader);
1981                                 // read the closing tag of the current element
1982                                 // YUKON FIX                            ReadEndElement(reader);
1983                                 //                            return XmlReadMode.DiffGram;
1984                                 ret = XmlReadMode.DiffGram; // continue reading for multiple schemas
1985                             }
1986
1987                             // if reader points to the schema load it...
1988
1989
1990                             if (!fSchemaFound && !fDataFound && reader.LocalName == Keywords.XDR_SCHEMA && reader.NamespaceURI == Keywords.XDRNS) {
1991                                 // load XDR schema and exit
1992                                 ReadXDRSchema(reader);
1993                                 fSchemaFound = true;
1994                                 fIsXdr = true;
1995                                 continue;
1996                             }
1997
1998                             if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI == Keywords.XSDNS) {
1999                                 // load XSD schema and exit
2000                                 ReadXSDSchema(reader, denyResolving);
2001                                 fSchemaFound = true;
2002                                 continue;
2003                             }
2004
2005                             if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI.StartsWith(Keywords.XSD_NS_START, StringComparison.Ordinal))
2006                                 throw ExceptionBuilder.DataSetUnsupportedSchema(Keywords.XSDNS);
2007
2008                             if ((reader.LocalName == Keywords.DIFFGRAM) && (reader.NamespaceURI == Keywords.DFFNS)) {
2009                                 this.ReadXmlDiffgram(reader);
2010                                 fDiffsFound = true;
2011                                 ret = XmlReadMode.DiffGram;
2012                             }
2013                             else {
2014                                 // We have found data IFF the reader.NodeType == Element and reader.depth == currentDepth-1
2015                                 // if reader.NodeType == whitespace, skip all white spaces.
2016                                 // skip processing i.e. continue if the first non-whitespace node is not of type element.
2017                                 while (!reader.EOF && reader.NodeType == XmlNodeType.Whitespace)
2018                                     reader.Read();
2019                                 if (reader.NodeType != XmlNodeType.Element)
2020                                     continue;
2021                                 // we found data here
2022                                 fDataFound = true;
2023
2024                                 if (!fSchemaFound && Tables.Count == 0) {
2025                                     XmlNode node = xdoc.ReadNode(reader);
2026                                     topNode.AppendChild(node);
2027                                 }
2028                                 else {
2029                                     if (xmlload == null)
2030                                         xmlload = new XmlDataLoader(this, fIsXdr, topNode, false);
2031                                     xmlload.LoadData(reader);
2032                                     topNodeIsProcessed = true; // we process the topnode
2033                                     if (fSchemaFound)
2034                                         ret = XmlReadMode.ReadSchema;
2035                                     else
2036                                         ret = XmlReadMode.IgnoreSchema;
2037                                 }
2038                             }
2039
2040                         }
2041                         // read the closing tag of the current element
2042                         ReadEndElement(reader);
2043                         bool isfTopLevelTableSet = false;
2044                         bool tmpValue = this.fTopLevelTable;
2045                         //While inference we ignore root elements text content
2046                         if (!fSchemaFound && Tables.Count == 0 && !topNode.HasChildNodes) { //We shoule not come add SC of root elemnt to topNode if we are not infering
2047                             this.fTopLevelTable = true;
2048                             isfTopLevelTableSet = true;
2049                             if ((rootNodeSimpleContent != null && rootNodeSimpleContent.Length > 0))
2050                                 topNode.InnerText = rootNodeSimpleContent;
2051                         }
2052                         if (!isEmptyDataSet) {
2053                             if ((rootNodeSimpleContent != null && rootNodeSimpleContent.Length > 0))
2054                                 topNode.InnerText = rootNodeSimpleContent;
2055                         }
2056
2057                         // now top node contains the data part
2058                         xdoc.AppendChild(topNode);
2059
2060                         if (xmlload == null)
2061                             xmlload = new XmlDataLoader(this, fIsXdr, topNode, false);
2062
2063                         if (!isEmptyDataSet && !topNodeIsProcessed) {
2064                             XmlElement root = xdoc.DocumentElement;
2065                             Debug.Assert(root.NamespaceURI != null, "root.NamespaceURI should not ne null, it should be empty string");
2066                             // just recognize that below given Xml represents datatable in toplevel
2067                             //<table attr1="foo" attr2="bar" table_Text="junk">text</table>
2068                             // only allow root element with simple content, if any
2069                             if (root.ChildNodes.Count == 0 ||
2070                                 ((root.ChildNodes.Count == 1) && root.FirstChild.GetType() == typeof(System.Xml.XmlText))) {
2071                                 bool initfTopLevelTable = this.fTopLevelTable;
2072                                 // if root element maps to a datatable
2073                                 // ds and dt cant have the samm name and ns at the same time, how to write to xml
2074                                 if (this.DataSetName != root.Name && this.namespaceURI != root.NamespaceURI &&
2075                                     Tables.Contains(root.Name, (root.NamespaceURI.Length == 0) ? null : root.NamespaceURI, false, true)) {
2076                                     this.fTopLevelTable = true;
2077                                 }
2078                                 try {
2079                                     xmlload.LoadData(xdoc);
2080                                 }
2081                                 finally {
2082                                     this.fTopLevelTable = initfTopLevelTable; // this is not for inference, we have schema and we were skipping
2083                                     // topnode where it was a datatable, We must restore the value
2084                                 }
2085                             }
2086                         }// above check and below check are orthogonal
2087                         // so we InferSchema
2088                         if (!fDiffsFound) {
2089                             // Load Data
2090                             if (!fSchemaFound && Tables.Count == 0) {
2091                                 InferSchema(xdoc, null, XmlReadMode.Auto);
2092                                 ret = XmlReadMode.InferSchema;
2093                                 xmlload.FromInference = true;
2094                                 try {
2095                                     xmlload.LoadData(xdoc);
2096                                 }
2097                                 finally {
2098                                     xmlload.FromInference = false;
2099                                 }
2100                             }
2101                             //We dont need this assignement. Once we set it(where we set it during inference), it won't be changed
2102                             if (isfTopLevelTableSet)
2103                                 this.fTopLevelTable = tmpValue;
2104                         }
2105                     }
2106
2107                     return ret;
2108                 }
2109                 finally {
2110                     rowDiffIdUsage.Cleanup();
2111                 }
2112             }
2113             finally {
2114                 Bid.ScopeLeave(ref hscp);
2115             }
2116         }
2117
2118
2119         /// <devdoc>
2120         /// </devdoc>
2121         public XmlReadMode ReadXml(Stream stream)
2122         {
2123             if (stream == null)
2124                 return XmlReadMode.Auto;
2125
2126             XmlTextReader xr = new XmlTextReader(stream);
2127
2128             // Prevent Dtd entity in dataset 
2129             xr.XmlResolver = null;
2130
2131             return ReadXml(xr, false);
2132         }
2133
2134         /// <devdoc>
2135         /// </devdoc>
2136         public XmlReadMode ReadXml(TextReader reader)
2137         {
2138             if (reader == null)
2139                 return XmlReadMode.Auto;
2140
2141             XmlTextReader xr = new XmlTextReader(reader);
2142
2143             // Prevent Dtd entity in dataset 
2144             xr.XmlResolver = null;
2145
2146             return ReadXml(xr, false);
2147         }
2148
2149         /// <devdoc>
2150         /// </devdoc>
2151         [ResourceExposure(ResourceScope.Machine)]
2152         [ResourceConsumption(ResourceScope.Machine)]
2153         public XmlReadMode ReadXml(string fileName)
2154         {
2155             XmlTextReader xr = new XmlTextReader(fileName);
2156
2157             // Prevent Dtd entity in dataset 
2158             xr.XmlResolver = null;
2159
2160             try
2161             {
2162                 return ReadXml(xr, false);
2163             }
2164             finally {
2165                 xr.Close();
2166             }
2167         }
2168
2169         internal void InferSchema(XmlDocument xdoc, string[] excludedNamespaces, XmlReadMode mode) {
2170             IntPtr hscp;
2171             Bid.ScopeEnter(out hscp, "<ds.DataSet.InferSchema|INFO> %d#, mode=%d{ds.XmlReadMode}\n", ObjectID, (int)mode);
2172             try {
2173                 string ns = xdoc.DocumentElement.NamespaceURI;
2174                 if (null == excludedNamespaces) {
2175                     excludedNamespaces = new string[0];
2176                 }
2177                 XmlNodeReader xnr = new XmlIgnoreNamespaceReader(xdoc, excludedNamespaces);
2178                 System.Xml.Schema.XmlSchemaInference infer = new System.Xml.Schema.XmlSchemaInference();
2179
2180                 infer.Occurrence = XmlSchemaInference.InferenceOption.Relaxed;
2181
2182                 if (mode == XmlReadMode.InferTypedSchema)
2183                     infer.TypeInference = XmlSchemaInference.InferenceOption.Restricted;
2184                 else
2185                     infer.TypeInference = XmlSchemaInference.InferenceOption.Relaxed;
2186
2187                 XmlSchemaSet schemaSet = infer.InferSchema(xnr);
2188                 schemaSet.Compile();
2189
2190                 XSDSchema schema = new XSDSchema();
2191                 schema.FromInference = true;
2192
2193                 try {
2194                     schema.LoadSchema(schemaSet, this);
2195                 }
2196                 finally {
2197                     schema.FromInference = false; // this is always false if you are not calling fron inference
2198                 }
2199             }
2200             finally {
2201                 Bid.ScopeLeave(ref hscp);
2202             }
2203         }
2204
2205         private bool IsEmpty() {
2206             foreach (DataTable table in this.Tables)
2207                 if (table.Rows.Count > 0)
2208                     return false;
2209             return true;
2210         }
2211
2212         private void ReadXmlDiffgram(XmlReader reader) {
2213             IntPtr hscp;
2214             Bid.ScopeEnter(out hscp, "<ds.DataSet.ReadXmlDiffgram|INFO> %d#\n", ObjectID);
2215             try {
2216                 int d = reader.Depth;
2217                 bool fEnforce = this.EnforceConstraints;
2218                 this.EnforceConstraints = false;
2219                 DataSet newDs;
2220                 bool isEmpty = this.IsEmpty();
2221
2222                 if (isEmpty) {
2223                     newDs = this;
2224                 }
2225                 else {
2226                     newDs = this.Clone();
2227                     newDs.EnforceConstraints = false;
2228                 }
2229
2230                 foreach (DataTable t in newDs.Tables) {
2231                     t.Rows.nullInList = 0;
2232                 }
2233                 reader.MoveToContent();
2234                 if ((reader.LocalName != Keywords.DIFFGRAM) && (reader.NamespaceURI != Keywords.DFFNS))
2235                     return;
2236                 reader.Read();
2237                 if (reader.NodeType == XmlNodeType.Whitespace)
2238                     MoveToElement(reader, reader.Depth - 1 /*iCurrentDepth*/); // skip over whitespaces.
2239
2240                 newDs.fInLoadDiffgram = true;
2241
2242                 if (reader.Depth > d) {
2243                     if ((reader.NamespaceURI != Keywords.DFFNS) && (reader.NamespaceURI != Keywords.MSDNS)) {
2244                         //we should be inside the dataset part
2245                         XmlDocument xdoc = new XmlDocument();
2246                         XmlElement node = xdoc.CreateElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
2247                         reader.Read();
2248                         if (reader.NodeType == XmlNodeType.Whitespace) {
2249                             MoveToElement(reader, reader.Depth - 1 /*iCurrentDepth*/); // skip over whitespaces.
2250                         }
2251                         if (reader.Depth - 1 > d) {
2252                             XmlDataLoader xmlload = new XmlDataLoader(newDs, false, node, false);
2253                             xmlload.isDiffgram = true; // turn on the special processing
2254                             xmlload.LoadData(reader);
2255                         }
2256                         ReadEndElement(reader);
2257                         if (reader.NodeType == XmlNodeType.Whitespace) {
2258                             MoveToElement(reader, reader.Depth - 1 /*iCurrentDepth*/); // skip over whitespaces.
2259                         }
2260                     }
2261                     Debug.Assert(reader.NodeType != XmlNodeType.Whitespace, "Should not be on Whitespace node");
2262
2263                     if (((reader.LocalName == Keywords.SQL_BEFORE) && (reader.NamespaceURI == Keywords.DFFNS)) ||
2264                         ((reader.LocalName == Keywords.MSD_ERRORS) && (reader.NamespaceURI == Keywords.DFFNS)))
2265
2266                     {
2267                         //this will consume the changes and the errors part
2268                         XMLDiffLoader diffLoader = new XMLDiffLoader();
2269                         diffLoader.LoadDiffGram(newDs, reader);
2270                     }
2271
2272                     // get to the closing diff tag
2273                     while (reader.Depth > d) {
2274                         reader.Read();
2275                     }
2276                     // read the closing tag
2277                     ReadEndElement(reader);
2278                 }
2279
2280                 foreach (DataTable t in newDs.Tables) {
2281                     if (t.Rows.nullInList > 0)
2282                         throw ExceptionBuilder.RowInsertMissing(t.TableName);
2283                 }
2284
2285                 newDs.fInLoadDiffgram = false;
2286
2287                 //terrible performance!
2288                 foreach (DataTable t in newDs.Tables) {
2289                     DataRelation[] nestedParentRelations = t.NestedParentRelations;
2290                     foreach (DataRelation rel in nestedParentRelations) {
2291                         if (rel.ParentTable == t) {
2292                             foreach (DataRow r in t.Rows) {
2293                                 foreach (DataRelation rel2 in nestedParentRelations) {
2294                                     r.CheckForLoops(rel2);
2295                                 }
2296                             }
2297                         }
2298                     }
2299                 }
2300
2301                 if (!isEmpty) {
2302                     this.Merge(newDs);
2303                     if (this.dataSetName == "NewDataSet")
2304                         this.dataSetName = newDs.dataSetName;
2305                     newDs.EnforceConstraints = fEnforce;
2306                 }
2307                 this.EnforceConstraints = fEnforce;
2308             }
2309             finally {
2310                 Bid.ScopeLeave(ref hscp);
2311             }
2312
2313         }
2314
2315         /// <devdoc>
2316         /// </devdoc>
2317         public XmlReadMode ReadXml(XmlReader reader, XmlReadMode mode)
2318         {
2319             return ReadXml(reader, mode, false);
2320         }
2321
2322         internal XmlReadMode ReadXml(XmlReader reader, XmlReadMode mode, bool denyResolving)
2323         {
2324             IntPtr hscp;
2325             Bid.ScopeEnter(out hscp, "<ds.DataSet.ReadXml|INFO> %d#, mode=%d{ds.XmlReadMode}, denyResolving=%d{bool}\n", ObjectID, (int)mode, denyResolving);
2326             try {
2327
2328                 XmlReadMode ret = mode;
2329
2330                 if (reader == null)
2331                     return ret;
2332
2333                 if (mode == XmlReadMode.Auto) {
2334                     // Dev11 915079: nested ReadXml calls on the same DataSet must be done outside of RowDiffIdUsage scope
2335                     return ReadXml(reader);
2336                 }
2337
2338                 DataTable.DSRowDiffIdUsageSection rowDiffIdUsage = new DataTable.DSRowDiffIdUsageSection();
2339                 try {
2340
2341                     bool fSchemaFound = false;
2342                     bool fDataFound = false;
2343                     bool fIsXdr = false;
2344                     int iCurrentDepth = -1;
2345
2346                     // Dev11 904428: prepare and cleanup rowDiffId hashtable
2347                     rowDiffIdUsage.Prepare(this);
2348
2349                     if (reader is XmlTextReader)
2350                         ((XmlTextReader)reader).WhitespaceHandling = WhitespaceHandling.Significant;
2351
2352                     XmlDocument xdoc = new XmlDocument(); // we may need this to infer the schema
2353
2354                     if ((mode != XmlReadMode.Fragment) && (reader.NodeType == XmlNodeType.Element))
2355                         iCurrentDepth = reader.Depth;
2356
2357                     reader.MoveToContent();
2358                     XmlDataLoader xmlload = null;
2359
2360                     if (reader.NodeType == XmlNodeType.Element) {
2361                         XmlElement topNode = null;
2362                         if (mode == XmlReadMode.Fragment) {
2363                             xdoc.AppendChild(xdoc.CreateElement("ds_sqlXmlWraPPeR"));
2364                             topNode = xdoc.DocumentElement;
2365                         }
2366                         else { //handle the top node
2367                             if ((reader.LocalName == Keywords.DIFFGRAM) && (reader.NamespaceURI == Keywords.DFFNS)) {
2368                                 if ((mode == XmlReadMode.DiffGram) || (mode == XmlReadMode.IgnoreSchema)) {
2369                                     this.ReadXmlDiffgram(reader);
2370                                     // read the closing tag of the current element
2371                                     ReadEndElement(reader);
2372                                 }
2373                                 else {
2374                                     reader.Skip();
2375                                 }
2376                                 return ret;
2377                             }
2378
2379                             if (reader.LocalName == Keywords.XDR_SCHEMA && reader.NamespaceURI == Keywords.XDRNS) {
2380                                 // load XDR schema and exit
2381                                 if ((mode != XmlReadMode.IgnoreSchema) && (mode != XmlReadMode.InferSchema) &&
2382                                     (mode != XmlReadMode.InferTypedSchema))
2383                                 {
2384                                     ReadXDRSchema(reader);
2385                                 }
2386                                 else {
2387                                     reader.Skip();
2388                                 }
2389                                 return ret; //since the top level element is a schema return
2390                             }
2391
2392                             if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI == Keywords.XSDNS) {
2393                                 // load XSD schema and exit
2394                                 if ((mode != XmlReadMode.IgnoreSchema) && (mode != XmlReadMode.InferSchema) &&
2395                                     (mode != XmlReadMode.InferTypedSchema))
2396                                 {
2397                                     ReadXSDSchema(reader, denyResolving);
2398                                 }
2399                                 else
2400                                     reader.Skip();
2401                                 return ret; //since the top level element is a schema return
2402                             }
2403
2404                             if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI.StartsWith(Keywords.XSD_NS_START, StringComparison.Ordinal))
2405                                 throw ExceptionBuilder.DataSetUnsupportedSchema(Keywords.XSDNS);
2406
2407                             // now either the top level node is a table and we load it through dataReader...
2408                             // ... or backup the top node and all its attributes
2409                             topNode = xdoc.CreateElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
2410                             if (reader.HasAttributes) {
2411                                 int attrCount = reader.AttributeCount;
2412                                 for (int i = 0; i < attrCount; i++) {
2413                                     reader.MoveToAttribute(i);
2414                                     if (reader.NamespaceURI.Equals(Keywords.XSD_XMLNS_NS))
2415                                         topNode.SetAttribute(reader.Name, reader.GetAttribute(i));
2416                                     else {
2417                                         XmlAttribute attr = topNode.SetAttributeNode(reader.LocalName, reader.NamespaceURI);
2418                                         attr.Prefix = reader.Prefix;
2419                                         attr.Value = reader.GetAttribute(i);
2420                                     }
2421                                 }
2422                             }
2423                             reader.Read();
2424                         }
2425
2426                         while (MoveToElement(reader, iCurrentDepth)) {
2427
2428                             if (reader.LocalName == Keywords.XDR_SCHEMA && reader.NamespaceURI == Keywords.XDRNS) {
2429                                 // load XDR schema
2430                                 if (!fSchemaFound && !fDataFound && (mode != XmlReadMode.IgnoreSchema) && (mode != XmlReadMode.InferSchema) &&
2431                                     (mode != XmlReadMode.InferTypedSchema))
2432                                 {
2433                                     ReadXDRSchema(reader);
2434                                     fSchemaFound = true;
2435                                     fIsXdr = true;
2436                                 }
2437                                 else {
2438                                     reader.Skip();
2439                                 }
2440                                 continue;
2441                             }
2442
2443                             if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI == Keywords.XSDNS) {
2444                                 // load XSD schema and exit
2445                                 if ((mode != XmlReadMode.IgnoreSchema) && (mode != XmlReadMode.InferSchema) &&
2446                                     (mode != XmlReadMode.InferTypedSchema))
2447                                 {
2448                                     ReadXSDSchema(reader, denyResolving);
2449                                     fSchemaFound = true;
2450                                 }
2451                                 else {
2452                                     reader.Skip();
2453                                 }
2454                                 continue;
2455                             }
2456
2457                             if ((reader.LocalName == Keywords.DIFFGRAM) && (reader.NamespaceURI == Keywords.DFFNS)) {
2458                                 if ((mode == XmlReadMode.DiffGram) || (mode == XmlReadMode.IgnoreSchema)) {
2459                                     this.ReadXmlDiffgram(reader);
2460                                     ret = XmlReadMode.DiffGram;
2461                                 }
2462                                 else {
2463                                     reader.Skip();
2464                                 }
2465                                 continue;
2466                             }
2467
2468                             if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI.StartsWith(Keywords.XSD_NS_START, StringComparison.Ordinal))
2469                                 throw ExceptionBuilder.DataSetUnsupportedSchema(Keywords.XSDNS);
2470
2471                             if (mode == XmlReadMode.DiffGram) {
2472                                 reader.Skip();
2473                                 continue; // we do not read data in diffgram mode
2474                             }
2475
2476                             // if we are here we found some data
2477                             fDataFound = true;
2478
2479                             if (mode == XmlReadMode.InferSchema || mode == XmlReadMode.InferTypedSchema) { //save the node in DOM until the end;
2480                                 XmlNode node = xdoc.ReadNode(reader);
2481                                 topNode.AppendChild(node);
2482                             }
2483                             else {
2484                                 if (xmlload == null)
2485                                     xmlload = new XmlDataLoader(this, fIsXdr, topNode, mode == XmlReadMode.IgnoreSchema);
2486                                 xmlload.LoadData(reader);
2487                             }
2488                         } //end of the while
2489
2490                         // read the closing tag of the current element
2491                         ReadEndElement(reader);
2492
2493                         // now top node contains the data part
2494                         xdoc.AppendChild(topNode);
2495                         if (xmlload == null)
2496                             xmlload = new XmlDataLoader(this, fIsXdr, mode == XmlReadMode.IgnoreSchema);
2497
2498                         if (mode == XmlReadMode.DiffGram) {
2499                             // we already got the diffs through XmlReader interface
2500                             return ret;
2501                         }
2502
2503                         // Load Data
2504                         if (mode == XmlReadMode.InferSchema || mode == XmlReadMode.InferTypedSchema) {
2505                             InferSchema(xdoc, null, mode);
2506                             ret = XmlReadMode.InferSchema;
2507                             xmlload.FromInference = true;
2508                             //                }
2509                             try {
2510                                 xmlload.LoadData(xdoc);
2511                             }
2512                             finally {
2513                                 xmlload.FromInference = false;
2514                             }
2515                         }
2516                     }
2517
2518                     return ret;
2519                 }
2520                 finally {
2521                     // Dev11 904428: prepare and cleanup rowDiffId hashtable
2522                     rowDiffIdUsage.Cleanup();
2523                 }
2524             }
2525             finally {
2526                 Bid.ScopeLeave(ref hscp);
2527             }
2528         }
2529
2530
2531         /// <devdoc>
2532         /// </devdoc>
2533         public XmlReadMode ReadXml(Stream stream, XmlReadMode mode)
2534         {
2535             if (stream == null)
2536                 return XmlReadMode.Auto;
2537
2538             XmlTextReader reader = (mode == XmlReadMode.Fragment) ? new XmlTextReader(stream, XmlNodeType.Element, null) : new XmlTextReader(stream);
2539             // Prevent Dtd entity in dataset 
2540             reader.XmlResolver = null;
2541             return ReadXml(reader, mode, false);
2542         }
2543
2544         /// <devdoc>
2545         /// </devdoc>
2546         public XmlReadMode ReadXml(TextReader reader, XmlReadMode mode)
2547         {
2548             if (reader == null)
2549                 return XmlReadMode.Auto;
2550
2551             XmlTextReader xmlreader = (mode == XmlReadMode.Fragment) ? new XmlTextReader(reader.ReadToEnd(), XmlNodeType.Element, null) : new XmlTextReader(reader);
2552             // Prevent Dtd entity in dataset 
2553             xmlreader.XmlResolver = null;
2554             return ReadXml(xmlreader, mode, false);
2555         }
2556
2557         /// <devdoc>
2558         /// </devdoc>
2559         [ResourceExposure(ResourceScope.Machine)]
2560         [ResourceConsumption(ResourceScope.Machine)]
2561         public XmlReadMode ReadXml(string fileName, XmlReadMode mode)
2562         {
2563             XmlTextReader xr = null;
2564             if (mode == XmlReadMode.Fragment) {
2565                 FileStream stream = new FileStream(fileName, FileMode.Open);
2566                 xr = new XmlTextReader(stream, XmlNodeType.Element, null);
2567             }
2568             else
2569                 xr = new XmlTextReader(fileName);
2570
2571             // Prevent Dtd entity in dataset             
2572             xr.XmlResolver = null;
2573
2574             try
2575             {
2576                 return ReadXml(xr, mode, false);
2577             }
2578             finally {
2579                 xr.Close();
2580             }
2581         }
2582
2583
2584         /// <devdoc>
2585         ///    Writes schema and data for the DataSet.
2586         /// </devdoc>
2587         public void WriteXml(Stream stream)
2588         {
2589             WriteXml(stream, XmlWriteMode.IgnoreSchema);
2590         }
2591
2592         /// <devdoc>
2593         /// </devdoc>
2594         public void WriteXml(TextWriter writer)
2595         {
2596             WriteXml(writer, XmlWriteMode.IgnoreSchema);
2597         }
2598
2599         /// <devdoc>
2600         /// </devdoc>
2601         public void WriteXml(XmlWriter writer)
2602         {
2603             WriteXml(writer, XmlWriteMode.IgnoreSchema);
2604         }
2605
2606         /// <devdoc>
2607         ///    <para>[To be supplied.]</para>
2608         /// </devdoc>
2609         [ResourceExposure(ResourceScope.Machine)]
2610         [ResourceConsumption(ResourceScope.Machine)]
2611         public void WriteXml(String fileName)
2612         {
2613             WriteXml(fileName, XmlWriteMode.IgnoreSchema);
2614         }
2615
2616         /// <devdoc>
2617         ///    Writes schema and data for the DataSet.
2618         /// </devdoc>
2619         public void WriteXml(Stream stream, XmlWriteMode mode)
2620         {
2621             if (stream != null) {
2622                 XmlTextWriter w = new XmlTextWriter(stream, null);
2623                 w.Formatting = Formatting.Indented;
2624
2625                 WriteXml(w, mode);
2626             }
2627         }
2628
2629         /// <devdoc>
2630         /// </devdoc>
2631         public void WriteXml(TextWriter writer, XmlWriteMode mode)
2632         {
2633             if (writer != null) {
2634                 XmlTextWriter w = new XmlTextWriter(writer);
2635                 w.Formatting = Formatting.Indented;
2636
2637                 WriteXml(w, mode);
2638             }
2639         }
2640
2641         /// <devdoc>
2642         /// </devdoc>
2643         public void WriteXml(XmlWriter writer, XmlWriteMode mode)
2644         {
2645             IntPtr hscp;
2646             Bid.ScopeEnter(out hscp, "<ds.DataSet.WriteXml|API> %d#, mode=%d{ds.XmlWriteMode}\n", ObjectID, (int)mode);
2647             try {
2648                 // Generate SchemaTree and write it out
2649                 if (writer != null) {
2650
2651                     if (mode == XmlWriteMode.DiffGram) {
2652                         // Create and save the updates
2653                         //                    new UpdateTreeGen(UpdateTreeGen.UPDATE, (DataRowState)(-1), this).Save(writer, null);
2654                         new NewDiffgramGen(this).Save(writer);
2655                     }
2656                     else {
2657                         // Create and save xml data
2658                         new XmlDataTreeWriter(this).Save(writer, mode == XmlWriteMode.WriteSchema);
2659                     }
2660                 }
2661             }
2662             finally {
2663                 Bid.ScopeLeave(ref hscp);
2664             }
2665         }
2666
2667         /// <devdoc>
2668         ///    <para>[To be supplied.]</para>
2669         /// </devdoc>
2670         [ResourceExposure(ResourceScope.Machine)]
2671         [ResourceConsumption(ResourceScope.Machine)]
2672         public void WriteXml(String fileName, XmlWriteMode mode)
2673         {
2674             IntPtr hscp;
2675             Bid.ScopeEnter(out hscp, "<ds.DataSet.WriteXml|API> %d#, fileName='%ls', mode=%d{ds.XmlWriteMode}\n", ObjectID, fileName, (int)mode);
2676             XmlTextWriter xw = new XmlTextWriter(fileName, null);
2677             try {
2678                 xw.Formatting = Formatting.Indented;
2679                 xw.WriteStartDocument(true);
2680                 if (xw != null) {
2681                     // Create and save the updates
2682                     if (mode == XmlWriteMode.DiffGram) {
2683                         new NewDiffgramGen(this).Save(xw);
2684                     }
2685                     else {
2686                         // Create and save xml data
2687                         new XmlDataTreeWriter(this).Save(xw, mode == XmlWriteMode.WriteSchema);
2688                     }
2689                 }
2690                 xw.WriteEndDocument();
2691             }
2692             finally {
2693                 xw.Close();
2694                 Bid.ScopeLeave(ref hscp);
2695             }
2696         }
2697
2698         /// <devdoc>
2699         ///    <para>
2700         ///       Gets the collection of parent relations which belong to a
2701         ///       specified table.
2702         ///    </para>
2703         /// </devdoc>
2704         internal DataRelationCollection GetParentRelations(DataTable table)
2705         {
2706             return table.ParentRelations;
2707         }
2708
2709         /// <devdoc>
2710         ///    <para>
2711         ///       Merges this <see cref='System.Data.DataSet'/> into a specified <see cref='System.Data.DataSet'/>.
2712         ///    </para>
2713         /// </devdoc>
2714         public void Merge(DataSet dataSet)
2715         {
2716             IntPtr hscp;
2717             Bid.ScopeEnter(out hscp, "<ds.DataSet.Merge|API> %d#, dataSet=%d\n", ObjectID, (dataSet != null) ? dataSet.ObjectID : 0);
2718             try {
2719                 Merge(dataSet, false, MissingSchemaAction.Add);
2720             }
2721             finally {
2722                 Bid.ScopeLeave(ref hscp);
2723             }
2724         }
2725
2726         /// <devdoc>
2727         ///    <para>
2728         ///       Merges this <see cref='System.Data.DataSet'/> into a specified <see cref='System.Data.DataSet'/> preserving changes according to
2729         ///       the specified argument.
2730         ///    </para>
2731         /// </devdoc>
2732         public void Merge(DataSet dataSet, bool preserveChanges)
2733         {
2734             IntPtr hscp;
2735             Bid.ScopeEnter(out hscp, "<ds.DataSet.Merge|API> %d#, dataSet=%d, preserveChanges=%d{bool}\n", ObjectID, (dataSet != null) ? dataSet.ObjectID : 0, preserveChanges);
2736             try {
2737                 Merge(dataSet, preserveChanges, MissingSchemaAction.Add);
2738             }
2739             finally {
2740                 Bid.ScopeLeave(ref hscp);
2741             }
2742         }
2743
2744         /// <devdoc>
2745         ///    <para>
2746         ///       Merges this <see cref='System.Data.DataSet'/> into a specified <see cref='System.Data.DataSet'/> preserving changes according to
2747         ///       the specified argument, and handling an incompatible schema according to the
2748         ///       specified argument.
2749         ///    </para>
2750         /// </devdoc>
2751         public void Merge(DataSet dataSet, bool preserveChanges, MissingSchemaAction missingSchemaAction) {
2752             IntPtr hscp;
2753             Bid.ScopeEnter(out hscp, "<ds.DataSet.Merge|API> %d#, dataSet=%d, preserveChanges=%d{bool}, missingSchemaAction=%d{ds.MissingSchemaAction}\n", ObjectID, (dataSet != null) ? dataSet.ObjectID : 0, preserveChanges, (int)missingSchemaAction);
2754             try {
2755
2756                 // Argument checks
2757                 if (dataSet == null)
2758                     throw ExceptionBuilder.ArgumentNull("dataSet");
2759
2760                 switch (missingSchemaAction) { // @perfnote: Enum.IsDefined
2761                     case MissingSchemaAction.Add:
2762                     case MissingSchemaAction.Ignore:
2763                     case MissingSchemaAction.Error:
2764                     case MissingSchemaAction.AddWithKey:
2765                         Merger merger = new Merger(this, preserveChanges, missingSchemaAction);
2766                         merger.MergeDataSet(dataSet);
2767                         break;
2768                     default:
2769                         throw Common.ADP.InvalidMissingSchemaAction(missingSchemaAction);
2770                 }
2771             }
2772             finally {
2773                 Bid.ScopeLeave(ref hscp);
2774             }
2775         }
2776
2777         /// <devdoc>
2778         ///    <para>
2779         ///       Merges this <see cref='System.Data.DataTable'/> into a specified <see cref='System.Data.DataTable'/>.
2780         ///    </para>
2781         /// </devdoc>
2782         public void Merge(DataTable table)
2783         {
2784             IntPtr hscp;
2785             Bid.ScopeEnter(out hscp, "<ds.DataSet.Merge|API> %d#, table=%d\n", ObjectID, (table != null) ? table.ObjectID : 0);
2786             try {
2787                 Merge(table, false, MissingSchemaAction.Add);
2788             }
2789             finally {
2790                 Bid.ScopeLeave(ref hscp);
2791             }
2792         }
2793
2794         /// <devdoc>
2795         ///    <para>
2796         ///       Merges this <see cref='System.Data.DataTable'/> into a specified <see cref='System.Data.DataTable'/>. with a value to preserve changes
2797         ///       made to the target, and a value to deal with missing schemas.
2798         ///    </para>
2799         /// </devdoc>
2800         public void Merge(DataTable table, bool preserveChanges, MissingSchemaAction missingSchemaAction)
2801         {
2802             IntPtr hscp;
2803             Bid.ScopeEnter(out hscp, "<ds.DataSet.Merge|API> %d#, table=%d, preserveChanges=%d{bool}, missingSchemaAction=%d{ds.MissingSchemaAction}\n", ObjectID, (table != null) ? table.ObjectID : 0, preserveChanges, (int)missingSchemaAction);
2804             try {
2805                 // Argument checks
2806                 if (table == null)
2807                     throw ExceptionBuilder.ArgumentNull("table");
2808
2809                 switch (missingSchemaAction) { // @perfnote: Enum.IsDefined
2810                     case MissingSchemaAction.Add:
2811                     case MissingSchemaAction.Ignore:
2812                     case MissingSchemaAction.Error:
2813                     case MissingSchemaAction.AddWithKey:
2814                         Merger merger = new Merger(this, preserveChanges, missingSchemaAction);
2815                         merger.MergeTable(table);
2816                         break;
2817                     default:
2818                         throw Common.ADP.InvalidMissingSchemaAction(missingSchemaAction);
2819                 }
2820             }
2821             finally {
2822                 Bid.ScopeLeave(ref hscp);
2823             }
2824         }
2825
2826
2827         /// <devdoc>
2828         ///    <para>[To be supplied.]</para>
2829         /// </devdoc>
2830         public void Merge(DataRow[] rows)
2831         {
2832             IntPtr hscp;
2833             Bid.ScopeEnter(out hscp, "<ds.DataSet.Merge|API> %d#, rows\n", ObjectID);
2834             try {
2835                 Merge(rows, false, MissingSchemaAction.Add);
2836             }
2837             finally {
2838                 Bid.ScopeLeave(ref hscp);
2839             }
2840         }
2841
2842         /// <devdoc>
2843         ///    <para>[To be supplied.]</para>
2844         /// </devdoc>
2845         public void Merge(DataRow[] rows, bool preserveChanges, MissingSchemaAction missingSchemaAction)
2846         {
2847             IntPtr hscp;
2848             Bid.ScopeEnter(out hscp, "<ds.DataSet.Merge|API> %d#, preserveChanges=%d{bool}, missingSchemaAction=%d{ds.MissingSchemaAction}\n", ObjectID, preserveChanges, (int)missingSchemaAction);
2849             try {
2850                 // Argument checks
2851                 if (rows == null)
2852                     throw ExceptionBuilder.ArgumentNull("rows");
2853
2854                 switch (missingSchemaAction) { // @perfnote: Enum.IsDefined
2855                     case MissingSchemaAction.Add:
2856                     case MissingSchemaAction.Ignore:
2857                     case MissingSchemaAction.Error:
2858                     case MissingSchemaAction.AddWithKey:
2859                         Merger merger = new Merger(this, preserveChanges, missingSchemaAction);
2860                         merger.MergeRows(rows);
2861                         break;
2862                     default:
2863                         throw Common.ADP.InvalidMissingSchemaAction(missingSchemaAction);
2864                 }
2865             }
2866             finally {
2867                 Bid.ScopeLeave(ref hscp);
2868             }
2869         }
2870
2871         protected virtual void OnPropertyChanging(PropertyChangedEventArgs pcevent)
2872         {
2873             if (onPropertyChangingDelegate != null)
2874                 onPropertyChangingDelegate(this, pcevent);
2875         }
2876
2877         /// <devdoc>
2878         ///     Inheriting classes should override this method to handle this event.
2879         ///     Call base.OnMergeFailed to send this event to any registered event
2880         ///     listeners.
2881         /// </devdoc>
2882         internal void OnMergeFailed(MergeFailedEventArgs mfevent)
2883         {
2884             if (onMergeFailed != null)
2885                 onMergeFailed(this, mfevent);
2886             else
2887                 throw ExceptionBuilder.MergeFailed(mfevent.Conflict);
2888         }
2889
2890         internal void RaiseMergeFailed(DataTable table, string conflict, MissingSchemaAction missingSchemaAction)
2891         {
2892             if (MissingSchemaAction.Error == missingSchemaAction)
2893                 throw ExceptionBuilder.MergeFailed(conflict);
2894
2895             MergeFailedEventArgs mfevent = new MergeFailedEventArgs(table, conflict);
2896             OnMergeFailed(mfevent);
2897             return;
2898         }
2899
2900         internal void OnDataRowCreated(DataRow row) {
2901             if (onDataRowCreated != null)
2902                 onDataRowCreated(this, row);
2903         }
2904
2905         internal void OnClearFunctionCalled(DataTable table) {
2906             if (onClearFunctionCalled != null)
2907                 onClearFunctionCalled(this, table);
2908         }
2909
2910         private void OnInitialized() {
2911             if (onInitialized != null) {
2912                 onInitialized(this, EventArgs.Empty);
2913             }
2914         }
2915
2916         /// <devdoc>
2917         /// This method should be overriden by subclasses to restrict tables being removed.
2918         /// </devdoc>
2919         protected internal virtual void OnRemoveTable(DataTable table) {
2920         }
2921
2922         internal void OnRemovedTable(DataTable table) {
2923             DataViewManager viewManager = defaultViewManager;
2924             if (null != viewManager) {
2925                 viewManager.DataViewSettings.Remove(table);
2926             }
2927         }
2928
2929         /// <devdoc>
2930         /// This method should be overriden by subclasses to restrict tables being removed.
2931         /// </devdoc>
2932         protected virtual void OnRemoveRelation(DataRelation relation)
2933         {
2934         }
2935
2936         // 
2937         internal void OnRemoveRelationHack(DataRelation relation)
2938         {
2939             OnRemoveRelation(relation);
2940         }
2941
2942
2943         protected internal void RaisePropertyChanging(string name)
2944         {
2945             OnPropertyChanging(new PropertyChangedEventArgs(name));
2946         }
2947
2948         internal DataTable[] TopLevelTables()
2949         {
2950             return TopLevelTables(false);
2951         }
2952
2953         internal DataTable[] TopLevelTables(bool forSchema)
2954         {
2955             // first let's figure out if we can represent the given dataSet as a tree using
2956             // the fact that all connected undirected graphs with n-1 edges are trees.
2957             List<DataTable> topTables = new List<DataTable>();
2958
2959             if (forSchema) {
2960                 // prepend the tables that are nested more than once
2961                 for (int i = 0; i < Tables.Count; i++)
2962                 {
2963                     DataTable table = Tables[i];
2964                     if (table.NestedParentsCount > 1 || table.SelfNested)
2965                         topTables.Add(table);
2966                 }
2967             }
2968             for (int i = 0; i < Tables.Count; i++)
2969             {
2970                 DataTable table = Tables[i];
2971                 if (table.NestedParentsCount == 0 && !topTables.Contains(table))
2972                     topTables.Add(table);
2973             }
2974             if (topTables.Count == 0)
2975                 return zeroTables;
2976             return topTables.ToArray();
2977         }
2978
2979         /// <devdoc>
2980         /// This method rolls back all the changes to have been made to this DataSet since
2981         /// it was loaded or the last time AcceptChanges was called.
2982         /// Any rows still in edit-mode cancel their edits.  New rows get removed.  Modified and
2983         /// Deleted rows return back to their original state.
2984         /// </devdoc>
2985         public virtual void RejectChanges()
2986         {
2987             IntPtr hscp;
2988             Bid.ScopeEnter(out hscp, "<ds.DataSet.RejectChanges|API> %d#\n", ObjectID);
2989             try {
2990                 bool fEnforce = EnforceConstraints;
2991                 EnforceConstraints = false;
2992                 for (int i = 0; i < Tables.Count; i++)
2993                     Tables[i].RejectChanges();
2994                 EnforceConstraints = fEnforce;
2995             }
2996             finally {
2997                 Bid.ScopeLeave(ref hscp);
2998             }
2999         }
3000
3001         /// <devdoc>
3002         ///    Resets the dataSet back to it's original state.  Subclasses should override
3003         ///    to restore back to it's original state.
3004         ///    
3005
3006         public virtual void Reset()
3007         {
3008             IntPtr hscp;
3009             Bid.ScopeEnter(out hscp, "<ds.DataSet.Reset|API> %d#\n", ObjectID);
3010             try {
3011                 for (int i = 0; i < Tables.Count; i++) {
3012                     ConstraintCollection cons = Tables[i].Constraints;
3013                     for (int j = 0; j < cons.Count; ) {
3014                         if (cons[j] is ForeignKeyConstraint) {
3015                             cons.Remove(cons[j]);
3016                         }
3017                         else
3018                             j++;
3019                     }
3020                 }
3021                 // SQLBU 502734: because of SQLBU 501916, dependent tables need to be notified when a table is cleared
3022                 // if relations are removed first, then exceptions happen
3023                 Clear();
3024                 Relations.Clear();
3025                 Tables.Clear();
3026             }
3027             finally {
3028                 Bid.ScopeLeave(ref hscp);
3029             }
3030         }
3031
3032         internal bool ValidateCaseConstraint() {
3033             IntPtr hscp;
3034             Bid.ScopeEnter(out hscp, "<ds.DataSet.ValidateCaseConstraint|INFO> %d#\n", ObjectID);
3035             try {
3036                 DataRelation relation = null;
3037                 for (int i = 0; i < Relations.Count; i++) {
3038                     relation = Relations[i];
3039                     if (relation.ChildTable.CaseSensitive != relation.ParentTable.CaseSensitive)
3040                         return false;
3041                 }
3042
3043                 ForeignKeyConstraint constraint = null;
3044                 ConstraintCollection constraints = null;
3045                 for (int i = 0; i < Tables.Count; i++) {
3046                     constraints = Tables[i].Constraints;
3047                     for (int j = 0; j < constraints.Count; j++) {
3048                         if (constraints[j] is ForeignKeyConstraint) {
3049                             constraint = (ForeignKeyConstraint)constraints[j];
3050                             if (constraint.Table.CaseSensitive != constraint.RelatedTable.CaseSensitive)
3051                                 return false;
3052                         }
3053                     }
3054                 }
3055                 return true;
3056             }
3057             finally {
3058                 Bid.ScopeLeave(ref hscp);
3059             }
3060         }
3061
3062         internal bool ValidateLocaleConstraint() {
3063             IntPtr hscp;
3064             Bid.ScopeEnter(out hscp, "<ds.DataSet.ValidateLocaleConstraint|INFO> %d#\n", ObjectID);
3065             try {
3066                 DataRelation relation = null;
3067                 for (int i = 0; i < Relations.Count; i++) {
3068                     relation = Relations[i];
3069                     if (relation.ChildTable.Locale.LCID != relation.ParentTable.Locale.LCID)
3070                         return false;
3071                 }
3072
3073                 ForeignKeyConstraint constraint = null;
3074                 ConstraintCollection constraints = null;
3075                 for (int i = 0; i < Tables.Count; i++) {
3076                     constraints = Tables[i].Constraints;
3077                     for (int j = 0; j < constraints.Count; j++) {
3078                         if (constraints[j] is ForeignKeyConstraint) {
3079                             constraint = (ForeignKeyConstraint)constraints[j];
3080                             if (constraint.Table.Locale.LCID != constraint.RelatedTable.Locale.LCID)
3081                                 return false;
3082                         }
3083                     }
3084                 }
3085                 return true;
3086             }
3087             finally {
3088                 Bid.ScopeLeave(ref hscp);
3089             }
3090         }
3091
3092         // [....]: may be better to rewrite this as nonrecursive?
3093         internal DataTable FindTable(DataTable baseTable, PropertyDescriptor[] props, int propStart) {
3094             if (props.Length < propStart + 1)
3095                 return baseTable;
3096
3097             PropertyDescriptor currentProp = props[propStart];
3098
3099             if (baseTable == null) {
3100                 // the accessor is the table name.  if we don't find it, return null.
3101                 if (currentProp is DataTablePropertyDescriptor) {
3102                     return FindTable(((DataTablePropertyDescriptor)currentProp).Table, props, propStart + 1);
3103                 }
3104                 return null;
3105             }
3106
3107             if (currentProp is DataRelationPropertyDescriptor) {
3108                 return FindTable(((DataRelationPropertyDescriptor)currentProp).Relation.ChildTable, props, propStart + 1);
3109             }
3110
3111             return null;
3112         }
3113
3114         protected virtual void ReadXmlSerializable(XmlReader reader) {
3115             //WebData 96421 and 104709, this is DataSet side fix for the thrown exception
3116             // <DataSet xsi:nil="true"> does not mean DataSet is null,but it does not have any child
3117             // so  dont do anything, ignore the attributes and just return empty DataSet;
3118             this.UseDataSetSchemaOnly = false;
3119             this.UdtIsWrapped = false;
3120
3121             if (reader.HasAttributes) {
3122                 const string xsinill = Keywords.XSI + ":" + Keywords.XSI_NIL;
3123                 if (reader.MoveToAttribute(xsinill)) {
3124                     string nilAttrib = reader.GetAttribute(xsinill);
3125                     if (string.Compare(nilAttrib, "true", StringComparison.Ordinal) == 0) {// case sensitive true comparison
3126                         MoveToElement(reader, 1);
3127                         return;
3128                     }
3129                 }
3130
3131                 const string useDataSetSchemaOnlyString = Keywords.MSD + ":" + Keywords.USEDATASETSCHEMAONLY;
3132                 if (reader.MoveToAttribute(useDataSetSchemaOnlyString)) {
3133                     string _useDataSetSchemaOnly = reader.GetAttribute(useDataSetSchemaOnlyString);
3134                     if (string.Equals(_useDataSetSchemaOnly, "true", StringComparison.Ordinal) ||
3135                         string.Equals(_useDataSetSchemaOnly, "1", StringComparison.Ordinal))
3136                     {
3137                         this.UseDataSetSchemaOnly = true;
3138                     }
3139                     else if (!string.Equals(_useDataSetSchemaOnly, "false", StringComparison.Ordinal) &&
3140                              !string.Equals(_useDataSetSchemaOnly, "0", StringComparison.Ordinal))
3141                     {
3142                         throw ExceptionBuilder.InvalidAttributeValue(Keywords.USEDATASETSCHEMAONLY, _useDataSetSchemaOnly);
3143                     }
3144                 }
3145
3146                 const string udtIsWrappedString = Keywords.MSD + ":" + Keywords.UDTCOLUMNVALUEWRAPPED;
3147                 if (reader.MoveToAttribute(udtIsWrappedString)) {
3148                     string _udtIsWrappedString = reader.GetAttribute(udtIsWrappedString);
3149                     if (string.Equals(_udtIsWrappedString, "true", StringComparison.Ordinal) ||
3150                         string.Equals(_udtIsWrappedString, "1", StringComparison.Ordinal))
3151                     {
3152                         this.UdtIsWrapped = true;
3153
3154                     }
3155                     else if (!string.Equals(_udtIsWrappedString, "false", StringComparison.Ordinal) &&
3156                              !string.Equals(_udtIsWrappedString, "0", StringComparison.Ordinal))
3157                     {
3158                         throw ExceptionBuilder.InvalidAttributeValue(Keywords.UDTCOLUMNVALUEWRAPPED, _udtIsWrappedString);
3159                     }
3160                 }
3161             }
3162             ReadXml(reader, XmlReadMode.DiffGram, true);
3163         }
3164
3165         protected virtual System.Xml.Schema.XmlSchema GetSchemaSerializable() {
3166             return null;
3167         }
3168
3169         /************************************************************************
3170         To publish
3171         int_tools\webserviceadmin.exe -install Application Application.dll 
3172
3173         To test
3174         http://localhost/application/service.asmx?wsdl
3175         or
3176         wsdl.exe /namespace:UserNamespace http://localhost/Application/Service.asmx?wsdl /out:Service.cs
3177
3178         The V1.0 & V1.1 WSDL for Untyped DataSet being returned as a result (no parameters)
3179         <s:element name="anyUserSpecifiedMethodName">
3180             <!--  This is where parameters go -->
3181             <s:complexType /> 
3182         </s:element>
3183         <s:element name="anyUserSpecifiedMethodName"+"Response">
3184             <s:complexType>
3185                 <s:sequence>
3186                     <s:element minOccurs="0" maxOccurs="1" name="anyUserSpecifiedMethodName"+"Result">
3187                         <s:complexType>
3188                             <s:sequence>
3189                                 <s:element ref="s:schema" /> 
3190                                 <s:any /> 
3191                             </s:sequence>
3192                         </s:complexType>
3193                     </s:element>
3194                 </s:sequence>
3195             </s:complexType>
3196         </s:element>
3197
3198         The V1.0 & V1.1 WSDL for Untyped DataSet as parameter, string for the result
3199         <s:element name="anyUserSpecifiedMethodName">
3200             <!--  This is where parameters go -->
3201             <s:complexType>
3202                 <s:sequence>
3203                     <s:element minOccurs="0" maxOccurs="1" name="set">
3204                         <s:complexType>
3205                             <s:sequence>
3206                                 <s:element ref="s:schema" /> 
3207                                 <s:any /> 
3208                             </s:sequence>
3209                         </s:complexType>
3210                     </s:element>
3211                 </s:sequence>
3212             </s:complexType>
3213         </s:element>
3214         <s:element name="anyUserSpecifiedMethodName"+"Response">
3215             <s:complexType>
3216                 <s:sequence>
3217                     <s:element minOccurs="0" maxOccurs="1" name="anyUserSpecifiedMethodName"+"Result" type="s:string" /> 
3218                 </s:sequence>
3219             </s:complexType>
3220         </s:element>
3221   
3222         The V2.0 WSDL for Untyped DataSet being returned as a result (no parameters)
3223         <s:element name="anyUserSpecifiedMethodName">
3224             <!--  This is where parameters go -->
3225             <s:complexType /> 
3226         </s:element>
3227         <s:element name="anyUserSpecifiedMethodName"+"Response">
3228             <s:complexType>
3229                 <s:sequence>
3230                     <s:element minOccurs="0" maxOccurs="1" name="anyUserSpecifiedMethodName"+"Result">
3231                         <s:complexType>
3232                             <s:sequence maxOccurs="unbounded">
3233                                 <s:any minOccurs="0" namespace="http://www.w3.org/2001/XMLSchema" processContents="lax" /> 
3234                                 <s:any minOccurs="0" namespace="urn:schemas-microsoft-com:xml-diffgram-v1" processContents="lax" /> 
3235                             </s:sequence>
3236                         </s:complexType>
3237                     </s:element>
3238                 </s:sequence>
3239             </s:complexType>
3240         </s:element>
3241         
3242         The V2.0 WSDL for Untyped DataSet as a parameter, string for the result
3243         <s:element name="anyUserSpecifiedMethodName">
3244             <!--  This is where parameters go -->
3245             <s:complexType>
3246                 <s:sequence>
3247                     <s:element minOccurs="0" maxOccurs="1" name="anyUserSpecifiedParameterName">
3248                         <s:complexType>
3249                             <s:sequence maxOccurs="unbounded">
3250                                 <s:any minOccurs="0" namespace="http://www.w3.org/2001/XMLSchema" processContents="lax" /> 
3251                                 <s:any minOccurs="0" namespace="urn:schemas-microsoft-com:xml-diffgram-v1" processContents="lax" /> 
3252                             </s:sequence>
3253                         </s:complexType>
3254                     </s:element>
3255                 </s:sequence>
3256             </s:complexType>
3257         </s:element>
3258         <s:element name="anyUserSpecifiedMethodName"+"Response">
3259             <s:complexType>
3260                 <s:sequence>
3261                     <s:element minOccurs="0" maxOccurs="1" name="anyUserSpecifiedMethodName"+"Result" type="s:string" /> 
3262                 </s:sequence>
3263             </s:complexType>
3264         </s:element>
3265   
3266         The V1.0, V1.1 & V2.0 WSDL for Typed DataSet
3267         <s:import schemaLocation="http://localhost/application/service.asmx?schema=typedDataSetName" namespace="typedDataSetName" /> 
3268         <s:element name="anyUserSpecifiedMethodName">
3269             <!--  This is where parameters go -->
3270             <s:complexType /> 
3271         </s:element>
3272         <s:element name="anyUserSpecifiedMethodName"+"Response">
3273             <s:complexType>
3274                 <s:sequence>
3275                     <s:element minOccurs="0" maxOccurs="1" name="anyUserSpecifiedMethodName"+"Result">
3276                         <s:complexType>
3277                             <s:sequence>
3278                                 <s:any namespace="typedDataSetName" /> 
3279                             </s:sequence>
3280                         </s:complexType>
3281                     </s:element>
3282                 </s:sequence>
3283             </s:complexType>
3284         </s:element>  
3285         ************************************************************************/
3286         public static XmlSchemaComplexType GetDataSetSchema(XmlSchemaSet schemaSet) {
3287             // For performance resons we are exploiting the fact that config files content is constant 
3288             // for a given appdomain so we can safely cache the prepared schema complex type and reuse it
3289             if (schemaTypeForWSDL == null) { // to change the config file, appdomain needs to restart; so it seems safe to cache the schema
3290                 XmlSchemaComplexType tempWSDL = new XmlSchemaComplexType();
3291                 XmlSchemaSequence sequence = new XmlSchemaSequence();
3292
3293                 if (PublishLegacyWSDL())
3294                 {   // Default is Version 1.0
3295                     XmlSchemaElement elem = new XmlSchemaElement();
3296                     elem.RefName = new XmlQualifiedName(Keywords.XSD_SCHEMA, Keywords.XSDNS);
3297                     sequence.Items.Add(elem);
3298                     XmlSchemaAny any = new XmlSchemaAny();
3299                     sequence.Items.Add(any);
3300                 }
3301                 else
3302                 {   // this means Version == V2.0 or newer
3303                     XmlSchemaAny any = new XmlSchemaAny();
3304                     any.Namespace = XmlSchema.Namespace;
3305                     any.MinOccurs = 0;
3306                     any.ProcessContents = XmlSchemaContentProcessing.Lax;
3307                     sequence.Items.Add(any);
3308
3309                     any = new XmlSchemaAny();
3310                     any.Namespace = Keywords.DFFNS;
3311                     any.MinOccurs = 0; // when recognizing WSDL - MinOccurs="0" denotes DataSet, a MinOccurs="1" for DataTable
3312                     any.ProcessContents = XmlSchemaContentProcessing.Lax;
3313                     sequence.Items.Add(any);
3314                     sequence.MaxOccurs = Decimal.MaxValue;
3315                 }
3316                 tempWSDL.Particle = sequence;
3317
3318                 schemaTypeForWSDL = tempWSDL;
3319             }
3320             return schemaTypeForWSDL;
3321         }
3322
3323         /********************************************
3324         <configuration>
3325             <configSections>
3326                 <section name="system.data.dataset" type="System.Configuration.NameValueFileSectionHandler, System, Version=%ASSEMBLY_VERSION%, Culture=neutral, PublicKeyToken=%ECMA_PUBLICKEY%" restartOnExternalChanges="false" />
3327             </configSections>
3328             <system.data.dataset>
3329                 <!--  if WSDL_VERSION is missing it will default to 1.0
3330                     <add key="WSDL_VERSION" value="1.0"/>
3331                 -->
3332                 <add key="WSDL_VERSION" value="2.0"/>
3333             </system.data.dataset>
3334         </configuration>
3335         *******************************************/
3336         private static bool PublishLegacyWSDL()
3337         {
3338             Single version = 1.0f; // Default is Version 1.0
3339 #if !NO_CONFIGURATION
3340             NameValueCollection settings = (NameValueCollection)PrivilegedConfigurationManager.GetSection(Keywords.WS_DATASETFULLQNAME);
3341             if (settings != null)
3342             {
3343                 string[] values = settings.GetValues(Keywords.WS_VERSION);
3344                 if ((null != values) && (0 < values.Length) && (null != values[0]))
3345                 {   // will throw FormatException if not a valid number
3346                     version = Single.Parse(values[0], CultureInfo.InvariantCulture);
3347                 }
3348             }
3349 #endif
3350             return (version < 2.0f); // if config does not exist, Default is Version 1.0
3351         }
3352
3353         XmlSchema IXmlSerializable.GetSchema() {
3354             if (GetType() == typeof(DataSet)) {
3355                 return null;
3356             }
3357             MemoryStream stream = new MemoryStream();
3358             // WriteXmlSchema(new XmlTextWriter(stream, null));
3359             XmlWriter writer = new XmlTextWriter(stream, null);
3360             if (writer != null) {
3361                 (new XmlTreeGen(SchemaFormat.WebService)).Save(this, writer);
3362             }
3363             stream.Position = 0;
3364             return XmlSchema.Read(new XmlTextReader(stream), null);
3365             //            return GetSchemaSerializable();
3366         }
3367
3368         void IXmlSerializable.ReadXml(XmlReader reader) {
3369             bool fNormalization = true;
3370             XmlTextReader xmlTextReader = null;
3371             IXmlTextParser xmlTextParser = reader as IXmlTextParser;
3372             if (xmlTextParser != null) {
3373                 fNormalization = xmlTextParser.Normalized;
3374                 xmlTextParser.Normalized = false;
3375             }
3376             else {
3377                 xmlTextReader = reader as XmlTextReader;
3378                 if (xmlTextReader != null) {
3379                     fNormalization = xmlTextReader.Normalization;
3380                     xmlTextReader.Normalization = false;
3381                 }
3382             }
3383
3384             ReadXmlSerializable(reader);
3385
3386             if (xmlTextParser != null)
3387                 xmlTextParser.Normalized = fNormalization;
3388             else if (xmlTextReader != null)
3389                 xmlTextReader.Normalization = fNormalization;
3390         }
3391
3392         void IXmlSerializable.WriteXml(XmlWriter writer) {
3393             this.WriteXmlSchema(writer, SchemaFormat.WebService, (Converter<Type, string>)null);
3394             this.WriteXml(writer, XmlWriteMode.DiffGram);
3395         }
3396
3397         public virtual void Load(IDataReader reader, LoadOption loadOption, FillErrorEventHandler errorHandler, params DataTable[] tables) {
3398             IntPtr hscp;
3399             Bid.ScopeEnter(out hscp, "<ds.DataSet.Load|API> reader, loadOption=%d{ds.LoadOption}", (int)loadOption);
3400             try {
3401                 foreach (DataTable dt in tables) {
3402                     Common.ADP.CheckArgumentNull(dt, "tables");
3403                     if (dt.DataSet != this) {
3404                         throw ExceptionBuilder.TableNotInTheDataSet(dt.TableName);
3405                     }
3406                 }
3407                 Common.LoadAdapter adapter = new Common.LoadAdapter();
3408                 adapter.FillLoadOption = loadOption;
3409                 adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey;
3410                 if (null != errorHandler) {
3411                     adapter.FillError += errorHandler;
3412                 }
3413                 adapter.FillFromReader(tables, reader, 0, 0);
3414
3415                 if (!reader.IsClosed && !reader.NextResult()) { // 
3416                     reader.Close();
3417                 }
3418             }
3419             finally {
3420                 Bid.ScopeLeave(ref hscp);
3421             }
3422         }
3423
3424         public void Load(IDataReader reader, LoadOption loadOption, params DataTable[] tables) {
3425             Load(reader, loadOption, null, tables);
3426         }
3427
3428         public void Load(IDataReader reader, LoadOption loadOption, params string[] tables) {
3429             Common.ADP.CheckArgumentNull(tables, "tables");
3430             DataTable[] dataTables = new DataTable[tables.Length];
3431             for (int i = 0; i < tables.Length; i++) {
3432                 DataTable tempDT = this.Tables[tables[i]];
3433                 if (null == tempDT) {
3434                     tempDT = new DataTable(tables[i]);
3435                     // fxcop: new DataTable should inherit the CaseSensitive, Locale, Namespace from DataSet
3436                     Tables.Add(tempDT);
3437                 }
3438                 dataTables[i] = tempDT;
3439             }
3440             Load(reader, loadOption, null, dataTables);
3441         }
3442
3443         public DataTableReader CreateDataReader() {
3444             if (Tables.Count == 0)
3445                 throw ExceptionBuilder.CannotCreateDataReaderOnEmptyDataSet();
3446
3447             DataTable[] dataTables = new DataTable[Tables.Count];
3448             for (int i = 0; i < Tables.Count; i++) {
3449                 dataTables[i] = Tables[i];
3450             }
3451             return CreateDataReader(dataTables);
3452         }
3453
3454         public DataTableReader CreateDataReader(params DataTable[] dataTables) {
3455             IntPtr hscp;
3456             Bid.ScopeEnter(out hscp, "<ds.DataSet.GetDataReader|API> %d#\n", ObjectID);
3457             try {
3458                 if (dataTables.Length == 0)
3459                     throw ExceptionBuilder.DataTableReaderArgumentIsEmpty();
3460
3461                 for (int i = 0; i < dataTables.Length; i++) {
3462                     if (dataTables[i] == null)
3463                         throw ExceptionBuilder.ArgumentContainsNullValue();
3464                 }
3465
3466                 return new DataTableReader(dataTables);
3467             }
3468             finally {
3469                 Bid.ScopeLeave(ref hscp);
3470             }
3471         }
3472
3473         internal string MainTableName {
3474             get {
3475                 return mainTableName;
3476             }
3477             set {
3478                 this.mainTableName = value;
3479             }
3480         }
3481
3482         internal int ObjectID {
3483             get {
3484                 return _objectID;
3485             }
3486         }
3487
3488     }
3489 #endif
3490
3491 #if !NO_CODEDOM
3492  public class DataSetSchemaImporterExtension : SchemaImporterExtension {
3493         // DataSetSchemaImporterExtension is used for WebServices, it is used to recognize the schema of DataSet within wsdl
3494         // If a non 2.0 enabled DataSetSchemaImporterExtension, wsdl will generate a classes that you can't cast to dataset / datatable
3495
3496         Hashtable importedTypes = new Hashtable();
3497
3498         /// <devdoc>
3499         ///    <para>[To be supplied.]</para>
3500         /// </devdoc>
3501         public override string ImportSchemaType(string name, string schemaNamespace, XmlSchemaObject context, XmlSchemas schemas, XmlSchemaImporter importer, CodeCompileUnit compileUnit, CodeNamespace mainNamespace, CodeGenerationOptions options, CodeDomProvider codeProvider) {
3502             IList values = schemas.GetSchemas(schemaNamespace);
3503             if (values.Count != 1) {
3504                 return null;
3505             }
3506             XmlSchema schema = values[0] as XmlSchema;
3507             if (schema == null)
3508                 return null;
3509             XmlSchemaType type = (XmlSchemaType)schema.SchemaTypes[new XmlQualifiedName(name, schemaNamespace)];
3510             return ImportSchemaType(type, context, schemas, importer, compileUnit, mainNamespace, options, codeProvider);
3511         }
3512
3513         /// <devdoc>
3514         ///    <para>[To be supplied.]</para>
3515         /// </devdoc>
3516         public override string ImportSchemaType(XmlSchemaType type, XmlSchemaObject context, XmlSchemas schemas, XmlSchemaImporter importer, CodeCompileUnit compileUnit, CodeNamespace mainNamespace, CodeGenerationOptions options, CodeDomProvider codeProvider) {
3517             if (type == null) {
3518                 return null;
3519             }
3520             if (importedTypes[type] != null) {
3521                 mainNamespace.Imports.Add(new CodeNamespaceImport(typeof(DataSet).Namespace));
3522                 compileUnit.ReferencedAssemblies.Add("System.Data.dll");
3523                 return (string)importedTypes[type];
3524             }
3525             if (!(context is XmlSchemaElement))
3526                 return null;
3527
3528             XmlSchemaElement e = (XmlSchemaElement)context;
3529
3530             // recognizing the following is important, but not as part of SQLPT 120015394: Support WSI Compliant WSDL for DataSet
3531             // <xs:element name="NewDataSet" msdata:IsDataSet="true">
3532             // see also SQLBU 338644, 410965, 423446
3533             //if (IsDataSet(e))
3534             //{
3535             //    return GenerateTypedDataSet(e, schemas, mainNamespace, compileUnit.ReferencedAssemblies, codeProvider);
3536             //}
3537
3538             if (type is XmlSchemaComplexType) {
3539                 XmlSchemaComplexType ct = (XmlSchemaComplexType)type;
3540
3541                 if (ct.Particle is XmlSchemaSequence)
3542                 {
3543                     XmlSchemaObjectCollection items = ((XmlSchemaSequence)ct.Particle).Items;
3544                     if ((2 == items.Count) && (items[0] is XmlSchemaAny) && (items[1] is XmlSchemaAny))
3545                     {
3546                         XmlSchemaAny any0 = (XmlSchemaAny)items[0];
3547                         XmlSchemaAny any1 = (XmlSchemaAny)items[1];
3548                         if ((any0.Namespace == XmlSchema.Namespace) && (any1.Namespace == "urn:schemas-microsoft-com:xml-diffgram-v1"))
3549                         {   // new diffgramm format
3550                             string ns = null;
3551                             foreach (XmlSchemaAttribute a in ct.Attributes)
3552                             {
3553                                 if (a.Name == "namespace")
3554                                 {
3555                                     ns = a.FixedValue.Trim();
3556                                     break;
3557                                 }
3558                             }
3559                             bool isDataSet = false;
3560
3561                             // check for DataSet or DataTable
3562                             if (((XmlSchemaSequence)ct.Particle).MaxOccurs == Decimal.MaxValue)
3563                             {
3564                                 isDataSet = true;
3565                             }
3566                             else if (any0.MaxOccurs == Decimal.MaxValue)
3567                             {
3568                                 isDataSet = false;
3569                             }
3570                             else
3571                             {
3572                                 return null;
3573                             }
3574
3575                             if (ns == null)
3576                             {   //Un-Typed DataSet / DataTable
3577                                 string typeName = isDataSet ? typeof(DataSet).FullName : typeof(DataTable).FullName;
3578                                 importedTypes.Add(type, typeName);
3579                                 mainNamespace.Imports.Add(new CodeNamespaceImport(typeof(DataSet).Namespace));
3580                                 compileUnit.ReferencedAssemblies.Add("System.Data.dll");
3581                                 return typeName;
3582                             }
3583                             else
3584                             {   // Typed DataSet / DataTable
3585                                 foreach (XmlSchema schema in schemas.GetSchemas(ns))
3586                                 {
3587                                     if ((schema != null) && (schema.Id != null))
3588                                     {
3589                                         XmlSchemaElement ds = FindDataSetElement(schema); // implement  FindDataTableElement(schema)
3590                                         if (ds != null)
3591                                         {
3592                                             return ImportSchemaType(ds.SchemaType, ds, schemas, importer, compileUnit, mainNamespace, options, codeProvider);
3593                                         }
3594                                         // else return null
3595                                     }
3596                                 }
3597                                 return null;
3598                             }
3599                         }
3600                     }
3601                 }
3602                 if (ct.Particle is XmlSchemaSequence || ct.Particle is XmlSchemaAll) {
3603                     XmlSchemaObjectCollection items = ((XmlSchemaGroupBase)ct.Particle).Items;
3604                     if (items.Count == 2) {
3605                         if (!(items[0] is XmlSchemaElement && items[1] is XmlSchemaAny)) return null;
3606                         XmlSchemaElement schema = (XmlSchemaElement)items[0];
3607                         if (!(schema.RefName.Name == "schema" && schema.RefName.Namespace == XmlSchema.Namespace)) return null;
3608                         string typeName = typeof(DataSet).FullName;
3609                         importedTypes.Add(type, typeName);
3610                         mainNamespace.Imports.Add(new CodeNamespaceImport(typeof(DataSet).Namespace));
3611                         compileUnit.ReferencedAssemblies.Add("System.Data.dll");
3612                         return typeName;
3613                     }
3614                     else if (1 == items.Count)
3615                     {
3616                         XmlSchemaAny any = items[0] as XmlSchemaAny;
3617                         if ((null != any) &&
3618                             (null != any.Namespace) &&
3619                             (any.Namespace.IndexOfAny(new char[] { '#', ' ' }) < 0)) // special syntax (##any, ##other, ...) or more than one Uri present
3620                         {
3621                             foreach (XmlSchema schema in schemas.GetSchemas(any.Namespace))
3622                             {
3623                                 if ((null != schema) &&
3624                                     (null != schema.Id))
3625                                 {
3626                                     XmlSchemaElement ds = FindDataSetElement(schema);
3627                                     if (ds != null)
3628                                     {
3629                                         return ImportSchemaType(ds.SchemaType, ds, schemas, importer, compileUnit, mainNamespace, options, codeProvider);
3630                                     }
3631                                     // else return null
3632                                 }
3633                                 // else return null
3634                             }
3635                         }
3636                         // else return null
3637                     }
3638                 }
3639             }
3640             return null;
3641         }
3642
3643
3644         internal XmlSchemaElement FindDataSetElement(XmlSchema schema) {
3645             foreach (XmlSchemaObject item in schema.Items) {
3646                 if (item is XmlSchemaElement && IsDataSet((XmlSchemaElement)item)) {
3647                     return (XmlSchemaElement)item;
3648                 }
3649             }
3650             return null;
3651         }
3652
3653         internal string GenerateTypedDataSet(XmlSchemaElement element, XmlSchemas schemas, CodeNamespace codeNamespace, StringCollection references, CodeDomProvider codeProvider) {
3654             if (element == null)
3655                 return null;
3656
3657             if (importedTypes[element.SchemaType] != null)
3658                 return (string)importedTypes[element.SchemaType];
3659
3660             IList values = schemas.GetSchemas(element.QualifiedName.Namespace);
3661             if (values.Count != 1) {
3662                 return null;
3663             }
3664             XmlSchema schema = values[0] as XmlSchema;
3665             if (schema == null)
3666                 return null;
3667
3668             DataSet ds = new DataSet();
3669
3670             // 
3671             using (MemoryStream stream = new MemoryStream()) {
3672                 schema.Write(stream);
3673                 stream.Position = 0;
3674                 ds.ReadXmlSchema(stream);
3675             }
3676
3677 #pragma warning disable 618 // ignore obsolete warning about TypedDataSetGenerator
3678             CodeTypeDeclaration dsClass = new TypedDataSetGenerator().GenerateCode(ds, codeNamespace, codeProvider.CreateGenerator());
3679 #pragma warning restore 618
3680             string typeName = dsClass.Name;
3681             importedTypes.Add(element.SchemaType, typeName);
3682             references.Add("System.Data.dll");
3683             return typeName;
3684         }
3685
3686         internal static bool IsDataSet(XmlSchemaElement e) {
3687             if (e.UnhandledAttributes != null) {
3688                 foreach (XmlAttribute a in e.UnhandledAttributes) {
3689                     if (a.LocalName == "IsDataSet" && a.NamespaceURI == Keywords.MSDNS) {
3690                         // currently the msdata:IsDataSet uses its own format for the boolean values
3691                         if (a.Value == "True" || a.Value == "true" || a.Value == "1") return true;
3692                     }
3693                 }
3694             }
3695             return false;
3696         }
3697     }
3698 #endif
3699 }