diff --git a/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/SqlBulkCopy.cs b/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/SqlBulkCopy.cs index 3cd94c72aebf7..ceaa311b434bf 100644 --- a/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/SqlBulkCopy.cs +++ b/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/SqlBulkCopy.cs @@ -552,7 +552,7 @@ private string AnalyzeTargetAndCreateUpdateBulkCommand(BulkCopySimpleResultSet i // Check for excluded types if ((metadata.type == SqlDbType.Timestamp) - || ((metadata.isIdentity) && !IsCopyOption(SqlBulkCopyOptions.KeepIdentity))) + || ((metadata.IsIdentity) && !IsCopyOption(SqlBulkCopyOptions.KeepIdentity))) { // Remove metadata for excluded columns metaDataSet[i] = null; @@ -1386,7 +1386,7 @@ private object ConvertValue(object value, _SqlMetaData metadata, bool isNull, re if (isNull) { - if (!metadata.isNullable) + if (!metadata.IsNullable) { throw SQL.BulkLoadBulkLoadNotAllowDBNull(metadata.column); } diff --git a/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/SqlConnection.cs b/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/SqlConnection.cs index 8c4db3108d126..85bde43de2059 100644 --- a/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/SqlConnection.cs +++ b/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/SqlConnection.cs @@ -1615,16 +1615,16 @@ private Assembly ResolveTypeAssembly(AssemblyName asmRef, bool throwOnError) internal void CheckGetExtendedUDTInfo(SqlMetaDataPriv metaData, bool fThrow) { - if (metaData.udtType == null) + if (metaData.udt?.Type == null) { // If null, we have not obtained extended info. - Debug.Assert(!string.IsNullOrEmpty(metaData.udtAssemblyQualifiedName), "Unexpected state on GetUDTInfo"); + Debug.Assert(!string.IsNullOrEmpty(metaData.udt?.AssemblyQualifiedName), "Unexpected state on GetUDTInfo"); // Parameter throwOnError determines whether exception from Assembly.Load is thrown. - metaData.udtType = - Type.GetType(typeName: metaData.udtAssemblyQualifiedName, assemblyResolver: asmRef => ResolveTypeAssembly(asmRef, fThrow), typeResolver: null, throwOnError: fThrow); + metaData.udt.Type = + Type.GetType(typeName: metaData.udt.AssemblyQualifiedName, assemblyResolver: asmRef => ResolveTypeAssembly(asmRef, fThrow), typeResolver: null, throwOnError: fThrow); - if (fThrow && metaData.udtType == null) + if (fThrow && metaData.udt.Type == null) { - throw SQL.UDTUnexpectedResult(metaData.udtAssemblyQualifiedName); + throw SQL.UDTUnexpectedResult(metaData.udt.AssemblyQualifiedName); } } } @@ -1641,7 +1641,7 @@ internal object GetUdtValue(object value, SqlMetaDataPriv metaData, bool returnD // Since the serializer doesn't handle nulls... if (ADP.IsNull(value)) { - Type t = metaData.udtType; + Type t = metaData.udt?.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(), CultureInfo.InvariantCulture); Debug.Assert(o != null); @@ -1652,7 +1652,7 @@ internal object GetUdtValue(object value, SqlMetaDataPriv metaData, bool returnD MemoryStream stm = new MemoryStream((byte[])value); - o = SerializationHelperSql9.Deserialize(stm, metaData.udtType); + o = SerializationHelperSql9.Deserialize(stm, metaData.udt?.Type); Debug.Assert(o != null, "object could NOT be created"); return o; diff --git a/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/SqlDataReader.cs b/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/SqlDataReader.cs index a509e7174681e..3d553a24f93ae 100644 --- a/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/SqlDataReader.cs +++ b/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/SqlDataReader.cs @@ -268,7 +268,7 @@ internal virtual SmiExtendedMetaData[] GetInternalSmiMetaData() { _SqlMetaData colMetaData = metaData[index]; - if (!colMetaData.isHidden) + if (!colMetaData.IsHidden) { SqlCollation collation = colMetaData.collation; @@ -278,17 +278,17 @@ internal virtual SmiExtendedMetaData[] GetInternalSmiMetaData() if (SqlDbType.Xml == colMetaData.type) { - typeSpecificNamePart1 = colMetaData.xmlSchemaCollectionDatabase; - typeSpecificNamePart2 = colMetaData.xmlSchemaCollectionOwningSchema; - typeSpecificNamePart3 = colMetaData.xmlSchemaCollectionName; + typeSpecificNamePart1 = colMetaData.xmlSchemaCollection?.Database; + typeSpecificNamePart2 = colMetaData.xmlSchemaCollection?.OwningSchema; + typeSpecificNamePart3 = colMetaData.xmlSchemaCollection?.Name; } else if (SqlDbType.Udt == colMetaData.type) { Connection.CheckGetExtendedUDTInfo(colMetaData, true); // Ensure that colMetaData.udtType is set - typeSpecificNamePart1 = colMetaData.udtDatabaseName; - typeSpecificNamePart2 = colMetaData.udtSchemaName; - typeSpecificNamePart3 = colMetaData.udtTypeName; + typeSpecificNamePart1 = colMetaData.udt?.DatabaseName; + typeSpecificNamePart2 = colMetaData.udt?.SchemaName; + typeSpecificNamePart3 = colMetaData.udt?.TypeName; } int length = colMetaData.length; @@ -310,7 +310,7 @@ internal virtual SmiExtendedMetaData[] GetInternalSmiMetaData() colMetaData.scale, (null != collation) ? collation.LCID : _defaultLCID, (null != collation) ? collation.SqlCompareOptions : SqlCompareOptions.None, - colMetaData.udtType, + colMetaData.udt?.Type, false, // isMultiValued null, // fieldmetadata null, // extended properties @@ -318,18 +318,19 @@ internal virtual SmiExtendedMetaData[] GetInternalSmiMetaData() typeSpecificNamePart1, typeSpecificNamePart2, typeSpecificNamePart3, - colMetaData.isNullable, + colMetaData.IsNullable, colMetaData.serverName, colMetaData.catalogName, colMetaData.schemaName, colMetaData.tableName, colMetaData.baseColumn, - colMetaData.isKey, - colMetaData.isIdentity, - 0 == colMetaData.updatability, - colMetaData.isExpression, - colMetaData.isDifferentName, - colMetaData.isHidden); + colMetaData.IsKey, + colMetaData.IsIdentity, + colMetaData.IsReadOnly, + colMetaData.IsExpression, + colMetaData.IsDifferentName, + colMetaData.IsHidden + ); } } } @@ -573,14 +574,14 @@ internal DataTable BuildSchemaTable() if (col.type == SqlDbType.Udt) { // Additional metadata for UDTs. Debug.Assert(Connection.IsKatmaiOrNewer, "Invalid Column type received from the server"); - schemaRow[udtAssemblyQualifiedName] = col.udtAssemblyQualifiedName; + schemaRow[udtAssemblyQualifiedName] = col.udt?.AssemblyQualifiedName; } else if (col.type == SqlDbType.Xml) { // Additional metadata for Xml. Debug.Assert(Connection.IsKatmaiOrNewer, "Invalid DataType (Xml) for the column"); - schemaRow[xmlSchemaCollectionDatabase] = col.xmlSchemaCollectionDatabase; - schemaRow[xmlSchemaCollectionOwningSchema] = col.xmlSchemaCollectionOwningSchema; - schemaRow[xmlSchemaCollectionName] = col.xmlSchemaCollectionName; + schemaRow[xmlSchemaCollectionDatabase] = col.xmlSchemaCollection?.Database; + schemaRow[xmlSchemaCollectionOwningSchema] = col.xmlSchemaCollection?.OwningSchema; + schemaRow[xmlSchemaCollectionName] = col.xmlSchemaCollection?.Name; } } else @@ -613,19 +614,19 @@ internal DataTable BuildSchemaTable() schemaRow[scale] = col.metaType.Scale; } - schemaRow[allowDBNull] = col.isNullable; + schemaRow[allowDBNull] = col.IsNullable; // If no ColInfo token received, do not set value, leave as null. if (_browseModeInfoConsumed) { - schemaRow[isAliased] = col.isDifferentName; - schemaRow[isKey] = col.isKey; - schemaRow[isHidden] = col.isHidden; - schemaRow[isExpression] = col.isExpression; + schemaRow[isAliased] = col.IsDifferentName; + schemaRow[isKey] = col.IsKey; + schemaRow[isHidden] = col.IsHidden; + schemaRow[isExpression] = col.IsExpression; } - schemaRow[isIdentity] = col.isIdentity; - schemaRow[isAutoIncrement] = col.isIdentity; + schemaRow[isIdentity] = col.IsIdentity; + schemaRow[isAutoIncrement] = col.IsIdentity; schemaRow[isLong] = col.metaType.IsLong; @@ -641,8 +642,8 @@ internal DataTable BuildSchemaTable() schemaRow[isRowVersion] = false; } - schemaRow[isReadOnly] = (0 == col.updatability); - schemaRow[isColumnSet] = col.isColumnSet; + schemaRow[isReadOnly] = col.IsReadOnly; + schemaRow[isColumnSet] = col.IsColumnSet; if (!string.IsNullOrEmpty(col.serverName)) { @@ -1095,7 +1096,7 @@ private bool TryConsumeMetaData() { indexMap[i] = _metaData.visibleColumns; - if (!(_metaData[i].isHidden)) + if (!(_metaData[i].IsHidden)) { _metaData.visibleColumns++; } @@ -1148,7 +1149,7 @@ private string GetDataTypeNameInternal(_SqlMetaData metaData) if (metaData.type == SqlDbType.Udt) { - dataTypeName = metaData.udtDatabaseName + "." + metaData.udtSchemaName + "." + metaData.udtTypeName; + dataTypeName = metaData.udt?.DatabaseName + "." + metaData.udt?.SchemaName + "." + metaData.udt?.TypeName; } else { // For all other types, including Xml - use data in MetaType. @@ -1221,7 +1222,7 @@ private Type GetFieldTypeInternal(_SqlMetaData metaData) if (metaData.type == SqlDbType.Udt) { Connection.CheckGetExtendedUDTInfo(metaData, false); - fieldType = metaData.udtType; + fieldType = metaData.udt?.Type; } else { // For all other types, including Xml - use data in MetaType. @@ -1301,7 +1302,7 @@ private Type GetProviderSpecificFieldTypeInternal(_SqlMetaData metaData) if (metaData.type == SqlDbType.Udt) { Connection.CheckGetExtendedUDTInfo(metaData, false); - providerSpecificFieldType = metaData.udtType; + providerSpecificFieldType = metaData.udt?.Type; } else { @@ -4968,10 +4969,10 @@ private ReadOnlyCollection BuildColumnSchema() if (_browseModeInfoConsumed) { - dbColumn.SqlIsAliased = col.isDifferentName; - dbColumn.SqlIsKey = col.isKey; - dbColumn.SqlIsHidden = col.isHidden; - dbColumn.SqlIsExpression = col.isExpression; + dbColumn.SqlIsAliased = col.IsDifferentName; + dbColumn.SqlIsKey = col.IsKey; + dbColumn.SqlIsHidden = col.IsHidden; + dbColumn.SqlIsExpression = col.IsExpression; } dbColumn.SqlDataType = GetFieldTypeInternal(col); diff --git a/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/SqlDbColumn.cs b/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/SqlDbColumn.cs index cd738f985da03..9a2ded3b93137 100644 --- a/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/SqlDbColumn.cs +++ b/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/SqlDbColumn.cs @@ -19,7 +19,7 @@ internal SqlDbColumn(_SqlMetaData md) private void Populate() { - AllowDBNull = _metadata.isNullable; + AllowDBNull = _metadata.IsNullable; BaseCatalogName = _metadata.catalogName; BaseColumnName = _metadata.baseColumn; BaseSchemaName = _metadata.schemaName; @@ -28,8 +28,8 @@ private void Populate() ColumnName = _metadata.column; ColumnOrdinal = _metadata.ordinal; ColumnSize = (_metadata.metaType.IsSizeInCharacters && (_metadata.length != 0x7fffffff)) ? (_metadata.length / 2) : _metadata.length; - IsAutoIncrement = _metadata.isIdentity; - IsIdentity = _metadata.isIdentity; + IsAutoIncrement = _metadata.IsIdentity; + IsIdentity = _metadata.IsIdentity; IsLong = _metadata.metaType.IsLong; if (SqlDbType.Timestamp == _metadata.type) @@ -50,9 +50,9 @@ private void Populate() NumericPrecision = _metadata.metaType.Precision; } - IsReadOnly = (0 == _metadata.updatability); + IsReadOnly = _metadata.IsReadOnly; - UdtAssemblyQualifiedName = _metadata.udtAssemblyQualifiedName; + UdtAssemblyQualifiedName = _metadata.udt?.AssemblyQualifiedName; } diff --git a/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/TdsParser.cs b/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/TdsParser.cs index 9206f2aa5001c..8d65ba249b8bf 100644 --- a/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/TdsParser.cs +++ b/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/TdsParser.cs @@ -3179,7 +3179,7 @@ internal bool TryProcessReturnValue(int length, TdsParserStateObject stateObj, o // always use the nullable type for parameters if Shiloh or later // Sphinx sometimes sends fixed length return values rec.tdsType = rec.metaType.NullableType; - rec.isNullable = true; + rec.IsNullable = true; if (tdsLen == TdsEnums.SQL_USHORTVARMAXLEN) { rec.metaType = MetaType.GetMaxMetaTypeFromMetaType(rec.metaType); @@ -3228,9 +3228,13 @@ internal bool TryProcessReturnValue(int length, TdsParserStateObject stateObj, o { return false; } + if (rec.xmlSchemaCollection is null) + { + rec.xmlSchemaCollection = new SqlMetaDataXmlSchemaCollection(); + } if (len != 0) { - if (!stateObj.TryReadString(len, out rec.xmlSchemaCollectionDatabase)) + if (!stateObj.TryReadString(len, out rec.xmlSchemaCollection.Database)) { return false; } @@ -3242,7 +3246,7 @@ internal bool TryProcessReturnValue(int length, TdsParserStateObject stateObj, o } if (len != 0) { - if (!stateObj.TryReadString(len, out rec.xmlSchemaCollectionOwningSchema)) + if (!stateObj.TryReadString(len, out rec.xmlSchemaCollection.OwningSchema)) { return false; } @@ -3256,7 +3260,7 @@ internal bool TryProcessReturnValue(int length, TdsParserStateObject stateObj, o if (slen != 0) { - if (!stateObj.TryReadString(slen, out rec.xmlSchemaCollectionName)) + if (!stateObj.TryReadString(slen, out rec.xmlSchemaCollection.Name)) { return false; } @@ -3629,9 +3633,9 @@ private bool TryCommonProcessMetaData(TdsParserStateObject stateObj, _SqlMetaDat return false; } - col.updatability = (byte)((flags & TdsEnums.Updatability) >> 2); - col.isNullable = (TdsEnums.Nullable == (flags & TdsEnums.Nullable)); - col.isIdentity = (TdsEnums.Identity == (flags & TdsEnums.Identity)); + col.Updatability = (byte)((flags & TdsEnums.Updatability) >> 2); + col.IsNullable = (TdsEnums.Nullable == (flags & TdsEnums.Nullable)); + col.IsIdentity = (TdsEnums.Identity == (flags & TdsEnums.Identity)); // read second byte of column metadata flags if (!stateObj.TryReadByte(out flags)) @@ -3639,7 +3643,7 @@ private bool TryCommonProcessMetaData(TdsParserStateObject stateObj, _SqlMetaDat return false; } - col.isColumnSet = (TdsEnums.IsColumnSet == (flags & TdsEnums.IsColumnSet)); + col.IsColumnSet = (TdsEnums.IsColumnSet == (flags & TdsEnums.IsColumnSet)); byte tdsType; if (!stateObj.TryReadByte(out tdsType)) @@ -3666,7 +3670,7 @@ private bool TryCommonProcessMetaData(TdsParserStateObject stateObj, _SqlMetaDat col.metaType = MetaType.GetSqlDataType(tdsType, userType, col.length); col.type = col.metaType.SqlDbType; - col.tdsType = (col.isNullable ? col.metaType.NullableType : col.metaType.TDSType); + col.tdsType = (col.IsNullable ? col.metaType.NullableType : col.metaType.TDSType); { if (TdsEnums.SQLUDT == tdsType) @@ -3702,9 +3706,13 @@ private bool TryCommonProcessMetaData(TdsParserStateObject stateObj, _SqlMetaDat { return false; } + if (col.xmlSchemaCollection is null) + { + col.xmlSchemaCollection = new SqlMetaDataXmlSchemaCollection(); + } if (byteLen != 0) { - if (!stateObj.TryReadString(byteLen, out col.xmlSchemaCollectionDatabase)) + if (!stateObj.TryReadString(byteLen, out col.xmlSchemaCollection.Database)) { return false; } @@ -3716,7 +3724,7 @@ private bool TryCommonProcessMetaData(TdsParserStateObject stateObj, _SqlMetaDat } if (byteLen != 0) { - if (!stateObj.TryReadString(byteLen, out col.xmlSchemaCollectionOwningSchema)) + if (!stateObj.TryReadString(byteLen, out col.xmlSchemaCollection.OwningSchema)) { return false; } @@ -3729,7 +3737,7 @@ private bool TryCommonProcessMetaData(TdsParserStateObject stateObj, _SqlMetaDat } if (byteLen != 0) { - if (!stateObj.TryReadString(shortLen, out col.xmlSchemaCollectionName)) + if (!stateObj.TryReadString(shortLen, out col.xmlSchemaCollection.Name)) { return false; } @@ -4014,13 +4022,13 @@ private bool TryProcessColInfo(_SqlMetaDataSet columns, SqlDataReader reader, Td return false; } - col.isDifferentName = (TdsEnums.SQLDifferentName == (status & TdsEnums.SQLDifferentName)); - col.isExpression = (TdsEnums.SQLExpression == (status & TdsEnums.SQLExpression)); - col.isKey = (TdsEnums.SQLKey == (status & TdsEnums.SQLKey)); - col.isHidden = (TdsEnums.SQLHidden == (status & TdsEnums.SQLHidden)); + col.IsDifferentName = (TdsEnums.SQLDifferentName == (status & TdsEnums.SQLDifferentName)); + col.IsExpression = (TdsEnums.SQLExpression == (status & TdsEnums.SQLExpression)); + col.IsKey = (TdsEnums.SQLKey == (status & TdsEnums.SQLKey)); + col.IsHidden = (TdsEnums.SQLHidden == (status & TdsEnums.SQLHidden)); // read off the base table name if it is different than the select list column name - if (col.isDifferentName) + if (col.IsDifferentName) { byte len; if (!stateObj.TryReadByte(out len)) @@ -4042,9 +4050,9 @@ private bool TryProcessColInfo(_SqlMetaDataSet columns, SqlDataReader reader, Td } // Expressions are readonly - if (col.isExpression) + if (col.IsExpression) { - col.updatability = 0; + col.Updatability = 0; } } @@ -8169,9 +8177,9 @@ internal void WriteBulkCopyMetaData(_SqlMetaDataSet metadataCollection, int coun ushort flags; - flags = (ushort)(md.updatability << 2); - flags |= (ushort)(md.isNullable ? (ushort)TdsEnums.Nullable : (ushort)0); - flags |= (ushort)(md.isIdentity ? (ushort)TdsEnums.Identity : (ushort)0); + flags = (ushort)(md.Updatability << 2); + flags |= (ushort)(md.IsNullable ? (ushort)TdsEnums.Nullable : (ushort)0); + flags |= (ushort)(md.IsIdentity ? (ushort)TdsEnums.Identity : (ushort)0); WriteShort(flags, stateObj); // write the flags @@ -9975,9 +9983,14 @@ private bool TryProcessUDTMetaData(SqlMetaDataPriv metaData, TdsParserStateObjec { return false; } + if (metaData.udt is null) + { + metaData.udt = new SqlMetaDataUdt(); + } + if (byteLength != 0) { - if (!stateObj.TryReadString(byteLength, out metaData.udtDatabaseName)) + if (!stateObj.TryReadString(byteLength, out metaData.udt.DatabaseName)) { return false; } @@ -9990,7 +10003,7 @@ private bool TryProcessUDTMetaData(SqlMetaDataPriv metaData, TdsParserStateObjec } if (byteLength != 0) { - if (!stateObj.TryReadString(byteLength, out metaData.udtSchemaName)) + if (!stateObj.TryReadString(byteLength, out metaData.udt.SchemaName)) { return false; } @@ -10003,7 +10016,7 @@ private bool TryProcessUDTMetaData(SqlMetaDataPriv metaData, TdsParserStateObjec } if (byteLength != 0) { - if (!stateObj.TryReadString(byteLength, out metaData.udtTypeName)) + if (!stateObj.TryReadString(byteLength, out metaData.udt.TypeName)) { return false; } @@ -10015,7 +10028,7 @@ private bool TryProcessUDTMetaData(SqlMetaDataPriv metaData, TdsParserStateObjec } if (shortLength != 0) { - if (!stateObj.TryReadString(shortLength, out metaData.udtAssemblyQualifiedName)) + if (!stateObj.TryReadString(shortLength, out metaData.udt.AssemblyQualifiedName)) { return false; } diff --git a/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserHelperClasses.cs b/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserHelperClasses.cs index 01923136a34db..1a8577479c176 100644 --- a/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserHelperClasses.cs +++ b/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserHelperClasses.cs @@ -280,20 +280,32 @@ sealed internal class SqlLoginAck sealed internal class _SqlMetaData : SqlMetaDataPriv { + [Flags] + private enum _SqlMetadataFlags : int + { + None = 0, + + Updatable = 1 << 0, + UpdateableUnknown = 1 << 1, + IsDifferentName = 1 << 2, + IsKey = 1 << 3, + IsHidden = 1 << 4, + IsExpression = 1 << 5, + IsIdentity = 1 << 6, + IsColumnSet = 1 << 7, + + IsReadOnlyMask = (Updatable | UpdateableUnknown) // two bit field (0 is read only, 1 is updatable, 2 is updatability unknown) + } + internal string column; internal string baseColumn; internal MultiPartTableName multiPartTableName; internal readonly int ordinal; - internal byte updatability; // two bit field (0 is read only, 1 is updatable, 2 is updatability unknown) internal byte tableNum; - internal bool isDifferentName; - internal bool isKey; - internal bool isHidden; - internal bool isExpression; - internal bool isIdentity; - internal bool isColumnSet; internal byte op; // for altrow-columns only internal ushort operand; // for altrow-columns only + private _SqlMetadataFlags flags; + internal _SqlMetaData(int ordinal) : base() { @@ -329,6 +341,59 @@ internal string tableName } } + + public byte Updatability + { + get => (byte)(flags & _SqlMetadataFlags.IsReadOnlyMask); + set => flags = (_SqlMetadataFlags)((value & 0x3) | ((int)flags & ~0x03)); + } + + public bool IsReadOnly + { + get => flags.HasFlag(_SqlMetadataFlags.IsReadOnlyMask); + } + + public bool IsDifferentName + { + get => flags.HasFlag(_SqlMetadataFlags.IsDifferentName); + set => Set(_SqlMetadataFlags.IsDifferentName, value); + } + + public bool IsKey + { + get => flags.HasFlag(_SqlMetadataFlags.IsKey); + set => Set(_SqlMetadataFlags.IsKey, value); + } + + public bool IsHidden + { + get => flags.HasFlag(_SqlMetadataFlags.IsHidden); + set => Set(_SqlMetadataFlags.IsHidden, value); + } + + public bool IsExpression + { + get => flags.HasFlag(_SqlMetadataFlags.IsExpression); + set => Set(_SqlMetadataFlags.IsExpression, value); + } + + public bool IsIdentity + { + get => flags.HasFlag(_SqlMetadataFlags.IsIdentity); + set => Set(_SqlMetadataFlags.IsIdentity, value); + } + + public bool IsColumnSet + { + get => flags.HasFlag(_SqlMetadataFlags.IsColumnSet); + set => Set(_SqlMetadataFlags.IsColumnSet, value); + } + + private void Set(_SqlMetadataFlags flag, bool value) + { + flags = value ? flags | flag : flags & ~flag; + } + internal bool IsNewKatmaiDateTimeType { get @@ -352,14 +417,8 @@ public object Clone() result.column = column; result.baseColumn = baseColumn; result.multiPartTableName = multiPartTableName; - result.updatability = updatability; result.tableNum = tableNum; - result.isDifferentName = isDifferentName; - result.isKey = isKey; - result.isHidden = isHidden; - result.isExpression = isExpression; - result.isIdentity = isIdentity; - result.isColumnSet = isColumnSet; + result.flags = flags; result.op = op; result.operand = operand; return result; @@ -487,44 +546,48 @@ public object Clone() internal class SqlMetaDataPriv { + [Flags] + private enum SqlMetaDataPrivFlags : byte + { + None = 0, + IsNullable = 1 << 1, + IsMultiValued = 1 << 2 + } + internal SqlDbType type; // SqlDbType enum value internal byte tdsType; // underlying tds type internal byte precision = TdsEnums.UNKNOWN_PRECISION_SCALE; // give default of unknown (-1) internal byte scale = TdsEnums.UNKNOWN_PRECISION_SCALE; // give default of unknown (-1) + private SqlMetaDataPrivFlags flags; internal int length; internal SqlCollation collation; internal int codePage; internal Encoding encoding; - internal bool isNullable; - internal bool isMultiValued = false; - - // UDT specific metadata - // server metadata info - // additional temporary UDT meta data - internal string udtDatabaseName; - internal string udtSchemaName; - internal string udtTypeName; - internal string udtAssemblyQualifiedName; - - // on demand - internal Type udtType; - - // Xml specific metadata - internal string xmlSchemaCollectionDatabase; - internal string xmlSchemaCollectionOwningSchema; - internal string xmlSchemaCollectionName; internal MetaType metaType; // cached metaType - - // Structured type-specific metadata - internal string structuredTypeDatabaseName; - internal string structuredTypeSchemaName; - internal string structuredTypeName; - internal IList structuredFields; + public SqlMetaDataUdt udt; + public SqlMetaDataXmlSchemaCollection xmlSchemaCollection; internal SqlMetaDataPriv() { } + public bool IsNullable + { + get => flags.HasFlag(SqlMetaDataPrivFlags.IsNullable); + set => Set(SqlMetaDataPrivFlags.IsNullable, value); + } + + public bool IsMultiValued + { + get => flags.HasFlag(SqlMetaDataPrivFlags.IsMultiValued); + set => Set(SqlMetaDataPrivFlags.IsMultiValued, value); + } + + private void Set(SqlMetaDataPrivFlags flag, bool value) + { + flags = value ? flags | flag : flags & ~flag; + } + internal virtual void CopyFrom(SqlMetaDataPriv original) { this.type = original.type; @@ -535,22 +598,58 @@ internal virtual void CopyFrom(SqlMetaDataPriv original) this.collation = original.collation; this.codePage = original.codePage; this.encoding = original.encoding; - this.isNullable = original.isNullable; - this.isMultiValued = original.isMultiValued; - this.udtDatabaseName = original.udtDatabaseName; - this.udtSchemaName = original.udtSchemaName; - this.udtTypeName = original.udtTypeName; - this.udtAssemblyQualifiedName = original.udtAssemblyQualifiedName; - this.udtType = original.udtType; - this.xmlSchemaCollectionDatabase = original.xmlSchemaCollectionDatabase; - this.xmlSchemaCollectionOwningSchema = original.xmlSchemaCollectionOwningSchema; - this.xmlSchemaCollectionName = original.xmlSchemaCollectionName; 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.structuredTypeDatabaseName = original.structuredTypeDatabaseName; - this.structuredTypeSchemaName = original.structuredTypeSchemaName; - this.structuredTypeName = original.structuredTypeName; - this.structuredFields = original.structuredFields; + sealed internal 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; + } + } + } + + sealed internal class SqlMetaDataUdt + { + 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/libraries/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStateObject.cs b/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStateObject.cs index 5b3e6a9d3421a..6e527a828ec55 100644 --- a/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStateObject.cs +++ b/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStateObject.cs @@ -3114,7 +3114,8 @@ private void WriteBytesSetupContinuation(byte[] array, int len, TaskCompletionSo // Dumps contents of buffer to SNI for network write. internal Task WritePacket(byte flushMode, bool canAccumulate = false) { - if ((_parser.State == TdsParserState.Closed) || (_parser.State == TdsParserState.Broken)) + TdsParserState state = _parser.State; + if ((state == TdsParserState.Closed) || (state == TdsParserState.Broken)) { throw ADP.ClosedConnectionError(); } @@ -3124,7 +3125,7 @@ internal Task WritePacket(byte flushMode, bool canAccumulate = false) // However, since we don't know the version prior to login IsYukonOrNewer was always false prior to login // So removing the IsYukonOrNewer check causes issues since the login packet happens to meet the rest of the conditions below // So we need to avoid this check prior to login completing - _parser.State == TdsParserState.OpenLoggedIn && + state == TdsParserState.OpenLoggedIn && !_bulkCopyOpperationInProgress && // ignore the condition checking for bulk copy _outBytesUsed == (_outputHeaderLen + BitConverter.ToInt32(_outBuff, _outputHeaderLen)) && _outputPacketNumber == 1