|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.Common;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
namespace System.Data
{
/// <summary>
/// Represents an in-memory cache of data.
/// </summary>
[Designer("Microsoft.VSDesigner.Data.VS.DataSetDesigner, Microsoft.VSDesigner, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
[DefaultProperty(nameof(DataSetName))]
[Serializable]
[ToolboxItem("Microsoft.VSDesigner.Data.VS.DataSetToolboxItem, Microsoft.VSDesigner, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
[XmlSchemaProvider(nameof(GetDataSetSchema))]
[XmlRoot(nameof(DataSet))]
[System.Runtime.CompilerServices.TypeForwardedFrom("System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.NonPublicConstructors)] // needed by Clone() to preserve derived ctors
public class DataSet : MarshalByValueComponent, IListSource, IXmlSerializable, ISupportInitializeNotification, ISerializable
{
internal const string RequiresDynamicCodeMessage = "Members from serialized types may use dynamic code generation.";
internal const string RequiresUnreferencedCodeMessage = "Members from serialized types may be trimmed if not referenced directly.";
private const string KEY_XMLSCHEMA = "XmlSchema";
private const string KEY_XMLDIFFGRAM = "XmlDiffGram";
private DataViewManager? _defaultViewManager;
// Public Collections
private readonly DataTableCollection _tableCollection;
private readonly DataRelationCollection _relationCollection;
internal PropertyCollection? _extendedProperties;
private string _dataSetName = "NewDataSet";
private string _datasetPrefix = string.Empty;
internal string _namespaceURI = string.Empty;
private bool _enforceConstraints = true;
// globalization stuff
private bool _caseSensitive;
private CultureInfo _culture;
private bool _cultureUserSet;
// Internal definitions
internal bool _fInReadXml;
internal bool _fInLoadDiffgram;
internal bool _fTopLevelTable;
internal bool _fInitInProgress;
internal bool _fEnableCascading = true;
internal bool _fIsSchemaLoading;
private bool _fBoundToDocument; // for XmlDataDocument
internal string _mainTableName = string.Empty;
//default remoting format is XML
private SerializationFormat _remotingFormat = SerializationFormat.Xml;
private readonly object _defaultViewManagerLock = new object();
private static int s_objectTypeCount; // Bid counter
private readonly int _objectID = Interlocked.Increment(ref s_objectTypeCount);
private static XmlSchemaComplexType? s_schemaTypeForWSDL;
internal bool _useDataSetSchemaOnly; // UseDataSetSchemaOnly , for YUKON
internal bool _udtIsWrapped; // if UDT is wrapped , for YUKON
[FeatureSwitchDefinition("System.Data.DataSet.XmlSerializationIsSupported")]
[FeatureGuard(typeof(RequiresUnreferencedCodeAttribute))]
[FeatureGuard(typeof(RequiresDynamicCodeAttribute))]
#pragma warning disable IL4000
internal static bool XmlSerializationIsSupported => AppContext.TryGetSwitch("System.Data.DataSet.XmlSerializationIsSupported", out bool isSupported) ? isSupported : true;
#pragma warning restore IL4000
/// <summary>
/// Initializes a new instance of the <see cref='System.Data.DataSet'/> class.
/// </summary>
public DataSet()
{
GC.SuppressFinalize(this);
DataCommonEventSource.Log.Trace("<ds.DataSet.DataSet|API> {0}", ObjectID); // others will call this constr
// Set default locale
_tableCollection = new DataTableCollection(this);
_relationCollection = new DataRelationCollection.DataSetRelationCollection(this);
_culture = CultureInfo.CurrentCulture; // Set default locale
}
/// <summary>
/// Initializes a new instance of a <see cref='System.Data.DataSet'/>
/// class with the given name.
/// </summary>
public DataSet(string dataSetName) : this()
{
DataSetName = dataSetName;
}
[DefaultValue(SerializationFormat.Xml)]
public SerializationFormat RemotingFormat
{
get { return _remotingFormat; }
set
{
switch (value)
{
case SerializationFormat.Xml:
break;
case SerializationFormat.Binary:
if (LocalAppContextSwitches.AllowUnsafeSerializationFormatBinary)
{
break;
}
throw ExceptionBuilder.SerializationFormatBinaryNotSupported();
default:
throw ExceptionBuilder.InvalidRemotingFormat(value);
}
_remotingFormat = value;
// this property is inherited to DataTable from DataSet.So we set this value to DataTable also
for (int i = 0; i < Tables.Count; i++)
{
Tables[i].RemotingFormat = value;
}
}
}
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public virtual SchemaSerializationMode SchemaSerializationMode
{
//Typed DataSet calls into this
get { return SchemaSerializationMode.IncludeSchema; }
set
{
if (value != SchemaSerializationMode.IncludeSchema)
{
throw ExceptionBuilder.CannotChangeSchemaSerializationMode();
}
}
}
// Check whether the stream is binary serialized.
// 'static' function that consumes SerializationInfo
protected bool IsBinarySerialized(SerializationInfo info, StreamingContext context)
{
// mainly for typed DS
// our default remoting format is XML
SerializationFormat remotingFormat = SerializationFormat.Xml;
SerializationInfoEnumerator e = info.GetEnumerator();
while (e.MoveNext())
{
if (e.Name == "DataSet.RemotingFormat")
{
//DataSet.RemotingFormat does not exist in V1/V1.1 versions
remotingFormat = (SerializationFormat)e.Value!;
break;
}
}
return (remotingFormat == SerializationFormat.Binary);
}
// Should Schema be included during Serialization
// 'static' function that consumes SerializationInfo
protected SchemaSerializationMode DetermineSchemaSerializationMode(SerializationInfo info, StreamingContext context)
{
//Typed DataSet calls into this
SchemaSerializationMode schemaSerializationMode = SchemaSerializationMode.IncludeSchema;
SerializationInfoEnumerator e = info.GetEnumerator();
while (e.MoveNext())
{
if (e.Name == "SchemaSerializationMode.DataSet")
{ //SchemaSerializationMode.DataSet does not exist in V1/V1.1 versions
schemaSerializationMode = (SchemaSerializationMode)e.Value!;
break;
}
}
return schemaSerializationMode;
}
protected SchemaSerializationMode DetermineSchemaSerializationMode(XmlReader reader)
{
//Typed DataSet calls into this
SchemaSerializationMode schemaSerializationMode = SchemaSerializationMode.IncludeSchema;
reader.MoveToContent();
if (reader.NodeType == XmlNodeType.Element)
{
if (reader.HasAttributes)
{
string? attribValue = reader.GetAttribute(Keywords.MSD_SCHEMASERIALIZATIONMODE, Keywords.MSDNS);
if (string.Equals(attribValue, Keywords.MSD_EXCLUDESCHEMA, StringComparison.OrdinalIgnoreCase))
{
schemaSerializationMode = SchemaSerializationMode.ExcludeSchema;
}
else if (string.Equals(attribValue, Keywords.MSD_INCLUDESCHEMA, StringComparison.OrdinalIgnoreCase))
{
schemaSerializationMode = SchemaSerializationMode.IncludeSchema;
}
else if (attribValue != null)
{
// if attrib does not exist, then don't throw
throw ExceptionBuilder.InvalidSchemaSerializationMode(typeof(SchemaSerializationMode), attribValue);
}
}
}
return schemaSerializationMode;
}
// Deserialize all the tables data of the dataset from binary/xml stream.
// 'instance' method that consumes SerializationInfo
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
protected void GetSerializationData(SerializationInfo info, StreamingContext context)
{
// mainly for typed DS
SerializationFormat remotingFormat = SerializationFormat.Xml;
SerializationInfoEnumerator e = info.GetEnumerator();
while (e.MoveNext())
{
if (e.Name == "DataSet.RemotingFormat")
{ //DataSet.RemotingFormat does not exist in V1/V1.1 versions
remotingFormat = (SerializationFormat)e.Value!;
break;
}
}
DeserializeDataSetData(info, remotingFormat);
}
// Deserialize all the tables schema and data of the dataset from binary/xml stream.
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2112:ReflectionToRequiresUnreferencedCode",
Justification = "CreateInstanceOfThisType's use of GetType uses only the parameterless constructor, but the annotations preserve all non-public constructors causing a warning for the serialization constructors. Those constructors won't be used here.")]
[Obsolete(Obsoletions.LegacyFormatterImplMessage, DiagnosticId = Obsoletions.LegacyFormatterImplDiagId, UrlFormat = Obsoletions.SharedUrlFormat)]
[EditorBrowsable(EditorBrowsableState.Never)]
protected DataSet(SerializationInfo info, StreamingContext context) : this(info, context, true)
{
}
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2112:ReflectionToRequiresUnreferencedCode",
Justification = "CreateInstanceOfThisType's use of GetType uses only the parameterless constructor, but the annotations preserve all non-public constructors causing a warning for the serialization constructors. Those constructors won't be used here.")]
[Obsolete(Obsoletions.LegacyFormatterImplMessage, DiagnosticId = Obsoletions.LegacyFormatterImplDiagId, UrlFormat = Obsoletions.SharedUrlFormat)]
[EditorBrowsable(EditorBrowsableState.Never)]
protected DataSet(SerializationInfo info, StreamingContext context, bool ConstructSchema) : this()
{
SerializationFormat remotingFormat = SerializationFormat.Xml;
SchemaSerializationMode schemaSerializationMode = SchemaSerializationMode.IncludeSchema;
SerializationInfoEnumerator e = info.GetEnumerator();
while (e.MoveNext())
{
switch (e.Name)
{
case "DataSet.RemotingFormat": //DataSet.RemotingFormat does not exist in V1/V1.1 versions
remotingFormat = (SerializationFormat)e.Value!;
break;
case "SchemaSerializationMode.DataSet": //SchemaSerializationMode.DataSet does not exist in V1/V1.1 versions
schemaSerializationMode = (SchemaSerializationMode)e.Value!;
break;
}
}
if (remotingFormat == SerializationFormat.Binary &&
!LocalAppContextSwitches.AllowUnsafeSerializationFormatBinary)
{
throw ExceptionBuilder.SerializationFormatBinaryNotSupported();
}
if (schemaSerializationMode == SchemaSerializationMode.ExcludeSchema)
{
InitializeDerivedDataSet();
}
// adding back this check will fix typed dataset XML remoting, but we have to fix case that
// a class inherits from DataSet and just relies on DataSet to deserialize (see SQL BU DT 374717)
// to fix that case also, we need to add a flag and add it to below check so return (no-op) will be
// conditional (flag needs to be set in TypedDataSet
if (remotingFormat == SerializationFormat.Xml && !ConstructSchema)
{
return; //For typed dataset xml remoting, this is a no-op
}
DeserializeDataSet(info, context, remotingFormat, schemaSerializationMode);
}
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "Binary serialization is unsafe in general and is planned to be obsoleted. We do not want to mark interface or ctors of this class as unsafe as that would show many unnecessary warnings elsewhere.")]
[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode",
Justification = "Binary serialization is unsafe in general and is planned to be obsoleted. We do not want to mark interface or ctors of this class as unsafe as that would show many unnecessary warnings elsewhere.")]
[Obsolete(Obsoletions.LegacyFormatterImplMessage, DiagnosticId = Obsoletions.LegacyFormatterImplDiagId, UrlFormat = Obsoletions.SharedUrlFormat)]
[EditorBrowsable(EditorBrowsableState.Never)]
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
SerializationFormat remotingFormat = RemotingFormat;
SerializeDataSet(info, context, remotingFormat);
}
// Deserialize all the tables data of the dataset from binary/xml stream.
protected virtual void InitializeDerivedDataSet() { }
// Serialize all the tables.
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
private void SerializeDataSet(SerializationInfo info, StreamingContext context, SerializationFormat remotingFormat)
{
Debug.Assert(info != null);
info.AddValue("DataSet.RemotingVersion", new Version(2, 0));
// SqlHotFix 299, SerializationFormat enumeration types don't exist in V1.1 SP1
if (SerializationFormat.Xml != remotingFormat)
{
info.AddValue("DataSet.RemotingFormat", remotingFormat);
}
// SqlHotFix 299, SchemaSerializationMode enumeration types don't exist in V1.1 SP1
if (SchemaSerializationMode.IncludeSchema != SchemaSerializationMode)
{
//SkipSchemaDuringSerialization
info.AddValue("SchemaSerializationMode.DataSet", SchemaSerializationMode);
}
if (remotingFormat != SerializationFormat.Xml)
{
if (SchemaSerializationMode == SchemaSerializationMode.IncludeSchema)
{
//DataSet public state properties
SerializeDataSetProperties(info);
//Tables Count
info.AddValue("DataSet.Tables.Count", Tables.Count);
//Tables, Columns, Rows
for (int i = 0; i < Tables.Count; i++)
{
MemoryStream memStream = new MemoryStream();
#pragma warning disable SYSLIB0011 // Issue https://github.com/dotnet/runtime/issues/39289 tracks finding an alternative to BinaryFormatter
#pragma warning disable SYSLIB0050 // StreamingContext ctor is obsolete
BinaryFormatter bf = new BinaryFormatter(null, new StreamingContext(context.State, false));
bf.Serialize(memStream, Tables[i]);
#pragma warning restore SYSLIB0050
#pragma warning restore SYSLIB0011
memStream.Position = 0;
info.AddValue(string.Format(CultureInfo.InvariantCulture, "DataSet.Tables_{0}", i), memStream.GetBuffer());
}
//Constraints
for (int i = 0; i < Tables.Count; i++)
{
Tables[i].SerializeConstraints(info, i, true);
}
//Relations
SerializeRelations(info);
//Expression Columns
for (int i = 0; i < Tables.Count; i++)
{
Tables[i].SerializeExpressionColumns(info, i);
}
}
else
{
//Serialize DataSet public properties.
SerializeDataSetProperties(info);
}
//Rows
for (int i = 0; i < Tables.Count; i++)
{
Tables[i].SerializeTableData(info, i);
}
}
else
{
// old behaviour
string strSchema = GetXmlSchemaForRemoting(null);
info.AddValue(KEY_XMLSCHEMA, strSchema);
StringBuilder strBuilder = new StringBuilder(EstimatedXmlStringSize() * 2);
StringWriter strWriter = new StringWriter(strBuilder, CultureInfo.InvariantCulture);
XmlTextWriter w = new XmlTextWriter(strWriter);
WriteXml(w, XmlWriteMode.DiffGram);
info.AddValue(KEY_XMLDIFFGRAM, strWriter.ToString());
}
}
// Deserialize all the tables - marked internal so that DataTable can call into this
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
internal void DeserializeDataSet(SerializationInfo info, StreamingContext context, SerializationFormat remotingFormat, SchemaSerializationMode schemaSerializationMode)
{
// deserialize schema
DeserializeDataSetSchema(info, context, remotingFormat, schemaSerializationMode);
// deserialize data
DeserializeDataSetData(info, remotingFormat);
}
// Deserialize schema.
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
private void DeserializeDataSetSchema(SerializationInfo info, StreamingContext context, SerializationFormat remotingFormat, SchemaSerializationMode schemaSerializationMode)
{
if (remotingFormat != SerializationFormat.Xml)
{
if (schemaSerializationMode == SchemaSerializationMode.IncludeSchema)
{
//DataSet public state properties
DeserializeDataSetProperties(info);
//Tables Count
int tableCount = info.GetInt32("DataSet.Tables.Count");
//Tables, Columns, Rows
for (int i = 0; i < tableCount; i++)
{
byte[] buffer = (byte[])info.GetValue(string.Format(CultureInfo.InvariantCulture, "DataSet.Tables_{0}", i), typeof(byte[]))!;
MemoryStream memStream = new MemoryStream(buffer);
memStream.Position = 0;
#pragma warning disable SYSLIB0011 // Issue https://github.com/dotnet/runtime/issues/39289 tracks finding an alternative to BinaryFormatter
#pragma warning disable SYSLIB0050 // StreamingContext ctor is obsolete
BinaryFormatter bf = new BinaryFormatter(null, new StreamingContext(context.State, false));
DataTable dt = (DataTable)bf.Deserialize(memStream);
#pragma warning restore SYSLIB0050
#pragma warning restore SYSLIB0011
Tables.Add(dt);
}
//Constraints
for (int i = 0; i < tableCount; i++)
{
Tables[i].DeserializeConstraints(info, /* table index */i, /* serialize all constraints */ true); //
}
//Relations
DeserializeRelations(info);
//Expression Columns
for (int i = 0; i < tableCount; i++)
{
Tables[i].DeserializeExpressionColumns(info, i);
}
}
else
{
//DeSerialize DataSet public properties.[Locale, CaseSensitive and EnforceConstraints]
DeserializeDataSetProperties(info);
}
}
else
{
string? strSchema = (string?)info.GetValue(KEY_XMLSCHEMA, typeof(string));
if (strSchema != null)
{
ReadXmlSchema(new XmlTextReader(new StringReader(strSchema)), true);
}
}
}
// Deserialize all data.
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
private void DeserializeDataSetData(SerializationInfo info, SerializationFormat remotingFormat)
{
if (remotingFormat != SerializationFormat.Xml)
{
for (int i = 0; i < Tables.Count; i++)
{
Tables[i].DeserializeTableData(info, i);
}
}
else
{
string? strData = (string?)info.GetValue(KEY_XMLDIFFGRAM, typeof(string));
if (strData != null)
{
ReadXml(new XmlTextReader(new StringReader(strData)), XmlReadMode.DiffGram);
}
}
}
// Serialize just the dataset properties
private void SerializeDataSetProperties(SerializationInfo info)
{
//DataSet basic properties
info.AddValue("DataSet.DataSetName", DataSetName);
info.AddValue("DataSet.Namespace", Namespace);
info.AddValue("DataSet.Prefix", Prefix);
//DataSet runtime properties
info.AddValue("DataSet.CaseSensitive", CaseSensitive);
info.AddValue("DataSet.LocaleLCID", Locale.LCID);
info.AddValue("DataSet.EnforceConstraints", EnforceConstraints);
//ExtendedProperties
info.AddValue("DataSet.ExtendedProperties", ExtendedProperties);
}
// DeSerialize dataset properties
private void DeserializeDataSetProperties(SerializationInfo info)
{
//DataSet basic properties
_dataSetName = info.GetString("DataSet.DataSetName")!;
_namespaceURI = info.GetString("DataSet.Namespace")!;
_datasetPrefix = info.GetString("DataSet.Prefix")!;
//DataSet runtime properties
_caseSensitive = info.GetBoolean("DataSet.CaseSensitive");
int lcid = (int)info.GetValue("DataSet.LocaleLCID", typeof(int))!;
_culture = new CultureInfo(lcid);
_cultureUserSet = true;
_enforceConstraints = info.GetBoolean("DataSet.EnforceConstraints");
//ExtendedProperties
_extendedProperties = (PropertyCollection?)info.GetValue("DataSet.ExtendedProperties", typeof(PropertyCollection));
}
// Gets relation info from the dataset.
// ***Schema for Serializing ArrayList of Relations***
// Relations -> [relationName]->[parentTableIndex, parentcolumnIndexes]->[childTableIndex, childColumnIndexes]->[Nested]->[extendedProperties]
private void SerializeRelations(SerializationInfo info)
{
ArrayList relationList = new ArrayList();
foreach (DataRelation rel in Relations)
{
int[] parentInfo = new int[rel.ParentColumns.Length + 1];
parentInfo[0] = Tables.IndexOf(rel.ParentTable);
for (int j = 1; j < parentInfo.Length; j++)
{
parentInfo[j] = rel.ParentColumns[j - 1].Ordinal;
}
int[] childInfo = new int[rel.ChildColumns.Length + 1];
childInfo[0] = Tables.IndexOf(rel.ChildTable);
for (int j = 1; j < childInfo.Length; j++)
{
childInfo[j] = rel.ChildColumns[j - 1].Ordinal;
}
ArrayList list = new ArrayList();
list.Add(rel.RelationName);
list.Add(parentInfo);
list.Add(childInfo);
list.Add(rel.Nested);
list.Add(rel._extendedProperties);
relationList.Add(list);
}
info.AddValue("DataSet.Relations", relationList);
}
// Adds relations to the dataset.
// ***Schema for Serializing ArrayList of Relations***
// Relations -> [relationName]->[parentTableIndex, parentcolumnIndexes]->[childTableIndex, childColumnIndexes]->[Nested]->[extendedProperties]
private void DeserializeRelations(SerializationInfo info)
{
ArrayList relationList = (ArrayList)info.GetValue("DataSet.Relations", typeof(ArrayList))!;
foreach (ArrayList list in relationList)
{
string relationName = (string)list[0]!;
int[] parentInfo = (int[])list[1]!;
int[] childInfo = (int[])list[2]!;
bool isNested = (bool)list[3]!;
PropertyCollection? extendedProperties = (PropertyCollection?)list[4]!;
//ParentKey Columns.
DataColumn[] parentkeyColumns = new DataColumn[parentInfo.Length - 1];
for (int i = 0; i < parentkeyColumns.Length; i++)
{
parentkeyColumns[i] = Tables[parentInfo[0]].Columns[parentInfo[i + 1]];
}
//ChildKey Columns.
DataColumn[] childkeyColumns = new DataColumn[childInfo.Length - 1];
for (int i = 0; i < childkeyColumns.Length; i++)
{
childkeyColumns[i] = Tables[childInfo[0]].Columns[childInfo[i + 1]];
}
//Create the Relation, without any constraints[Assumption: The constraints are added earlier than the relations]
DataRelation rel = new DataRelation(relationName, parentkeyColumns, childkeyColumns, false);
rel.CheckMultipleNested = false; // disable the check for multiple nested parent
rel.Nested = isNested;
rel._extendedProperties = extendedProperties;
Relations.Add(rel);
rel.CheckMultipleNested = true; // enable the check for multiple nested parent
}
}
internal void FailedEnableConstraints()
{
EnforceConstraints = false;
throw ExceptionBuilder.EnforceConstraint();
}
/// <summary>
/// Gets or sets a value indicating whether string
/// comparisons within <see cref='System.Data.DataTable'/>
/// objects are case-sensitive.
/// </summary>
[DefaultValue(false)]
public bool CaseSensitive
{
get { return _caseSensitive; }
set
{
if (_caseSensitive != value)
{
bool oldValue = _caseSensitive;
_caseSensitive = value;
if (!ValidateCaseConstraint())
{
_caseSensitive = oldValue;
throw ExceptionBuilder.CannotChangeCaseLocale();
}
foreach (DataTable table in Tables)
{
table.SetCaseSensitiveValue(value, false, true);
}
}
}
}
bool IListSource.ContainsListCollection => true;
/// <summary>
/// Gets a custom view of the data contained by the <see cref='System.Data.DataSet'/> , one
/// that allows filtering, searching, and navigating through the custom data view.
/// </summary>
[Browsable(false)]
public DataViewManager DefaultViewManager
{
get
{
if (_defaultViewManager == null)
{
lock (_defaultViewManagerLock)
{
_defaultViewManager ??= new DataViewManager(this, true);
}
}
return _defaultViewManager;
}
}
/// <summary>
/// Gets or sets a value indicating whether constraint rules are followed when
/// attempting any update operation.
/// </summary>
[DefaultValue(true)]
public bool EnforceConstraints
{
get { return _enforceConstraints; }
set
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.set_EnforceConstraints|API> {0}, {1}", ObjectID, value);
try
{
if (_enforceConstraints != value)
{
if (value)
{
EnableConstraints();
}
_enforceConstraints = value;
}
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
}
internal void RestoreEnforceConstraints(bool value)
{
_enforceConstraints = value;
}
internal void EnableConstraints()
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.EnableConstraints|INFO> {0}", ObjectID);
try
{
bool errors = false;
for (ConstraintEnumerator constraints = new ConstraintEnumerator(this); constraints.GetNext();)
{
Constraint constraint = constraints.GetConstraint();
errors |= constraint.IsConstraintViolated();
}
foreach (DataTable table in Tables)
{
foreach (DataColumn column in table.Columns)
{
if (!column.AllowDBNull)
{
errors |= column.IsNotAllowDBNullViolated();
}
if (column.MaxLength >= 0)
{
errors |= column.IsMaxLengthViolated();
}
}
}
if (errors)
{
FailedEnableConstraints();
}
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
/// <summary>
/// Gets or sets the name of this <see cref='System.Data.DataSet'/> .
/// </summary>
[DefaultValue("")]
public string DataSetName
{
get { return _dataSetName; }
set
{
DataCommonEventSource.Log.Trace("<ds.DataSet.set_DataSetName|API> {0}, '{1}'", ObjectID, value);
if (value != _dataSetName)
{
if (string.IsNullOrEmpty(value))
{
throw ExceptionBuilder.SetDataSetNameToEmpty();
}
DataTable? conflicting = Tables[value, Namespace];
if ((conflicting != null) && (!conflicting._fNestedInDataset))
{
throw ExceptionBuilder.SetDataSetNameConflicting(value);
}
RaisePropertyChanging(nameof(DataSetName));
_dataSetName = value;
}
}
}
[DefaultValue("")]
[AllowNull]
public string Namespace
{
get { return _namespaceURI; }
set
{
DataCommonEventSource.Log.Trace("<ds.DataSet.set_Namespace|API> {0}, '{1}'", ObjectID, value);
value ??= string.Empty;
if (value != _namespaceURI)
{
RaisePropertyChanging(nameof(Namespace));
foreach (DataTable dt in Tables)
{
if (dt._tableNamespace != null)
{
continue;
}
if ((dt.NestedParentRelations.Length == 0) ||
(dt.NestedParentRelations.Length == 1 && dt.NestedParentRelations[0].ChildTable == dt))
{
if (Tables.Contains(dt.TableName, value, false, true))
{
throw ExceptionBuilder.DuplicateTableName2(dt.TableName, value);
}
dt.CheckCascadingNamespaceConflict(value);
dt.DoRaiseNamespaceChange();
}
}
_namespaceURI = value;
if (string.IsNullOrEmpty(value))
{
_datasetPrefix = string.Empty;
}
}
}
}
[DefaultValue("")]
[AllowNull]
public string Prefix
{
get { return _datasetPrefix; }
set
{
value ??= string.Empty;
if ((XmlConvert.DecodeName(value) == value) && (XmlConvert.EncodeName(value) != value))
{
throw ExceptionBuilder.InvalidPrefix(value);
}
if (value != _datasetPrefix)
{
RaisePropertyChanging(nameof(Prefix));
_datasetPrefix = value;
}
}
}
/// <summary>
/// Gets the collection of custom user information.
/// </summary>
[Browsable(false)]
public PropertyCollection ExtendedProperties => _extendedProperties ??= new PropertyCollection();
/// <summary>
/// Gets a value indicating whether there are errors in any
/// of the rows in any of the tables of this <see cref='System.Data.DataSet'/> .
/// </summary>
[Browsable(false)]
public bool HasErrors
{
get
{
for (int i = 0; i < Tables.Count; i++)
{
if (Tables[i].HasErrors)
{
return true;
}
}
return false;
}
}
[Browsable(false)]
public bool IsInitialized => !_fInitInProgress;
/// <summary>
/// Gets or sets the locale information used to compare strings within the table.
/// </summary>
public CultureInfo Locale
{
get
{
// used for comparing not formating/parsing
Debug.Assert(null != _culture, "DataSet.Locale: null culture");
return _culture;
}
set
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.set_Locale|API> {0}", ObjectID);
try
{
if (value != null)
{
if (!_culture.Equals(value))
{
SetLocaleValue(value, true);
}
_cultureUserSet = true;
}
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
}
internal void SetLocaleValue(CultureInfo value, bool userSet)
{
bool flag = false;
bool exceptionThrown = false;
int tableCount = 0;
CultureInfo oldLocale = _culture;
bool oldUserSet = _cultureUserSet;
try
{
_culture = value;
_cultureUserSet = userSet;
foreach (DataTable table in Tables)
{
if (!table.ShouldSerializeLocale())
{
table.SetLocaleValue(value, false, false);
}
}
flag = ValidateLocaleConstraint();
if (flag)
{
flag = false;
foreach (DataTable table in Tables)
{
tableCount++;
if (!table.ShouldSerializeLocale())
{
table.SetLocaleValue(value, false, true);
}
}
flag = true;
}
}
catch
{
exceptionThrown = true;
throw;
}
finally
{
if (!flag)
{ // reset old locale if ValidationFailed or exception thrown
_culture = oldLocale;
_cultureUserSet = oldUserSet;
foreach (DataTable table in Tables)
{
if (!table.ShouldSerializeLocale())
{
table.SetLocaleValue(oldLocale, false, false);
}
}
try
{
for (int i = 0; i < tableCount; ++i)
{
if (!Tables[i].ShouldSerializeLocale())
{
Tables[i].SetLocaleValue(oldLocale, false, true);
}
}
}
catch (Exception e) when (ADP.IsCatchableExceptionType(e))
{
ADP.TraceExceptionWithoutRethrow(e);
}
if (!exceptionThrown)
{
throw ExceptionBuilder.CannotChangeCaseLocale(null);
}
}
}
}
internal bool ShouldSerializeLocale()
{
// this method is used design-time scenarios via reflection
// by the property grid to show the Locale property in bold or not
// by the code dom for persisting the Locale property or not
// we always want the locale persisted if set by user or different the current thread
// but that logic should by performed by the serializion code
return _cultureUserSet;
}
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override ISite? Site
{
get { return base.Site; }
set
{
ISite? oldSite = Site;
if (value == null && oldSite != null)
{
IContainer? cont = oldSite.Container;
if (cont != null)
{
for (int i = 0; i < Tables.Count; i++)
{
if (Tables[i].Site != null)
{
cont.Remove(Tables[i]);
}
}
}
}
base.Site = value;
}
}
/// <summary>
/// Get the collection of relations that link tables and
/// allow navigation from parent tables to child tables.
/// </summary>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public DataRelationCollection Relations => _relationCollection;
/// <summary>
/// Indicates whether <see cref='Relations'/> property should be persisted.
/// </summary>
protected virtual bool ShouldSerializeRelations() => true;
/// <summary>
/// Resets the <see cref='System.Data.DataSet.Relations'/> property to its default state.
/// </summary>
private void ResetRelations() => Relations.Clear();
/// <summary>
/// Gets the collection of tables contained in the <see cref='System.Data.DataSet'/>.
/// </summary>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public DataTableCollection Tables => _tableCollection;
/// <summary>
/// Indicates whether <see cref='System.Data.DataSet.Tables'/> property should be persisted.
/// </summary>
protected virtual bool ShouldSerializeTables() => true;
/// <summary>
/// Resets the <see cref='System.Data.DataSet.Tables'/> property to its default state.
/// </summary>
private void ResetTables() => Tables.Clear();
internal bool FBoundToDocument
{
get { return _fBoundToDocument; }
set { _fBoundToDocument = value; }
}
/// <summary>
/// Commits all the changes made to this <see cref='System.Data.DataSet'/> since it was loaded or the last
/// time <see cref='System.Data.DataSet.AcceptChanges'/> was called.
/// </summary>
public void AcceptChanges()
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.AcceptChanges|API> {0}", ObjectID);
try
{
for (int i = 0; i < Tables.Count; i++)
{
Tables[i].AcceptChanges();
}
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
internal event PropertyChangedEventHandler? PropertyChanging;
/// <summary>
/// Occurs when attempting to merge schemas for two tables with the same name.
/// </summary>
public event MergeFailedEventHandler? MergeFailed;
internal event DataRowCreatedEventHandler? DataRowCreated; // Internal for XmlDataDocument only
internal event DataSetClearEventhandler? ClearFunctionCalled; // Internal for XmlDataDocument only
public event EventHandler? Initialized;
public void BeginInit()
{
_fInitInProgress = true;
}
public void EndInit()
{
Tables.FinishInitCollection();
for (int i = 0; i < Tables.Count; i++)
{
Tables[i].Columns.FinishInitCollection();
}
for (int i = 0; i < Tables.Count; i++)
{
Tables[i].Constraints.FinishInitConstraints();
}
((DataRelationCollection.DataSetRelationCollection)Relations).FinishInitRelations();
_fInitInProgress = false;
OnInitialized();
}
/// <summary>
/// Clears the <see cref='System.Data.DataSet'/> of any data by removing all rows in all tables.
/// </summary>
public void Clear()
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.Clear|API> {0}", ObjectID);
try
{
OnClearFunctionCalled(null);
bool fEnforce = EnforceConstraints;
EnforceConstraints = false;
for (int i = 0; i < Tables.Count; i++)
{
Tables[i].Clear();
}
EnforceConstraints = fEnforce;
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
private DataSet CreateInstanceOfThisType()
{
return (DataSet)Activator.CreateInstance(GetType(), true)!;
}
/// <summary>
/// Clones the structure of the <see cref='System.Data.DataSet'/>, including all <see cref='System.Data.DataTable'/> schemas, relations, and
/// constraints.
/// </summary>
// 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.
[MethodImpl(MethodImplOptions.NoInlining)]
public virtual DataSet Clone()
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.Clone|API> {0}", ObjectID);
try
{
DataSet ds = CreateInstanceOfThisType();
if (ds.Tables.Count > 0) // To clean up all the schema in strong typed dataset.
{
ds.Reset();
}
//copy some original dataset properties
ds.DataSetName = DataSetName;
ds.CaseSensitive = CaseSensitive;
ds._culture = _culture;
ds._cultureUserSet = _cultureUserSet;
ds.EnforceConstraints = EnforceConstraints;
ds.Namespace = Namespace;
ds.Prefix = Prefix;
ds.RemotingFormat = RemotingFormat;
ds._fIsSchemaLoading = true; //delay expression evaluation
// ...Tables...
DataTableCollection tbls = Tables;
for (int i = 0; i < tbls.Count; i++)
{
DataTable dt = tbls[i].Clone(ds);
dt._tableNamespace = tbls[i].Namespace; // hardcode the namespace for a second to not mess up
// DataRelation cloning.
ds.Tables.Add(dt);
}
// ...Constraints...
for (int i = 0; i < tbls.Count; i++)
{
ConstraintCollection constraints = tbls[i].Constraints;
for (int j = 0; j < constraints.Count; j++)
{
if (constraints[j] is UniqueConstraint)
{
continue;
}
ForeignKeyConstraint foreign = (ForeignKeyConstraint)constraints[j];
if (foreign.Table == foreign.RelatedTable)
{
continue; // we have already added this foreign key in while cloning the datatable
}
ds.Tables[i].Constraints.Add(constraints[j].Clone(ds)!);
}
}
// ...Relations...
DataRelationCollection rels = Relations;
for (int i = 0; i < rels.Count; i++)
{
DataRelation rel = rels[i].Clone(ds);
rel.CheckMultipleNested = false; // disable the check for multiple nested parent
ds.Relations.Add(rel);
rel.CheckMultipleNested = true; // enable the check for multiple nested parent
}
// ...Extended Properties...
if (_extendedProperties != null)
{
foreach (object key in _extendedProperties.Keys)
{
ds.ExtendedProperties[key] = _extendedProperties[key];
}
}
foreach (DataTable table in Tables)
{
foreach (DataColumn col in table.Columns)
{
if (col.Expression.Length != 0)
{
ds.Tables[table.TableName, table.Namespace]!.Columns[col.ColumnName]!.CopyExpressionFrom(col);
}
}
}
for (int i = 0; i < tbls.Count; i++)
{
ds.Tables[i]._tableNamespace = tbls[i]._tableNamespace; // undo the hardcoding of the namespace
}
ds._fIsSchemaLoading = false; //reactivate column computations
return ds;
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
/// <summary>
/// Copies both the structure and data for this <see cref='System.Data.DataSet'/>.
/// </summary>
public DataSet Copy()
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.Copy|API> {0}", ObjectID);
try
{
DataSet dsNew = Clone();
bool fEnforceConstraints = dsNew.EnforceConstraints;
dsNew.EnforceConstraints = false;
foreach (DataTable table in Tables)
{
DataTable destTable = dsNew.Tables[table.TableName, table.Namespace]!;
foreach (DataRow row in table.Rows)
{
DataTable.CopyRow(destTable, row);
}
}
dsNew.EnforceConstraints = fEnforceConstraints;
return dsNew;
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
internal int EstimatedXmlStringSize()
{
int bytes = 100;
for (int i = 0; i < Tables.Count; i++)
{
int rowBytes = (Tables[i].TableName.Length + 4) << 2;
DataTable table = Tables[i];
for (int j = 0; j < table.Columns.Count; j++)
{
rowBytes += ((table.Columns[j].ColumnName.Length + 4) << 2);
rowBytes += 20;
}
bytes += table.Rows.Count * rowBytes;
}
return bytes;
}
/// <summary>
/// Returns a copy of the <see cref='System.Data.DataSet'/> that contains all changes made to
/// it since it was loaded or <see cref='System.Data.DataSet.AcceptChanges'/> was last called.
/// </summary>
public DataSet? GetChanges() =>
GetChanges(DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
private struct TableChanges
{
private readonly BitArray _rowChanges;
internal TableChanges(int rowCount)
{
_rowChanges = new BitArray(rowCount);
HasChanges = 0;
}
internal int HasChanges { get; set; }
internal bool this[int index]
{
get { return _rowChanges[index]; }
set
{
Debug.Assert(value && !_rowChanges[index], "setting twice or to false");
_rowChanges[index] = value;
HasChanges++;
}
}
}
public DataSet? GetChanges(DataRowState rowStates)
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.GetChanges|API> {0}, rowStates={1}", ObjectID, rowStates);
try
{
DataSet? dsNew = null;
bool fEnforceConstraints = false;
if (0 != (rowStates & ~(DataRowState.Added | DataRowState.Deleted | DataRowState.Modified | DataRowState.Unchanged)))
{
throw ExceptionBuilder.InvalidRowState(rowStates);
}
// Initialize all the individual table bitmaps.
TableChanges[] bitMatrix = new TableChanges[Tables.Count];
for (int i = 0; i < bitMatrix.Length; ++i)
{
bitMatrix[i] = new TableChanges(Tables[i].Rows.Count);
}
// find all the modified rows and their parents
MarkModifiedRows(bitMatrix, rowStates);
// copy the changes to a cloned table
for (int i = 0; i < bitMatrix.Length; ++i)
{
Debug.Assert(0 <= bitMatrix[i].HasChanges, "negative change count");
if (0 < bitMatrix[i].HasChanges)
{
if (null == dsNew)
{
dsNew = Clone();
fEnforceConstraints = dsNew.EnforceConstraints;
dsNew.EnforceConstraints = false;
}
DataTable table = Tables[i];
DataTable destTable = dsNew.Tables[table.TableName, table.Namespace]!;
Debug.Assert(bitMatrix[i].HasChanges <= table.Rows.Count, "to many changes");
for (int j = 0; 0 < bitMatrix[i].HasChanges; ++j)
{
// Loop through the rows.
if (bitMatrix[i][j])
{
DataTable.CopyRow(destTable, table.Rows[j]);
bitMatrix[i].HasChanges--;
}
}
}
}
if (null != dsNew)
{
dsNew.EnforceConstraints = fEnforceConstraints;
}
return dsNew;
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
private void MarkModifiedRows(TableChanges[] bitMatrix, DataRowState rowStates)
{
// for every table, every row & every relation find the modified rows and for non-deleted rows, their parents
for (int tableIndex = 0; tableIndex < bitMatrix.Length; ++tableIndex)
{
DataRowCollection rows = Tables[tableIndex].Rows;
int rowCount = rows.Count;
for (int rowIndex = 0; rowIndex < rowCount; ++rowIndex)
{
DataRow row = rows[rowIndex];
DataRowState rowState = row.RowState;
Debug.Assert(DataRowState.Added == rowState ||
DataRowState.Deleted == rowState ||
DataRowState.Modified == rowState ||
DataRowState.Unchanged == rowState,
"unexpected DataRowState");
// if bit not already set and row is modified
if ((0 != (rowStates & rowState)) && !bitMatrix[tableIndex][rowIndex])
{
bitMatrix[tableIndex][rowIndex] = true;
if (DataRowState.Deleted != rowState)
{
MarkRelatedRowsAsModified(bitMatrix, row);
}
}
}
}
}
private void MarkRelatedRowsAsModified(TableChanges[] bitMatrix, DataRow row)
{
DataRelationCollection relations = row.Table.ParentRelations;
int relationCount = relations.Count;
for (int relatedIndex = 0; relatedIndex < relationCount; ++relatedIndex)
{
DataRow[] relatedRows = row.GetParentRows(relations[relatedIndex], DataRowVersion.Current);
foreach (DataRow relatedRow in relatedRows)
{
int relatedTableIndex = Tables.IndexOf(relatedRow.Table);
int relatedRowIndex = relatedRow.Table.Rows.IndexOf(relatedRow);
if (!bitMatrix[relatedTableIndex][relatedRowIndex])
{
bitMatrix[relatedTableIndex][relatedRowIndex] = true;
if (DataRowState.Deleted != relatedRow.RowState)
{
// recurse into related rows
MarkRelatedRowsAsModified(bitMatrix, relatedRow);
}
}
}
}
}
IList IListSource.GetList() => DefaultViewManager;
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
internal static string GetRemotingDiffGram(DataTable table)
{
StringWriter strWriter = new StringWriter(CultureInfo.InvariantCulture);
XmlTextWriter writer = new XmlTextWriter(strWriter);
writer.Formatting = Formatting.Indented;
// Create and save the updates
new NewDiffgramGen(table, false).Save(writer, table);
return strWriter.ToString();
}
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public string GetXml()
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.GetXml|API> {0}", ObjectID);
try
{
// StringBuilder strBuilder = new StringBuilder(EstimatedXmlStringSize());
// StringWriter strWriter = new StringWriter(strBuilder);
StringWriter strWriter = new StringWriter(CultureInfo.InvariantCulture);
XmlTextWriter w = new XmlTextWriter(strWriter);
w.Formatting = Formatting.Indented;
new XmlDataTreeWriter(this).Save(w, false);
return strWriter.ToString();
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public string GetXmlSchema()
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.GetXmlSchema|API> {0}", ObjectID);
try
{
StringWriter strWriter = new StringWriter(CultureInfo.InvariantCulture);
XmlTextWriter writer = new XmlTextWriter(strWriter);
writer.Formatting = Formatting.Indented;
(new XmlTreeGen(SchemaFormat.Public)).Save(this, writer);
return strWriter.ToString();
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
internal string GetXmlSchemaForRemoting(DataTable? table)
{
StringWriter strWriter = new StringWriter(CultureInfo.InvariantCulture);
XmlTextWriter writer = new XmlTextWriter(strWriter);
writer.Formatting = Formatting.Indented;
if (table == null)
{
if (SchemaSerializationMode == SchemaSerializationMode.ExcludeSchema)
{
(new XmlTreeGen(SchemaFormat.RemotingSkipSchema)).Save(this, writer);
}
else
{
(new XmlTreeGen(SchemaFormat.Remoting)).Save(this, writer);
}
}
else
{
// no skip schema support for typed datatable
(new XmlTreeGen(SchemaFormat.Remoting)).Save(table, writer);
}
return strWriter.ToString();
}
/// <summary>
/// Gets a value indicating whether the <see cref='System.Data.DataSet'/> has changes, including new,
/// deleted, or modified rows.
/// </summary>
public bool HasChanges() => HasChanges(DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
/// <summary>
/// Gets a value indicating whether the <see cref='System.Data.DataSet'/> has changes, including new,
/// deleted, or modified rows, filtered by <see cref='System.Data.DataRowState'/>.
/// </summary>
public bool HasChanges(DataRowState rowStates)
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.HasChanges|API> {0}, rowStates={1}", ObjectID, (int)rowStates);
try
{
const DataRowState allRowStates = DataRowState.Detached | DataRowState.Unchanged | DataRowState.Added | DataRowState.Deleted | DataRowState.Modified;
if ((rowStates & (~allRowStates)) != 0)
{
throw ExceptionBuilder.ArgumentOutOfRange("rowState");
}
for (int i = 0; i < Tables.Count; i++)
{
DataTable table = Tables[i];
for (int j = 0; j < table.Rows.Count; j++)
{
DataRow row = table.Rows[j];
if ((row.RowState & rowStates) != 0)
{
return true;
}
}
}
return false;
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
/// <summary>
/// Infer the XML schema from the specified <see cref='System.IO.TextReader'/> into the <see cref='System.Data.DataSet'/>.
/// </summary>
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public void InferXmlSchema(XmlReader? reader, string[]? nsArray)
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.InferXmlSchema|API> {0}", ObjectID);
try
{
if (reader == null)
{
return;
}
XmlDocument xdoc = new XmlDocument();
if (reader.NodeType == XmlNodeType.Element)
{
XmlNode node = xdoc.ReadNode(reader)!;
xdoc.AppendChild(node);
}
else
{
xdoc.Load(reader);
}
if (xdoc.DocumentElement == null)
{
return;
}
InferSchema(xdoc, nsArray, XmlReadMode.InferSchema);
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
/// <summary>
/// Infer the XML schema from the specified <see cref='System.IO.TextReader'/> into the <see cref='System.Data.DataSet'/>.
/// </summary>
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public void InferXmlSchema(Stream? stream, string[]? nsArray)
{
if (stream == null)
{
return;
}
InferXmlSchema(new XmlTextReader(stream), nsArray);
}
/// <summary>
/// Infer the XML schema from the specified <see cref='System.IO.TextReader'/> into the <see cref='System.Data.DataSet'/>.
/// </summary>
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public void InferXmlSchema(TextReader? reader, string[]? nsArray)
{
if (reader == null)
{
return;
}
InferXmlSchema(new XmlTextReader(reader), nsArray);
}
/// <summary>
/// Infer the XML schema from the specified file into the <see cref='System.Data.DataSet'/>.
/// </summary>
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public void InferXmlSchema(string fileName, string[]? nsArray)
{
XmlTextReader xr = new XmlTextReader(fileName);
try
{
InferXmlSchema(xr, nsArray);
}
finally
{
xr.Close();
}
}
/// <summary>
/// Reads the XML schema from the specified <see cref="System.Xml.XmlReader" /> into the <see cref="System.Data.DataSet" />
/// </summary>
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public void ReadXmlSchema(XmlReader? reader) => ReadXmlSchema(reader, false);
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
internal void ReadXmlSchema(XmlReader? reader, bool denyResolving)
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.ReadXmlSchema|INFO> {0}, reader, denyResolving={1}", ObjectID, denyResolving);
try
{
int iCurrentDepth = -1;
if (reader == null)
{
return;
}
if (reader is XmlTextReader)
{
((XmlTextReader)reader).WhitespaceHandling = WhitespaceHandling.None;
}
XmlDocument xdoc = new XmlDocument(); // we may need this to infer the schema
if (reader.NodeType == XmlNodeType.Element)
{
iCurrentDepth = reader.Depth;
}
reader.MoveToContent();
if (reader.NodeType == XmlNodeType.Element)
{
// if reader points to the schema load it...
if (reader.LocalName == Keywords.XDR_SCHEMA && reader.NamespaceURI == Keywords.XDRNS)
{
// load XDR schema and exit
ReadXDRSchema(reader);
return;
}
if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI == Keywords.XSDNS)
{
// load XSD schema and exit
ReadXSDSchema(reader);
return;
}
if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI.StartsWith(Keywords.XSD_NS_START, StringComparison.Ordinal))
{
throw ExceptionBuilder.DataSetUnsupportedSchema(Keywords.XSDNS);
}
// ... otherwise backup the top node and all its attributes
XmlElement topNode = xdoc.CreateElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
if (reader.HasAttributes)
{
int attrCount = reader.AttributeCount;
for (int i = 0; i < attrCount; i++)
{
reader.MoveToAttribute(i);
if (reader.NamespaceURI.Equals(Keywords.XSD_XMLNS_NS))
{
topNode.SetAttribute(reader.Name, reader.GetAttribute(i));
}
else
{
XmlAttribute attr = topNode.SetAttributeNode(reader.LocalName, reader.NamespaceURI);
attr.Prefix = reader.Prefix;
attr.Value = reader.GetAttribute(i);
}
}
}
reader.Read();
while (MoveToElement(reader, iCurrentDepth))
{
// if reader points to the schema load it...
if (reader.LocalName == Keywords.XDR_SCHEMA && reader.NamespaceURI == Keywords.XDRNS)
{
// load XDR schema and exit
ReadXDRSchema(reader);
return;
}
if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI == Keywords.XSDNS)
{
// load XSD schema and exit
ReadXSDSchema(reader);
return;
}
if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI.StartsWith(Keywords.XSD_NS_START, StringComparison.Ordinal))
{
throw ExceptionBuilder.DataSetUnsupportedSchema(Keywords.XSDNS);
}
XmlNode node = xdoc.ReadNode(reader)!;
topNode.AppendChild(node);
}
// read the closing tag of the current element
ReadEndElement(reader);
// if we are here no schema has been found
xdoc.AppendChild(topNode);
// so we InferSchema
InferSchema(xdoc, null, XmlReadMode.Auto);
}
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
internal static bool MoveToElement(XmlReader reader, int depth)
{
while (!reader.EOF && reader.NodeType != XmlNodeType.EndElement && reader.NodeType != XmlNodeType.Element && reader.Depth > depth)
{
reader.Read();
}
return (reader.NodeType == XmlNodeType.Element);
}
private static void MoveToElement(XmlReader reader)
{
while (!reader.EOF && reader.NodeType != XmlNodeType.EndElement && reader.NodeType != XmlNodeType.Element)
{
reader.Read();
}
}
internal static void ReadEndElement(XmlReader reader)
{
while (reader.NodeType == XmlNodeType.Whitespace)
{
reader.Skip();
}
if (reader.NodeType == XmlNodeType.None)
{
reader.Skip();
}
else if (reader.NodeType == XmlNodeType.EndElement)
{
reader.ReadEndElement();
}
}
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
internal void ReadXSDSchema(XmlReader reader)
{
XmlSchemaSet sSet = new XmlSchemaSet();
int schemaFragmentCount = 1;
//read from current schmema element
if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI == Keywords.XSDNS)
{
if (reader.HasAttributes)
{
string? attribValue = reader.GetAttribute(Keywords.MSD_FRAGMENTCOUNT, Keywords.MSDNS); // this must not move the position
if (!string.IsNullOrEmpty(attribValue))
{
schemaFragmentCount = int.Parse(attribValue, null);
}
}
}
while (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI == Keywords.XSDNS)
{
XmlSchema s = XmlSchema.Read(reader, null)!;
sSet.Add(s);
//read the end tag
ReadEndElement(reader);
if (--schemaFragmentCount > 0)
{
MoveToElement(reader);
}
while (reader.NodeType == XmlNodeType.Whitespace)
{
reader.Skip();
}
}
sSet.Compile();
XSDSchema schema = new XSDSchema();
schema.LoadSchema(sSet, this);
}
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
internal void ReadXDRSchema(XmlReader reader)
{
XmlDocument xdoc = new XmlDocument(); // we may need this to infer the schema
XmlNode schNode = xdoc.ReadNode(reader)!;
xdoc.AppendChild(schNode);
XDRSchema schema = new XDRSchema(this);
DataSetName = xdoc.DocumentElement!.LocalName;
schema.LoadSchema((XmlElement)schNode, this);
}
/// <summary>
/// Reads the XML schema from the specified <see cref='System.IO.Stream'/> into the
/// <see cref='System.Data.DataSet'/>.
/// </summary>
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public void ReadXmlSchema(Stream? stream)
{
if (stream == null)
{
return;
}
ReadXmlSchema(new XmlTextReader(stream), false);
}
/// <summary>
/// Reads the XML schema from the specified <see cref='System.IO.TextReader'/> into the <see cref='System.Data.DataSet'/>.
/// </summary>
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public void ReadXmlSchema(TextReader? reader)
{
if (reader == null)
{
return;
}
ReadXmlSchema(new XmlTextReader(reader), false);
}
/// <summary>
/// Reads the XML schema from the specified file into the <see cref='System.Data.DataSet'/>.
/// </summary>
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public void ReadXmlSchema(string fileName)
{
XmlTextReader xr = new XmlTextReader(fileName);
try
{
ReadXmlSchema(xr, false);
}
finally
{
xr.Close();
}
}
#region WriteXmlSchema
/// <summary>Writes the <see cref='DataSet'/> structure as an XML schema to using the specified <see cref='Stream'/> object.</summary>
/// <param name="stream">A <see cref='Stream'/> object used to write to a file.</param>
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public void WriteXmlSchema(Stream? stream) => WriteXmlSchema(stream, SchemaFormat.Public, null);
/// <summary>Writes the <see cref='DataSet'/> structure as an XML schema to using the specified <see cref='Stream'/> object.</summary>
/// <param name="stream">A <see cref='Stream'/> object used to write to a file.</param>
/// <param name="multipleTargetConverter">A delegate used to convert <see cref='Type'/> into string.</param>
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public void WriteXmlSchema(Stream? stream, Converter<Type, string> multipleTargetConverter)
{
ADP.CheckArgumentNull(multipleTargetConverter, nameof(multipleTargetConverter));
WriteXmlSchema(stream, SchemaFormat.Public, multipleTargetConverter);
}
/// <summary>Writes the <see cref='DataSet'/> structure as an XML schema to a file.</summary>
/// <param name="fileName">The file name (including the path) to which to write.</param>
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public void WriteXmlSchema(string fileName) => WriteXmlSchema(fileName, SchemaFormat.Public, null);
/// <summary>Writes the <see cref='DataSet'/> structure as an XML schema to a file.</summary>
/// <param name="fileName">The file name (including the path) to which to write.</param>
/// <param name="multipleTargetConverter">A delegate used to convert <see cref='Type'/> into string.</param>
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public void WriteXmlSchema(string fileName, Converter<Type, string> multipleTargetConverter)
{
ADP.CheckArgumentNull(multipleTargetConverter, nameof(multipleTargetConverter));
WriteXmlSchema(fileName, SchemaFormat.Public, multipleTargetConverter);
}
/// <summary>Writes the <see cref='DataSet'/> structure as an XML schema to a <see cref='TextWriter'/> object.</summary>
/// <param name="writer">The <see cref='TextWriter'/> object with which to write.</param>
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public void WriteXmlSchema(TextWriter? writer) => WriteXmlSchema(writer, SchemaFormat.Public, null);
/// <summary>Writes the <see cref='DataSet'/> structure as an XML schema to a <see cref='TextWriter'/> object.</summary>
/// <param name="writer">The <see cref='TextWriter'/> object with which to write.</param>
/// <param name="multipleTargetConverter">A delegate used to convert <see cref='Type'/> into string.</param>
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public void WriteXmlSchema(TextWriter? writer, Converter<Type, string> multipleTargetConverter)
{
ADP.CheckArgumentNull(multipleTargetConverter, nameof(multipleTargetConverter));
WriteXmlSchema(writer, SchemaFormat.Public, multipleTargetConverter);
}
/// <summary>Writes the <see cref='DataSet'/> structure as an XML schema to an <see cref='XmlWriter'/> object.</summary>
/// <param name="writer">The <see cref='XmlWriter'/> object with which to write.</param>
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public void WriteXmlSchema(XmlWriter? writer) => WriteXmlSchema(writer, SchemaFormat.Public, null);
/// <summary>Writes the <see cref='DataSet'/> structure as an XML schema to an <see cref='XmlWriter'/> object.</summary>
/// <param name="writer">The <see cref='XmlWriter'/> object with which to write.</param>
/// <param name="multipleTargetConverter">A delegate used to convert <see cref='Type'/> into string.</param>
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public void WriteXmlSchema(XmlWriter? writer, Converter<Type, string> multipleTargetConverter)
{
ADP.CheckArgumentNull(multipleTargetConverter, nameof(multipleTargetConverter));
WriteXmlSchema(writer, SchemaFormat.Public, multipleTargetConverter);
}
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
private void WriteXmlSchema(string fileName, SchemaFormat schemaFormat, Converter<Type, string>? multipleTargetConverter)
{
XmlTextWriter xw = new XmlTextWriter(fileName, null);
try
{
xw.Formatting = Formatting.Indented;
xw.WriteStartDocument(true);
WriteXmlSchema(xw, schemaFormat, multipleTargetConverter);
xw.WriteEndDocument();
}
finally
{
xw.Close();
}
}
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
private void WriteXmlSchema(Stream? stream, SchemaFormat schemaFormat, Converter<Type, string>? multipleTargetConverter)
{
if (stream == null)
{
return;
}
XmlTextWriter w = new XmlTextWriter(stream, null);
w.Formatting = Formatting.Indented;
WriteXmlSchema(w, schemaFormat, multipleTargetConverter);
}
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
private void WriteXmlSchema(TextWriter? writer, SchemaFormat schemaFormat, Converter<Type, string>? multipleTargetConverter)
{
if (writer == null)
{
return;
}
XmlTextWriter w = new XmlTextWriter(writer);
w.Formatting = Formatting.Indented;
WriteXmlSchema(w, schemaFormat, multipleTargetConverter);
}
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
private void WriteXmlSchema(XmlWriter? writer, SchemaFormat schemaFormat, Converter<Type, string>? multipleTargetConverter)
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.WriteXmlSchema|INFO> {0}, schemaFormat={1}", ObjectID, schemaFormat);
try
{
// Generate SchemaTree and write it out
if (writer != null)
{
XmlTreeGen treeGen;
if (schemaFormat == SchemaFormat.WebService &&
SchemaSerializationMode == SchemaSerializationMode.ExcludeSchema &&
writer.WriteState == WriteState.Element)
{
treeGen = new XmlTreeGen(SchemaFormat.WebServiceSkipSchema);
}
else
{
treeGen = new XmlTreeGen(schemaFormat);
}
treeGen.Save(this, null, writer, false, multipleTargetConverter);
}
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
#endregion
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public XmlReadMode ReadXml(XmlReader? reader) => ReadXml(reader, false);
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
internal XmlReadMode ReadXml(XmlReader? reader, bool denyResolving)
{
IDisposable? restrictedScope = null;
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.ReadXml|INFO> {0}, denyResolving={1}", ObjectID, denyResolving);
try
{
restrictedScope = TypeLimiter.EnterRestrictedScope(this);
DataTable.DSRowDiffIdUsageSection rowDiffIdUsage = default;
try
{
bool fDataFound = false;
bool fSchemaFound = false;
bool fDiffsFound = false;
bool fIsXdr = false;
int iCurrentDepth = -1;
XmlReadMode ret = XmlReadMode.Auto;
bool isEmptyDataSet = false;
bool topNodeIsProcessed = false; // we chanche topnode and there is just one case that we miss to process it
// it is : <elem attrib1="Attrib">txt</elem>
// clear the hashtable to avoid conflicts between diffgrams, SqlHotFix 782
rowDiffIdUsage.Prepare(this);
if (reader == null)
{
return ret;
}
if (Tables.Count == 0)
{
isEmptyDataSet = true;
}
if (reader is XmlTextReader)
{
((XmlTextReader)reader).WhitespaceHandling = WhitespaceHandling.Significant;
}
XmlDocument xdoc = new XmlDocument(); // we may need this to infer the schema
XmlDataLoader? xmlload = null;
reader.MoveToContent();
if (reader.NodeType == XmlNodeType.Element)
{
iCurrentDepth = reader.Depth;
}
if (reader.NodeType == XmlNodeType.Element)
{
if ((reader.LocalName == Keywords.DIFFGRAM) && (reader.NamespaceURI == Keywords.DFFNS))
{
ReadXmlDiffgram(reader);
// read the closing tag of the current element
ReadEndElement(reader);
return XmlReadMode.DiffGram;
}
// if reader points to the schema load it
if (reader.LocalName == Keywords.XDR_SCHEMA && reader.NamespaceURI == Keywords.XDRNS)
{
// load XDR schema and exit
ReadXDRSchema(reader);
return XmlReadMode.ReadSchema; //since the top level element is a schema return
}
if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI == Keywords.XSDNS)
{
// load XSD schema and exit
ReadXSDSchema(reader);
return XmlReadMode.ReadSchema; //since the top level element is a schema return
}
if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI.StartsWith(Keywords.XSD_NS_START, StringComparison.Ordinal))
{
throw ExceptionBuilder.DataSetUnsupportedSchema(Keywords.XSDNS);
}
// now either the top level node is a table and we load it through dataReader...
// ... or backup the top node and all its attributes because we may need to InferSchema
XmlElement topNode = xdoc.CreateElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
if (reader.HasAttributes)
{
int attrCount = reader.AttributeCount;
for (int i = 0; i < attrCount; i++)
{
reader.MoveToAttribute(i);
if (reader.NamespaceURI.Equals(Keywords.XSD_XMLNS_NS))
topNode.SetAttribute(reader.Name, reader.GetAttribute(i));
else
{
XmlAttribute attr = topNode.SetAttributeNode(reader.LocalName, reader.NamespaceURI);
attr.Prefix = reader.Prefix;
attr.Value = reader.GetAttribute(i);
}
}
}
reader.Read();
string rootNodeSimpleContent = reader.Value;
while (MoveToElement(reader, iCurrentDepth))
{
if ((reader.LocalName == Keywords.DIFFGRAM) && (reader.NamespaceURI == Keywords.DFFNS))
{
ReadXmlDiffgram(reader);
// read the closing tag of the current element
// YUKON FIX ReadEndElement(reader);
// return XmlReadMode.DiffGram;
ret = XmlReadMode.DiffGram; // continue reading for multiple schemas
}
// if reader points to the schema load it...
if (!fSchemaFound && !fDataFound && reader.LocalName == Keywords.XDR_SCHEMA && reader.NamespaceURI == Keywords.XDRNS)
{
// load XDR schema and exit
ReadXDRSchema(reader);
fSchemaFound = true;
fIsXdr = true;
continue;
}
if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI == Keywords.XSDNS)
{
// load XSD schema and exit
ReadXSDSchema(reader);
fSchemaFound = true;
continue;
}
if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI.StartsWith(Keywords.XSD_NS_START, StringComparison.Ordinal))
{
throw ExceptionBuilder.DataSetUnsupportedSchema(Keywords.XSDNS);
}
if ((reader.LocalName == Keywords.DIFFGRAM) && (reader.NamespaceURI == Keywords.DFFNS))
{
ReadXmlDiffgram(reader);
fDiffsFound = true;
ret = XmlReadMode.DiffGram;
}
else
{
// We have found data IFF the reader.NodeType == Element and reader.depth == currentDepth-1
// if reader.NodeType == whitespace, skip all whitespace.
// skip processing i.e. continue if the first non-whitespace node is not of type element.
while (!reader.EOF && reader.NodeType == XmlNodeType.Whitespace)
reader.Read();
if (reader.NodeType != XmlNodeType.Element)
continue;
// we found data here
fDataFound = true;
if (!fSchemaFound && Tables.Count == 0)
{
XmlNode node = xdoc.ReadNode(reader)!;
topNode.AppendChild(node);
}
else
{
xmlload ??= new XmlDataLoader(this, fIsXdr, topNode, false);
xmlload.LoadData(reader);
topNodeIsProcessed = true; // we process the topnode
if (fSchemaFound)
{
ret = XmlReadMode.ReadSchema;
}
else
{
ret = XmlReadMode.IgnoreSchema;
}
}
}
}
// read the closing tag of the current element
ReadEndElement(reader);
bool isfTopLevelTableSet = false;
bool tmpValue = _fTopLevelTable;
//While inference we ignore root elements text content
if (!fSchemaFound && Tables.Count == 0 && !topNode.HasChildNodes)
{
//We shoule not come add SC of root elemnt to topNode if we are not inferring
_fTopLevelTable = true;
isfTopLevelTableSet = true;
if ((rootNodeSimpleContent != null && rootNodeSimpleContent.Length > 0))
{
topNode.InnerText = rootNodeSimpleContent;
}
}
if (!isEmptyDataSet)
{
if ((rootNodeSimpleContent != null && rootNodeSimpleContent.Length > 0))
{
topNode.InnerText = rootNodeSimpleContent;
}
}
// now top node contains the data part
xdoc.AppendChild(topNode);
xmlload ??= new XmlDataLoader(this, fIsXdr, topNode, false);
if (!isEmptyDataSet && !topNodeIsProcessed)
{
XmlElement root = xdoc.DocumentElement!;
Debug.Assert(root.NamespaceURI != null, "root.NamespaceURI should not ne null, it should be empty string");
// just recognize that below given Xml represents datatable in toplevel
//<table attr1="foo" attr2="bar" table_Text="junk">text</table>
// only allow root element with simple content, if any
if (root.ChildNodes.Count == 0 || ((root.ChildNodes.Count == 1) && root.FirstChild!.GetType() == typeof(System.Xml.XmlText)))
{
bool initfTopLevelTable = _fTopLevelTable;
// if root element maps to a datatable
// ds and dt cant have the samm name and ns at the same time, how to write to xml
if (DataSetName != root.Name && _namespaceURI != root.NamespaceURI &&
Tables.Contains(root.Name, (root.NamespaceURI.Length == 0) ? null : root.NamespaceURI, false, true))
{
_fTopLevelTable = true;
}
try
{
xmlload.LoadData(xdoc);
}
finally
{
_fTopLevelTable = initfTopLevelTable; // this is not for inference, we have schema and we were skipping
// topnode where it was a datatable, We must restore the value
}
}
}
// above check and below check are orthogonal
// so we InferSchema
if (!fDiffsFound)
{
// Load Data
if (!fSchemaFound && Tables.Count == 0)
{
InferSchema(xdoc, null, XmlReadMode.Auto);
ret = XmlReadMode.InferSchema;
xmlload.FromInference = true;
try
{
xmlload.LoadData(xdoc);
}
finally
{
xmlload.FromInference = false;
}
}
//We dont need this assignement. Once we set it(where we set it during inference), it won't be changed
if (isfTopLevelTableSet)
_fTopLevelTable = tmpValue;
}
}
return ret;
}
finally
{
rowDiffIdUsage.Cleanup();
}
}
finally
{
restrictedScope?.Dispose();
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public XmlReadMode ReadXml(Stream? stream)
{
if (stream == null)
{
return XmlReadMode.Auto;
}
XmlTextReader xr = new XmlTextReader(stream);
// Prevent Dtd entity in dataset
xr.XmlResolver = null;
return ReadXml(xr, false);
}
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public XmlReadMode ReadXml(TextReader? reader)
{
if (reader == null)
{
return XmlReadMode.Auto;
}
XmlTextReader xr = new XmlTextReader(reader);
// Prevent Dtd entity in dataset
xr.XmlResolver = null;
return ReadXml(xr, false);
}
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public XmlReadMode ReadXml(string fileName)
{
XmlTextReader xr = new XmlTextReader(fileName);
// Prevent Dtd entity in dataset
xr.XmlResolver = null;
try
{
return ReadXml(xr, false);
}
finally
{
xr.Close();
}
}
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
internal void InferSchema(XmlDocument xdoc, string[]? excludedNamespaces, XmlReadMode mode)
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.InferSchema|INFO> {0}, mode={1}", ObjectID, mode);
try
{
if (null == excludedNamespaces)
{
excludedNamespaces = Array.Empty<string>();
}
XmlNodeReader xnr = new XmlIgnoreNamespaceReader(xdoc, excludedNamespaces);
XmlSchemaInference infer = new XmlSchemaInference();
infer.Occurrence = XmlSchemaInference.InferenceOption.Relaxed;
infer.TypeInference = (mode == XmlReadMode.InferTypedSchema) ?
XmlSchemaInference.InferenceOption.Restricted :
XmlSchemaInference.InferenceOption.Relaxed;
XmlSchemaSet schemaSet = infer.InferSchema(xnr);
schemaSet.Compile();
XSDSchema schema = new XSDSchema();
schema.FromInference = true;
try
{
schema.LoadSchema(schemaSet, this);
}
finally
{
schema.FromInference = false; // this is always false if you are not calling fron inference
}
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
private bool IsEmpty()
{
foreach (DataTable table in Tables)
{
if (table.Rows.Count > 0)
{
return false;
}
}
return true;
}
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
private void ReadXmlDiffgram(XmlReader reader)
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.ReadXmlDiffgram|INFO> {0}", ObjectID);
try
{
int d = reader.Depth;
bool fEnforce = EnforceConstraints;
EnforceConstraints = false;
DataSet newDs;
bool isEmpty = IsEmpty();
if (isEmpty)
{
newDs = this;
}
else
{
newDs = Clone();
newDs.EnforceConstraints = false;
}
foreach (DataTable t in newDs.Tables)
{
t.Rows._nullInList = 0;
}
reader.MoveToContent();
if ((reader.LocalName != Keywords.DIFFGRAM) && (reader.NamespaceURI != Keywords.DFFNS))
{
return;
}
reader.Read();
if (reader.NodeType == XmlNodeType.Whitespace)
{
MoveToElement(reader, reader.Depth - 1 /*iCurrentDepth*/); // skip over whitespace.
}
newDs._fInLoadDiffgram = true;
if (reader.Depth > d)
{
if ((reader.NamespaceURI != Keywords.DFFNS) && (reader.NamespaceURI != Keywords.MSDNS))
{
//we should be inside the dataset part
XmlDocument xdoc = new XmlDocument();
XmlElement node = xdoc.CreateElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
reader.Read();
if (reader.NodeType == XmlNodeType.Whitespace)
{
MoveToElement(reader, reader.Depth - 1 /*iCurrentDepth*/); // skip over whitespace.
}
if (reader.Depth - 1 > d)
{
XmlDataLoader xmlload = new XmlDataLoader(newDs, false, node, false);
xmlload._isDiffgram = true; // turn on the special processing
xmlload.LoadData(reader);
}
ReadEndElement(reader);
if (reader.NodeType == XmlNodeType.Whitespace)
{
MoveToElement(reader, reader.Depth - 1 /*iCurrentDepth*/); // skip over whitespace.
}
}
Debug.Assert(reader.NodeType != XmlNodeType.Whitespace, "Should not be on Whitespace node");
if (((reader.LocalName == Keywords.SQL_BEFORE) && (reader.NamespaceURI == Keywords.DFFNS)) ||
((reader.LocalName == Keywords.MSD_ERRORS) && (reader.NamespaceURI == Keywords.DFFNS)))
{
//this will consume the changes and the errors part
XMLDiffLoader diffLoader = new XMLDiffLoader();
diffLoader.LoadDiffGram(newDs, reader);
}
// get to the closing diff tag
while (reader.Depth > d)
{
reader.Read();
}
// read the closing tag
ReadEndElement(reader);
}
foreach (DataTable t in newDs.Tables)
{
if (t.Rows._nullInList > 0)
{
throw ExceptionBuilder.RowInsertMissing(t.TableName);
}
}
newDs._fInLoadDiffgram = false;
//terrible performance!
foreach (DataTable t in newDs.Tables)
{
DataRelation[] nestedParentRelations = t.NestedParentRelations;
foreach (DataRelation rel in nestedParentRelations)
{
if (rel.ParentTable == t)
{
foreach (DataRow r in t.Rows)
{
foreach (DataRelation rel2 in nestedParentRelations)
{
r.CheckForLoops(rel2);
}
}
}
}
}
if (!isEmpty)
{
Merge(newDs);
if (_dataSetName == "NewDataSet")
{
_dataSetName = newDs._dataSetName;
}
newDs.EnforceConstraints = fEnforce;
}
EnforceConstraints = fEnforce;
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
/// <summary>
/// </summary>
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public XmlReadMode ReadXml(XmlReader? reader, XmlReadMode mode) => ReadXml(reader, mode, false);
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
internal XmlReadMode ReadXml(XmlReader? reader, XmlReadMode mode, bool denyResolving)
{
IDisposable? restictedScope = null;
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.ReadXml|INFO> {0}, mode={1}, denyResolving={2}", ObjectID, mode, denyResolving);
try
{
restictedScope = TypeLimiter.EnterRestrictedScope(this);
XmlReadMode ret = mode;
if (reader == null)
{
return ret;
}
if (mode == XmlReadMode.Auto)
{
// nested ReadXml calls on the same DataSet must be done outside of RowDiffIdUsage scope
return ReadXml(reader);
}
DataTable.DSRowDiffIdUsageSection rowDiffIdUsage = default;
try
{
bool fSchemaFound = false;
bool fDataFound = false;
bool fIsXdr = false;
int iCurrentDepth = -1;
// prepare and cleanup rowDiffId hashtable
rowDiffIdUsage.Prepare(this);
if (reader is XmlTextReader)
{
((XmlTextReader)reader).WhitespaceHandling = WhitespaceHandling.Significant;
}
XmlDocument xdoc = new XmlDocument(); // we may need this to infer the schema
if ((mode != XmlReadMode.Fragment) && (reader.NodeType == XmlNodeType.Element))
{
iCurrentDepth = reader.Depth;
}
reader.MoveToContent();
XmlDataLoader? xmlload = null;
if (reader.NodeType == XmlNodeType.Element)
{
XmlElement? topNode = null;
if (mode == XmlReadMode.Fragment)
{
xdoc.AppendChild(xdoc.CreateElement("ds_sqlXmlWraPPeR"));
topNode = xdoc.DocumentElement!;
}
else
{
//handle the top node
if ((reader.LocalName == Keywords.DIFFGRAM) && (reader.NamespaceURI == Keywords.DFFNS))
{
if ((mode == XmlReadMode.DiffGram) || (mode == XmlReadMode.IgnoreSchema))
{
ReadXmlDiffgram(reader);
// read the closing tag of the current element
ReadEndElement(reader);
}
else
{
reader.Skip();
}
return ret;
}
if (reader.LocalName == Keywords.XDR_SCHEMA && reader.NamespaceURI == Keywords.XDRNS)
{
// load XDR schema and exit
if ((mode != XmlReadMode.IgnoreSchema) && (mode != XmlReadMode.InferSchema) &&
(mode != XmlReadMode.InferTypedSchema))
{
ReadXDRSchema(reader);
}
else
{
reader.Skip();
}
return ret; //since the top level element is a schema return
}
if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI == Keywords.XSDNS)
{
// load XSD schema and exit
if ((mode != XmlReadMode.IgnoreSchema) && (mode != XmlReadMode.InferSchema) &&
(mode != XmlReadMode.InferTypedSchema))
{
ReadXSDSchema(reader);
}
else
{
reader.Skip();
}
return ret; //since the top level element is a schema return
}
if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI.StartsWith(Keywords.XSD_NS_START, StringComparison.Ordinal))
{
throw ExceptionBuilder.DataSetUnsupportedSchema(Keywords.XSDNS);
}
// now either the top level node is a table and we load it through dataReader...
// ... or backup the top node and all its attributes
topNode = xdoc.CreateElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
if (reader.HasAttributes)
{
int attrCount = reader.AttributeCount;
for (int i = 0; i < attrCount; i++)
{
reader.MoveToAttribute(i);
if (reader.NamespaceURI.Equals(Keywords.XSD_XMLNS_NS))
topNode.SetAttribute(reader.Name, reader.GetAttribute(i));
else
{
XmlAttribute attr = topNode.SetAttributeNode(reader.LocalName, reader.NamespaceURI);
attr.Prefix = reader.Prefix;
attr.Value = reader.GetAttribute(i);
}
}
}
reader.Read();
}
while (MoveToElement(reader, iCurrentDepth))
{
if (reader.LocalName == Keywords.XDR_SCHEMA && reader.NamespaceURI == Keywords.XDRNS)
{
// load XDR schema
if (!fSchemaFound && !fDataFound && (mode != XmlReadMode.IgnoreSchema) && (mode != XmlReadMode.InferSchema) &&
(mode != XmlReadMode.InferTypedSchema))
{
ReadXDRSchema(reader);
fSchemaFound = true;
fIsXdr = true;
}
else
{
reader.Skip();
}
continue;
}
if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI == Keywords.XSDNS)
{
// load XSD schema and exit
if ((mode != XmlReadMode.IgnoreSchema) && (mode != XmlReadMode.InferSchema) &&
(mode != XmlReadMode.InferTypedSchema))
{
ReadXSDSchema(reader);
fSchemaFound = true;
}
else
{
reader.Skip();
}
continue;
}
if ((reader.LocalName == Keywords.DIFFGRAM) && (reader.NamespaceURI == Keywords.DFFNS))
{
if ((mode == XmlReadMode.DiffGram) || (mode == XmlReadMode.IgnoreSchema))
{
ReadXmlDiffgram(reader);
ret = XmlReadMode.DiffGram;
}
else
{
reader.Skip();
}
continue;
}
if (reader.LocalName == Keywords.XSD_SCHEMA && reader.NamespaceURI.StartsWith(Keywords.XSD_NS_START, StringComparison.Ordinal))
throw ExceptionBuilder.DataSetUnsupportedSchema(Keywords.XSDNS);
if (mode == XmlReadMode.DiffGram)
{
reader.Skip();
continue; // we do not read data in diffgram mode
}
// if we are here we found some data
fDataFound = true;
if (mode == XmlReadMode.InferSchema || mode == XmlReadMode.InferTypedSchema)
{ //save the node in DOM until the end;
XmlNode node = xdoc.ReadNode(reader)!;
topNode.AppendChild(node);
}
else
{
xmlload ??= new XmlDataLoader(this, fIsXdr, topNode, mode == XmlReadMode.IgnoreSchema);
xmlload.LoadData(reader);
}
} //end of the while
// read the closing tag of the current element
ReadEndElement(reader);
// now top node contains the data part
xdoc.AppendChild(topNode);
xmlload ??= new XmlDataLoader(this, fIsXdr, mode == XmlReadMode.IgnoreSchema);
if (mode == XmlReadMode.DiffGram)
{
// we already got the diffs through XmlReader interface
return ret;
}
// Load Data
if (mode == XmlReadMode.InferSchema || mode == XmlReadMode.InferTypedSchema)
{
InferSchema(xdoc, null, mode);
ret = XmlReadMode.InferSchema;
xmlload.FromInference = true;
try
{
xmlload.LoadData(xdoc);
}
finally
{
xmlload.FromInference = false;
}
}
}
return ret;
}
finally
{
// prepare and cleanup rowDiffId hashtable
rowDiffIdUsage.Cleanup();
}
}
finally
{
restictedScope?.Dispose();
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public XmlReadMode ReadXml(Stream? stream, XmlReadMode mode)
{
if (stream == null)
{
return XmlReadMode.Auto;
}
XmlTextReader reader = (mode == XmlReadMode.Fragment) ? new XmlTextReader(stream, XmlNodeType.Element, null) : new XmlTextReader(stream);
// Prevent Dtd entity in dataset
reader.XmlResolver = null;
return ReadXml(reader, mode, false);
}
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public XmlReadMode ReadXml(TextReader? reader, XmlReadMode mode)
{
if (reader == null)
{
return XmlReadMode.Auto;
}
XmlTextReader xmlreader = (mode == XmlReadMode.Fragment) ? new XmlTextReader(reader.ReadToEnd(), XmlNodeType.Element, null) : new XmlTextReader(reader);
// Prevent Dtd entity in dataset
xmlreader.XmlResolver = null;
return ReadXml(xmlreader, mode, false);
}
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public XmlReadMode ReadXml(string fileName, XmlReadMode mode)
{
XmlTextReader xr;
if (mode == XmlReadMode.Fragment)
{
FileStream stream = new FileStream(fileName, FileMode.Open);
xr = new XmlTextReader(stream, XmlNodeType.Element, null);
}
else
{
xr = new XmlTextReader(fileName);
}
// Prevent Dtd entity in dataset
xr.XmlResolver = null;
try
{
return ReadXml(xr, mode, false);
}
finally
{
xr.Close();
}
}
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public void WriteXml(Stream? stream) => WriteXml(stream, XmlWriteMode.IgnoreSchema);
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public void WriteXml(TextWriter? writer) => WriteXml(writer, XmlWriteMode.IgnoreSchema);
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public void WriteXml(XmlWriter? writer) => WriteXml(writer, XmlWriteMode.IgnoreSchema);
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public void WriteXml(string fileName) => WriteXml(fileName, XmlWriteMode.IgnoreSchema);
/// <summary>
/// Writes schema and data for the DataSet.
/// </summary>
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public void WriteXml(Stream? stream, XmlWriteMode mode)
{
if (stream != null)
{
XmlTextWriter w = new XmlTextWriter(stream, null);
w.Formatting = Formatting.Indented;
WriteXml(w, mode);
}
}
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public void WriteXml(TextWriter? writer, XmlWriteMode mode)
{
if (writer != null)
{
XmlTextWriter w = new XmlTextWriter(writer);
w.Formatting = Formatting.Indented;
WriteXml(w, mode);
}
}
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public void WriteXml(XmlWriter? writer, XmlWriteMode mode)
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.WriteXml|API> {0}, mode={1}", ObjectID, mode);
try
{
// Generate SchemaTree and write it out
if (writer != null)
{
if (mode == XmlWriteMode.DiffGram)
{
// Create and save the updates
new NewDiffgramGen(this).Save(writer);
}
else
{
// Create and save xml data
new XmlDataTreeWriter(this).Save(writer, mode == XmlWriteMode.WriteSchema);
}
}
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
public void WriteXml(string fileName, XmlWriteMode mode)
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.WriteXml|API> {0}, fileName='{1}', mode={2}", ObjectID, fileName, (int)mode);
XmlTextWriter xw = new XmlTextWriter(fileName, null);
try
{
xw.Formatting = Formatting.Indented;
xw.WriteStartDocument(true);
// Create and save the updates
if (mode == XmlWriteMode.DiffGram)
{
new NewDiffgramGen(this).Save(xw);
}
else
{
// Create and save xml data
new XmlDataTreeWriter(this).Save(xw, mode == XmlWriteMode.WriteSchema);
}
xw.WriteEndDocument();
}
finally
{
xw.Close();
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
/// <summary>
/// Gets the collection of parent relations which belong to a
/// specified table.
/// </summary>
internal static DataRelationCollection GetParentRelations(DataTable table) => table.ParentRelations;
/// <summary>
/// Merges this <see cref='System.Data.DataSet'/> into a specified <see cref='System.Data.DataSet'/>.
/// </summary>
public void Merge(DataSet dataSet)
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.Merge|API> {0}, dataSet={1}", ObjectID, (dataSet != null) ? dataSet.ObjectID : 0);
Debug.Assert(dataSet != null);
try
{
Merge(dataSet, false, MissingSchemaAction.Add);
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
/// <summary>
/// Merges this <see cref='System.Data.DataSet'/> into a specified <see cref='System.Data.DataSet'/> preserving changes according to
/// the specified argument.
/// </summary>
public void Merge(DataSet dataSet, bool preserveChanges)
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.Merge|API> {0}, dataSet={1}, preserveChanges={2}", ObjectID, (dataSet != null) ? dataSet.ObjectID : 0, preserveChanges);
Debug.Assert(dataSet != null);
try
{
Merge(dataSet, preserveChanges, MissingSchemaAction.Add);
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
/// <summary>
/// Merges this <see cref='System.Data.DataSet'/> into a specified <see cref='System.Data.DataSet'/> preserving changes according to
/// the specified argument, and handling an incompatible schema according to the
/// specified argument.
/// </summary>
public void Merge(DataSet dataSet, bool preserveChanges, MissingSchemaAction missingSchemaAction)
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.Merge|API> {0}, dataSet={1}, preserveChanges={2}, missingSchemaAction={3}", ObjectID, (dataSet != null) ? dataSet.ObjectID : 0, preserveChanges, missingSchemaAction);
try
{
// Argument checks
if (dataSet == null)
{
throw ExceptionBuilder.ArgumentNull(nameof(dataSet));
}
switch (missingSchemaAction)
{
case MissingSchemaAction.Add:
case MissingSchemaAction.Ignore:
case MissingSchemaAction.Error:
case MissingSchemaAction.AddWithKey:
Merger merger = new Merger(this, preserveChanges, missingSchemaAction);
merger.MergeDataSet(dataSet);
break;
default:
throw ADP.InvalidMissingSchemaAction(missingSchemaAction);
}
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
/// <summary>
/// Merges this <see cref='System.Data.DataTable'/> into a specified <see cref='System.Data.DataTable'/>.
/// </summary>
public void Merge(DataTable table)
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.Merge|API> {0}, table={1}", ObjectID, (table != null) ? table.ObjectID : 0);
Debug.Assert(table != null);
try
{
Merge(table, false, MissingSchemaAction.Add);
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
/// <summary>
/// Merges this <see cref='System.Data.DataTable'/> into a specified <see cref='System.Data.DataTable'/>. with a value to preserve changes
/// made to the target, and a value to deal with missing schemas.
/// </summary>
public void Merge(DataTable table, bool preserveChanges, MissingSchemaAction missingSchemaAction)
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.Merge|API> {0}, table={1}, preserveChanges={2}, missingSchemaAction={3}", ObjectID, (table != null) ? table.ObjectID : 0, preserveChanges, missingSchemaAction);
try
{
// Argument checks
if (table == null)
{
throw ExceptionBuilder.ArgumentNull(nameof(table));
}
switch (missingSchemaAction)
{
case MissingSchemaAction.Add:
case MissingSchemaAction.Ignore:
case MissingSchemaAction.Error:
case MissingSchemaAction.AddWithKey:
Merger merger = new Merger(this, preserveChanges, missingSchemaAction);
merger.MergeTable(table);
break;
default:
throw ADP.InvalidMissingSchemaAction(missingSchemaAction);
}
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
public void Merge(DataRow[] rows)
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.Merge|API> {0}, rows", ObjectID);
try
{
Merge(rows, false, MissingSchemaAction.Add);
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
public void Merge(DataRow[] rows, bool preserveChanges, MissingSchemaAction missingSchemaAction)
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.Merge|API> {0}, preserveChanges={1}, missingSchemaAction={2}", ObjectID, preserveChanges, missingSchemaAction);
try
{
// Argument checks
if (rows == null)
{
throw ExceptionBuilder.ArgumentNull(nameof(rows));
}
switch (missingSchemaAction)
{
case MissingSchemaAction.Add:
case MissingSchemaAction.Ignore:
case MissingSchemaAction.Error:
case MissingSchemaAction.AddWithKey:
Merger merger = new Merger(this, preserveChanges, missingSchemaAction);
merger.MergeRows(rows);
break;
default:
throw ADP.InvalidMissingSchemaAction(missingSchemaAction);
}
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
protected virtual void OnPropertyChanging(PropertyChangedEventArgs pcevent)
{
PropertyChanging?.Invoke(this, pcevent);
}
/// <summary>
/// Inheriting classes should override this method to handle this event.
/// Call base.OnMergeFailed to send this event to any registered event
/// listeners.
/// </summary>
internal void OnMergeFailed(MergeFailedEventArgs mfevent)
{
if (MergeFailed != null)
{
MergeFailed(this, mfevent);
}
else
{
throw ExceptionBuilder.MergeFailed(mfevent.Conflict);
}
}
internal void RaiseMergeFailed(DataTable? table, string conflict, MissingSchemaAction missingSchemaAction)
{
if (MissingSchemaAction.Error == missingSchemaAction)
{
throw ExceptionBuilder.MergeFailed(conflict);
}
OnMergeFailed(new MergeFailedEventArgs(table, conflict));
}
internal void OnDataRowCreated(DataRow row) => DataRowCreated?.Invoke(this, row);
internal void OnClearFunctionCalled(DataTable? table) => ClearFunctionCalled?.Invoke(this, table);
private void OnInitialized() => Initialized?.Invoke(this, EventArgs.Empty);
/// <summary>
/// This method should be overridden by subclasses to restrict tables being removed.
/// </summary>
protected internal virtual void OnRemoveTable(DataTable table) { }
internal void OnRemovedTable(DataTable table)
{
_defaultViewManager?.DataViewSettings.Remove(table);
}
/// <summary>
/// This method should be overridden by subclasses to restrict tables being removed.
/// </summary>
protected virtual void OnRemoveRelation(DataRelation relation) { }
internal void OnRemoveRelationHack(DataRelation relation) => OnRemoveRelation(relation);
protected internal void RaisePropertyChanging(string name) => OnPropertyChanging(new PropertyChangedEventArgs(name));
internal DataTable[] TopLevelTables() => TopLevelTables(false);
internal DataTable[] TopLevelTables(bool forSchema)
{
// first let's figure out if we can represent the given dataSet as a tree using
// the fact that all connected undirected graphs with n-1 edges are trees.
List<DataTable> topTables = new List<DataTable>();
if (forSchema)
{
// prepend the tables that are nested more than once
for (int i = 0; i < Tables.Count; i++)
{
DataTable table = Tables[i];
if (table.NestedParentsCount > 1 || table.SelfNested)
{
topTables.Add(table);
}
}
}
for (int i = 0; i < Tables.Count; i++)
{
DataTable table = Tables[i];
if (table.NestedParentsCount == 0 && !topTables.Contains(table))
{
topTables.Add(table);
}
}
return topTables.Count == 0 ?
Array.Empty<DataTable>() :
topTables.ToArray();
}
/// <summary>
/// This method rolls back all the changes to have been made to this DataSet since
/// it was loaded or the last time AcceptChanges was called.
/// Any rows still in edit-mode cancel their edits. New rows get removed. Modified and
/// Deleted rows return back to their original state.
/// </summary>
public virtual void RejectChanges()
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.RejectChanges|API> {0}", ObjectID);
try
{
bool fEnforce = EnforceConstraints;
EnforceConstraints = false;
for (int i = 0; i < Tables.Count; i++)
{
Tables[i].RejectChanges();
}
EnforceConstraints = fEnforce;
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
/// <summary>
/// Resets the dataSet back to it's original state. Subclasses should override
/// to restore back to it's original state.
/// </summary>
public virtual void Reset()
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.Reset|API> {0}", ObjectID);
try
{
for (int i = 0; i < Tables.Count; i++)
{
ConstraintCollection cons = Tables[i].Constraints;
for (int j = 0; j < cons.Count;)
{
if (cons[j] is ForeignKeyConstraint)
{
cons.Remove(cons[j]);
}
else
{
j++;
}
}
}
Clear();
Relations.Clear();
Tables.Clear();
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
internal bool ValidateCaseConstraint()
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.ValidateCaseConstraint|INFO> {0}", ObjectID);
try
{
DataRelation? relation = null;
for (int i = 0; i < Relations.Count; i++)
{
relation = Relations[i];
if (relation.ChildTable.CaseSensitive != relation.ParentTable.CaseSensitive)
{
return false;
}
}
ForeignKeyConstraint? constraint;
ConstraintCollection? constraints;
for (int i = 0; i < Tables.Count; i++)
{
constraints = Tables[i].Constraints;
for (int j = 0; j < constraints.Count; j++)
{
if (constraints[j] is ForeignKeyConstraint)
{
constraint = (ForeignKeyConstraint)constraints[j];
if (constraint.Table!.CaseSensitive != constraint.RelatedTable.CaseSensitive)
{
return false;
}
}
}
}
return true;
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
internal bool ValidateLocaleConstraint()
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.ValidateLocaleConstraint|INFO> {0}", ObjectID);
try
{
DataRelation? relation = null;
for (int i = 0; i < Relations.Count; i++)
{
relation = Relations[i];
if (relation.ChildTable.Locale.LCID != relation.ParentTable.Locale.LCID)
{
return false;
}
}
ForeignKeyConstraint? constraint;
ConstraintCollection? constraints;
for (int i = 0; i < Tables.Count; i++)
{
constraints = Tables[i].Constraints;
for (int j = 0; j < constraints.Count; j++)
{
if (constraints[j] is ForeignKeyConstraint)
{
constraint = (ForeignKeyConstraint)constraints[j];
if (constraint.Table!.Locale.LCID != constraint.RelatedTable.Locale.LCID)
{
return false;
}
}
}
}
return true;
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
// SDUB: may be better to rewrite this as nonrecursive?
internal static DataTable? FindTable(DataTable? baseTable, PropertyDescriptor[] props, int propStart)
{
if (props.Length < propStart + 1)
{
return baseTable;
}
PropertyDescriptor currentProp = props[propStart];
if (baseTable == null)
{
// the accessor is the table name. if we don't find it, return null.
if (currentProp is DataTablePropertyDescriptor)
{
return FindTable(((DataTablePropertyDescriptor)currentProp).Table, props, propStart + 1);
}
return null;
}
if (currentProp is DataRelationPropertyDescriptor)
{
return FindTable(((DataRelationPropertyDescriptor)currentProp).Relation.ChildTable, props, propStart + 1);
}
return null;
}
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
protected virtual void ReadXmlSerializable(XmlReader reader)
{
// <DataSet xsi:nil="true"> does not mean DataSet is null,but it does not have any child
// so dont do anything, ignore the attributes and just return empty DataSet;
_useDataSetSchemaOnly = false;
_udtIsWrapped = false;
if (reader.HasAttributes)
{
const string xsinill = Keywords.XSI + ":" + Keywords.XSI_NIL;
if (reader.MoveToAttribute(xsinill))
{
string? nilAttrib = reader.GetAttribute(xsinill);
if (string.Equals(nilAttrib, "true", StringComparison.Ordinal))
{
// case sensitive true comparison
MoveToElement(reader, 1);
return;
}
}
const string UseDataSetSchemaOnlyString = Keywords.MSD + ":" + Keywords.USEDATASETSCHEMAONLY;
if (reader.MoveToAttribute(UseDataSetSchemaOnlyString))
{
string? useDataSetSchemaOnly = reader.GetAttribute(UseDataSetSchemaOnlyString);
if (string.Equals(useDataSetSchemaOnly, "true", StringComparison.Ordinal) ||
string.Equals(useDataSetSchemaOnly, "1", StringComparison.Ordinal))
{
_useDataSetSchemaOnly = true;
}
else if (!string.Equals(useDataSetSchemaOnly, "false", StringComparison.Ordinal) &&
!string.Equals(useDataSetSchemaOnly, "0", StringComparison.Ordinal))
{
throw ExceptionBuilder.InvalidAttributeValue(Keywords.USEDATASETSCHEMAONLY, useDataSetSchemaOnly!);
}
}
const string udtIsWrappedString = Keywords.MSD + ":" + Keywords.UDTCOLUMNVALUEWRAPPED;
if (reader.MoveToAttribute(udtIsWrappedString))
{
string? _udtIsWrappedString = reader.GetAttribute(udtIsWrappedString);
if (string.Equals(_udtIsWrappedString, "true", StringComparison.Ordinal) ||
string.Equals(_udtIsWrappedString, "1", StringComparison.Ordinal))
{
_udtIsWrapped = true;
}
else if (!string.Equals(_udtIsWrappedString, "false", StringComparison.Ordinal) &&
!string.Equals(_udtIsWrappedString, "0", StringComparison.Ordinal))
{
throw ExceptionBuilder.InvalidAttributeValue(Keywords.UDTCOLUMNVALUEWRAPPED, _udtIsWrappedString!);
}
}
}
ReadXml(reader, XmlReadMode.DiffGram, true);
}
protected virtual System.Xml.Schema.XmlSchema? GetSchemaSerializable() => null;
public static XmlSchemaComplexType GetDataSetSchema(XmlSchemaSet? schemaSet)
{
// For performance reasons we are exploiting the fact that config files content is constant
// for a given appdomain so we can safely cache the prepared schema complex type and reuse it
if (s_schemaTypeForWSDL == null)
{
// to change the config file, appdomain needs to restart; so it seems safe to cache the schema
XmlSchemaComplexType tempWSDL = new XmlSchemaComplexType();
XmlSchemaSequence sequence = new XmlSchemaSequence();
XmlSchemaAny any = new XmlSchemaAny();
any.Namespace = XmlSchema.Namespace;
any.MinOccurs = 0;
any.ProcessContents = XmlSchemaContentProcessing.Lax;
sequence.Items.Add(any);
any = new XmlSchemaAny();
any.Namespace = Keywords.DFFNS;
any.MinOccurs = 0; // when recognizing WSDL - MinOccurs="0" denotes DataSet, a MinOccurs="1" for DataTable
any.ProcessContents = XmlSchemaContentProcessing.Lax;
sequence.Items.Add(any);
sequence.MaxOccurs = decimal.MaxValue;
tempWSDL.Particle = sequence;
s_schemaTypeForWSDL = tempWSDL;
}
return s_schemaTypeForWSDL;
}
private static bool PublishLegacyWSDL() => false;
XmlSchema? IXmlSerializable.GetSchema()
{
if (!XmlSerializationIsSupported)
{
throw new NotSupportedException(SR.DataSet_XmlSerializationUnsupported);
}
if (GetType() == typeof(DataSet))
{
return null;
}
MemoryStream stream = new MemoryStream();
// WriteXmlSchema(new XmlTextWriter(stream, null));
XmlWriter writer = new XmlTextWriter(stream, null);
if (writer != null)
{
WriteXmlSchema(this, writer);
}
stream.Position = 0;
return XmlSchema.Read(new XmlTextReader(stream), null);
}
[RequiresUnreferencedCode("DataSet.GetSchema uses TypeDescriptor and XmlSerialization underneath which are not trimming safe. Members from serialized types may be trimmed if not referenced directly.")]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
private static void WriteXmlSchema(DataSet ds, XmlWriter writer)
{
(new XmlTreeGen(SchemaFormat.WebService)).Save(ds, writer);
}
void IXmlSerializable.ReadXml(XmlReader reader)
{
if (!XmlSerializationIsSupported)
{
throw new NotSupportedException(SR.DataSet_XmlSerializationUnsupported);
}
bool fNormalization = true;
XmlTextReader? xmlTextReader = null;
IXmlTextParser? xmlTextParser = reader as IXmlTextParser;
if (xmlTextParser != null)
{
fNormalization = xmlTextParser.Normalized;
xmlTextParser.Normalized = false;
}
else
{
xmlTextReader = reader as XmlTextReader;
if (xmlTextReader != null)
{
fNormalization = xmlTextReader.Normalization;
xmlTextReader.Normalization = false;
}
}
ReadXmlSerializableInternal(reader);
if (xmlTextParser != null)
{
xmlTextParser.Normalized = fNormalization;
}
else if (xmlTextReader != null)
{
xmlTextReader.Normalization = fNormalization;
}
}
[RequiresUnreferencedCode("DataSet.ReadXml uses XmlSerialization underneath which is not trimming safe. Members from serialized types may be trimmed if not referenced directly.")]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
private void ReadXmlSerializableInternal(XmlReader reader)
{
ReadXmlSerializable(reader);
}
void IXmlSerializable.WriteXml(XmlWriter writer)
{
if (!XmlSerializationIsSupported)
{
throw new NotSupportedException(SR.DataSet_XmlSerializationUnsupported);
}
WriteXmlInternal(writer);
}
[RequiresUnreferencedCode("DataSet.WriteXml uses XmlSerialization underneath which is not trimming safe. Members from serialized types may be trimmed if not referenced directly.")]
[RequiresDynamicCode(RequiresDynamicCodeMessage)]
private void WriteXmlInternal(XmlWriter writer)
{
WriteXmlSchema(writer, SchemaFormat.WebService, null);
WriteXml(writer, XmlWriteMode.DiffGram);
}
[RequiresUnreferencedCode("Using LoadOption may cause members from types used in the expression column to be trimmed if not referenced directly.")]
public virtual void Load(IDataReader reader, LoadOption loadOption, FillErrorEventHandler? errorHandler, params DataTable[] tables)
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.Load|API> reader, loadOption={0}", loadOption);
try
{
foreach (DataTable dt in tables)
{
ADP.CheckArgumentNull(dt, nameof(tables));
if (dt.DataSet != this)
{
throw ExceptionBuilder.TableNotInTheDataSet(dt.TableName);
}
}
var adapter = new LoadAdapter();
adapter.FillLoadOption = loadOption;
adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey;
if (null != errorHandler)
{
adapter.FillError += errorHandler;
}
adapter.FillFromReader(tables, reader, 0, 0);
if (!reader.IsClosed && !reader.NextResult())
{
reader.Close();
}
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
[RequiresUnreferencedCode("Using LoadOption may cause members from types used in the expression column to be trimmed if not referenced directly.")]
public void Load(IDataReader reader, LoadOption loadOption, params DataTable[] tables) =>
Load(reader, loadOption, null, tables);
[RequiresUnreferencedCode("Using LoadOption may cause members from types used in the expression column to be trimmed if not referenced directly.")]
public void Load(IDataReader reader, LoadOption loadOption, params string[] tables)
{
ADP.CheckArgumentNull(tables, nameof(tables));
var dataTables = new DataTable[tables.Length];
for (int i = 0; i < tables.Length; i++)
{
DataTable? tempDT = Tables[tables[i]];
if (null == tempDT)
{
tempDT = new DataTable(tables[i]);
Tables.Add(tempDT);
}
dataTables[i] = tempDT;
}
Load(reader, loadOption, null, dataTables);
}
public DataTableReader CreateDataReader()
{
if (Tables.Count == 0)
{
throw ExceptionBuilder.CannotCreateDataReaderOnEmptyDataSet();
}
var dataTables = new DataTable[Tables.Count];
for (int i = 0; i < Tables.Count; i++)
{
dataTables[i] = Tables[i];
}
return CreateDataReader(dataTables);
}
public DataTableReader CreateDataReader(params DataTable[] dataTables)
{
long logScopeId = DataCommonEventSource.Log.EnterScope("<ds.DataSet.GetDataReader|API> {0}", ObjectID);
try
{
if (dataTables.Length == 0)
{
throw ExceptionBuilder.DataTableReaderArgumentIsEmpty();
}
for (int i = 0; i < dataTables.Length; i++)
{
if (dataTables[i] == null)
{
throw ExceptionBuilder.ArgumentContainsNullValue();
}
}
return new DataTableReader(dataTables);
}
finally
{
DataCommonEventSource.Log.ExitScope(logScopeId);
}
}
internal string MainTableName
{
get { return _mainTableName; }
set { _mainTableName = value; }
}
internal int ObjectID => _objectID;
}
}
|