Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.Data / Microsoft / SqlServer / Server / SmiMetaData.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="SmiMetaData.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">[....]</owner>
6 // <owner current="true" primary="false">[....]</owner>
7 //------------------------------------------------------------------------------
8
9 namespace Microsoft.SqlServer.Server {
10
11     using System;
12     using System.Collections.Generic;
13     using System.Diagnostics;
14     using System.Data;
15     using System.Data.Sql;
16     using System.Data.SqlTypes;
17     using System.Globalization;
18
19
20     // DESIGN NOTES
21     //
22     //  The following classes are a tight inheritance heirarchy, and are not designed for
23     //  being inherited outside of this file.  Instances are guaranteed to be immutable, and
24     //  outside classes rely on this fact.
25     //
26     //  The various levels may not all be used outside of this file, but for clarity of purpose
27     //  they are all usefull distinctions to make.
28     //
29     //  In general, moving lower in the type heirarchy exposes less portable values.  Thus,
30     //  the root metadata can be readily shared across different (MSSQL) servers and clients,
31     //  while QueryMetaData has attributes tied to a specific query, running against specific
32     //  data storage on a specific server.
33     //
34     //  The SmiMetaData heirarchy does not do data validation on retail builds!  It will assert
35     //  that the values passed to it have been validated externally, however.
36     //
37
38
39     // SmiMetaData
40     //
41     //  Root of the heirarchy.
42     //  Represents the minimal amount of metadata required to represent any Sql Server datum
43     //  without any references to any particular server or schema (thus, no server-specific multi-part names).
44     //  It could be used to communicate solely between two disconnected clients, for instance.
45     //
46     //  NOTE: It currently does not contain sufficient information to describe typed XML, since we
47     //      don't have a good server-independent mechanism for such.
48     //
49     //  This class is also used as implementation for the public SqlMetaData class.
50     internal class SmiMetaData {
51
52         private SqlDbType           _databaseType;          // Main enum that determines what is valid for other attributes.
53         private long                _maxLength;             // Varies for variable-length types, others are fixed value per type
54         private byte                _precision;             // Varies for SqlDbType.Decimal, others are fixed value per type
55         private byte                _scale;                 // Varies for SqlDbType.Decimal, others are fixed value per type
56         private long                _localeId;              // Valid only for character types, others are 0
57         private SqlCompareOptions   _compareOptions;        // Valid only for character types, others are SqlCompareOptions.Default
58         private Type                _clrType;               // Varies for SqlDbType.Udt, others are fixed value per type.
59         private string _udtAssemblyQualifiedName;           // Valid only for UDT types when _clrType is not available
60         private bool                _isMultiValued;         // Multiple instances per value? (I.e. tables, arrays)
61         private IList<SmiExtendedMetaData>  _fieldMetaData;         // Metadata of fields for structured types
62         private SmiMetaDataPropertyCollection _extendedProperties;  // Extended properties, Key columns, sort order, etc.
63
64         // DevNote: For now, since the list of extended property types is small, we can handle them in a simple list.
65         //  In the future, we may need to create a more performant storage & lookup mechanism, such as a hash table
66         //  of lists indexed by type of property or an array of lists with a well-known index for each type.
67
68
69
70         // Limits for attributes (SmiMetaData will assert that these limits as applicable in constructor)
71         internal const long UnlimitedMaxLengthIndicator = -1;  // unlimited (except by implementation) max-length.
72         internal const long MaxUnicodeCharacters = 4000;        // Maximum for limited type
73         internal const long MaxANSICharacters = 8000;           // Maximum for limited type
74         internal const long MaxBinaryLength = 8000;             // Maximum for limited type
75         internal const int  MinPrecision = 1;       // SqlDecimal defines max precision
76         internal const int  MinScale = 0;            // SqlDecimal defines max scale
77         internal const int  MaxTimeScale = 7;        // Max scale for time, datetime2, and datetimeoffset
78         internal static readonly DateTime MaxSmallDateTime = new DateTime(2079, 06, 06, 23, 59, 29, 998);
79         internal static readonly DateTime MinSmallDateTime = new DateTime(1899, 12, 31, 23, 59, 29, 999);
80         internal static readonly SqlMoney MaxSmallMoney = new SqlMoney( ( (Decimal)Int32.MaxValue ) / 10000 );
81         internal static readonly SqlMoney MinSmallMoney = new SqlMoney( ( (Decimal)Int32.MinValue ) / 10000 );
82         internal const SqlCompareOptions DefaultStringCompareOptions = SqlCompareOptions.IgnoreCase 
83                                         | SqlCompareOptions.IgnoreKanaType | SqlCompareOptions.IgnoreWidth;
84         
85         internal const long MaxNameLength = 128;        // maximum length in the server is 128.
86         private static readonly IList<SmiExtendedMetaData> __emptyFieldList = new List<SmiExtendedMetaData>().AsReadOnly();
87
88
89         // Precision to max length lookup table
90         private static byte[] __maxLenFromPrecision = new byte[] {5,5,5,5,5,5,5,5,5,9,9,9,9,9,
91             9,9,9,9,9,13,13,13,13,13,13,13,13,13,17,17,17,17,17,17,17,17,17,17};
92
93         // Scale offset to max length lookup table
94         private static byte[] __maxVarTimeLenOffsetFromScale = new byte[] { 2, 2, 2, 1, 1, 0, 0, 0 };
95
96         // Defaults
97                                                                          //    SmiMetaData(SqlDbType,                  MaxLen,                     Prec, Scale,  CompareOptions)
98         internal static readonly SmiMetaData DefaultBigInt               = new SmiMetaData(SqlDbType.BigInt,           8,                          19,   0,      SqlCompareOptions.None);     // SqlDbType.BigInt
99         internal static readonly SmiMetaData DefaultBinary               = new SmiMetaData(SqlDbType.Binary,           1,                          0,    0,      SqlCompareOptions.None);     // SqlDbType.Binary
100         internal static readonly SmiMetaData DefaultBit                  = new SmiMetaData(SqlDbType.Bit,              1,                          1,    0,      SqlCompareOptions.None);     // SqlDbType.Bit
101         internal static readonly SmiMetaData DefaultChar_NoCollation     = new SmiMetaData(SqlDbType.Char,             1,                          0,    0,      DefaultStringCompareOptions);// SqlDbType.Char
102         internal static readonly SmiMetaData DefaultDateTime             = new SmiMetaData(SqlDbType.DateTime,         8,                          23,   3,      SqlCompareOptions.None);     // SqlDbType.DateTime
103         internal static readonly SmiMetaData DefaultDecimal              = new SmiMetaData(SqlDbType.Decimal,          9,                          18,   0,      SqlCompareOptions.None);     // SqlDbType.Decimal
104         internal static readonly SmiMetaData DefaultFloat                = new SmiMetaData(SqlDbType.Float,            8,                          53,   0,      SqlCompareOptions.None);     // SqlDbType.Float
105         internal static readonly SmiMetaData DefaultImage                = new SmiMetaData(SqlDbType.Image,            UnlimitedMaxLengthIndicator,0,    0,      SqlCompareOptions.None);     // SqlDbType.Image
106         internal static readonly SmiMetaData DefaultInt                  = new SmiMetaData(SqlDbType.Int,              4,                          10,   0,      SqlCompareOptions.None);     // SqlDbType.Int
107         internal static readonly SmiMetaData DefaultMoney                = new SmiMetaData(SqlDbType.Money,            8,                          19,   4,      SqlCompareOptions.None);     // SqlDbType.Money
108         internal static readonly SmiMetaData DefaultNChar_NoCollation    = new SmiMetaData(SqlDbType.NChar,            1,                          0,    0,      DefaultStringCompareOptions);// SqlDbType.NChar
109         internal static readonly SmiMetaData DefaultNText_NoCollation    = new SmiMetaData(SqlDbType.NText,            UnlimitedMaxLengthIndicator,0,    0,      DefaultStringCompareOptions);// SqlDbType.NText
110         internal static readonly SmiMetaData DefaultNVarChar_NoCollation = new SmiMetaData(SqlDbType.NVarChar,         MaxUnicodeCharacters,       0,    0,      DefaultStringCompareOptions);// SqlDbType.NVarChar
111         internal static readonly SmiMetaData DefaultReal                 = new SmiMetaData(SqlDbType.Real,             4,                          24,   0,      SqlCompareOptions.None);     // SqlDbType.Real
112         internal static readonly SmiMetaData DefaultUniqueIdentifier     = new SmiMetaData(SqlDbType.UniqueIdentifier, 16,                         0,    0,      SqlCompareOptions.None);     // SqlDbType.UniqueIdentifier
113         internal static readonly SmiMetaData DefaultSmallDateTime        = new SmiMetaData(SqlDbType.SmallDateTime,    4,                          16,   0,      SqlCompareOptions.None);     // SqlDbType.SmallDateTime
114         internal static readonly SmiMetaData DefaultSmallInt             = new SmiMetaData(SqlDbType.SmallInt,         2,                          5,    0,      SqlCompareOptions.None);     // SqlDbType.SmallInt
115         internal static readonly SmiMetaData DefaultSmallMoney           = new SmiMetaData(SqlDbType.SmallMoney,       4,                          10,   4,      SqlCompareOptions.None);     // SqlDbType.SmallMoney
116         internal static readonly SmiMetaData DefaultText_NoCollation     = new SmiMetaData(SqlDbType.Text,             UnlimitedMaxLengthIndicator,0,    0,      DefaultStringCompareOptions);// SqlDbType.Text
117         internal static readonly SmiMetaData DefaultTimestamp            = new SmiMetaData(SqlDbType.Timestamp,        8,                          0,    0,      SqlCompareOptions.None);     // SqlDbType.Timestamp
118         internal static readonly SmiMetaData DefaultTinyInt              = new SmiMetaData(SqlDbType.TinyInt,          1,                          3,    0,      SqlCompareOptions.None);     // SqlDbType.TinyInt
119         internal static readonly SmiMetaData DefaultVarBinary            = new SmiMetaData(SqlDbType.VarBinary,        MaxBinaryLength,            0,    0,      SqlCompareOptions.None);     // SqlDbType.VarBinary
120         internal static readonly SmiMetaData DefaultVarChar_NoCollation  = new SmiMetaData(SqlDbType.VarChar,          MaxANSICharacters,          0,    0,      DefaultStringCompareOptions);// SqlDbType.VarChar
121         internal static readonly SmiMetaData DefaultVariant              = new SmiMetaData(SqlDbType.Variant,          8016,                       0,    0,      SqlCompareOptions.None);     // SqlDbType.Variant
122         internal static readonly SmiMetaData DefaultXml                  = new SmiMetaData(SqlDbType.Xml,              UnlimitedMaxLengthIndicator,0,    0,      DefaultStringCompareOptions);// SqlDbType.Xml
123         internal static readonly SmiMetaData DefaultUdt_NoType           = new SmiMetaData(SqlDbType.Udt,              0,                          0,    0,      SqlCompareOptions.None);     // SqlDbType.Udt
124         internal static readonly SmiMetaData DefaultStructured           = new SmiMetaData(SqlDbType.Structured,       0,                          0,    0,      SqlCompareOptions.None);     // SqlDbType.Structured
125         internal static readonly SmiMetaData DefaultDate                 = new SmiMetaData(SqlDbType.Date,             3,                          10,   0,      SqlCompareOptions.None);     // SqlDbType.Date
126         internal static readonly SmiMetaData DefaultTime                 = new SmiMetaData(SqlDbType.Time,             5,                          0,    7,      SqlCompareOptions.None);     // SqlDbType.Time
127         internal static readonly SmiMetaData DefaultDateTime2            = new SmiMetaData(SqlDbType.DateTime2,        8,                          0,    7,      SqlCompareOptions.None);     // SqlDbType.DateTime2
128         internal static readonly SmiMetaData DefaultDateTimeOffset       = new SmiMetaData(SqlDbType.DateTimeOffset,   10,                         0,    7,      SqlCompareOptions.None);     // SqlDbType.DateTimeOffset
129         // No default for generic UDT
130
131         // character defaults hook thread-local culture to get collation
132         internal static SmiMetaData DefaultChar {
133             get {
134                 return new SmiMetaData(
135                         DefaultChar_NoCollation.SqlDbType,
136                         DefaultChar_NoCollation.MaxLength,
137                         DefaultChar_NoCollation.Precision,
138                         DefaultChar_NoCollation.Scale,
139                         System.Globalization.CultureInfo.CurrentCulture.LCID,
140                         SqlCompareOptions.IgnoreCase | SqlCompareOptions.IgnoreKanaType | SqlCompareOptions.IgnoreWidth,
141                         null
142                         );
143             }
144         }
145
146         internal static SmiMetaData DefaultNChar {
147             get {
148                 return new SmiMetaData(
149                         DefaultNChar_NoCollation.SqlDbType,
150                         DefaultNChar_NoCollation.MaxLength,
151                         DefaultNChar_NoCollation.Precision,
152                         DefaultNChar_NoCollation.Scale,
153                         System.Globalization.CultureInfo.CurrentCulture.LCID,
154                         SqlCompareOptions.IgnoreCase | SqlCompareOptions.IgnoreKanaType | SqlCompareOptions.IgnoreWidth,
155                         null
156                         );
157             }
158         }
159
160         internal static SmiMetaData DefaultNText {
161             get {
162                 return new SmiMetaData(
163                         DefaultNText_NoCollation.SqlDbType,
164                         DefaultNText_NoCollation.MaxLength,
165                         DefaultNText_NoCollation.Precision,
166                         DefaultNText_NoCollation.Scale,
167                         System.Globalization.CultureInfo.CurrentCulture.LCID,
168                         SqlCompareOptions.IgnoreCase | SqlCompareOptions.IgnoreKanaType | SqlCompareOptions.IgnoreWidth,
169                         null
170                         );
171             }
172         }
173
174         internal static SmiMetaData DefaultNVarChar {
175             get {
176                 return new SmiMetaData(
177                         DefaultNVarChar_NoCollation.SqlDbType,
178                         DefaultNVarChar_NoCollation.MaxLength,
179                         DefaultNVarChar_NoCollation.Precision,
180                         DefaultNVarChar_NoCollation.Scale,
181                         System.Globalization.CultureInfo.CurrentCulture.LCID,
182                         SqlCompareOptions.IgnoreCase | SqlCompareOptions.IgnoreKanaType | SqlCompareOptions.IgnoreWidth,
183                         null
184                         );
185             }
186         }
187
188         internal static SmiMetaData DefaultText {
189             get {
190                 return new SmiMetaData(
191                         DefaultText_NoCollation.SqlDbType,
192                         DefaultText_NoCollation.MaxLength,
193                         DefaultText_NoCollation.Precision,
194                         DefaultText_NoCollation.Scale,
195                         System.Globalization.CultureInfo.CurrentCulture.LCID,
196                         SqlCompareOptions.IgnoreCase | SqlCompareOptions.IgnoreKanaType | SqlCompareOptions.IgnoreWidth,
197                         null
198                         );
199             }
200         }
201
202         internal static SmiMetaData DefaultVarChar {
203             get {
204                 return new SmiMetaData(
205                         DefaultVarChar_NoCollation.SqlDbType,
206                         DefaultVarChar_NoCollation.MaxLength,
207                         DefaultVarChar_NoCollation.Precision,
208                         DefaultVarChar_NoCollation.Scale,
209                         System.Globalization.CultureInfo.CurrentCulture.LCID,
210                         SqlCompareOptions.IgnoreCase | SqlCompareOptions.IgnoreKanaType | SqlCompareOptions.IgnoreWidth,
211                         null
212                         );
213             }
214         }
215
216         // The one and only constructor for use by outside code.
217         //
218         //  Parameters that matter for given values of dbType (other parameters are ignored in favor of internal defaults).
219         //  Thus, if dbType parameter value is SqlDbType.Decimal, the values of precision and scale passed in are used, but
220         //  maxLength, localeId, compareOptions, etc are set to defaults for the Decimal type:
221         //      SqlDbType.BigInt:               dbType
222         //      SqlDbType.Binary:               dbType, maxLength
223         //      SqlDbType.Bit:                  dbType
224         //      SqlDbType.Char:                 dbType, maxLength, localeId, compareOptions
225         //      SqlDbType.DateTime:             dbType
226         //      SqlDbType.Decimal:              dbType, precision, scale
227         //      SqlDbType.Float:                dbType
228         //      SqlDbType.Image:                dbType
229         //      SqlDbType.Int:                  dbType
230         //      SqlDbType.Money:                dbType
231         //      SqlDbType.NChar:                dbType, maxLength, localeId, compareOptions
232         //      SqlDbType.NText:                dbType, localeId, compareOptions
233         //      SqlDbType.NVarChar:             dbType, maxLength, localeId, compareOptions
234         //      SqlDbType.Real:                 dbType
235         //      SqlDbType.UniqueIdentifier:     dbType
236         //      SqlDbType.SmallDateTime:        dbType
237         //      SqlDbType.SmallInt:             dbType
238         //      SqlDbType.SmallMoney:           dbType
239         //      SqlDbType.Text:                 dbType, localeId, compareOptions
240         //      SqlDbType.Timestamp:            dbType
241         //      SqlDbType.TinyInt:              dbType
242         //      SqlDbType.VarBinary:            dbType, maxLength
243         //      SqlDbType.VarChar:              dbType, maxLength, localeId, compareOptions
244         //      SqlDbType.Variant:              dbType
245         //      PlaceHolder for value 24
246         //      SqlDbType.Xml:                  dbType
247         //      Placeholder for value 26
248         //      Placeholder for value 27
249         //      Placeholder for value 28
250         //      SqlDbType.Udt:                  dbType, userDefinedType
251         //
252
253         [ObsoleteAttribute( "Not supported as of SMI v2.  Will be removed when v1 support dropped. Use ctor without columns param." )]
254         internal SmiMetaData(
255                                 SqlDbType dbType, 
256                                 long maxLength,
257                                 byte precision, 
258                                 byte scale, 
259                                 long localeId, 
260                                 SqlCompareOptions compareOptions, 
261                                 Type userDefinedType, 
262                                 SmiMetaData[] columns) :
263                           // Implement as calling the new ctor
264                           this(
265                                 dbType,
266                                 maxLength,
267                                 precision,
268                                 scale, 
269                                 localeId, 
270                                 compareOptions, 
271                                 userDefinedType ) {
272             Debug.Assert( null == columns, "Row types not supported" );
273         }
274
275         // SMI V100 (aka V3) constructor.  Superceded in V200.
276         internal SmiMetaData(
277                                 SqlDbType dbType, 
278                                 long maxLength,
279                                 byte precision, 
280                                 byte scale, 
281                                 long localeId, 
282                                 SqlCompareOptions compareOptions, 
283                                 Type userDefinedType) :
284                         this(   dbType,
285                                 maxLength,
286                                 precision,
287                                 scale,
288                                 localeId,
289                                 compareOptions,
290                                 userDefinedType,
291                                 false,
292                                 null, 
293                                 null ) {
294         }
295
296         // SMI V200 ctor.
297         internal SmiMetaData(
298                                 SqlDbType dbType,
299                                 long maxLength,
300                                 byte precision,
301                                 byte scale,
302                                 long localeId,
303                                 SqlCompareOptions compareOptions,
304                                 Type userDefinedType,
305                                 bool isMultiValued,
306                                 IList<SmiExtendedMetaData> fieldTypes,
307                                 SmiMetaDataPropertyCollection extendedProperties)
308             :
309                         this(dbType,
310                                 maxLength,
311                                 precision,
312                                 scale,
313                                 localeId,
314                                 compareOptions,
315                                 userDefinedType,
316                                 null,
317                                 isMultiValued,
318                                 fieldTypes,
319                                 extendedProperties) {
320         }
321
322         // SMI V220 ctor.
323         internal SmiMetaData(
324                                 SqlDbType dbType, 
325                                 long maxLength,
326                                 byte precision, 
327                                 byte scale, 
328                                 long localeId, 
329                                 SqlCompareOptions compareOptions, 
330                                 Type userDefinedType,
331                                 string udtAssemblyQualifiedName,
332                                 bool isMultiValued,
333                                 IList<SmiExtendedMetaData> fieldTypes,
334                                 SmiMetaDataPropertyCollection extendedProperties) {
335
336             
337             Debug.Assert( IsSupportedDbType(dbType), "Invalid SqlDbType: " + dbType );
338
339             SetDefaultsForType( dbType );
340             
341             // 
342
343             
344             switch ( dbType ) {
345                 case SqlDbType.BigInt:
346                 case SqlDbType.Bit:
347                 case SqlDbType.DateTime:
348                 case SqlDbType.Float:
349                 case SqlDbType.Image:
350                 case SqlDbType.Int:
351                 case SqlDbType.Money:
352                 case SqlDbType.Real:
353                 case SqlDbType.SmallDateTime:
354                 case SqlDbType.SmallInt:
355                 case SqlDbType.SmallMoney:
356                 case SqlDbType.Timestamp:
357                 case SqlDbType.TinyInt:
358                 case SqlDbType.UniqueIdentifier:
359                 case SqlDbType.Variant:
360                 case SqlDbType.Xml:
361                 case SqlDbType.Date:
362                     break;
363                 case SqlDbType.Binary:
364                 case SqlDbType.VarBinary:
365                     _maxLength = maxLength;
366                     break;
367                 case SqlDbType.Char:
368                 case SqlDbType.NChar:
369                 case SqlDbType.NVarChar:
370                 case SqlDbType.VarChar:
371                     // locale and compare options are not validated until they get to the server
372                     _maxLength = maxLength;
373                     _localeId = localeId;
374                     _compareOptions = compareOptions;
375                     break;
376                 case SqlDbType.NText:
377                 case SqlDbType.Text:
378                     _localeId = localeId;
379                     _compareOptions = compareOptions;
380                     break;
381                 case SqlDbType.Decimal:
382                     Debug.Assert( MinPrecision <= precision && SqlDecimal.MaxPrecision >= precision, "Invalid precision: " + precision );
383                     Debug.Assert( MinScale <= scale && SqlDecimal.MaxScale >= scale, "Invalid scale: " + scale );
384                     Debug.Assert( scale <= precision, "Precision: " + precision + " greater than scale: " + scale );
385                     _precision = precision;
386                     _scale = scale;
387                     _maxLength = __maxLenFromPrecision[precision - 1];
388                     break;
389                 case SqlDbType.Udt:
390                     // Assert modified for VSFTDEVDIV479492 - for SqlParameter both userDefinedType and udtAssemblyQualifiedName
391                     // can be NULL, we are checking only maxLength if it will be used (i.e. userDefinedType is NULL)
392                     Debug.Assert((null != userDefinedType) || (0 <= maxLength || UnlimitedMaxLengthIndicator == maxLength),
393                             String.Format((IFormatProvider)null, "SmiMetaData.ctor: Udt name={0}, maxLength={1}", udtAssemblyQualifiedName, maxLength));
394                     // Type not validated until matched to a server.  Could be null if extended metadata supplies three-part name!
395                     _clrType = userDefinedType;
396                     if (null != userDefinedType) {
397                         _maxLength = SerializationHelperSql9.GetUdtMaxLength(userDefinedType);
398                     }
399                     else {
400                         _maxLength = maxLength;
401                     }
402                     _udtAssemblyQualifiedName = udtAssemblyQualifiedName;
403                     break;
404                 case SqlDbType.Structured:
405                     if (null != fieldTypes) {
406                         _fieldMetaData = (new List<SmiExtendedMetaData>(fieldTypes)).AsReadOnly();
407                     }
408                     _isMultiValued = isMultiValued;
409                     _maxLength = _fieldMetaData.Count;
410                     break;
411                 case SqlDbType.Time:
412                     Debug.Assert(MinScale <= scale && scale <= MaxTimeScale, "Invalid time scale: " + scale);
413                     _scale = scale;
414                     _maxLength = 5 - __maxVarTimeLenOffsetFromScale[scale];
415                     break;
416                 case SqlDbType.DateTime2:
417                     Debug.Assert(MinScale <= scale && scale <= MaxTimeScale, "Invalid time scale: " + scale);
418                     _scale = scale;
419                     _maxLength = 8 - __maxVarTimeLenOffsetFromScale[scale];
420                     break;
421                 case SqlDbType.DateTimeOffset:
422                     Debug.Assert(MinScale <= scale && scale <= MaxTimeScale, "Invalid time scale: " + scale);
423                     _scale = scale;
424                     _maxLength = 10 - __maxVarTimeLenOffsetFromScale[scale];
425                     break;
426                 default:
427                     Debug.Assert( false, "How in the world did we get here? :" + dbType );
428                     break;
429             }
430
431             if (null != extendedProperties) {
432                 extendedProperties.SetReadOnly();
433                 _extendedProperties = extendedProperties;
434             }
435
436             // properties and fields must meet the following conditions at this point:
437             //  1) not null
438             //  2) read only
439             //  3) same number of columns in each list (0 count acceptable for properties that are "unused")
440             Debug.Assert(null != _extendedProperties && _extendedProperties.IsReadOnly, "SmiMetaData.ctor: _extendedProperties is " + (null!=_extendedProperties?"writeable":"null"));
441             Debug.Assert(null != _fieldMetaData && _fieldMetaData.IsReadOnly, "SmiMetaData.ctor: _fieldMetaData is " + (null!=_fieldMetaData?"writeable":"null"));
442 #if DEBUG
443             ((SmiDefaultFieldsProperty)_extendedProperties[SmiPropertySelector.DefaultFields]).CheckCount(_fieldMetaData.Count);
444             ((SmiOrderProperty)_extendedProperties[SmiPropertySelector.SortOrder]).CheckCount(_fieldMetaData.Count);
445             ((SmiUniqueKeyProperty)_extendedProperties[SmiPropertySelector.UniqueKey]).CheckCount(_fieldMetaData.Count);
446 #endif
447         }
448
449
450         internal bool IsValidMaxLengthForCtorGivenType( SqlDbType dbType, long maxLength ) {
451             bool result = true;
452             switch( dbType ) {
453                 case SqlDbType.BigInt:
454                 case SqlDbType.Bit:
455                 case SqlDbType.DateTime:
456                 case SqlDbType.Float:
457                 case SqlDbType.Image:
458                 case SqlDbType.Int:
459                 case SqlDbType.Money:
460                 case SqlDbType.Real:
461                 case SqlDbType.SmallDateTime:
462                 case SqlDbType.SmallInt:
463                 case SqlDbType.SmallMoney:
464                 case SqlDbType.Timestamp:
465                 case SqlDbType.TinyInt:
466                 case SqlDbType.UniqueIdentifier:
467                 case SqlDbType.Variant:
468                 case SqlDbType.Xml:
469                 case SqlDbType.NText:
470                 case SqlDbType.Text:
471                 case SqlDbType.Decimal:
472                 case SqlDbType.Udt:
473                 case SqlDbType.Structured:  // 
474                 case SqlDbType.Date:
475                 case SqlDbType.Time:
476                 case SqlDbType.DateTime2:
477                 case SqlDbType.DateTimeOffset:
478                     break;
479                 case SqlDbType.Binary:
480                     result = 0 < maxLength && MaxBinaryLength >= maxLength;
481                     break;
482                 case SqlDbType.VarBinary:
483                     result = UnlimitedMaxLengthIndicator == maxLength || ( 0 < maxLength && MaxBinaryLength >= maxLength );
484                     break;
485                 case SqlDbType.Char:
486                     result = 0 < maxLength && MaxANSICharacters >= maxLength;
487                     break;
488                 case SqlDbType.NChar:
489                     result = 0 < maxLength && MaxUnicodeCharacters >= maxLength;
490                     break;
491                 case SqlDbType.NVarChar:
492                     result = UnlimitedMaxLengthIndicator == maxLength || ( 0 < maxLength && MaxUnicodeCharacters >= maxLength );
493                     break;
494                 case SqlDbType.VarChar:
495                     result = UnlimitedMaxLengthIndicator == maxLength || ( 0 < maxLength && MaxANSICharacters >= maxLength );
496                     break;
497                 default:
498                     Debug.Assert( false, "How in the world did we get here? :" + dbType );
499                     break;
500             }
501
502             return result;
503         }
504
505         // Sql-style compare options for character types.
506         internal SqlCompareOptions CompareOptions {
507             get {   
508                 return _compareOptions;
509             }
510         }
511
512         // LCID for type.  0 for non-character types.
513         internal long LocaleId {
514             get{
515                 return _localeId;
516             }
517         }
518
519         // Units of length depend on type.
520         //  NVarChar, NChar, NText: # of unicode characters
521         //  Everything else: # of bytes
522         internal long MaxLength {
523             get { 
524                 return _maxLength;
525             }
526         }
527
528         internal byte Precision {
529             get {
530                 return _precision;
531             }
532         }
533
534         internal byte Scale {
535             get {
536                 return _scale;
537             }
538         }
539
540         internal SqlDbType SqlDbType {
541             get {
542                 return _databaseType;
543             }
544         }
545
546         // Clr Type instance for user-defined types
547         internal Type Type {
548             get {
549                 // Fault-in UDT clr types on access if have assembly-qualified name
550                 if (null == _clrType && SqlDbType.Udt == _databaseType && _udtAssemblyQualifiedName != null) {
551                     _clrType = Type.GetType(_udtAssemblyQualifiedName, true);
552                 }
553                 return _clrType;
554             }
555         }
556
557         // Clr Type instance for user-defined types in cases where we don't want to throw if the assembly isn't available
558         internal Type TypeWithoutThrowing {
559             get {
560                 // Fault-in UDT clr types on access if have assembly-qualified name
561                 if (null == _clrType && SqlDbType.Udt == _databaseType && _udtAssemblyQualifiedName != null) {
562                     _clrType = Type.GetType(_udtAssemblyQualifiedName, false);
563                 }
564                 return _clrType;
565             }
566         }
567
568         internal string TypeName {
569             get { 
570                 string result = null;
571                 if (SqlDbType.Udt == _databaseType) {
572                     Debug.Assert(String.Empty == __typeNameByDatabaseType[(int)_databaseType], "unexpected udt?");
573                     result = Type.FullName;
574                 }
575                 else {
576                     result = __typeNameByDatabaseType[(int)_databaseType];
577                     Debug.Assert(null != result, "unknown type name?");
578                 }
579                 return result;
580             }
581         }
582
583         internal string AssemblyQualifiedName {
584             get {
585                 string result = null;
586                 if (SqlDbType.Udt == _databaseType) {
587                     // Fault-in assembly-qualified name if type is available
588                     if (_udtAssemblyQualifiedName == null && _clrType != null) {
589                         _udtAssemblyQualifiedName = _clrType.AssemblyQualifiedName;
590                     }
591                     result = _udtAssemblyQualifiedName;
592                 }
593                 return result;
594             }
595         }
596
597         internal bool IsMultiValued {
598             get {
599                 return _isMultiValued;
600             }
601         }
602
603         // Returns read-only list of field metadata
604         internal IList<SmiExtendedMetaData> FieldMetaData {
605             get {
606                 return _fieldMetaData;
607             }
608         }
609
610         // Returns read-only list of extended properties
611         internal SmiMetaDataPropertyCollection ExtendedProperties {
612             get {
613                 return _extendedProperties;
614             }
615         }
616
617         internal static bool IsSupportedDbType(SqlDbType dbType) {
618             // Hole in SqlDbTypes between Xml and Udt for non-WinFS scenarios.
619             return (SqlDbType.BigInt <= dbType && SqlDbType.Xml >= dbType) || 
620                     (SqlDbType.Udt <= dbType && SqlDbType.DateTimeOffset >= dbType);
621         }
622
623         // Only correct access point for defaults per SqlDbType.
624         internal static SmiMetaData GetDefaultForType( SqlDbType dbType ) {
625                 Debug.Assert( IsSupportedDbType(dbType), "Unsupported SqlDbtype: " + dbType);
626
627                 return __defaultValues[(int)dbType];
628         }
629
630         // Private constructor used only to initialize default instance array elements.
631         // DO NOT EXPOSE OUTSIDE THIS CLASS!
632         private SmiMetaData (
633                                 SqlDbType         sqlDbType,
634                                 long              maxLength,
635                                 byte              precision,
636                                 byte              scale,
637                                 SqlCompareOptions compareOptions) {
638             _databaseType      = sqlDbType;
639             _maxLength         = maxLength;
640             _precision         = precision;
641             _scale             = scale;
642             _compareOptions    = compareOptions;
643
644             // defaults are the same for all types for the following attributes.
645             _localeId           = 0; 
646             _clrType            = null;
647             _isMultiValued      = false;
648             _fieldMetaData      = __emptyFieldList;
649             _extendedProperties = SmiMetaDataPropertyCollection.EmptyInstance;
650         }
651
652         // static array of default-valued metadata ordered by corresponding SqlDbType.
653         // NOTE: INDEXED BY SqlDbType ENUM!  MUST UPDATE THIS ARRAY WHEN UPDATING SqlDbType!
654         //   ONLY ACCESS THIS GLOBAL FROM GetDefaultForType!
655         private static SmiMetaData[] __defaultValues =
656             {
657                 DefaultBigInt,                 // SqlDbType.BigInt
658                 DefaultBinary,                 // SqlDbType.Binary
659                 DefaultBit,                    // SqlDbType.Bit
660                 DefaultChar_NoCollation,       // SqlDbType.Char
661                 DefaultDateTime,               // SqlDbType.DateTime
662                 DefaultDecimal,                // SqlDbType.Decimal
663                 DefaultFloat,                  // SqlDbType.Float
664                 DefaultImage,                  // SqlDbType.Image
665                 DefaultInt,                    // SqlDbType.Int
666                 DefaultMoney,                  // SqlDbType.Money
667                 DefaultNChar_NoCollation,      // SqlDbType.NChar
668                 DefaultNText_NoCollation,      // SqlDbType.NText
669                 DefaultNVarChar_NoCollation,   // SqlDbType.NVarChar
670                 DefaultReal,                   // SqlDbType.Real
671                 DefaultUniqueIdentifier,       // SqlDbType.UniqueIdentifier
672                 DefaultSmallDateTime,          // SqlDbType.SmallDateTime
673                 DefaultSmallInt,               // SqlDbType.SmallInt
674                 DefaultSmallMoney,             // SqlDbType.SmallMoney
675                 DefaultText_NoCollation,       // SqlDbType.Text
676                 DefaultTimestamp,              // SqlDbType.Timestamp
677                 DefaultTinyInt,                // SqlDbType.TinyInt
678                 DefaultVarBinary,              // SqlDbType.VarBinary
679                 DefaultVarChar_NoCollation,    // SqlDbType.VarChar
680                 DefaultVariant,                // SqlDbType.Variant
681                 DefaultNVarChar_NoCollation,   // Placeholder for value 24
682                 DefaultXml,                    // SqlDbType.Xml
683                 DefaultNVarChar_NoCollation,   // Placeholder for value 26
684                 DefaultNVarChar_NoCollation,   // Placeholder for value 27
685                 DefaultNVarChar_NoCollation,   // Placeholder for value 28
686                 DefaultUdt_NoType,             // Generic Udt 
687                 DefaultStructured,             // Generic structured type
688                 DefaultDate,                   // SqlDbType.Date
689                 DefaultTime,                   // SqlDbType.Time
690                 DefaultDateTime2,              // SqlDbType.DateTime2
691                 DefaultDateTimeOffset,         // SqlDbType.DateTimeOffset
692             };
693
694         // static array of type names ordered by corresponding SqlDbType.
695         // NOTE: INDEXED BY SqlDbType ENUM!  MUST UPDATE THIS ARRAY WHEN UPDATING SqlDbType!
696         //   ONLY ACCESS THIS GLOBAL FROM get_TypeName!
697         private static string[] __typeNameByDatabaseType =
698             {
699                 "bigint",               // SqlDbType.BigInt
700                 "binary",               // SqlDbType.Binary
701                 "bit",                  // SqlDbType.Bit
702                 "char",                 // SqlDbType.Char
703                 "datetime",             // SqlDbType.DateTime
704                 "decimal",              // SqlDbType.Decimal
705                 "float",                // SqlDbType.Float
706                 "image",                // SqlDbType.Image
707                 "int",                  // SqlDbType.Int
708                 "money",                // SqlDbType.Money
709                 "nchar",                // SqlDbType.NChar
710                 "ntext",                // SqlDbType.NText
711                 "nvarchar",             // SqlDbType.NVarChar
712                 "real",                 // SqlDbType.Real
713                 "uniqueidentifier",     // SqlDbType.UniqueIdentifier
714                 "smalldatetime",        // SqlDbType.SmallDateTime
715                 "smallint",             // SqlDbType.SmallInt
716                 "smallmoney",           // SqlDbType.SmallMoney
717                 "text",                 // SqlDbType.Text
718                 "timestamp",            // SqlDbType.Timestamp
719                 "tinyint",              // SqlDbType.TinyInt
720                 "varbinary",            // SqlDbType.VarBinary
721                 "varchar",              // SqlDbType.VarChar
722                 "sql_variant",          // SqlDbType.Variant
723                 null,                   // placeholder for 24
724                 "xml",                  // SqlDbType.Xml
725                 null,                   // placeholder for 26
726                 null,                   // placeholder for 27
727                 null,                   // placeholder for 28
728                 String.Empty,           // SqlDbType.Udt  -- get type name from Type.FullName instead.
729                 String.Empty,           // Structured types have user-defined type names.
730                 "date",                 // SqlDbType.Date
731                 "time",                 // SqlDbType.Time
732                 "datetime2",            // SqlDbType.DateTime2
733                 "datetimeoffset",       // SqlDbType.DateTimeOffset
734             };
735
736         // Internal setter to be used by constructors only!  Modifies state!
737         private void SetDefaultsForType( SqlDbType dbType )
738             {
739                 SmiMetaData smdDflt = GetDefaultForType( dbType );
740                 _databaseType = dbType;
741                 _maxLength = smdDflt.MaxLength;
742                 _precision = smdDflt.Precision;
743                 _scale = smdDflt.Scale;
744                 _localeId = smdDflt.LocaleId;
745                 _compareOptions = smdDflt.CompareOptions;
746                 _clrType = null;
747                 _isMultiValued = smdDflt._isMultiValued;
748                 _fieldMetaData = smdDflt._fieldMetaData;            // This is ok due to immutability
749                 _extendedProperties = smdDflt._extendedProperties;  // This is ok due to immutability
750             }
751
752         internal string TraceString() {
753             return TraceString(0);
754         }
755         virtual internal string TraceString(int indent) {
756             string indentStr = new String(' ', indent);
757             string fields = String.Empty;
758             if (null != _fieldMetaData) {
759                 foreach(SmiMetaData fieldMd in _fieldMetaData) {
760                     fields = String.Format(CultureInfo.InvariantCulture, 
761                                 "{0}{1}\n\t", fields, fieldMd.TraceString(indent+5));
762                 }
763             }
764
765             string properties = String.Empty;
766             if (null != _extendedProperties) {
767                 foreach(SmiMetaDataProperty property in _extendedProperties.Values) {
768                     properties = String.Format(CultureInfo.InvariantCulture, 
769                                 "{0}{1}                   {2}\n\t", properties, indentStr, property.TraceString());
770                 }
771             }
772
773             return String.Format(CultureInfo.InvariantCulture, "\n\t"
774                                +"{0}            SqlDbType={1:g}\n\t"
775                                +"{0}            MaxLength={2:d}\n\t"
776                                +"{0}            Precision={3:d}\n\t"
777                                +"{0}                Scale={4:d}\n\t"
778                                +"{0}             LocaleId={5:x}\n\t"
779                                +"{0}       CompareOptions={6:g}\n\t"
780                                +"{0}                 Type={7}\n\t"
781                                +"{0}          MultiValued={8}\n\t"
782                                +"{0}               fields=\n\t{9}"
783                                +"{0}           properties=\n\t{10}",
784                                 indentStr,
785                                 SqlDbType,
786                                 MaxLength,
787                                 Precision,
788                                 Scale,
789                                 LocaleId,
790                                 CompareOptions,
791                                 (null!=Type) ? Type.ToString():"<null>",
792                                 IsMultiValued,
793                                 fields,
794                                 properties);
795
796         }
797     }
798
799
800     // SmiExtendedMetaData
801     //
802     //  Adds server-specific type extension information to base metadata, but still portable across a specific server.
803     //
804     internal class SmiExtendedMetaData : SmiMetaData {
805
806         private string _name;           // context-dependant identifier, ie. parameter name for parameters, column name for columns, etc.
807
808         // three-part name for typed xml schema and for udt names
809         private string _typeSpecificNamePart1;
810         private string _typeSpecificNamePart2;
811         private string _typeSpecificNamePart3;
812
813         [ObsoleteAttribute( "Not supported as of SMI v2.  Will be removed when v1 support dropped. Use ctor without columns param." )]
814         internal SmiExtendedMetaData(
815                                         SqlDbType dbType, 
816                                         long maxLength,
817                                         byte precision, 
818                                         byte scale, 
819                                         long localeId, 
820                                         SqlCompareOptions compareOptions, 
821                                         Type userDefinedType, 
822                                         SmiMetaData[] columns, 
823                                         string name, 
824                                         string typeSpecificNamePart1, 
825                                         string typeSpecificNamePart2, 
826                                         string typeSpecificNamePart3) :
827                                 // Implement as calling the new ctor
828                                 this( 
829                                         dbType, 
830                                         maxLength, 
831                                         precision, 
832                                         scale, 
833                                         localeId, 
834                                         compareOptions, 
835                                         userDefinedType, 
836                                         name, 
837                                         typeSpecificNamePart1, 
838                                         typeSpecificNamePart2, 
839                                         typeSpecificNamePart3 ) {
840             Debug.Assert( null == columns, "Row types not supported" );
841         }
842
843         internal SmiExtendedMetaData(
844                                         SqlDbType dbType, 
845                                         long maxLength,
846                                         byte precision, 
847                                         byte scale, 
848                                         long localeId, 
849                                         SqlCompareOptions compareOptions, 
850                                         Type userDefinedType, 
851                                         string name, 
852                                         string typeSpecificNamePart1, 
853                                         string typeSpecificNamePart2, 
854                                         string typeSpecificNamePart3) :
855                                     this(
856                                         dbType,
857                                         maxLength,
858                                         precision,
859                                         scale,
860                                         localeId,
861                                         compareOptions,
862                                         userDefinedType,
863                                         false,
864                                         null,
865                                         null,
866                                         name,
867                                         typeSpecificNamePart1,
868                                         typeSpecificNamePart2,
869                                         typeSpecificNamePart3) {
870         }
871
872         // SMI V200 ctor.
873         internal SmiExtendedMetaData(
874                                         SqlDbType dbType,
875                                         long maxLength,
876                                         byte precision,
877                                         byte scale,
878                                         long localeId,
879                                         SqlCompareOptions compareOptions,
880                                         Type userDefinedType,
881                                         bool isMultiValued,
882                                         IList<SmiExtendedMetaData> fieldMetaData,
883                                         SmiMetaDataPropertyCollection extendedProperties,
884                                         string name,
885                                         string typeSpecificNamePart1,
886                                         string typeSpecificNamePart2,
887                                         string typeSpecificNamePart3) :
888                                 this(   dbType,
889                                         maxLength,
890                                         precision,
891                                         scale,
892                                         localeId,
893                                         compareOptions,
894                                         userDefinedType,
895                                         null,
896                                         isMultiValued,
897                                         fieldMetaData,
898                                         extendedProperties,
899                                         name,
900                                         typeSpecificNamePart1,
901                                         typeSpecificNamePart2,
902                                         typeSpecificNamePart3) {
903         }
904
905         // SMI V220 ctor.
906         internal SmiExtendedMetaData(
907                                         SqlDbType dbType, 
908                                         long maxLength,
909                                         byte precision, 
910                                         byte scale, 
911                                         long localeId, 
912                                         SqlCompareOptions compareOptions, 
913                                         Type userDefinedType, 
914                                         string udtAssemblyQualifiedName,
915                                         bool isMultiValued,
916                                         IList<SmiExtendedMetaData> fieldMetaData,
917                                         SmiMetaDataPropertyCollection extendedProperties,
918                                         string name, 
919                                         string typeSpecificNamePart1, 
920                                         string typeSpecificNamePart2, 
921                                         string typeSpecificNamePart3 ):
922                                     base( dbType,
923                                         maxLength, 
924                                         precision, 
925                                         scale, 
926                                         localeId, 
927                                         compareOptions, 
928                                         userDefinedType,
929                                         udtAssemblyQualifiedName,
930                                         isMultiValued,
931                                         fieldMetaData,
932                                         extendedProperties) {
933             Debug.Assert(null == name || MaxNameLength >= name.Length, "Name is too long");
934             
935             _name = name;
936             _typeSpecificNamePart1 = typeSpecificNamePart1;
937             _typeSpecificNamePart2 = typeSpecificNamePart2;
938             _typeSpecificNamePart3 = typeSpecificNamePart3;
939         }
940
941         internal string Name {
942             get {
943                 return _name;
944             }
945         }
946
947         internal string TypeSpecificNamePart1 {
948             get {
949                 return _typeSpecificNamePart1;
950             }
951         }
952
953         internal string TypeSpecificNamePart2 {
954             get {
955                 return _typeSpecificNamePart2;
956             }
957         }
958
959         internal string TypeSpecificNamePart3 {
960             get {
961                 return _typeSpecificNamePart3;
962             }
963         }
964
965         internal override string TraceString(int indent) {
966             return String.Format(CultureInfo.InvariantCulture, 
967                                  "{2}                 Name={0}"
968                                 +"{1}"
969                                 +"{2}TypeSpecificNamePart1='{3}'\n\t"
970                                 +"{2}TypeSpecificNamePart2='{4}'\n\t"
971                                 +"{2}TypeSpecificNamePart3='{5}'\n\t",
972                                 (null!=_name) ? _name : "<null>",
973                                 base.TraceString(indent),
974                                 new String(' ', indent),
975                                 (null!=TypeSpecificNamePart1) ? TypeSpecificNamePart1:"<null>",
976                                 (null!=TypeSpecificNamePart2) ? TypeSpecificNamePart2:"<null>",
977                                 (null!=TypeSpecificNamePart3) ? TypeSpecificNamePart3:"<null>");
978         }
979     }
980
981
982     // SmiParameterMetaData
983     //
984     //  MetaData class to send parameter definitions to server.
985     //  Sealed because we don't need to derive from it yet.
986     // IMPORTANT DEVNOTE: This class is being used for parameter encryption functionality, to get the type_info TDS object from SqlParameter.
987     // Please consider impact to that when changing this class. Refer to the callers of SqlParameter.GetMetadataForTypeInfo().
988     internal sealed class SmiParameterMetaData : SmiExtendedMetaData {
989
990         private ParameterDirection _direction;
991
992         [ObsoleteAttribute( "Not supported as of SMI v2.  Will be removed when v1 support dropped. Use ctor without columns param." )]
993         internal SmiParameterMetaData( 
994                                         SqlDbType dbType, 
995                                         long maxLength, 
996                                         byte precision, 
997                                         byte scale, 
998                                         long  localeId, 
999                                         SqlCompareOptions compareOptions, 
1000                                         Type userDefinedType, 
1001                                         SmiMetaData[] columns, 
1002                                         string name, 
1003                                         string typeSpecificNamePart1, 
1004                                         string typeSpecificNamePart2, 
1005                                         string typeSpecificNamePart3,
1006                                         ParameterDirection direction) :
1007                                 // Implement as calling the new ctor
1008                                 this ( 
1009                                         dbType, 
1010                                         maxLength, 
1011                                         precision, 
1012                                         scale, 
1013                                         localeId, 
1014                                         compareOptions, 
1015                                         userDefinedType, 
1016                                         name, 
1017                                         typeSpecificNamePart1, 
1018                                         typeSpecificNamePart2, 
1019                                         typeSpecificNamePart3,
1020                                         direction ) {
1021             Debug.Assert( null == columns, "Row types not supported" );
1022         }
1023
1024         // SMI V100 (aka V3) ctor
1025         internal SmiParameterMetaData( 
1026                                         SqlDbType dbType, 
1027                                         long maxLength, 
1028                                         byte precision, 
1029                                         byte scale, 
1030                                         long  localeId, 
1031                                         SqlCompareOptions compareOptions, 
1032                                         Type userDefinedType, 
1033                                         string name, 
1034                                         string typeSpecificNamePart1, 
1035                                         string typeSpecificNamePart2, 
1036                                         string typeSpecificNamePart3,
1037                                         ParameterDirection direction) :
1038                                     this(
1039                                         dbType,
1040                                         maxLength, 
1041                                         precision, 
1042                                         scale, 
1043                                         localeId, 
1044                                         compareOptions, 
1045                                         userDefinedType,
1046                                         false,
1047                                         null,
1048                                         null,
1049                                         name, 
1050                                         typeSpecificNamePart1, 
1051                                         typeSpecificNamePart2,
1052                                         typeSpecificNamePart3,
1053                                         direction) {
1054         }
1055                                         
1056         // SMI V200 ctor.
1057         internal SmiParameterMetaData( 
1058                                         SqlDbType dbType, 
1059                                         long maxLength, 
1060                                         byte precision, 
1061                                         byte scale, 
1062                                         long  localeId, 
1063                                         SqlCompareOptions compareOptions, 
1064                                         Type userDefinedType, 
1065                                         bool isMultiValued,
1066                                         IList<SmiExtendedMetaData> fieldMetaData,
1067                                         SmiMetaDataPropertyCollection extendedProperties,
1068                                         string name, 
1069                                         string typeSpecificNamePart1, 
1070                                         string typeSpecificNamePart2, 
1071                                         string typeSpecificNamePart3,
1072                                         ParameterDirection direction) :
1073                                     this( dbType, 
1074                                         maxLength, 
1075                                         precision, 
1076                                         scale, 
1077                                         localeId, 
1078                                         compareOptions, 
1079                                         userDefinedType, 
1080                                         null,
1081                                         isMultiValued,
1082                                         fieldMetaData,
1083                                         extendedProperties,
1084                                         name, 
1085                                         typeSpecificNamePart1, 
1086                                         typeSpecificNamePart2,
1087                                         typeSpecificNamePart3,
1088                                         direction) {
1089         }
1090
1091         // SMI V220 ctor.
1092         internal SmiParameterMetaData( 
1093                                         SqlDbType dbType, 
1094                                         long maxLength, 
1095                                         byte precision, 
1096                                         byte scale, 
1097                                         long  localeId, 
1098                                         SqlCompareOptions compareOptions, 
1099                                         Type userDefinedType,
1100                                         string udtAssemblyQualifiedName,
1101                                         bool isMultiValued,
1102                                         IList<SmiExtendedMetaData> fieldMetaData,
1103                                         SmiMetaDataPropertyCollection extendedProperties,
1104                                         string name, 
1105                                         string typeSpecificNamePart1, 
1106                                         string typeSpecificNamePart2, 
1107                                         string typeSpecificNamePart3,
1108                                         ParameterDirection direction) :
1109                                     base( dbType, 
1110                                         maxLength, 
1111                                         precision, 
1112                                         scale, 
1113                                         localeId, 
1114                                         compareOptions, 
1115                                         userDefinedType, 
1116                                         udtAssemblyQualifiedName,
1117                                         isMultiValued,
1118                                         fieldMetaData,
1119                                         extendedProperties,
1120                                         name, 
1121                                         typeSpecificNamePart1, 
1122                                         typeSpecificNamePart2,
1123                                         typeSpecificNamePart3) {
1124             Debug.Assert( ParameterDirection.Input == direction
1125                        || ParameterDirection.Output == direction 
1126                        || ParameterDirection.InputOutput == direction 
1127                        || ParameterDirection.ReturnValue == direction, "Invalid direction: " + direction );
1128             _direction = direction;
1129         }
1130
1131         internal ParameterDirection Direction {
1132             get {
1133                 return _direction;
1134             }
1135         }
1136
1137         internal override string TraceString(int indent) {
1138             return String.Format(CultureInfo.InvariantCulture, "{0}"
1139                                 +"{1}            Direction={2:g}\n\t",
1140                                 base.TraceString(indent),
1141                                 new String(' ', indent),
1142                                 Direction);
1143         }
1144     }
1145
1146
1147     // SmiStorageMetaData
1148     //
1149     //  This class represents the addition of storage-level attributes to the heirarchy (i.e. attributes from 
1150     //  underlying table, source variables, or whatever).
1151     //
1152     //  Most values use Null (either IsNullable == true or CLR null) to indicate "Not specified" state.  Selection
1153     //  of which values allow "not specified" determined by backward compatibility.
1154     //
1155     //  Maps approximately to TDS' COLMETADATA token with TABNAME and part of COLINFO thrown in.
1156     internal class SmiStorageMetaData : SmiExtendedMetaData {
1157
1158         // AllowsDBNull is the only value required to be specified.
1159         private bool        _allowsDBNull;      // could the column return nulls? equivalent to TDS's IsNullable bit
1160         private string      _serverName;        // underlying column's server
1161         private string      _catalogName;       // underlying column's database
1162         private string      _schemaName;        // underlying column's schema
1163         private string      _tableName;         // underlying column's table
1164         private string      _columnName;        // underlying column's name
1165         private SqlBoolean  _isKey;             // Is this one of a set of key columns that uniquely identify an underlying table?
1166         private bool        _isIdentity;        // Is this from an identity column
1167         private bool        _isColumnSet;       // Is this column the XML representation of a columnset?
1168
1169         [ObsoleteAttribute( "Not supported as of SMI v2.  Will be removed when v1 support dropped. Use ctor without columns param." )]
1170         internal SmiStorageMetaData(
1171                                         SqlDbType dbType, 
1172                                         long maxLength, 
1173                                         byte precision, 
1174                                         byte scale, 
1175                                         long localeId, 
1176                                         SqlCompareOptions compareOptions,
1177                                         Type userDefinedType, 
1178                                         SmiMetaData[] columns, 
1179                                         string name, 
1180                                         string typeSpecificNamePart1, 
1181                                         string typeSpecificNamePart2, 
1182                                         string typeSpecificNamePart3,
1183                                         bool allowsDBNull, 
1184                                         string serverName, 
1185                                         string catalogName, 
1186                                         string schemaName, 
1187                                         string tableName, 
1188                                         string columnName, 
1189                                         SqlBoolean isKey, 
1190                                         bool isIdentity) :
1191                                 // Implement as calling the new ctor
1192                                 this ( 
1193                                         dbType, 
1194                                         maxLength, 
1195                                         precision, 
1196                                         scale, 
1197                                         localeId, 
1198                                         compareOptions, 
1199                                         userDefinedType, 
1200                                         name, 
1201                                         typeSpecificNamePart1, 
1202                                         typeSpecificNamePart2, 
1203                                         typeSpecificNamePart3,
1204                                         allowsDBNull,
1205                                         serverName,
1206                                         catalogName,
1207                                         schemaName,
1208                                         tableName,
1209                                         columnName,
1210                                         isKey,
1211                                         isIdentity) {
1212             Debug.Assert( null == columns, "Row types not supported" );
1213         }
1214
1215         internal SmiStorageMetaData(
1216                                         SqlDbType dbType, 
1217                                         long maxLength, 
1218                                         byte precision, 
1219                                         byte scale, 
1220                                         long localeId, 
1221                                         SqlCompareOptions compareOptions,
1222                                         Type userDefinedType, 
1223                                         string name, 
1224                                         string typeSpecificNamePart1, 
1225                                         string typeSpecificNamePart2, 
1226                                         string typeSpecificNamePart3,
1227                                         bool allowsDBNull, 
1228                                         string serverName, 
1229                                         string catalogName, 
1230                                         string schemaName, 
1231                                         string tableName, 
1232                                         string columnName, 
1233                                         SqlBoolean isKey, 
1234                                         bool isIdentity) :
1235                                     this(dbType, 
1236                                         maxLength, 
1237                                         precision, 
1238                                         scale, 
1239                                         localeId, 
1240                                         compareOptions,
1241                                         userDefinedType,
1242                                         false,
1243                                         null,
1244                                         null,
1245                                         name, 
1246                                         typeSpecificNamePart1, 
1247                                         typeSpecificNamePart2,
1248                                         typeSpecificNamePart3,
1249                                         allowsDBNull,
1250                                         serverName,
1251                                         catalogName,
1252                                         schemaName,
1253                                         tableName,
1254                                         columnName,
1255                                         isKey,
1256                                         isIdentity) {
1257         }
1258                                         
1259         // SMI V200 ctor.
1260         internal SmiStorageMetaData(
1261                                         SqlDbType dbType, 
1262                                         long maxLength, 
1263                                         byte precision, 
1264                                         byte scale, 
1265                                         long localeId, 
1266                                         SqlCompareOptions compareOptions,
1267                                         Type userDefinedType, 
1268                                         bool isMultiValued,
1269                                         IList<SmiExtendedMetaData> fieldMetaData,
1270                                         SmiMetaDataPropertyCollection extendedProperties,
1271                                         string name, 
1272                                         string typeSpecificNamePart1, 
1273                                         string typeSpecificNamePart2, 
1274                                         string typeSpecificNamePart3,
1275                                         bool allowsDBNull, 
1276                                         string serverName, 
1277                                         string catalogName, 
1278                                         string schemaName, 
1279                                         string tableName, 
1280                                         string columnName, 
1281                                         SqlBoolean isKey, 
1282                                         bool isIdentity) :
1283                                 this(   dbType, 
1284                                         maxLength, 
1285                                         precision, 
1286                                         scale, 
1287                                         localeId, 
1288                                         compareOptions, 
1289                                         userDefinedType, 
1290                                         null,
1291                                         isMultiValued,
1292                                         fieldMetaData,
1293                                         extendedProperties,
1294                                         name, 
1295                                         typeSpecificNamePart1, 
1296                                         typeSpecificNamePart2,
1297                                         typeSpecificNamePart3,
1298                                         allowsDBNull,
1299                                         serverName,
1300                                         catalogName,
1301                                         schemaName,
1302                                         tableName,
1303                                         columnName,
1304                                         isKey,
1305                                         isIdentity,
1306                                         false) {
1307         }
1308
1309         // SMI V220 ctor.
1310         internal SmiStorageMetaData(
1311                                         SqlDbType dbType, 
1312                                         long maxLength, 
1313                                         byte precision, 
1314                                         byte scale, 
1315                                         long localeId, 
1316                                         SqlCompareOptions compareOptions,
1317                                         Type userDefinedType,
1318                                         string udtAssemblyQualifiedName,
1319                                         bool isMultiValued,
1320                                         IList<SmiExtendedMetaData> fieldMetaData,
1321                                         SmiMetaDataPropertyCollection extendedProperties,
1322                                         string name, 
1323                                         string typeSpecificNamePart1, 
1324                                         string typeSpecificNamePart2, 
1325                                         string typeSpecificNamePart3,
1326                                         bool allowsDBNull, 
1327                                         string serverName, 
1328                                         string catalogName, 
1329                                         string schemaName, 
1330                                         string tableName, 
1331                                         string columnName, 
1332                                         SqlBoolean isKey, 
1333                                         bool isIdentity,
1334                                         bool isColumnSet) :
1335                                     base( dbType, 
1336                                         maxLength, 
1337                                         precision, 
1338                                         scale, 
1339                                         localeId, 
1340                                         compareOptions, 
1341                                         userDefinedType,
1342                                         udtAssemblyQualifiedName,
1343                                         isMultiValued,
1344                                         fieldMetaData,
1345                                         extendedProperties,
1346                                         name, 
1347                                         typeSpecificNamePart1, 
1348                                         typeSpecificNamePart2,
1349                                         typeSpecificNamePart3) {
1350             _allowsDBNull = allowsDBNull;
1351             _serverName = serverName;
1352             _catalogName = catalogName;
1353             _schemaName = schemaName;
1354             _tableName = tableName;
1355             _columnName = columnName;
1356             _isKey = isKey;
1357             _isIdentity = isIdentity;
1358             _isColumnSet = isColumnSet;
1359         }
1360
1361         internal bool AllowsDBNull {
1362             get {
1363                 return _allowsDBNull;
1364             }
1365         }
1366
1367         internal string ServerName {
1368             get {
1369                 return _serverName;
1370             }
1371         }
1372
1373         internal string CatalogName {
1374             get {
1375                 return _catalogName;
1376             }
1377         }
1378
1379         internal string SchemaName {
1380             get {
1381                 return _schemaName;
1382             }
1383         }
1384
1385         internal string TableName {
1386             get {
1387                 return _tableName;
1388             }
1389         }
1390
1391         internal string ColumnName {
1392             get {
1393                 return _columnName;
1394             }
1395         }
1396
1397         internal SqlBoolean IsKey {
1398             get {
1399                 return _isKey;
1400             }
1401         }
1402
1403         internal bool IsIdentity {
1404             get {
1405                 return _isIdentity;
1406             }
1407         }
1408
1409         internal bool IsColumnSet {
1410             get {
1411                 return _isColumnSet;
1412             }
1413         }
1414
1415         internal override string TraceString(int indent) {
1416             return String.Format(CultureInfo.InvariantCulture, "{0}"
1417                                 +"{1}         AllowsDBNull={2}\n\t"
1418                                 +"{1}           ServerName='{3}'\n\t"
1419                                 +"{1}          CatalogName='{4}'\n\t"
1420                                 +"{1}           SchemaName='{5}'\n\t"
1421                                 +"{1}            TableName='{6}'\n\t"
1422                                 +"{1}           ColumnName='{7}'\n\t"
1423                                 +"{1}                IsKey={8}\n\t"
1424                                 +"{1}           IsIdentity={9}\n\t",
1425                                 base.TraceString(indent),
1426                                 new String(' ', indent),
1427                                 AllowsDBNull,
1428                                 (null!=ServerName) ? ServerName:"<null>",
1429                                 (null!=CatalogName) ? CatalogName:"<null>",
1430                                 (null!=SchemaName) ? SchemaName:"<null>",
1431                                 (null!=TableName) ? TableName:"<null>",
1432                                 (null!=ColumnName) ? ColumnName:"<null>",
1433                                 IsKey,
1434                                 IsIdentity);
1435         }
1436
1437     }
1438
1439     // SmiQueryMetaData
1440     //
1441     //  Adds Query-specific attributes.
1442     //  Sealed since we don't need to extend it for now.
1443     //  Maps to full COLMETADATA + COLINFO + TABNAME tokens on TDS.
1444     internal class SmiQueryMetaData : SmiStorageMetaData {
1445
1446         private bool _isReadOnly;
1447         private SqlBoolean _isExpression;
1448         private SqlBoolean _isAliased;
1449         private SqlBoolean _isHidden;
1450
1451         [ObsoleteAttribute( "Not supported as of SMI v2.  Will be removed when v1 support dropped. Use ctor without columns param." )]
1452         internal SmiQueryMetaData(
1453                                         SqlDbType dbType, 
1454                                         long maxLength, 
1455                                         byte precision, 
1456                                         byte scale, 
1457                                         long localeId, 
1458                                         SqlCompareOptions compareOptions,
1459                                         Type userDefinedType, 
1460                                         SmiMetaData[] columns, 
1461                                         string name, 
1462                                         string typeSpecificNamePart1, 
1463                                         string typeSpecificNamePart2, 
1464                                         string typeSpecificNamePart3,
1465                                         bool allowsDBNull, 
1466                                         string serverName, 
1467                                         string catalogName, 
1468                                         string schemaName, 
1469                                         string tableName, 
1470                                         string columnName, 
1471                                         SqlBoolean isKey, 
1472                                         bool isIdentity, 
1473                                         bool isReadOnly, 
1474                                         SqlBoolean isExpression, 
1475                                         SqlBoolean isAliased, 
1476                                         SqlBoolean isHidden ) :
1477                                 // Implement as calling the new ctor
1478                                 this ( 
1479                                         dbType, 
1480                                         maxLength, 
1481                                         precision, 
1482                                         scale, 
1483                                         localeId, 
1484                                         compareOptions, 
1485                                         userDefinedType, 
1486                                         name, 
1487                                         typeSpecificNamePart1, 
1488                                         typeSpecificNamePart2, 
1489                                         typeSpecificNamePart3,
1490                                         allowsDBNull,
1491                                         serverName,
1492                                         catalogName,
1493                                         schemaName,
1494                                         tableName,
1495                                         columnName,
1496                                         isKey,
1497                                         isIdentity,
1498                                         isReadOnly,
1499                                         isExpression,
1500                                         isAliased,
1501                                         isHidden ) {
1502             Debug.Assert( null == columns, "Row types not supported" );
1503         }
1504
1505         internal SmiQueryMetaData( SqlDbType dbType,
1506                                         long maxLength, 
1507                                         byte precision, 
1508                                         byte scale, 
1509                                         long localeId, 
1510                                         SqlCompareOptions compareOptions,
1511                                         Type userDefinedType, 
1512                                         string name,
1513                                         string typeSpecificNamePart1, 
1514                                         string typeSpecificNamePart2, 
1515                                         string typeSpecificNamePart3,
1516                                         bool allowsDBNull, 
1517                                         string serverName, 
1518                                         string catalogName, 
1519                                         string schemaName,
1520                                         string tableName, 
1521                                         string columnName, 
1522                                         SqlBoolean isKey,
1523                                         bool isIdentity, 
1524                                         bool isReadOnly, 
1525                                         SqlBoolean isExpression, 
1526                                         SqlBoolean isAliased, 
1527                                         SqlBoolean isHidden ) :
1528                                     this( dbType,
1529                                         maxLength, 
1530                                         precision, 
1531                                         scale, 
1532                                         localeId, 
1533                                         compareOptions, 
1534                                         userDefinedType, 
1535                                         false,
1536                                         null,
1537                                         null,
1538                                         name,
1539                                         typeSpecificNamePart1, 
1540                                         typeSpecificNamePart2,
1541                                         typeSpecificNamePart3,
1542                                         allowsDBNull, 
1543                                         serverName, 
1544                                         catalogName, 
1545                                         schemaName, 
1546                                         tableName, 
1547                                         columnName, 
1548                                         isKey, 
1549                                         isIdentity,
1550                                         isReadOnly,
1551                                         isExpression,
1552                                         isAliased,
1553                                         isHidden) {
1554         }
1555
1556         // SMI V200 ctor.
1557         internal SmiQueryMetaData( SqlDbType dbType,
1558                                         long maxLength, 
1559                                         byte precision, 
1560                                         byte scale, 
1561                                         long localeId, 
1562                                         SqlCompareOptions compareOptions,
1563                                         Type userDefinedType, 
1564                                         bool isMultiValued,
1565                                         IList<SmiExtendedMetaData> fieldMetaData,
1566                                         SmiMetaDataPropertyCollection extendedProperties,
1567                                         string name,
1568                                         string typeSpecificNamePart1, 
1569                                         string typeSpecificNamePart2, 
1570                                         string typeSpecificNamePart3,
1571                                         bool allowsDBNull, 
1572                                         string serverName, 
1573                                         string catalogName, 
1574                                         string schemaName,
1575                                         string tableName, 
1576                                         string columnName, 
1577                                         SqlBoolean isKey,
1578                                         bool isIdentity,
1579                                         bool isReadOnly, 
1580                                         SqlBoolean isExpression, 
1581                                         SqlBoolean isAliased, 
1582                                         SqlBoolean isHidden) :
1583                                    this( dbType,
1584                                         maxLength, 
1585                                         precision, 
1586                                         scale, 
1587                                         localeId, 
1588                                         compareOptions, 
1589                                         userDefinedType, 
1590                                         null,
1591                                         isMultiValued,
1592                                         fieldMetaData,
1593                                         extendedProperties,
1594                                         name,
1595                                         typeSpecificNamePart1, 
1596                                         typeSpecificNamePart2,
1597                                         typeSpecificNamePart3,
1598                                         allowsDBNull, 
1599                                         serverName, 
1600                                         catalogName, 
1601                                         schemaName, 
1602                                         tableName, 
1603                                         columnName, 
1604                                         isKey, 
1605                                         isIdentity,
1606                                         false,
1607                                         isReadOnly, 
1608                                         isExpression, 
1609                                         isAliased, 
1610                                         isHidden ) {
1611         }
1612         // SMI V220 ctor.
1613         internal SmiQueryMetaData( SqlDbType dbType,
1614                                         long maxLength, 
1615                                         byte precision, 
1616                                         byte scale, 
1617                                         long localeId, 
1618                                         SqlCompareOptions compareOptions,
1619                                         Type userDefinedType, 
1620                                         string udtAssemblyQualifiedName,
1621                                         bool isMultiValued,
1622                                         IList<SmiExtendedMetaData> fieldMetaData,
1623                                         SmiMetaDataPropertyCollection extendedProperties,
1624                                         string name,
1625                                         string typeSpecificNamePart1, 
1626                                         string typeSpecificNamePart2, 
1627                                         string typeSpecificNamePart3,
1628                                         bool allowsDBNull, 
1629                                         string serverName, 
1630                                         string catalogName, 
1631                                         string schemaName,
1632                                         string tableName, 
1633                                         string columnName, 
1634                                         SqlBoolean isKey,
1635                                         bool isIdentity, 
1636                                         bool isColumnSet,
1637                                         bool isReadOnly, 
1638                                         SqlBoolean isExpression, 
1639                                         SqlBoolean isAliased, 
1640                                         SqlBoolean isHidden ) :
1641                                     base( dbType,
1642                                         maxLength, 
1643                                         precision, 
1644                                         scale, 
1645                                         localeId, 
1646                                         compareOptions, 
1647                                         userDefinedType, 
1648                                         udtAssemblyQualifiedName,
1649                                         isMultiValued,
1650                                         fieldMetaData,
1651                                         extendedProperties,
1652                                         name,
1653                                         typeSpecificNamePart1, 
1654                                         typeSpecificNamePart2,
1655                                         typeSpecificNamePart3,
1656                                         allowsDBNull, 
1657                                         serverName, 
1658                                         catalogName, 
1659                                         schemaName, 
1660                                         tableName, 
1661                                         columnName, 
1662                                         isKey, 
1663                                         isIdentity,
1664                                         isColumnSet ) {
1665         _isReadOnly = isReadOnly;
1666         _isExpression = isExpression;
1667         _isAliased = isAliased;
1668         _isHidden = isHidden;
1669         }
1670
1671         internal bool IsReadOnly {
1672             get {
1673                 return _isReadOnly;
1674             }
1675         }
1676
1677         internal SqlBoolean IsExpression {
1678             get {
1679                 return _isExpression;
1680             }
1681         }
1682
1683         internal SqlBoolean IsAliased {
1684             get {
1685                 return _isAliased;
1686             }
1687         }
1688
1689         internal SqlBoolean IsHidden {
1690             get {
1691                 return _isHidden;
1692             }
1693         }
1694
1695
1696     internal override string TraceString(int indent) {
1697         return String.Format(CultureInfo.InvariantCulture, "{0}"
1698                             +"{1}           IsReadOnly={2}\n\t"
1699                             +"{1}         IsExpression={3}\n\t"
1700                             +"{1}            IsAliased={4}\n\t"
1701                             +"{1}             IsHidden={5}",
1702                             base.TraceString(indent),
1703                             new String(' ', indent),
1704                             AllowsDBNull,
1705                             IsExpression,
1706                             IsAliased,
1707                             IsHidden);
1708     }
1709
1710     }
1711 }
1712