//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // // Microsoft // Microsoft //------------------------------------------------------------------------------ namespace Microsoft.SqlServer.Server { using System; using System.Collections.Generic; using System.Diagnostics; using System.Data; using System.Data.Sql; using System.Data.SqlTypes; using System.Globalization; // DESIGN NOTES // // The following classes are a tight inheritance heirarchy, and are not designed for // being inherited outside of this file. Instances are guaranteed to be immutable, and // outside classes rely on this fact. // // The various levels may not all be used outside of this file, but for clarity of purpose // they are all usefull distinctions to make. // // In general, moving lower in the type heirarchy exposes less portable values. Thus, // the root metadata can be readily shared across different (MSSQL) servers and clients, // while QueryMetaData has attributes tied to a specific query, running against specific // data storage on a specific server. // // The SmiMetaData heirarchy does not do data validation on retail builds! It will assert // that the values passed to it have been validated externally, however. // // SmiMetaData // // Root of the heirarchy. // Represents the minimal amount of metadata required to represent any Sql Server datum // without any references to any particular server or schema (thus, no server-specific multi-part names). // It could be used to communicate solely between two disconnected clients, for instance. // // NOTE: It currently does not contain sufficient information to describe typed XML, since we // don't have a good server-independent mechanism for such. // // This class is also used as implementation for the public SqlMetaData class. internal class SmiMetaData { private SqlDbType _databaseType; // Main enum that determines what is valid for other attributes. private long _maxLength; // Varies for variable-length types, others are fixed value per type private byte _precision; // Varies for SqlDbType.Decimal, others are fixed value per type private byte _scale; // Varies for SqlDbType.Decimal, others are fixed value per type private long _localeId; // Valid only for character types, others are 0 private SqlCompareOptions _compareOptions; // Valid only for character types, others are SqlCompareOptions.Default private Type _clrType; // Varies for SqlDbType.Udt, others are fixed value per type. private string _udtAssemblyQualifiedName; // Valid only for UDT types when _clrType is not available private bool _isMultiValued; // Multiple instances per value? (I.e. tables, arrays) private IList _fieldMetaData; // Metadata of fields for structured types private SmiMetaDataPropertyCollection _extendedProperties; // Extended properties, Key columns, sort order, etc. // DevNote: For now, since the list of extended property types is small, we can handle them in a simple list. // In the future, we may need to create a more performant storage & lookup mechanism, such as a hash table // of lists indexed by type of property or an array of lists with a well-known index for each type. // Limits for attributes (SmiMetaData will assert that these limits as applicable in constructor) internal const long UnlimitedMaxLengthIndicator = -1; // unlimited (except by implementation) max-length. internal const long MaxUnicodeCharacters = 4000; // Maximum for limited type internal const long MaxANSICharacters = 8000; // Maximum for limited type internal const long MaxBinaryLength = 8000; // Maximum for limited type internal const int MinPrecision = 1; // SqlDecimal defines max precision internal const int MinScale = 0; // SqlDecimal defines max scale internal const int MaxTimeScale = 7; // Max scale for time, datetime2, and datetimeoffset internal static readonly DateTime MaxSmallDateTime = new DateTime(2079, 06, 06, 23, 59, 29, 998); internal static readonly DateTime MinSmallDateTime = new DateTime(1899, 12, 31, 23, 59, 29, 999); internal static readonly SqlMoney MaxSmallMoney = new SqlMoney( ( (Decimal)Int32.MaxValue ) / 10000 ); internal static readonly SqlMoney MinSmallMoney = new SqlMoney( ( (Decimal)Int32.MinValue ) / 10000 ); internal const SqlCompareOptions DefaultStringCompareOptions = SqlCompareOptions.IgnoreCase | SqlCompareOptions.IgnoreKanaType | SqlCompareOptions.IgnoreWidth; internal const long MaxNameLength = 128; // maximum length in the server is 128. private static readonly IList __emptyFieldList = new List().AsReadOnly(); // Precision to max length lookup table private static byte[] __maxLenFromPrecision = new byte[] {5,5,5,5,5,5,5,5,5,9,9,9,9,9, 9,9,9,9,9,13,13,13,13,13,13,13,13,13,17,17,17,17,17,17,17,17,17,17}; // Scale offset to max length lookup table private static byte[] __maxVarTimeLenOffsetFromScale = new byte[] { 2, 2, 2, 1, 1, 0, 0, 0 }; // Defaults // SmiMetaData(SqlDbType, MaxLen, Prec, Scale, CompareOptions) internal static readonly SmiMetaData DefaultBigInt = new SmiMetaData(SqlDbType.BigInt, 8, 19, 0, SqlCompareOptions.None); // SqlDbType.BigInt internal static readonly SmiMetaData DefaultBinary = new SmiMetaData(SqlDbType.Binary, 1, 0, 0, SqlCompareOptions.None); // SqlDbType.Binary internal static readonly SmiMetaData DefaultBit = new SmiMetaData(SqlDbType.Bit, 1, 1, 0, SqlCompareOptions.None); // SqlDbType.Bit internal static readonly SmiMetaData DefaultChar_NoCollation = new SmiMetaData(SqlDbType.Char, 1, 0, 0, DefaultStringCompareOptions);// SqlDbType.Char internal static readonly SmiMetaData DefaultDateTime = new SmiMetaData(SqlDbType.DateTime, 8, 23, 3, SqlCompareOptions.None); // SqlDbType.DateTime internal static readonly SmiMetaData DefaultDecimal = new SmiMetaData(SqlDbType.Decimal, 9, 18, 0, SqlCompareOptions.None); // SqlDbType.Decimal internal static readonly SmiMetaData DefaultFloat = new SmiMetaData(SqlDbType.Float, 8, 53, 0, SqlCompareOptions.None); // SqlDbType.Float internal static readonly SmiMetaData DefaultImage = new SmiMetaData(SqlDbType.Image, UnlimitedMaxLengthIndicator,0, 0, SqlCompareOptions.None); // SqlDbType.Image internal static readonly SmiMetaData DefaultInt = new SmiMetaData(SqlDbType.Int, 4, 10, 0, SqlCompareOptions.None); // SqlDbType.Int internal static readonly SmiMetaData DefaultMoney = new SmiMetaData(SqlDbType.Money, 8, 19, 4, SqlCompareOptions.None); // SqlDbType.Money internal static readonly SmiMetaData DefaultNChar_NoCollation = new SmiMetaData(SqlDbType.NChar, 1, 0, 0, DefaultStringCompareOptions);// SqlDbType.NChar internal static readonly SmiMetaData DefaultNText_NoCollation = new SmiMetaData(SqlDbType.NText, UnlimitedMaxLengthIndicator,0, 0, DefaultStringCompareOptions);// SqlDbType.NText internal static readonly SmiMetaData DefaultNVarChar_NoCollation = new SmiMetaData(SqlDbType.NVarChar, MaxUnicodeCharacters, 0, 0, DefaultStringCompareOptions);// SqlDbType.NVarChar internal static readonly SmiMetaData DefaultReal = new SmiMetaData(SqlDbType.Real, 4, 24, 0, SqlCompareOptions.None); // SqlDbType.Real internal static readonly SmiMetaData DefaultUniqueIdentifier = new SmiMetaData(SqlDbType.UniqueIdentifier, 16, 0, 0, SqlCompareOptions.None); // SqlDbType.UniqueIdentifier internal static readonly SmiMetaData DefaultSmallDateTime = new SmiMetaData(SqlDbType.SmallDateTime, 4, 16, 0, SqlCompareOptions.None); // SqlDbType.SmallDateTime internal static readonly SmiMetaData DefaultSmallInt = new SmiMetaData(SqlDbType.SmallInt, 2, 5, 0, SqlCompareOptions.None); // SqlDbType.SmallInt internal static readonly SmiMetaData DefaultSmallMoney = new SmiMetaData(SqlDbType.SmallMoney, 4, 10, 4, SqlCompareOptions.None); // SqlDbType.SmallMoney internal static readonly SmiMetaData DefaultText_NoCollation = new SmiMetaData(SqlDbType.Text, UnlimitedMaxLengthIndicator,0, 0, DefaultStringCompareOptions);// SqlDbType.Text internal static readonly SmiMetaData DefaultTimestamp = new SmiMetaData(SqlDbType.Timestamp, 8, 0, 0, SqlCompareOptions.None); // SqlDbType.Timestamp internal static readonly SmiMetaData DefaultTinyInt = new SmiMetaData(SqlDbType.TinyInt, 1, 3, 0, SqlCompareOptions.None); // SqlDbType.TinyInt internal static readonly SmiMetaData DefaultVarBinary = new SmiMetaData(SqlDbType.VarBinary, MaxBinaryLength, 0, 0, SqlCompareOptions.None); // SqlDbType.VarBinary internal static readonly SmiMetaData DefaultVarChar_NoCollation = new SmiMetaData(SqlDbType.VarChar, MaxANSICharacters, 0, 0, DefaultStringCompareOptions);// SqlDbType.VarChar internal static readonly SmiMetaData DefaultVariant = new SmiMetaData(SqlDbType.Variant, 8016, 0, 0, SqlCompareOptions.None); // SqlDbType.Variant internal static readonly SmiMetaData DefaultXml = new SmiMetaData(SqlDbType.Xml, UnlimitedMaxLengthIndicator,0, 0, DefaultStringCompareOptions);// SqlDbType.Xml internal static readonly SmiMetaData DefaultUdt_NoType = new SmiMetaData(SqlDbType.Udt, 0, 0, 0, SqlCompareOptions.None); // SqlDbType.Udt internal static readonly SmiMetaData DefaultStructured = new SmiMetaData(SqlDbType.Structured, 0, 0, 0, SqlCompareOptions.None); // SqlDbType.Structured internal static readonly SmiMetaData DefaultDate = new SmiMetaData(SqlDbType.Date, 3, 10, 0, SqlCompareOptions.None); // SqlDbType.Date internal static readonly SmiMetaData DefaultTime = new SmiMetaData(SqlDbType.Time, 5, 0, 7, SqlCompareOptions.None); // SqlDbType.Time internal static readonly SmiMetaData DefaultDateTime2 = new SmiMetaData(SqlDbType.DateTime2, 8, 0, 7, SqlCompareOptions.None); // SqlDbType.DateTime2 internal static readonly SmiMetaData DefaultDateTimeOffset = new SmiMetaData(SqlDbType.DateTimeOffset, 10, 0, 7, SqlCompareOptions.None); // SqlDbType.DateTimeOffset // No default for generic UDT // character defaults hook thread-local culture to get collation internal static SmiMetaData DefaultChar { get { return new SmiMetaData( DefaultChar_NoCollation.SqlDbType, DefaultChar_NoCollation.MaxLength, DefaultChar_NoCollation.Precision, DefaultChar_NoCollation.Scale, System.Globalization.CultureInfo.CurrentCulture.LCID, SqlCompareOptions.IgnoreCase | SqlCompareOptions.IgnoreKanaType | SqlCompareOptions.IgnoreWidth, null ); } } internal static SmiMetaData DefaultNChar { get { return new SmiMetaData( DefaultNChar_NoCollation.SqlDbType, DefaultNChar_NoCollation.MaxLength, DefaultNChar_NoCollation.Precision, DefaultNChar_NoCollation.Scale, System.Globalization.CultureInfo.CurrentCulture.LCID, SqlCompareOptions.IgnoreCase | SqlCompareOptions.IgnoreKanaType | SqlCompareOptions.IgnoreWidth, null ); } } internal static SmiMetaData DefaultNText { get { return new SmiMetaData( DefaultNText_NoCollation.SqlDbType, DefaultNText_NoCollation.MaxLength, DefaultNText_NoCollation.Precision, DefaultNText_NoCollation.Scale, System.Globalization.CultureInfo.CurrentCulture.LCID, SqlCompareOptions.IgnoreCase | SqlCompareOptions.IgnoreKanaType | SqlCompareOptions.IgnoreWidth, null ); } } internal static SmiMetaData DefaultNVarChar { get { return new SmiMetaData( DefaultNVarChar_NoCollation.SqlDbType, DefaultNVarChar_NoCollation.MaxLength, DefaultNVarChar_NoCollation.Precision, DefaultNVarChar_NoCollation.Scale, System.Globalization.CultureInfo.CurrentCulture.LCID, SqlCompareOptions.IgnoreCase | SqlCompareOptions.IgnoreKanaType | SqlCompareOptions.IgnoreWidth, null ); } } internal static SmiMetaData DefaultText { get { return new SmiMetaData( DefaultText_NoCollation.SqlDbType, DefaultText_NoCollation.MaxLength, DefaultText_NoCollation.Precision, DefaultText_NoCollation.Scale, System.Globalization.CultureInfo.CurrentCulture.LCID, SqlCompareOptions.IgnoreCase | SqlCompareOptions.IgnoreKanaType | SqlCompareOptions.IgnoreWidth, null ); } } internal static SmiMetaData DefaultVarChar { get { return new SmiMetaData( DefaultVarChar_NoCollation.SqlDbType, DefaultVarChar_NoCollation.MaxLength, DefaultVarChar_NoCollation.Precision, DefaultVarChar_NoCollation.Scale, System.Globalization.CultureInfo.CurrentCulture.LCID, SqlCompareOptions.IgnoreCase | SqlCompareOptions.IgnoreKanaType | SqlCompareOptions.IgnoreWidth, null ); } } // The one and only constructor for use by outside code. // // Parameters that matter for given values of dbType (other parameters are ignored in favor of internal defaults). // Thus, if dbType parameter value is SqlDbType.Decimal, the values of precision and scale passed in are used, but // maxLength, localeId, compareOptions, etc are set to defaults for the Decimal type: // SqlDbType.BigInt: dbType // SqlDbType.Binary: dbType, maxLength // SqlDbType.Bit: dbType // SqlDbType.Char: dbType, maxLength, localeId, compareOptions // SqlDbType.DateTime: dbType // SqlDbType.Decimal: dbType, precision, scale // SqlDbType.Float: dbType // SqlDbType.Image: dbType // SqlDbType.Int: dbType // SqlDbType.Money: dbType // SqlDbType.NChar: dbType, maxLength, localeId, compareOptions // SqlDbType.NText: dbType, localeId, compareOptions // SqlDbType.NVarChar: dbType, maxLength, localeId, compareOptions // SqlDbType.Real: dbType // SqlDbType.UniqueIdentifier: dbType // SqlDbType.SmallDateTime: dbType // SqlDbType.SmallInt: dbType // SqlDbType.SmallMoney: dbType // SqlDbType.Text: dbType, localeId, compareOptions // SqlDbType.Timestamp: dbType // SqlDbType.TinyInt: dbType // SqlDbType.VarBinary: dbType, maxLength // SqlDbType.VarChar: dbType, maxLength, localeId, compareOptions // SqlDbType.Variant: dbType // PlaceHolder for value 24 // SqlDbType.Xml: dbType // Placeholder for value 26 // Placeholder for value 27 // Placeholder for value 28 // SqlDbType.Udt: dbType, userDefinedType // [ObsoleteAttribute( "Not supported as of SMI v2. Will be removed when v1 support dropped. Use ctor without columns param." )] internal SmiMetaData( SqlDbType dbType, long maxLength, byte precision, byte scale, long localeId, SqlCompareOptions compareOptions, Type userDefinedType, SmiMetaData[] columns) : // Implement as calling the new ctor this( dbType, maxLength, precision, scale, localeId, compareOptions, userDefinedType ) { Debug.Assert( null == columns, "Row types not supported" ); } // SMI V100 (aka V3) constructor. Superceded in V200. internal SmiMetaData( SqlDbType dbType, long maxLength, byte precision, byte scale, long localeId, SqlCompareOptions compareOptions, Type userDefinedType) : this( dbType, maxLength, precision, scale, localeId, compareOptions, userDefinedType, false, null, null ) { } // SMI V200 ctor. internal SmiMetaData( SqlDbType dbType, long maxLength, byte precision, byte scale, long localeId, SqlCompareOptions compareOptions, Type userDefinedType, bool isMultiValued, IList fieldTypes, SmiMetaDataPropertyCollection extendedProperties) : this(dbType, maxLength, precision, scale, localeId, compareOptions, userDefinedType, null, isMultiValued, fieldTypes, extendedProperties) { } // SMI V220 ctor. internal SmiMetaData( SqlDbType dbType, long maxLength, byte precision, byte scale, long localeId, SqlCompareOptions compareOptions, Type userDefinedType, string udtAssemblyQualifiedName, bool isMultiValued, IList fieldTypes, SmiMetaDataPropertyCollection extendedProperties) { Debug.Assert( IsSupportedDbType(dbType), "Invalid SqlDbType: " + dbType ); SetDefaultsForType( dbType ); // switch ( dbType ) { case SqlDbType.BigInt: case SqlDbType.Bit: case SqlDbType.DateTime: case SqlDbType.Float: case SqlDbType.Image: case SqlDbType.Int: case SqlDbType.Money: case SqlDbType.Real: case SqlDbType.SmallDateTime: case SqlDbType.SmallInt: case SqlDbType.SmallMoney: case SqlDbType.Timestamp: case SqlDbType.TinyInt: case SqlDbType.UniqueIdentifier: case SqlDbType.Variant: case SqlDbType.Xml: case SqlDbType.Date: break; case SqlDbType.Binary: case SqlDbType.VarBinary: _maxLength = maxLength; break; case SqlDbType.Char: case SqlDbType.NChar: case SqlDbType.NVarChar: case SqlDbType.VarChar: // locale and compare options are not validated until they get to the server _maxLength = maxLength; _localeId = localeId; _compareOptions = compareOptions; break; case SqlDbType.NText: case SqlDbType.Text: _localeId = localeId; _compareOptions = compareOptions; break; case SqlDbType.Decimal: Debug.Assert( MinPrecision <= precision && SqlDecimal.MaxPrecision >= precision, "Invalid precision: " + precision ); Debug.Assert( MinScale <= scale && SqlDecimal.MaxScale >= scale, "Invalid scale: " + scale ); Debug.Assert( scale <= precision, "Precision: " + precision + " greater than scale: " + scale ); _precision = precision; _scale = scale; _maxLength = __maxLenFromPrecision[precision - 1]; break; case SqlDbType.Udt: // Assert modified for VSFTDEVDIV479492 - for SqlParameter both userDefinedType and udtAssemblyQualifiedName // can be NULL, we are checking only maxLength if it will be used (i.e. userDefinedType is NULL) Debug.Assert((null != userDefinedType) || (0 <= maxLength || UnlimitedMaxLengthIndicator == maxLength), String.Format((IFormatProvider)null, "SmiMetaData.ctor: Udt name={0}, maxLength={1}", udtAssemblyQualifiedName, maxLength)); // Type not validated until matched to a server. Could be null if extended metadata supplies three-part name! _clrType = userDefinedType; if (null != userDefinedType) { _maxLength = SerializationHelperSql9.GetUdtMaxLength(userDefinedType); } else { _maxLength = maxLength; } _udtAssemblyQualifiedName = udtAssemblyQualifiedName; break; case SqlDbType.Structured: if (null != fieldTypes) { _fieldMetaData = (new List(fieldTypes)).AsReadOnly(); } _isMultiValued = isMultiValued; _maxLength = _fieldMetaData.Count; break; case SqlDbType.Time: Debug.Assert(MinScale <= scale && scale <= MaxTimeScale, "Invalid time scale: " + scale); _scale = scale; _maxLength = 5 - __maxVarTimeLenOffsetFromScale[scale]; break; case SqlDbType.DateTime2: Debug.Assert(MinScale <= scale && scale <= MaxTimeScale, "Invalid time scale: " + scale); _scale = scale; _maxLength = 8 - __maxVarTimeLenOffsetFromScale[scale]; break; case SqlDbType.DateTimeOffset: Debug.Assert(MinScale <= scale && scale <= MaxTimeScale, "Invalid time scale: " + scale); _scale = scale; _maxLength = 10 - __maxVarTimeLenOffsetFromScale[scale]; break; default: Debug.Assert( false, "How in the world did we get here? :" + dbType ); break; } if (null != extendedProperties) { extendedProperties.SetReadOnly(); _extendedProperties = extendedProperties; } // properties and fields must meet the following conditions at this point: // 1) not null // 2) read only // 3) same number of columns in each list (0 count acceptable for properties that are "unused") Debug.Assert(null != _extendedProperties && _extendedProperties.IsReadOnly, "SmiMetaData.ctor: _extendedProperties is " + (null!=_extendedProperties?"writeable":"null")); Debug.Assert(null != _fieldMetaData && _fieldMetaData.IsReadOnly, "SmiMetaData.ctor: _fieldMetaData is " + (null!=_fieldMetaData?"writeable":"null")); #if DEBUG ((SmiDefaultFieldsProperty)_extendedProperties[SmiPropertySelector.DefaultFields]).CheckCount(_fieldMetaData.Count); ((SmiOrderProperty)_extendedProperties[SmiPropertySelector.SortOrder]).CheckCount(_fieldMetaData.Count); ((SmiUniqueKeyProperty)_extendedProperties[SmiPropertySelector.UniqueKey]).CheckCount(_fieldMetaData.Count); #endif } internal bool IsValidMaxLengthForCtorGivenType( SqlDbType dbType, long maxLength ) { bool result = true; switch( dbType ) { case SqlDbType.BigInt: case SqlDbType.Bit: case SqlDbType.DateTime: case SqlDbType.Float: case SqlDbType.Image: case SqlDbType.Int: case SqlDbType.Money: case SqlDbType.Real: case SqlDbType.SmallDateTime: case SqlDbType.SmallInt: case SqlDbType.SmallMoney: case SqlDbType.Timestamp: case SqlDbType.TinyInt: case SqlDbType.UniqueIdentifier: case SqlDbType.Variant: case SqlDbType.Xml: case SqlDbType.NText: case SqlDbType.Text: case SqlDbType.Decimal: case SqlDbType.Udt: case SqlDbType.Structured: // case SqlDbType.Date: case SqlDbType.Time: case SqlDbType.DateTime2: case SqlDbType.DateTimeOffset: break; case SqlDbType.Binary: result = 0 < maxLength && MaxBinaryLength >= maxLength; break; case SqlDbType.VarBinary: result = UnlimitedMaxLengthIndicator == maxLength || ( 0 < maxLength && MaxBinaryLength >= maxLength ); break; case SqlDbType.Char: result = 0 < maxLength && MaxANSICharacters >= maxLength; break; case SqlDbType.NChar: result = 0 < maxLength && MaxUnicodeCharacters >= maxLength; break; case SqlDbType.NVarChar: result = UnlimitedMaxLengthIndicator == maxLength || ( 0 < maxLength && MaxUnicodeCharacters >= maxLength ); break; case SqlDbType.VarChar: result = UnlimitedMaxLengthIndicator == maxLength || ( 0 < maxLength && MaxANSICharacters >= maxLength ); break; default: Debug.Assert( false, "How in the world did we get here? :" + dbType ); break; } return result; } // Sql-style compare options for character types. internal SqlCompareOptions CompareOptions { get { return _compareOptions; } } // LCID for type. 0 for non-character types. internal long LocaleId { get{ return _localeId; } } // Units of length depend on type. // NVarChar, NChar, NText: # of unicode characters // Everything else: # of bytes internal long MaxLength { get { return _maxLength; } } internal byte Precision { get { return _precision; } } internal byte Scale { get { return _scale; } } internal SqlDbType SqlDbType { get { return _databaseType; } } // Clr Type instance for user-defined types internal Type Type { get { // Fault-in UDT clr types on access if have assembly-qualified name if (null == _clrType && SqlDbType.Udt == _databaseType && _udtAssemblyQualifiedName != null) { _clrType = Type.GetType(_udtAssemblyQualifiedName, true); } return _clrType; } } // Clr Type instance for user-defined types in cases where we don't want to throw if the assembly isn't available internal Type TypeWithoutThrowing { get { // Fault-in UDT clr types on access if have assembly-qualified name if (null == _clrType && SqlDbType.Udt == _databaseType && _udtAssemblyQualifiedName != null) { _clrType = Type.GetType(_udtAssemblyQualifiedName, false); } return _clrType; } } internal string TypeName { get { string result = null; if (SqlDbType.Udt == _databaseType) { Debug.Assert(String.Empty == __typeNameByDatabaseType[(int)_databaseType], "unexpected udt?"); result = Type.FullName; } else { result = __typeNameByDatabaseType[(int)_databaseType]; Debug.Assert(null != result, "unknown type name?"); } return result; } } internal string AssemblyQualifiedName { get { string result = null; if (SqlDbType.Udt == _databaseType) { // Fault-in assembly-qualified name if type is available if (_udtAssemblyQualifiedName == null && _clrType != null) { _udtAssemblyQualifiedName = _clrType.AssemblyQualifiedName; } result = _udtAssemblyQualifiedName; } return result; } } internal bool IsMultiValued { get { return _isMultiValued; } } // Returns read-only list of field metadata internal IList FieldMetaData { get { return _fieldMetaData; } } // Returns read-only list of extended properties internal SmiMetaDataPropertyCollection ExtendedProperties { get { return _extendedProperties; } } internal static bool IsSupportedDbType(SqlDbType dbType) { // Hole in SqlDbTypes between Xml and Udt for non-WinFS scenarios. return (SqlDbType.BigInt <= dbType && SqlDbType.Xml >= dbType) || (SqlDbType.Udt <= dbType && SqlDbType.DateTimeOffset >= dbType); } // Only correct access point for defaults per SqlDbType. internal static SmiMetaData GetDefaultForType( SqlDbType dbType ) { Debug.Assert( IsSupportedDbType(dbType), "Unsupported SqlDbtype: " + dbType); return __defaultValues[(int)dbType]; } // Private constructor used only to initialize default instance array elements. // DO NOT EXPOSE OUTSIDE THIS CLASS! private SmiMetaData ( SqlDbType sqlDbType, long maxLength, byte precision, byte scale, SqlCompareOptions compareOptions) { _databaseType = sqlDbType; _maxLength = maxLength; _precision = precision; _scale = scale; _compareOptions = compareOptions; // defaults are the same for all types for the following attributes. _localeId = 0; _clrType = null; _isMultiValued = false; _fieldMetaData = __emptyFieldList; _extendedProperties = SmiMetaDataPropertyCollection.EmptyInstance; } // static array of default-valued metadata ordered by corresponding SqlDbType. // NOTE: INDEXED BY SqlDbType ENUM! MUST UPDATE THIS ARRAY WHEN UPDATING SqlDbType! // ONLY ACCESS THIS GLOBAL FROM GetDefaultForType! private static SmiMetaData[] __defaultValues = { DefaultBigInt, // SqlDbType.BigInt DefaultBinary, // SqlDbType.Binary DefaultBit, // SqlDbType.Bit DefaultChar_NoCollation, // SqlDbType.Char DefaultDateTime, // SqlDbType.DateTime DefaultDecimal, // SqlDbType.Decimal DefaultFloat, // SqlDbType.Float DefaultImage, // SqlDbType.Image DefaultInt, // SqlDbType.Int DefaultMoney, // SqlDbType.Money DefaultNChar_NoCollation, // SqlDbType.NChar DefaultNText_NoCollation, // SqlDbType.NText DefaultNVarChar_NoCollation, // SqlDbType.NVarChar DefaultReal, // SqlDbType.Real DefaultUniqueIdentifier, // SqlDbType.UniqueIdentifier DefaultSmallDateTime, // SqlDbType.SmallDateTime DefaultSmallInt, // SqlDbType.SmallInt DefaultSmallMoney, // SqlDbType.SmallMoney DefaultText_NoCollation, // SqlDbType.Text DefaultTimestamp, // SqlDbType.Timestamp DefaultTinyInt, // SqlDbType.TinyInt DefaultVarBinary, // SqlDbType.VarBinary DefaultVarChar_NoCollation, // SqlDbType.VarChar DefaultVariant, // SqlDbType.Variant DefaultNVarChar_NoCollation, // Placeholder for value 24 DefaultXml, // SqlDbType.Xml DefaultNVarChar_NoCollation, // Placeholder for value 26 DefaultNVarChar_NoCollation, // Placeholder for value 27 DefaultNVarChar_NoCollation, // Placeholder for value 28 DefaultUdt_NoType, // Generic Udt DefaultStructured, // Generic structured type DefaultDate, // SqlDbType.Date DefaultTime, // SqlDbType.Time DefaultDateTime2, // SqlDbType.DateTime2 DefaultDateTimeOffset, // SqlDbType.DateTimeOffset }; // static array of type names ordered by corresponding SqlDbType. // NOTE: INDEXED BY SqlDbType ENUM! MUST UPDATE THIS ARRAY WHEN UPDATING SqlDbType! // ONLY ACCESS THIS GLOBAL FROM get_TypeName! private static string[] __typeNameByDatabaseType = { "bigint", // SqlDbType.BigInt "binary", // SqlDbType.Binary "bit", // SqlDbType.Bit "char", // SqlDbType.Char "datetime", // SqlDbType.DateTime "decimal", // SqlDbType.Decimal "float", // SqlDbType.Float "image", // SqlDbType.Image "int", // SqlDbType.Int "money", // SqlDbType.Money "nchar", // SqlDbType.NChar "ntext", // SqlDbType.NText "nvarchar", // SqlDbType.NVarChar "real", // SqlDbType.Real "uniqueidentifier", // SqlDbType.UniqueIdentifier "smalldatetime", // SqlDbType.SmallDateTime "smallint", // SqlDbType.SmallInt "smallmoney", // SqlDbType.SmallMoney "text", // SqlDbType.Text "timestamp", // SqlDbType.Timestamp "tinyint", // SqlDbType.TinyInt "varbinary", // SqlDbType.VarBinary "varchar", // SqlDbType.VarChar "sql_variant", // SqlDbType.Variant null, // placeholder for 24 "xml", // SqlDbType.Xml null, // placeholder for 26 null, // placeholder for 27 null, // placeholder for 28 String.Empty, // SqlDbType.Udt -- get type name from Type.FullName instead. String.Empty, // Structured types have user-defined type names. "date", // SqlDbType.Date "time", // SqlDbType.Time "datetime2", // SqlDbType.DateTime2 "datetimeoffset", // SqlDbType.DateTimeOffset }; // Internal setter to be used by constructors only! Modifies state! private void SetDefaultsForType( SqlDbType dbType ) { SmiMetaData smdDflt = GetDefaultForType( dbType ); _databaseType = dbType; _maxLength = smdDflt.MaxLength; _precision = smdDflt.Precision; _scale = smdDflt.Scale; _localeId = smdDflt.LocaleId; _compareOptions = smdDflt.CompareOptions; _clrType = null; _isMultiValued = smdDflt._isMultiValued; _fieldMetaData = smdDflt._fieldMetaData; // This is ok due to immutability _extendedProperties = smdDflt._extendedProperties; // This is ok due to immutability } internal string TraceString() { return TraceString(0); } virtual internal string TraceString(int indent) { string indentStr = new String(' ', indent); string fields = String.Empty; if (null != _fieldMetaData) { foreach(SmiMetaData fieldMd in _fieldMetaData) { fields = String.Format(CultureInfo.InvariantCulture, "{0}{1}\n\t", fields, fieldMd.TraceString(indent+5)); } } string properties = String.Empty; if (null != _extendedProperties) { foreach(SmiMetaDataProperty property in _extendedProperties.Values) { properties = String.Format(CultureInfo.InvariantCulture, "{0}{1} {2}\n\t", properties, indentStr, property.TraceString()); } } return String.Format(CultureInfo.InvariantCulture, "\n\t" +"{0} SqlDbType={1:g}\n\t" +"{0} MaxLength={2:d}\n\t" +"{0} Precision={3:d}\n\t" +"{0} Scale={4:d}\n\t" +"{0} LocaleId={5:x}\n\t" +"{0} CompareOptions={6:g}\n\t" +"{0} Type={7}\n\t" +"{0} MultiValued={8}\n\t" +"{0} fields=\n\t{9}" +"{0} properties=\n\t{10}", indentStr, SqlDbType, MaxLength, Precision, Scale, LocaleId, CompareOptions, (null!=Type) ? Type.ToString():"", IsMultiValued, fields, properties); } } // SmiExtendedMetaData // // Adds server-specific type extension information to base metadata, but still portable across a specific server. // internal class SmiExtendedMetaData : SmiMetaData { private string _name; // context-dependant identifier, ie. parameter name for parameters, column name for columns, etc. // three-part name for typed xml schema and for udt names private string _typeSpecificNamePart1; private string _typeSpecificNamePart2; private string _typeSpecificNamePart3; [ObsoleteAttribute( "Not supported as of SMI v2. Will be removed when v1 support dropped. Use ctor without columns param." )] internal SmiExtendedMetaData( SqlDbType dbType, long maxLength, byte precision, byte scale, long localeId, SqlCompareOptions compareOptions, Type userDefinedType, SmiMetaData[] columns, string name, string typeSpecificNamePart1, string typeSpecificNamePart2, string typeSpecificNamePart3) : // Implement as calling the new ctor this( dbType, maxLength, precision, scale, localeId, compareOptions, userDefinedType, name, typeSpecificNamePart1, typeSpecificNamePart2, typeSpecificNamePart3 ) { Debug.Assert( null == columns, "Row types not supported" ); } internal SmiExtendedMetaData( SqlDbType dbType, long maxLength, byte precision, byte scale, long localeId, SqlCompareOptions compareOptions, Type userDefinedType, string name, string typeSpecificNamePart1, string typeSpecificNamePart2, string typeSpecificNamePart3) : this( dbType, maxLength, precision, scale, localeId, compareOptions, userDefinedType, false, null, null, name, typeSpecificNamePart1, typeSpecificNamePart2, typeSpecificNamePart3) { } // SMI V200 ctor. internal SmiExtendedMetaData( SqlDbType dbType, long maxLength, byte precision, byte scale, long localeId, SqlCompareOptions compareOptions, Type userDefinedType, bool isMultiValued, IList fieldMetaData, SmiMetaDataPropertyCollection extendedProperties, string name, string typeSpecificNamePart1, string typeSpecificNamePart2, string typeSpecificNamePart3) : this( dbType, maxLength, precision, scale, localeId, compareOptions, userDefinedType, null, isMultiValued, fieldMetaData, extendedProperties, name, typeSpecificNamePart1, typeSpecificNamePart2, typeSpecificNamePart3) { } // SMI V220 ctor. internal SmiExtendedMetaData( SqlDbType dbType, long maxLength, byte precision, byte scale, long localeId, SqlCompareOptions compareOptions, Type userDefinedType, string udtAssemblyQualifiedName, bool isMultiValued, IList fieldMetaData, SmiMetaDataPropertyCollection extendedProperties, string name, string typeSpecificNamePart1, string typeSpecificNamePart2, string typeSpecificNamePart3 ): base( dbType, maxLength, precision, scale, localeId, compareOptions, userDefinedType, udtAssemblyQualifiedName, isMultiValued, fieldMetaData, extendedProperties) { Debug.Assert(null == name || MaxNameLength >= name.Length, "Name is too long"); _name = name; _typeSpecificNamePart1 = typeSpecificNamePart1; _typeSpecificNamePart2 = typeSpecificNamePart2; _typeSpecificNamePart3 = typeSpecificNamePart3; } internal string Name { get { return _name; } } internal string TypeSpecificNamePart1 { get { return _typeSpecificNamePart1; } } internal string TypeSpecificNamePart2 { get { return _typeSpecificNamePart2; } } internal string TypeSpecificNamePart3 { get { return _typeSpecificNamePart3; } } internal override string TraceString(int indent) { return String.Format(CultureInfo.InvariantCulture, "{2} Name={0}" +"{1}" +"{2}TypeSpecificNamePart1='{3}'\n\t" +"{2}TypeSpecificNamePart2='{4}'\n\t" +"{2}TypeSpecificNamePart3='{5}'\n\t", (null!=_name) ? _name : "", base.TraceString(indent), new String(' ', indent), (null!=TypeSpecificNamePart1) ? TypeSpecificNamePart1:"", (null!=TypeSpecificNamePart2) ? TypeSpecificNamePart2:"", (null!=TypeSpecificNamePart3) ? TypeSpecificNamePart3:""); } } // SmiParameterMetaData // // MetaData class to send parameter definitions to server. // Sealed because we don't need to derive from it yet. // IMPORTANT DEVNOTE: This class is being used for parameter encryption functionality, to get the type_info TDS object from SqlParameter. // Please consider impact to that when changing this class. Refer to the callers of SqlParameter.GetMetadataForTypeInfo(). internal sealed class SmiParameterMetaData : SmiExtendedMetaData { private ParameterDirection _direction; [ObsoleteAttribute( "Not supported as of SMI v2. Will be removed when v1 support dropped. Use ctor without columns param." )] internal SmiParameterMetaData( SqlDbType dbType, long maxLength, byte precision, byte scale, long localeId, SqlCompareOptions compareOptions, Type userDefinedType, SmiMetaData[] columns, string name, string typeSpecificNamePart1, string typeSpecificNamePart2, string typeSpecificNamePart3, ParameterDirection direction) : // Implement as calling the new ctor this ( dbType, maxLength, precision, scale, localeId, compareOptions, userDefinedType, name, typeSpecificNamePart1, typeSpecificNamePart2, typeSpecificNamePart3, direction ) { Debug.Assert( null == columns, "Row types not supported" ); } // SMI V100 (aka V3) ctor internal SmiParameterMetaData( SqlDbType dbType, long maxLength, byte precision, byte scale, long localeId, SqlCompareOptions compareOptions, Type userDefinedType, string name, string typeSpecificNamePart1, string typeSpecificNamePart2, string typeSpecificNamePart3, ParameterDirection direction) : this( dbType, maxLength, precision, scale, localeId, compareOptions, userDefinedType, false, null, null, name, typeSpecificNamePart1, typeSpecificNamePart2, typeSpecificNamePart3, direction) { } // SMI V200 ctor. internal SmiParameterMetaData( SqlDbType dbType, long maxLength, byte precision, byte scale, long localeId, SqlCompareOptions compareOptions, Type userDefinedType, bool isMultiValued, IList fieldMetaData, SmiMetaDataPropertyCollection extendedProperties, string name, string typeSpecificNamePart1, string typeSpecificNamePart2, string typeSpecificNamePart3, ParameterDirection direction) : this( dbType, maxLength, precision, scale, localeId, compareOptions, userDefinedType, null, isMultiValued, fieldMetaData, extendedProperties, name, typeSpecificNamePart1, typeSpecificNamePart2, typeSpecificNamePart3, direction) { } // SMI V220 ctor. internal SmiParameterMetaData( SqlDbType dbType, long maxLength, byte precision, byte scale, long localeId, SqlCompareOptions compareOptions, Type userDefinedType, string udtAssemblyQualifiedName, bool isMultiValued, IList fieldMetaData, SmiMetaDataPropertyCollection extendedProperties, string name, string typeSpecificNamePart1, string typeSpecificNamePart2, string typeSpecificNamePart3, ParameterDirection direction) : base( dbType, maxLength, precision, scale, localeId, compareOptions, userDefinedType, udtAssemblyQualifiedName, isMultiValued, fieldMetaData, extendedProperties, name, typeSpecificNamePart1, typeSpecificNamePart2, typeSpecificNamePart3) { Debug.Assert( ParameterDirection.Input == direction || ParameterDirection.Output == direction || ParameterDirection.InputOutput == direction || ParameterDirection.ReturnValue == direction, "Invalid direction: " + direction ); _direction = direction; } internal ParameterDirection Direction { get { return _direction; } } internal override string TraceString(int indent) { return String.Format(CultureInfo.InvariantCulture, "{0}" +"{1} Direction={2:g}\n\t", base.TraceString(indent), new String(' ', indent), Direction); } } // SmiStorageMetaData // // This class represents the addition of storage-level attributes to the heirarchy (i.e. attributes from // underlying table, source variables, or whatever). // // Most values use Null (either IsNullable == true or CLR null) to indicate "Not specified" state. Selection // of which values allow "not specified" determined by backward compatibility. // // Maps approximately to TDS' COLMETADATA token with TABNAME and part of COLINFO thrown in. internal class SmiStorageMetaData : SmiExtendedMetaData { // AllowsDBNull is the only value required to be specified. private bool _allowsDBNull; // could the column return nulls? equivalent to TDS's IsNullable bit private string _serverName; // underlying column's server private string _catalogName; // underlying column's database private string _schemaName; // underlying column's schema private string _tableName; // underlying column's table private string _columnName; // underlying column's name private SqlBoolean _isKey; // Is this one of a set of key columns that uniquely identify an underlying table? private bool _isIdentity; // Is this from an identity column private bool _isColumnSet; // Is this column the XML representation of a columnset? [ObsoleteAttribute( "Not supported as of SMI v2. Will be removed when v1 support dropped. Use ctor without columns param." )] internal SmiStorageMetaData( SqlDbType dbType, long maxLength, byte precision, byte scale, long localeId, SqlCompareOptions compareOptions, Type userDefinedType, SmiMetaData[] columns, string name, string typeSpecificNamePart1, string typeSpecificNamePart2, string typeSpecificNamePart3, bool allowsDBNull, string serverName, string catalogName, string schemaName, string tableName, string columnName, SqlBoolean isKey, bool isIdentity) : // Implement as calling the new ctor this ( dbType, maxLength, precision, scale, localeId, compareOptions, userDefinedType, name, typeSpecificNamePart1, typeSpecificNamePart2, typeSpecificNamePart3, allowsDBNull, serverName, catalogName, schemaName, tableName, columnName, isKey, isIdentity) { Debug.Assert( null == columns, "Row types not supported" ); } internal SmiStorageMetaData( SqlDbType dbType, long maxLength, byte precision, byte scale, long localeId, SqlCompareOptions compareOptions, Type userDefinedType, string name, string typeSpecificNamePart1, string typeSpecificNamePart2, string typeSpecificNamePart3, bool allowsDBNull, string serverName, string catalogName, string schemaName, string tableName, string columnName, SqlBoolean isKey, bool isIdentity) : this(dbType, maxLength, precision, scale, localeId, compareOptions, userDefinedType, false, null, null, name, typeSpecificNamePart1, typeSpecificNamePart2, typeSpecificNamePart3, allowsDBNull, serverName, catalogName, schemaName, tableName, columnName, isKey, isIdentity) { } // SMI V200 ctor. internal SmiStorageMetaData( SqlDbType dbType, long maxLength, byte precision, byte scale, long localeId, SqlCompareOptions compareOptions, Type userDefinedType, bool isMultiValued, IList fieldMetaData, SmiMetaDataPropertyCollection extendedProperties, string name, string typeSpecificNamePart1, string typeSpecificNamePart2, string typeSpecificNamePart3, bool allowsDBNull, string serverName, string catalogName, string schemaName, string tableName, string columnName, SqlBoolean isKey, bool isIdentity) : this( dbType, maxLength, precision, scale, localeId, compareOptions, userDefinedType, null, isMultiValued, fieldMetaData, extendedProperties, name, typeSpecificNamePart1, typeSpecificNamePart2, typeSpecificNamePart3, allowsDBNull, serverName, catalogName, schemaName, tableName, columnName, isKey, isIdentity, false) { } // SMI V220 ctor. internal SmiStorageMetaData( SqlDbType dbType, long maxLength, byte precision, byte scale, long localeId, SqlCompareOptions compareOptions, Type userDefinedType, string udtAssemblyQualifiedName, bool isMultiValued, IList fieldMetaData, SmiMetaDataPropertyCollection extendedProperties, string name, string typeSpecificNamePart1, string typeSpecificNamePart2, string typeSpecificNamePart3, bool allowsDBNull, string serverName, string catalogName, string schemaName, string tableName, string columnName, SqlBoolean isKey, bool isIdentity, bool isColumnSet) : base( dbType, maxLength, precision, scale, localeId, compareOptions, userDefinedType, udtAssemblyQualifiedName, isMultiValued, fieldMetaData, extendedProperties, name, typeSpecificNamePart1, typeSpecificNamePart2, typeSpecificNamePart3) { _allowsDBNull = allowsDBNull; _serverName = serverName; _catalogName = catalogName; _schemaName = schemaName; _tableName = tableName; _columnName = columnName; _isKey = isKey; _isIdentity = isIdentity; _isColumnSet = isColumnSet; } internal bool AllowsDBNull { get { return _allowsDBNull; } } internal string ServerName { get { return _serverName; } } internal string CatalogName { get { return _catalogName; } } internal string SchemaName { get { return _schemaName; } } internal string TableName { get { return _tableName; } } internal string ColumnName { get { return _columnName; } } internal SqlBoolean IsKey { get { return _isKey; } } internal bool IsIdentity { get { return _isIdentity; } } internal bool IsColumnSet { get { return _isColumnSet; } } internal override string TraceString(int indent) { return String.Format(CultureInfo.InvariantCulture, "{0}" +"{1} AllowsDBNull={2}\n\t" +"{1} ServerName='{3}'\n\t" +"{1} CatalogName='{4}'\n\t" +"{1} SchemaName='{5}'\n\t" +"{1} TableName='{6}'\n\t" +"{1} ColumnName='{7}'\n\t" +"{1} IsKey={8}\n\t" +"{1} IsIdentity={9}\n\t", base.TraceString(indent), new String(' ', indent), AllowsDBNull, (null!=ServerName) ? ServerName:"", (null!=CatalogName) ? CatalogName:"", (null!=SchemaName) ? SchemaName:"", (null!=TableName) ? TableName:"", (null!=ColumnName) ? ColumnName:"", IsKey, IsIdentity); } } // SmiQueryMetaData // // Adds Query-specific attributes. // Sealed since we don't need to extend it for now. // Maps to full COLMETADATA + COLINFO + TABNAME tokens on TDS. internal class SmiQueryMetaData : SmiStorageMetaData { private bool _isReadOnly; private SqlBoolean _isExpression; private SqlBoolean _isAliased; private SqlBoolean _isHidden; [ObsoleteAttribute( "Not supported as of SMI v2. Will be removed when v1 support dropped. Use ctor without columns param." )] internal SmiQueryMetaData( SqlDbType dbType, long maxLength, byte precision, byte scale, long localeId, SqlCompareOptions compareOptions, Type userDefinedType, SmiMetaData[] columns, string name, string typeSpecificNamePart1, string typeSpecificNamePart2, string typeSpecificNamePart3, bool allowsDBNull, string serverName, string catalogName, string schemaName, string tableName, string columnName, SqlBoolean isKey, bool isIdentity, bool isReadOnly, SqlBoolean isExpression, SqlBoolean isAliased, SqlBoolean isHidden ) : // Implement as calling the new ctor this ( dbType, maxLength, precision, scale, localeId, compareOptions, userDefinedType, name, typeSpecificNamePart1, typeSpecificNamePart2, typeSpecificNamePart3, allowsDBNull, serverName, catalogName, schemaName, tableName, columnName, isKey, isIdentity, isReadOnly, isExpression, isAliased, isHidden ) { Debug.Assert( null == columns, "Row types not supported" ); } internal SmiQueryMetaData( SqlDbType dbType, long maxLength, byte precision, byte scale, long localeId, SqlCompareOptions compareOptions, Type userDefinedType, string name, string typeSpecificNamePart1, string typeSpecificNamePart2, string typeSpecificNamePart3, bool allowsDBNull, string serverName, string catalogName, string schemaName, string tableName, string columnName, SqlBoolean isKey, bool isIdentity, bool isReadOnly, SqlBoolean isExpression, SqlBoolean isAliased, SqlBoolean isHidden ) : this( dbType, maxLength, precision, scale, localeId, compareOptions, userDefinedType, false, null, null, name, typeSpecificNamePart1, typeSpecificNamePart2, typeSpecificNamePart3, allowsDBNull, serverName, catalogName, schemaName, tableName, columnName, isKey, isIdentity, isReadOnly, isExpression, isAliased, isHidden) { } // SMI V200 ctor. internal SmiQueryMetaData( SqlDbType dbType, long maxLength, byte precision, byte scale, long localeId, SqlCompareOptions compareOptions, Type userDefinedType, bool isMultiValued, IList fieldMetaData, SmiMetaDataPropertyCollection extendedProperties, string name, string typeSpecificNamePart1, string typeSpecificNamePart2, string typeSpecificNamePart3, bool allowsDBNull, string serverName, string catalogName, string schemaName, string tableName, string columnName, SqlBoolean isKey, bool isIdentity, bool isReadOnly, SqlBoolean isExpression, SqlBoolean isAliased, SqlBoolean isHidden) : this( dbType, maxLength, precision, scale, localeId, compareOptions, userDefinedType, null, isMultiValued, fieldMetaData, extendedProperties, name, typeSpecificNamePart1, typeSpecificNamePart2, typeSpecificNamePart3, allowsDBNull, serverName, catalogName, schemaName, tableName, columnName, isKey, isIdentity, false, isReadOnly, isExpression, isAliased, isHidden ) { } // SMI V220 ctor. internal SmiQueryMetaData( SqlDbType dbType, long maxLength, byte precision, byte scale, long localeId, SqlCompareOptions compareOptions, Type userDefinedType, string udtAssemblyQualifiedName, bool isMultiValued, IList fieldMetaData, SmiMetaDataPropertyCollection extendedProperties, string name, string typeSpecificNamePart1, string typeSpecificNamePart2, string typeSpecificNamePart3, bool allowsDBNull, string serverName, string catalogName, string schemaName, string tableName, string columnName, SqlBoolean isKey, bool isIdentity, bool isColumnSet, bool isReadOnly, SqlBoolean isExpression, SqlBoolean isAliased, SqlBoolean isHidden ) : base( dbType, maxLength, precision, scale, localeId, compareOptions, userDefinedType, udtAssemblyQualifiedName, isMultiValued, fieldMetaData, extendedProperties, name, typeSpecificNamePart1, typeSpecificNamePart2, typeSpecificNamePart3, allowsDBNull, serverName, catalogName, schemaName, tableName, columnName, isKey, isIdentity, isColumnSet ) { _isReadOnly = isReadOnly; _isExpression = isExpression; _isAliased = isAliased; _isHidden = isHidden; } internal bool IsReadOnly { get { return _isReadOnly; } } internal SqlBoolean IsExpression { get { return _isExpression; } } internal SqlBoolean IsAliased { get { return _isAliased; } } internal SqlBoolean IsHidden { get { return _isHidden; } } internal override string TraceString(int indent) { return String.Format(CultureInfo.InvariantCulture, "{0}" +"{1} IsReadOnly={2}\n\t" +"{1} IsExpression={3}\n\t" +"{1} IsAliased={4}\n\t" +"{1} IsHidden={5}", base.TraceString(indent), new String(' ', indent), AllowsDBNull, IsExpression, IsAliased, IsHidden); } } }