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