diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/TdsParser.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/TdsParser.cs
index 4707cb9086..fd8fa365e4 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/TdsParser.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/TdsParser.cs
@@ -4793,13 +4793,13 @@ internal TdsOperationStatus TryProcessReturnValue(int length,
{
return result;
}
- if (rec.XmlSchemaCollection is null)
+ if (rec.XmlTypeInfo is null)
{
- rec.XmlSchemaCollection = new SqlMetaDataXmlSchemaCollection();
+ rec.XmlTypeInfo = new TdsXmlTypeInfo();
}
if (len != 0)
{
- result = stateObj.TryReadString(len, out rec.XmlSchemaCollection.Database);
+ result = stateObj.TryReadString(len, out rec.XmlTypeInfo.Database);
if (result != TdsOperationStatus.Done)
{
return result;
@@ -4813,7 +4813,7 @@ internal TdsOperationStatus TryProcessReturnValue(int length,
}
if (len != 0)
{
- result = stateObj.TryReadString(len, out rec.XmlSchemaCollection.OwningSchema);
+ result = stateObj.TryReadString(len, out rec.XmlTypeInfo.OwningSchema);
if (result != TdsOperationStatus.Done)
{
return result;
@@ -4829,7 +4829,7 @@ internal TdsOperationStatus TryProcessReturnValue(int length,
if (slen != 0)
{
- result = stateObj.TryReadString(slen, out rec.XmlSchemaCollection.Name);
+ result = stateObj.TryReadString(slen, out rec.XmlTypeInfo.Name);
if (result != TdsOperationStatus.Done)
{
return result;
@@ -5551,13 +5551,13 @@ private TdsOperationStatus TryProcessTypeInfo(TdsParserStateObject stateObj, Tds
{
return result;
}
- if (col.XmlSchemaCollection is null)
+ if (col.XmlTypeInfo is null)
{
- col.XmlSchemaCollection = new SqlMetaDataXmlSchemaCollection();
+ col.XmlTypeInfo = new TdsXmlTypeInfo();
}
if (byteLen != 0)
{
- result = stateObj.TryReadString(byteLen, out col.XmlSchemaCollection.Database);
+ result = stateObj.TryReadString(byteLen, out col.XmlTypeInfo.Database);
if (result != TdsOperationStatus.Done)
{
return result;
@@ -5571,7 +5571,7 @@ private TdsOperationStatus TryProcessTypeInfo(TdsParserStateObject stateObj, Tds
}
if (byteLen != 0)
{
- result = stateObj.TryReadString(byteLen, out col.XmlSchemaCollection.OwningSchema);
+ result = stateObj.TryReadString(byteLen, out col.XmlTypeInfo.OwningSchema);
if (result != TdsOperationStatus.Done)
{
return result;
@@ -5586,7 +5586,7 @@ private TdsOperationStatus TryProcessTypeInfo(TdsParserStateObject stateObj, Tds
}
if (byteLen != 0)
{
- result = stateObj.TryReadString(shortLen, out col.XmlSchemaCollection.Name);
+ result = stateObj.TryReadString(shortLen, out col.XmlTypeInfo.Name);
if (result != TdsOperationStatus.Done)
{
return result;
@@ -5791,13 +5791,13 @@ private TdsOperationStatus TryProcessUDTMetaData(TdsTypeInfo metaData, TdsParser
{
return result;
}
- if (metaData.Udt is null)
+ if (metaData.UdtTypeInfo is null)
{
- metaData.Udt = new SqlMetaDataUdt();
+ metaData.UdtTypeInfo = new TdsUdtTypeInfo();
}
if (byteLength != 0)
{
- result = stateObj.TryReadString(byteLength, out metaData.Udt.DatabaseName);
+ result = stateObj.TryReadString(byteLength, out metaData.UdtTypeInfo.DatabaseName);
if (result != TdsOperationStatus.Done)
{
return result;
@@ -5812,7 +5812,7 @@ private TdsOperationStatus TryProcessUDTMetaData(TdsTypeInfo metaData, TdsParser
}
if (byteLength != 0)
{
- result = stateObj.TryReadString(byteLength, out metaData.Udt.SchemaName);
+ result = stateObj.TryReadString(byteLength, out metaData.UdtTypeInfo.SchemaName);
if (result != TdsOperationStatus.Done)
{
return result;
@@ -5827,7 +5827,7 @@ private TdsOperationStatus TryProcessUDTMetaData(TdsTypeInfo metaData, TdsParser
}
if (byteLength != 0)
{
- result = stateObj.TryReadString(byteLength, out metaData.Udt.TypeName);
+ result = stateObj.TryReadString(byteLength, out metaData.UdtTypeInfo.TypeName);
if (result != TdsOperationStatus.Done)
{
return result;
@@ -5841,7 +5841,7 @@ private TdsOperationStatus TryProcessUDTMetaData(TdsTypeInfo metaData, TdsParser
}
if (shortLength != 0)
{
- result = stateObj.TryReadString(shortLength, out metaData.Udt.AssemblyQualifiedName);
+ result = stateObj.TryReadString(shortLength, out metaData.UdtTypeInfo.AssemblyQualifiedName);
if (result != TdsOperationStatus.Done)
{
return result;
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/Tokens/SqlMetaDataUdt.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/Tokens/SqlMetaDataUdt.cs
deleted file mode 100644
index 06367dbda4..0000000000
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/Tokens/SqlMetaDataUdt.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Diagnostics.CodeAnalysis;
-
-namespace Microsoft.Data.SqlClient.Parser.Tokens;
-
-internal sealed class SqlMetaDataUdt
-{
- #if NET
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
- #endif
- internal Type Type;
-
- internal string DatabaseName;
-
- internal string SchemaName;
-
- internal string TypeName;
-
- internal string AssemblyQualifiedName;
-
- public void CopyFrom(SqlMetaDataUdt original)
- {
- if (original != null)
- {
- Type = original.Type;
- DatabaseName = original.DatabaseName;
- SchemaName = original.SchemaName;
- TypeName = original.TypeName;
- AssemblyQualifiedName = original.AssemblyQualifiedName;
- }
- }
-}
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/Tokens/SqlMetaDataXmlSchemaCollection.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/Tokens/SqlMetaDataXmlSchemaCollection.cs
deleted file mode 100644
index e5d609917c..0000000000
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/Tokens/SqlMetaDataXmlSchemaCollection.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-namespace Microsoft.Data.SqlClient.Parser.Tokens;
-
-internal sealed class SqlMetaDataXmlSchemaCollection
-{
- internal string Database;
- internal string OwningSchema;
- internal string Name;
-
- public void CopyFrom(SqlMetaDataXmlSchemaCollection original)
- {
- if (original != null)
- {
- Database = original.Database;
- OwningSchema = original.OwningSchema;
- Name = original.Name;
- }
- }
-}
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/Tokens/TdsColumnMetadata.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/Tokens/TdsColumnMetadata.cs
index 267c96a1e2..7273191876 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/Tokens/TdsColumnMetadata.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/Tokens/TdsColumnMetadata.cs
@@ -11,6 +11,7 @@ namespace Microsoft.Data.SqlClient.Parser.Tokens;
/// Represents metadata information for a specific column in a TDS stream. Corresponds with a
/// single column within a SQLCOLMETADATA/SQLALTMETADATA token.
///
+// @TODO: We have a mix of patterns here where some subtypes are contained within the types, while some are inherited. It seems this class would be better suited to contain the TdsTypeInfo rather than inherit from it.
internal sealed class TdsColumnMetadata : TdsTypeInfo
{
[Flags]
@@ -70,6 +71,19 @@ internal TdsColumnMetadata(int ordinal) : base()
Ordinal = ordinal;
}
+ private TdsColumnMetadata(TdsColumnMetadata original) : base(original)
+ {
+ _flags = original._flags;
+
+ baseColumn = original.baseColumn;
+ column = original.column;
+ tableName = original.tableName;
+ tableNum = original.tableNum;
+ op = original.op;
+ Operand = original.Operand;
+ Ordinal = original.Ordinal;
+ }
+
///
/// Gets the catalog name associated with the column's metadata.
///
@@ -77,9 +91,9 @@ internal TdsColumnMetadata(int ordinal) : base()
internal bool Is2008DateTimeType => DbType is SqlDbType.Date
- or SqlDbType.Time
- or SqlDbType.DateTime2
- or SqlDbType.DateTimeOffset;
+ or SqlDbType.Time
+ or SqlDbType.DateTime2
+ or SqlDbType.DateTimeOffset;
///
/// Indicates whether the column is part of a sparse column set.
@@ -187,19 +201,8 @@ public byte Updatability
///
/// A new TdsColumnMetadata object that is a copy of the current instance.
///
- public object Clone()
- {
- TdsColumnMetadata result = new TdsColumnMetadata(Ordinal);
- result.CopyFrom(this);
- result.column = column;
- result.baseColumn = baseColumn;
- result.tableName = tableName;
- result.tableNum = tableNum;
- result._flags = _flags;
- result.op = op;
- result.Operand = Operand;
- return result;
- }
+ internal TdsColumnMetadata Clone() =>
+ new TdsColumnMetadata(this);
private bool HasFlag(MetadataFlags flag)
{
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/Tokens/TdsColumnMetadataToken.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/Tokens/TdsColumnMetadataToken.cs
index e4e2a85474..9a95a6d24e 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/Tokens/TdsColumnMetadataToken.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/Tokens/TdsColumnMetadataToken.cs
@@ -59,7 +59,7 @@ private TdsColumnMetadataToken(TdsColumnMetadataToken original)
_metadataArray = new TdsColumnMetadata[original._metadataArray.Length];
for (int idx = 0; idx < _metadataArray.Length; idx++)
{
- _metadataArray[idx] = (TdsColumnMetadata)original._metadataArray[idx].Clone();
+ _metadataArray[idx] = original._metadataArray[idx].Clone();
}
}
}
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/Tokens/TdsTypeInfo.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/Tokens/TdsTypeInfo.cs
index 1447d74298..d8f91e00c1 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/Tokens/TdsTypeInfo.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/Tokens/TdsTypeInfo.cs
@@ -58,6 +58,30 @@ internal TdsTypeInfo()
{
}
+ protected TdsTypeInfo(TdsTypeInfo original)
+ {
+ // @TODO: Some of these fields are not simple types, should they also be cloned?
+
+ collation = original.collation;
+ flags = original.flags;
+ length = original.length;
+ precision = original.precision;
+ scale = original.scale;
+
+ CodePage = original.CodePage;
+ DbType = original.DbType;
+ Encoding = original.Encoding;
+ MetaType = original.MetaType; // This is a cached instance, it should not be cloned.
+ TdsType = original.TdsType;
+
+ UdtTypeInfo = original.UdtTypeInfo?.Clone();
+ XmlTypeInfo = original.XmlTypeInfo?.Clone();
+
+ BaseTypeInfo = original.BaseTypeInfo;
+ CipherMetadata = original.CipherMetadata;
+ IsEncrypted = original.IsEncrypted;
+ }
+
///
/// Gets or sets the plaintext type information for the column if the column is encrypted.
///
@@ -130,43 +154,12 @@ public bool IsNullable
///
/// Gets or sets the UDT metadata associated with this object.
///
- public SqlMetaDataUdt Udt { get; set; }
+ public TdsUdtTypeInfo UdtTypeInfo { get; set; }
///
/// Gets or sets the metadata for the XML schema collection associated with this data type.
///
- public SqlMetaDataXmlSchemaCollection XmlSchemaCollection { get; set; }
-
- // @TODO: Can this be converted to Clone like all the other token types do?
- internal virtual void CopyFrom(TdsTypeInfo original)
- {
- this.DbType = original.DbType;
- this.TdsType = original.TdsType;
- this.precision = original.precision;
- this.scale = original.scale;
- this.length = original.length;
- this.collation = original.collation;
- this.CodePage = original.CodePage;
- this.Encoding = original.Encoding;
- this.MetaType = original.MetaType;
- this.flags = original.flags;
-
- if (original.Udt != null)
- {
- Udt = new SqlMetaDataUdt();
- Udt.CopyFrom(original.Udt);
- }
-
- if (original.XmlSchemaCollection != null)
- {
- XmlSchemaCollection = new SqlMetaDataXmlSchemaCollection();
- XmlSchemaCollection.CopyFrom(original.XmlSchemaCollection);
- }
-
- this.IsEncrypted = original.IsEncrypted;
- this.BaseTypeInfo = original.BaseTypeInfo;
- this.CipherMetadata = original.CipherMetadata;
- }
+ public TdsXmlTypeInfo XmlTypeInfo { get; set; }
private bool HasFlag(TdsTypeInfoFlags flag)
{
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/Tokens/TdsUdtTypeInfo.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/Tokens/TdsUdtTypeInfo.cs
new file mode 100644
index 0000000000..d96d7109f7
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/Tokens/TdsUdtTypeInfo.cs
@@ -0,0 +1,64 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+
+namespace Microsoft.Data.SqlClient.Parser.Tokens;
+
+///
+/// Represents UDT metadata inside a TYPE_INFO TDS object used by metadata and return value tokens.
+///
+internal sealed class TdsUdtTypeInfo
+{
+ ///
+ /// Represents the fully qualified type name of the UDT, including the name of the assembly
+ /// in which the type is defined.
+ ///
+ // @TODO: This cannot be an auto property yet because this value is set via an out parameter in TryRead*.
+ internal string AssemblyQualifiedName;
+
+ ///
+ /// Represents the name of the database associated with the UDT.
+ ///
+ // @TODO: This cannot be an auto property yet because this value is set via an out parameter in TryRead*.
+ internal string DatabaseName;
+
+ ///
+ /// Represents the schema name of the UDT within the TYPE_INFO TDS object.
+ ///
+ // @TODO: This cannot be an auto property yet because this value is set via an out parameter in TryRead*.
+ internal string SchemaName;
+
+ ///
+ /// Represents the name of the UDT as specified in the TYPE_INFO TDS object.
+ ///
+ // @TODO: This cannot be an auto property yet because this value is set via an out parameter in TryRead*.
+ internal string TypeName;
+
+ ///
+ /// Represents the data type of the UDT, providing metadata necessary for runtime type resolution
+ /// and compatibility checks.
+ ///
+ #if NET
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
+ #endif
+ internal Type Type { get; set; }
+
+ ///
+ /// Creates a new instance of and initializes it with the values
+ /// of the current instance.
+ ///
+ internal TdsUdtTypeInfo Clone()
+ {
+ return new TdsUdtTypeInfo
+ {
+ AssemblyQualifiedName = AssemblyQualifiedName,
+ DatabaseName = DatabaseName,
+ SchemaName = SchemaName,
+ Type = Type,
+ TypeName = TypeName
+ };
+ }
+}
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/Tokens/TdsXmlTypeInfo.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/Tokens/TdsXmlTypeInfo.cs
new file mode 100644
index 0000000000..888770d757
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/Tokens/TdsXmlTypeInfo.cs
@@ -0,0 +1,40 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.Data.SqlClient.Parser.Tokens;
+
+internal sealed class TdsXmlTypeInfo
+{
+ ///
+ /// Represents the name of the database associated with the XML schema collection.
+ ///
+ // @TODO: This cannot be an auto property yet because this value is set via an out parameter in TryRead*.
+ internal string Database;
+
+ ///
+ /// Represents the name of the XML schema collection associated with the type information.
+ ///
+ // @TODO: This cannot be an auto property yet because this value is set via an out parameter in TryRead*.
+ internal string Name;
+
+ ///
+ /// Represents the schema that owns the XML schema collection associated with the database.
+ ///
+ // @TODO: This cannot be an auto property yet because this value is set via an out parameter in TryRead*.
+ internal string OwningSchema;
+
+ ///
+ /// Creates a new instance of and initializes it with the
+ /// properties of the current instance.
+ ///
+ internal TdsXmlTypeInfo Clone()
+ {
+ return new TdsXmlTypeInfo
+ {
+ Database = Database,
+ Name = Name,
+ OwningSchema = OwningSchema
+ };
+ }
+}
diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnection.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnection.cs
index 038b04d7d1..8282f039c2 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnection.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnection.cs
@@ -3094,16 +3094,16 @@ private Assembly ResolveTypeAssembly(AssemblyName asmRef, bool throwOnError)
internal void CheckGetExtendedUDTInfo(TdsTypeInfo metaData, bool fThrow)
{
- if (metaData.Udt?.Type == null)
+ if (metaData.UdtTypeInfo?.Type == null)
{ // If null, we have not obtained extended info.
- Debug.Assert(!string.IsNullOrEmpty(metaData.Udt?.AssemblyQualifiedName), "Unexpected state on GetUDTInfo");
+ Debug.Assert(!string.IsNullOrEmpty(metaData.UdtTypeInfo?.AssemblyQualifiedName), "Unexpected state on GetUDTInfo");
// Parameter throwOnError determines whether exception from Assembly.Load is thrown.
- metaData.Udt.Type =
- Type.GetType(typeName: metaData.Udt.AssemblyQualifiedName, assemblyResolver: asmRef => ResolveTypeAssembly(asmRef, fThrow), typeResolver: null, throwOnError: fThrow);
+ metaData.UdtTypeInfo.Type =
+ Type.GetType(typeName: metaData.UdtTypeInfo.AssemblyQualifiedName, assemblyResolver: asmRef => ResolveTypeAssembly(asmRef, fThrow), typeResolver: null, throwOnError: fThrow);
- if (fThrow && metaData.Udt.Type == null)
+ if (fThrow && metaData.UdtTypeInfo.Type == null)
{
- throw SQL.UDTUnexpectedResult(metaData.Udt.AssemblyQualifiedName);
+ throw SQL.UDTUnexpectedResult(metaData.UdtTypeInfo.AssemblyQualifiedName);
}
}
}
@@ -3120,7 +3120,7 @@ internal object GetUdtValue(object value, TdsTypeInfo metaData, bool returnDBNul
// Since the serializer doesn't handle nulls...
if (ADP.IsNull(value))
{
- Type t = metaData.Udt?.Type;
+ Type t = metaData.UdtTypeInfo?.Type;
Debug.Assert(t != null, "Unexpected null of udtType on GetUdtValue!");
o = t.InvokeMember("Null", BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.Static, null, null, Array.Empty