Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.Data / System / Data / SqlClient / SqlParameter.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="SqlParameter.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 System.Data.SqlClient {
10
11     using System;
12     using System.ComponentModel;
13     using System.Collections.Generic;
14     using System.Data;
15     using System.Data.Common;
16     using System.Data.ProviderBase;
17     using System.Data.Sql;
18     using System.Data.SqlTypes;
19     using System.Diagnostics;
20     using System.IO;
21     using System.Globalization;
22     using System.Reflection;
23     using System.Text;
24     using System.Xml;
25     using MSS=Microsoft.SqlServer.Server;
26
27     using Microsoft.SqlServer.Server;
28     using System.Threading.Tasks;
29
30     internal abstract class DataFeed  {       
31     }
32
33     internal class StreamDataFeed : DataFeed {
34         internal Stream _source;
35         
36         internal StreamDataFeed(Stream source) {
37             _source = source;
38         }       
39     }
40
41     internal class TextDataFeed : DataFeed {
42         internal TextReader _source;
43
44         internal TextDataFeed(TextReader source) {
45             _source = source;
46         }       
47     }
48
49     internal class XmlDataFeed : DataFeed {
50         internal  XmlReader _source;
51
52         internal XmlDataFeed(XmlReader source) {
53             _source = source;
54         }
55     }
56
57     [
58     System.ComponentModel.TypeConverterAttribute(typeof(System.Data.SqlClient.SqlParameter.SqlParameterConverter))
59     ]
60     public sealed partial class SqlParameter : DbParameter, IDbDataParameter, ICloneable {
61         private MetaType              _metaType;
62
63         private SqlCollation          _collation;
64         private string                _xmlSchemaCollectionDatabase;
65         private string                _xmlSchemaCollectionOwningSchema;
66         private string                _xmlSchemaCollectionName;
67
68         private string                _udtTypeName;
69         private string                _typeName;
70         private Type                  _udtType;
71         private Exception             _udtLoadError;
72
73         private string                _parameterName;
74         private byte                  _precision;
75         private byte                  _scale;
76         private bool                  _hasScale; // V1.0 compat, ignore _hasScale
77
78         private MetaType              _internalMetaType;
79         private SqlBuffer             _sqlBufferReturnValue;
80         private INullable             _valueAsINullable;
81         private bool                  _isSqlParameterSqlType;
82         private bool                  _isNull = true;
83         private bool                  _coercedValueIsSqlType;
84         private bool                  _coercedValueIsDataFeed;
85         private int                   _actualSize = -1;
86
87         /// <summary>
88         /// Column Encryption Cipher Related Metadata.
89         /// </summary>
90         private SqlCipherMetadata _columnEncryptionCipherMetadata;
91
92         /// <summary>
93         /// Get or set the encryption related metadata of this SqlParameter.
94         /// Should be set to a non-null value only once.
95         /// </summary>
96         internal SqlCipherMetadata CipherMetadata {
97             get {
98                 return _columnEncryptionCipherMetadata;
99             }
100
101             set {
102                 Debug.Assert(_columnEncryptionCipherMetadata == null || value == null,
103                     "_columnEncryptionCipherMetadata should be set to a non-null value only once.");
104
105                 _columnEncryptionCipherMetadata = value;
106             }
107         }
108
109         /// <summary>
110         /// Indicates if the parameter encryption metadata received by sp_describe_parameter_encryption.
111         /// For unencrypted parameters, the encryption metadata should still be sent (and will indicate 
112         /// that no encryption is needed).
113         /// </summary>
114         internal bool HasReceivedMetadata { get; set; }
115
116         /// <summary>
117         /// Returns the normalization rule version number as a byte
118         /// </summary>
119         internal byte NormalizationRuleVersion {
120             get {
121                 if (_columnEncryptionCipherMetadata != null) {
122                     return _columnEncryptionCipherMetadata.NormalizationRuleVersion;
123                 }
124
125                 return 0x00;
126             }
127         }
128
129         public SqlParameter() : base() {
130         }
131
132         [ EditorBrowsableAttribute(EditorBrowsableState.Advanced) ] // MDAC 69508
133         public SqlParameter(string parameterName,
134                             SqlDbType dbType, int size,
135                             ParameterDirection direction, bool isNullable,
136                             byte precision, byte scale,
137                             string sourceColumn, DataRowVersion sourceVersion,
138                             object value) : this() { // V1.0 everything
139             this.ParameterName = parameterName;
140             this.SqlDbType = dbType;
141             this.Size = size;
142             this.Direction = direction;
143             this.IsNullable = isNullable;
144             PrecisionInternal = precision;
145             ScaleInternal = scale;
146             this.SourceColumn = sourceColumn;
147             this.SourceVersion = sourceVersion;
148             this.Value = value;
149         }
150         public SqlParameter(string parameterName,
151                                SqlDbType dbType, int size,
152                                ParameterDirection direction,
153                                byte precision, byte scale,
154                                string sourceColumn, DataRowVersion sourceVersion, bool sourceColumnNullMapping,
155                                object value,
156                                string xmlSchemaCollectionDatabase, string xmlSchemaCollectionOwningSchema,
157                                string xmlSchemaCollectionName
158                                ) { // V2.0 everything - round trip all browsable properties + precision/scale
159             this.ParameterName = parameterName;
160             this.SqlDbType = dbType;
161             this.Size = size;
162             this.Direction = direction;
163             this.PrecisionInternal = precision;
164             this.ScaleInternal = scale;
165             this.SourceColumn = sourceColumn;
166             this.SourceVersion = sourceVersion;
167             this.SourceColumnNullMapping = sourceColumnNullMapping;
168             this.Value = value;
169             this._xmlSchemaCollectionDatabase = xmlSchemaCollectionDatabase;
170             this._xmlSchemaCollectionOwningSchema = xmlSchemaCollectionOwningSchema;
171             this._xmlSchemaCollectionName = xmlSchemaCollectionName;
172         }
173         public SqlParameter(string parameterName, SqlDbType dbType) : this() {
174             this.ParameterName = parameterName;
175             this.SqlDbType = dbType;
176         }
177
178         public SqlParameter(string parameterName, object value) : this() {
179             Debug.Assert(!(value is SqlDbType), "use SqlParameter(string, SqlDbType)");
180
181             this.ParameterName = parameterName;
182             this.Value = value;
183         }
184
185         public SqlParameter(string parameterName, SqlDbType dbType, int size) : this() {
186             this.ParameterName = parameterName;
187             this.SqlDbType = dbType;
188             this.Size = size;
189         }
190
191         public SqlParameter(string parameterName, SqlDbType dbType, int size, string sourceColumn) : this() {
192             this.ParameterName = parameterName;
193             this.SqlDbType = dbType;
194             this.Size = size;
195             this.SourceColumn = sourceColumn;
196         }
197
198         //
199         // currently the user can't set this value.  it gets set by the returnvalue from tds
200         //
201         internal SqlCollation Collation {
202             get {
203                 return _collation;
204             }
205             set {
206                 _collation = value;
207             }
208         }
209
210         [
211         Browsable(false),
212         ]
213         public SqlCompareOptions CompareInfo {
214             // Bits 21 through 25 represent the CompareInfo
215             get {
216                 SqlCollation collation = _collation;
217                 if (null != collation) {
218                     return collation.SqlCompareOptions;
219                 }
220                 return SqlCompareOptions.None;
221             }
222             set {
223                 SqlCollation collation = _collation;
224                 if (null == collation) {
225                     _collation = collation = new SqlCollation();
226                 }
227                 if ((value & SqlString.x_iValidSqlCompareOptionMask) != value) {
228                     throw ADP.ArgumentOutOfRange("CompareInfo");
229                 }
230                 collation.SqlCompareOptions = value;
231             }
232         }
233
234         [
235         ResCategoryAttribute(Res.DataCategory_Xml),
236         ResDescriptionAttribute(Res.SqlParameter_XmlSchemaCollectionDatabase),
237         ]
238         public string  XmlSchemaCollectionDatabase {
239             get {
240                 string xmlSchemaCollectionDatabase = _xmlSchemaCollectionDatabase;
241                 return ((xmlSchemaCollectionDatabase != null) ? xmlSchemaCollectionDatabase : ADP.StrEmpty);
242             }
243             set {
244                 _xmlSchemaCollectionDatabase = value;
245             }
246         }
247
248         [
249         ResCategoryAttribute(Res.DataCategory_Xml),
250         ResDescriptionAttribute(Res.SqlParameter_XmlSchemaCollectionOwningSchema),
251         ]
252         public string XmlSchemaCollectionOwningSchema {
253             get {
254                 string xmlSchemaCollectionOwningSchema = _xmlSchemaCollectionOwningSchema;
255                 return ((xmlSchemaCollectionOwningSchema != null) ? xmlSchemaCollectionOwningSchema : ADP.StrEmpty);
256             }
257             set {
258                 _xmlSchemaCollectionOwningSchema = value;
259             }
260         }
261
262         [
263         ResCategoryAttribute(Res.DataCategory_Xml),
264         ResDescriptionAttribute(Res.SqlParameter_XmlSchemaCollectionName),
265         ]
266         public string XmlSchemaCollectionName {
267             get {
268                 string xmlSchemaCollectionName = _xmlSchemaCollectionName;
269                 return ((xmlSchemaCollectionName != null) ? xmlSchemaCollectionName : ADP.StrEmpty);
270             }
271             set {
272                 _xmlSchemaCollectionName = value;
273             }
274         }
275
276         [
277         DefaultValue(false),
278         ResCategoryAttribute(Res.DataCategory_Data),
279         ResDescriptionAttribute(Res.TCE_SqlParameter_ForceColumnEncryption),
280         ]
281         public bool ForceColumnEncryption {
282             get; 
283             set;
284         }
285
286         override public DbType DbType {
287             get {
288                 return GetMetaTypeOnly().DbType;
289             }
290             set {
291                 MetaType metatype = _metaType;
292                 if ((null == metatype) || (metatype.DbType != value) ||
293                         // SQLBU 504029: Two special datetime cases for backward compat
294                         //  DbType.Date and DbType.Time should always be treated as setting DbType.DateTime instead
295                         value == DbType.Date ||
296                         value == DbType.Time) {
297                     PropertyTypeChanging();
298                     _metaType = MetaType.GetMetaTypeFromDbType(value);
299                 }
300             }
301         }
302
303         public override void ResetDbType() {
304             ResetSqlDbType();
305         }
306
307         internal MetaType InternalMetaType {
308             get {
309                 Debug.Assert(null != _internalMetaType, "null InternalMetaType");
310                 return _internalMetaType;
311             }
312             set { _internalMetaType = value; }
313         }
314
315         [
316         Browsable(false),
317         ]
318         public int LocaleId {
319             // Lowest 20 bits represent LocaleId
320             get {
321                 SqlCollation collation = _collation;
322                 if (null != collation) {
323                     return collation.LCID;
324                 }
325                 return 0;
326             }
327             set {
328                 SqlCollation collation = _collation;
329                 if (null == collation) {
330                     _collation = collation = new SqlCollation();
331                 }
332                 if (value != (SqlCollation.MaskLcid & value)) {
333                     throw ADP.ArgumentOutOfRange("LocaleId");
334                 }
335                 collation.LCID = value;
336             }
337         }
338
339         private SqlMetaData MetaData {
340             get {
341                 MetaType mt = GetMetaTypeOnly();
342                             long maxlen;
343
344                                 if (mt.IsFixed) {
345                                         maxlen = (long)mt.FixedLength;
346                                 }
347                 else if (Size > 0 || Size < 0) {
348                         maxlen = Size;   // Bug Fix: 302768, 302695, 302694, 302693
349                 }
350                                 else {
351                                         maxlen = MSS.SmiMetaData.GetDefaultForType( mt.SqlDbType ).MaxLength;
352                                 }
353                 return new SqlMetaData(this.ParameterName, mt.SqlDbType, maxlen, GetActualPrecision(), GetActualScale(), LocaleId, CompareInfo,
354                                        XmlSchemaCollectionDatabase, XmlSchemaCollectionOwningSchema, XmlSchemaCollectionName, mt.IsPlp, _udtType);
355             }
356         }
357
358         internal bool SizeInferred {
359             get {
360                 return 0 == _size;
361             }
362         }
363
364         /// <summary>
365         /// Get SMI Metadata to write out type_info stream.
366         /// </summary>
367         /// <returns></returns>
368         internal MSS.SmiParameterMetaData GetMetadataForTypeInfo() {
369             ParameterPeekAheadValue peekAhead = null;
370
371             if (_internalMetaType == null) {
372                 _internalMetaType = GetMetaTypeOnly();
373             }
374
375             return MetaDataForSmi(out peekAhead);
376         }
377
378         // IMPORTANT DEVNOTE: This method is being used for parameter encryption functionality, to get the type_info TDS object from SqlParameter.
379         // Please consider impact to that when changing this method. Refer to the callers of SqlParameter.GetMetadataForTypeInfo().
380         internal MSS.SmiParameterMetaData MetaDataForSmi(out ParameterPeekAheadValue peekAhead) {
381             peekAhead = null;
382             MetaType mt = ValidateTypeLengths( true /* Yukon or newer */ );
383             long actualLen = GetActualSize( );
384             long maxLen = this.Size; 
385
386             // GetActualSize returns bytes length, but smi expects char length for 
387             //  character types, so adjust
388             if ( !mt.IsLong ) { 
389                 if ( SqlDbType.NChar == mt.SqlDbType || SqlDbType.NVarChar == mt.SqlDbType ) {
390                     actualLen = actualLen / sizeof( char );
391                 }
392
393                 if ( actualLen > maxLen ) {
394                     maxLen = actualLen;
395                 }
396             }
397
398             // Determine maxLength for types that ValidateTypeLengths won't figure out
399             if ( 0 == maxLen  ) {
400                 if ( SqlDbType.Binary == mt.SqlDbType || SqlDbType.VarBinary == mt.SqlDbType ) {
401                     maxLen = MSS.SmiMetaData.MaxBinaryLength;
402                 }
403                 else if ( SqlDbType.Char == mt.SqlDbType || SqlDbType.VarChar == mt.SqlDbType ) {
404                     maxLen = MSS.SmiMetaData.MaxANSICharacters;
405                 }
406                 else if ( SqlDbType.NChar == mt.SqlDbType || SqlDbType.NVarChar == mt.SqlDbType ) {
407                     maxLen = MSS.SmiMetaData.MaxUnicodeCharacters;
408                 }
409             }
410             else if (( maxLen > MSS.SmiMetaData.MaxBinaryLength     && ( SqlDbType.Binary == mt.SqlDbType || SqlDbType.VarBinary == mt.SqlDbType ))
411                   || ( maxLen > MSS.SmiMetaData.MaxANSICharacters   && ( SqlDbType.Char   == mt.SqlDbType || SqlDbType.VarChar   == mt.SqlDbType ))
412                   || ( maxLen > MSS.SmiMetaData.MaxUnicodeCharacters&& ( SqlDbType.NChar  == mt.SqlDbType || SqlDbType.NVarChar  == mt.SqlDbType )) ) {
413                 maxLen = -1;
414             }
415
416
417             int localeId = LocaleId;
418             if ( 0 == localeId && mt.IsCharType ) {
419                 object value = GetCoercedValue();
420                 if ( value is SqlString && !( (SqlString)value ).IsNull ) {
421                     localeId = ( (SqlString)value ).LCID;
422                 }
423                 else {
424                     localeId = System.Globalization.CultureInfo.CurrentCulture.LCID;
425                 }
426             }
427
428             SqlCompareOptions compareOpts = CompareInfo;
429             if ( 0 == compareOpts && mt.IsCharType ) {
430                 object value = GetCoercedValue();
431                 if ( value is SqlString && !( (SqlString)value ).IsNull ) {
432                     compareOpts = ( (SqlString)value ).SqlCompareOptions;
433                 }
434                 else {
435                     compareOpts = MSS.SmiMetaData.GetDefaultForType( mt.SqlDbType ).CompareOptions;
436                 }
437             }
438
439             string typeSpecificNamePart1 = null;
440             string typeSpecificNamePart2 = null;
441             string typeSpecificNamePart3 = null;
442             
443             if (SqlDbType.Xml == mt.SqlDbType) {
444                 typeSpecificNamePart1 = this.XmlSchemaCollectionDatabase;
445                 typeSpecificNamePart2 = this.XmlSchemaCollectionOwningSchema;
446                 typeSpecificNamePart3 = this.XmlSchemaCollectionName;
447             }
448             else if (SqlDbType.Udt == mt.SqlDbType || (SqlDbType.Structured == mt.SqlDbType && !ADP.IsEmpty(this.TypeName))) {
449                 // Split the input name. The type name is specified as single 3 part name.
450                 // NOTE: ParseTypeName throws if format is incorrect
451                 String[] names;
452                 if (SqlDbType.Udt == mt.SqlDbType) {
453                     names = ParseTypeName(this.UdtTypeName, true /* is UdtTypeName */);
454                 }
455                 else {
456                     names = ParseTypeName(this.TypeName, false /* not UdtTypeName */);
457                 }
458
459                 if (1 == names.Length) {
460                     typeSpecificNamePart3 = names[0];
461                 }
462                 else if (2 == names.Length) {
463                     typeSpecificNamePart2 = names[0];
464                     typeSpecificNamePart3 = names[1];
465                 }
466                 else if (3 == names.Length) {
467                     typeSpecificNamePart1 = names[0];
468                     typeSpecificNamePart2 = names[1];
469                     typeSpecificNamePart3 = names[2];
470                 }
471                 else {
472                     throw ADP.ArgumentOutOfRange("names");
473                 }
474                 
475                 if ((!ADP.IsEmpty(typeSpecificNamePart1) && TdsEnums.MAX_SERVERNAME < typeSpecificNamePart1.Length)
476                     || (!ADP.IsEmpty(typeSpecificNamePart2) && TdsEnums.MAX_SERVERNAME < typeSpecificNamePart2.Length)
477                     || (!ADP.IsEmpty(typeSpecificNamePart3) && TdsEnums.MAX_SERVERNAME < typeSpecificNamePart3.Length)) {
478                     throw ADP.ArgumentOutOfRange("names");
479                 }
480             }
481
482             byte precision = GetActualPrecision();
483             byte scale = GetActualScale();
484
485             // precision for decimal types may still need adjustment.
486             if ( SqlDbType.Decimal == mt.SqlDbType ) {
487                 if ( 0 == precision ) {
488                     precision = TdsEnums.DEFAULT_NUMERIC_PRECISION;
489                 }
490             }
491
492             // Sub-field determination
493             List<SmiExtendedMetaData> fields = null;
494             MSS.SmiMetaDataPropertyCollection extendedProperties = null;
495             if (SqlDbType.Structured == mt.SqlDbType) {
496                 GetActualFieldsAndProperties(out fields, out extendedProperties, out peekAhead);
497             }
498             
499             return new MSS.SmiParameterMetaData( mt.SqlDbType,
500                                             maxLen,
501                                             precision,
502                                             scale,
503                                             localeId,
504                                             compareOpts,
505                                             null,           // Udt type not used for parameters
506                                             SqlDbType.Structured == mt.SqlDbType,
507                                             fields,
508                                             extendedProperties,
509                                             this.ParameterNameFixed,
510                                             typeSpecificNamePart1,
511                                             typeSpecificNamePart2,
512                                             typeSpecificNamePart3,
513                                             this.Direction);
514         }
515
516         internal bool ParamaterIsSqlType {
517             get {
518                 return _isSqlParameterSqlType;
519             }
520             set {
521                     _isSqlParameterSqlType = value;
522                 }
523         }
524
525         [
526         ResCategoryAttribute(Res.DataCategory_Data),
527         ResDescriptionAttribute(Res.SqlParameter_ParameterName),
528         ]
529         override public string ParameterName {
530             get {
531                 string parameterName = _parameterName;
532                 return ((null != parameterName) ? parameterName : ADP.StrEmpty);
533             }
534             set {
535                 if (ADP.IsEmpty(value) || (value.Length < TdsEnums.MAX_PARAMETER_NAME_LENGTH)
536                     || (('@' == value[0]) && (value.Length <= TdsEnums.MAX_PARAMETER_NAME_LENGTH))) {
537                     if (_parameterName != value) {
538                         PropertyChanging();
539                         _parameterName = value;
540                     }
541                 }
542                 else {
543                     throw SQL.InvalidParameterNameLength(value);
544                 }
545             }
546         }
547
548         internal string ParameterNameFixed {
549             get {
550                 string parameterName = ParameterName;
551                 if ((0 < parameterName.Length) && ('@' != parameterName[0])) {
552                     parameterName = "@" + parameterName;
553                 }
554                 Debug.Assert(parameterName.Length <= TdsEnums.MAX_PARAMETER_NAME_LENGTH, "parameter name too long");
555                 return parameterName;
556             }
557         }
558
559         [DefaultValue((Byte)0)] // MDAC 65862
560         [ResCategoryAttribute(Res.DataCategory_Data)]
561         [ResDescriptionAttribute(Res.DbDataParameter_Precision)]
562         public new Byte Precision {
563             get {
564                 return PrecisionInternal;
565             }
566             set {
567                 PrecisionInternal = value;
568             }
569         }
570
571         internal byte PrecisionInternal {
572             get {
573                 byte precision = _precision;
574                 SqlDbType dbtype = GetMetaSqlDbTypeOnly();
575                 if ((0 == precision) && (SqlDbType.Decimal == dbtype)) {
576                     precision = ValuePrecision(SqlValue);
577                 }
578                 return precision;
579             }
580             set {
581                 SqlDbType sqlDbType = SqlDbType;
582                 if (sqlDbType == SqlDbType.Decimal && value > TdsEnums.MAX_NUMERIC_PRECISION) {
583                     throw SQL.PrecisionValueOutOfRange(value);
584                 }
585                 if (_precision != value) {
586                     PropertyChanging();
587                     _precision = value;
588                 }
589             }
590         }
591
592         private bool ShouldSerializePrecision() {
593             return (0 != _precision);
594         }
595
596         [DefaultValue((Byte)0)] // MDAC 65862
597         [ResCategoryAttribute(Res.DataCategory_Data)]
598         [ResDescriptionAttribute(Res.DbDataParameter_Scale)]
599         public new Byte Scale {
600             get {
601                 return ScaleInternal;
602             }
603             set {
604                 ScaleInternal = value;
605             }
606         }
607         internal byte ScaleInternal {
608             get {
609                 byte scale = _scale;
610                 SqlDbType dbtype = GetMetaSqlDbTypeOnly();
611                 if ((0 == scale) && (SqlDbType.Decimal == dbtype)) {
612                     scale = ValueScale(SqlValue);
613                 }
614                 return scale;
615             }
616             set {
617                 if (_scale != value || !_hasScale) {
618                     PropertyChanging();
619                     _scale = value;
620                     _hasScale = true;
621                     _actualSize = -1;   // Invalidate actual size such that it is re-calculated
622                 }
623             }
624         }
625
626         private bool ShouldSerializeScale() {
627             return (0 != _scale); // V1.0 compat, ignore _hasScale
628         }
629
630         [
631         RefreshProperties(RefreshProperties.All),
632         ResCategoryAttribute(Res.DataCategory_Data),
633         ResDescriptionAttribute(Res.SqlParameter_SqlDbType),
634         System.Data.Common.DbProviderSpecificTypePropertyAttribute(true),
635         ]
636         public SqlDbType SqlDbType {
637             get {
638                 return GetMetaTypeOnly().SqlDbType;
639             }
640             set {
641                 MetaType metatype = _metaType;
642                 // HACK!!!
643                 // We didn't want to expose SmallVarBinary on SqlDbType so we 
644                 // stuck it at the end of SqlDbType in v1.0, except that now 
645                 // we have new data types after that and it's smack dab in the
646                 // middle of the valid range.  To prevent folks from setting 
647                 // this invalid value we have to have this code here until we
648                 // can take the time to fix it later.
649                 if ((SqlDbType)TdsEnums.SmallVarBinary == value) {
650                     throw SQL.InvalidSqlDbType(value);
651                 }
652                 if ((null == metatype) || (metatype.SqlDbType != value)) {
653                     PropertyTypeChanging();
654                     _metaType = MetaType.GetMetaTypeFromSqlDbType(value, value == SqlDbType.Structured);
655                 }
656             }
657         }
658
659         private bool ShouldSerializeSqlDbType() {
660             return (null != _metaType);
661         }
662
663         public void ResetSqlDbType() {
664             if (null != _metaType) {
665                 PropertyTypeChanging();
666                 _metaType = null;
667             }
668         }
669
670         [
671         Browsable(false),
672         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
673         ]
674         public object SqlValue {
675             get {
676                 if (_udtLoadError != null) { // SQL BU DT 329981
677                     throw _udtLoadError;
678                 }
679
680                 if (_value != null) {
681                     if (_value == DBNull.Value) {
682                         return MetaType.GetNullSqlValue(GetMetaTypeOnly().SqlType);
683                     }
684                     if (_value is INullable) {
685                           return _value;
686                     }
687
688                     // SQLBU 503165: for Date and DateTime2, return the CLR object directly without converting it to a SqlValue
689                     // SQLBU 527900: GetMetaTypeOnly() will convert _value to a string in the case of char or char[], so only check
690                     //               the SqlDbType for DateTime. This is the only case when we might return the CLR value directly.
691                     if (_value is DateTime) {
692                         SqlDbType sqlDbType = GetMetaTypeOnly().SqlDbType;                        
693                         if (sqlDbType == SqlDbType.Date || sqlDbType == SqlDbType.DateTime2) {
694                             return _value;
695                         }
696                     }
697
698                     return (MetaType.GetSqlValueFromComVariant(_value));
699                 }
700                 else if (_sqlBufferReturnValue != null) {
701                     return _sqlBufferReturnValue.SqlValue;
702                 }
703                 return null;
704             }
705             set {
706                 Value = value;
707             }
708         }
709
710         [
711         Browsable(false),
712         EditorBrowsableAttribute(EditorBrowsableState.Advanced)
713         ]
714         public String UdtTypeName {
715             get {
716                 string typeName = _udtTypeName;
717                 return ((null != typeName) ? typeName : ADP.StrEmpty);
718             }
719             set {
720                 _udtTypeName = value;
721             }
722         }
723
724         [
725         Browsable(false),
726         EditorBrowsableAttribute(EditorBrowsableState.Advanced)
727         ]
728         public String TypeName {
729             get {
730                 string typeName = _typeName;
731                 return ((null != typeName) ? typeName : ADP.StrEmpty);
732             }
733             set {
734                 _typeName = value;
735             }
736         }
737
738         [
739         RefreshProperties(RefreshProperties.All),
740         ResCategoryAttribute(Res.DataCategory_Data),
741         ResDescriptionAttribute(Res.DbParameter_Value),
742         TypeConverterAttribute(typeof(StringConverter)),
743         ]
744         override public object Value { // V1.2.3300, XXXParameter V1.0.3300
745             get {
746                 if (_udtLoadError != null) { // SQL BU DT 329981
747                     throw _udtLoadError;
748                 }
749
750                 if (_value != null) {
751                     return _value;
752                 }
753                 else if (_sqlBufferReturnValue != null) {
754                     if (ParamaterIsSqlType) {
755                         return _sqlBufferReturnValue.SqlValue;
756                     }
757                     return _sqlBufferReturnValue.Value;
758                 }
759                 return null;
760             }
761             set {
762                 _value = value;
763                 _sqlBufferReturnValue = null;
764                 _coercedValue = null;
765                 _valueAsINullable = _value as INullable;
766                 _isSqlParameterSqlType = (_valueAsINullable != null);
767                 _isNull = ((_value == null) || (_value == DBNull.Value) || ((_isSqlParameterSqlType) && (_valueAsINullable.IsNull)));
768                 _udtLoadError = null;
769                 _actualSize = -1;
770             }
771         }
772
773         internal INullable ValueAsINullable {
774             get {
775                 return _valueAsINullable;
776             }
777         }
778
779         internal bool IsNull {
780             get {
781                 // NOTE: Udts can change their value any time
782                 if (_internalMetaType.SqlDbType == Data.SqlDbType.Udt) {
783                     _isNull = ((_value == null) || (_value == DBNull.Value) || ((_isSqlParameterSqlType) && (_valueAsINullable.IsNull)));
784                 }
785                 return _isNull;
786             }
787         }
788
789         //
790         // always returns data in bytes - except for non-unicode chars, which will be in number of chars
791         //
792         internal int GetActualSize() {
793             MetaType mt = InternalMetaType;
794             SqlDbType actualType = mt.SqlDbType;
795             // NOTE: Users can change the Udt at any time, so we may need to recalculate
796             if ((_actualSize == -1) || (actualType == Data.SqlDbType.Udt)) {
797                 _actualSize = 0;
798                 object val = GetCoercedValue();
799                 bool isSqlVariant = false;
800
801                 // 
802                 if (IsNull && !mt.IsVarTime) {
803                     return 0;
804                 }
805
806                 // if this is a backend SQLVariant type, then infer the TDS type from the SQLVariant type
807                 if (actualType == SqlDbType.Variant) {
808                     mt = MetaType.GetMetaTypeFromValue(val, streamAllowed: false);
809                     actualType = MetaType.GetSqlDataType(mt.TDSType, 0 /*no user type*/, 0 /*non-nullable type*/).SqlDbType;
810                     isSqlVariant = true;
811                 }
812
813                 if (mt.IsFixed) {
814                     _actualSize = mt.FixedLength;
815                 }
816                 else {
817                     // @hack: until we have ForceOffset behavior we have the following semantics:
818                     // @hack: if the user supplies a Size through the Size propeprty or constructor,
819                     // @hack: we only send a MAX of Size bytes over.  If the actualSize is < Size, then
820                     // @hack: we send over actualSize
821                     int coercedSize = 0;
822
823                     // get the actual length of the data, in bytes
824                     switch (actualType) {
825                         case SqlDbType.NChar:
826                         case SqlDbType.NVarChar:
827                         case SqlDbType.NText:
828                         case SqlDbType.Xml:
829                             {
830                                 coercedSize = ((!_isNull) && (!_coercedValueIsDataFeed)) ? (StringSize(val, _coercedValueIsSqlType)) : 0;
831                                 _actualSize = (ShouldSerializeSize() ? Size : 0);
832                                 _actualSize = ((ShouldSerializeSize() && (_actualSize <= coercedSize)) ? _actualSize : coercedSize);
833                                 if (_actualSize == -1)
834                                     _actualSize = coercedSize;
835                                 _actualSize <<= 1;
836                             }
837                             break;
838                         case SqlDbType.Char:
839                         case SqlDbType.VarChar:
840                         case SqlDbType.Text:
841                             {
842                                 // for these types, ActualSize is the num of chars, not actual bytes - since non-unicode chars are not always uniform size
843                                 coercedSize = ((!_isNull) && (!_coercedValueIsDataFeed)) ? (StringSize(val, _coercedValueIsSqlType)) : 0;
844                                 _actualSize = (ShouldSerializeSize() ? Size : 0);
845                                 _actualSize = ((ShouldSerializeSize() && (_actualSize <= coercedSize)) ? _actualSize : coercedSize);
846                                 if (_actualSize == -1)
847                                     _actualSize = coercedSize;
848                             }
849                             break;
850                         case SqlDbType.Binary:
851                         case SqlDbType.VarBinary:
852                         case SqlDbType.Image:
853                         case SqlDbType.Timestamp:
854                             coercedSize = ((!_isNull) && (!_coercedValueIsDataFeed)) ? (BinarySize(val, _coercedValueIsSqlType)) : 0;
855                             _actualSize = (ShouldSerializeSize() ? Size : 0);
856                             _actualSize = ((ShouldSerializeSize() && (_actualSize <= coercedSize)) ? _actualSize : coercedSize);
857                             if (_actualSize == -1)
858                                 _actualSize = coercedSize;
859                             break;
860                          case SqlDbType.Udt:
861                             //we assume that the object is UDT
862                             if (!IsNull) {
863                                 //call the static function
864                                 coercedSize = AssemblyCache.GetLength(val);
865                             }
866                             break;
867                         case SqlDbType.Structured:
868                             coercedSize = -1;
869                             break;
870                         case SqlDbType.Time:
871                             _actualSize = (isSqlVariant ? 5 : MetaType.GetTimeSizeFromScale(GetActualScale()));
872                             break;
873                         case SqlDbType.DateTime2:
874                             // Date in number of days (3 bytes) + time
875                             _actualSize = 3 + (isSqlVariant ? 5 : MetaType.GetTimeSizeFromScale(GetActualScale()));
876                             break;
877                         case SqlDbType.DateTimeOffset:
878                             // Date in days (3 bytes) + offset in minutes (2 bytes) + time
879                             _actualSize = 5 + (isSqlVariant ? 5 : MetaType.GetTimeSizeFromScale(GetActualScale()));
880                             break;
881                         default:
882                             Debug.Assert(false, "Unknown variable length type!");
883                             break;
884                     } // switch
885
886                     // don't even send big values over to the variant
887                     if (isSqlVariant && (coercedSize > TdsEnums.TYPE_SIZE_LIMIT))
888                         throw SQL.ParameterInvalidVariant(this.ParameterName);
889                 }
890             }
891
892             return _actualSize;
893         }
894
895         object ICloneable.Clone() {
896             return new SqlParameter(this);
897         }
898
899         // Coerced Value is also used in SqlBulkCopy.ConvertValue(object value, _SqlMetaData metadata)
900         internal static object CoerceValue(object value, MetaType destinationType, out bool coercedToDataFeed, out bool typeChanged, bool allowStreaming = true) {
901             Debug.Assert(!(value is DataFeed), "Value provided should not already be a data feed");
902             Debug.Assert(!ADP.IsNull(value), "Value provided should not be null");
903             Debug.Assert(null != destinationType, "null destinationType");
904
905             coercedToDataFeed = false;
906             typeChanged = false;
907             Type currentType = value.GetType();
908
909             if ((typeof(object) != destinationType.ClassType) &&
910                     (currentType != destinationType.ClassType) && 
911                     ((currentType != destinationType.SqlType) || (SqlDbType.Xml == destinationType.SqlDbType))) {   // Special case for Xml types (since we need to convert SqlXml into a string)
912                 try {
913                     // Assume that the type changed
914                     typeChanged = true;
915                     if ((typeof(string) == destinationType.ClassType)) {
916                         // For Xml data, destination Type is always string
917                         if (typeof(SqlXml) == currentType) {
918                             value = MetaType.GetStringFromXml((XmlReader)(((SqlXml)value).CreateReader()));
919                         }
920                         else if (typeof(SqlString) == currentType) {
921                             typeChanged = false;   // Do nothing
922                         }
923                         else if (typeof(XmlReader).IsAssignableFrom(currentType)) {
924                             if (allowStreaming) {
925                                 coercedToDataFeed = true;
926                                 value = new XmlDataFeed((XmlReader)value);
927                             }
928                             else {
929                                 value = MetaType.GetStringFromXml((XmlReader)value);
930                             }
931                         }
932                         else if (typeof(char[]) == currentType) {
933                             value = new string((char[])value);
934                         }
935                         else if (typeof(SqlChars) == currentType) {
936                             value = new string(((SqlChars)value).Value);
937                         } 
938                         else if (value is TextReader && allowStreaming) {
939                             coercedToDataFeed = true;
940                             value = new TextDataFeed((TextReader)value);
941                         }
942                         else {
943                             value = Convert.ChangeType(value, destinationType.ClassType, (IFormatProvider)null);
944                         }
945                     }
946                     else if ((DbType.Currency == destinationType.DbType) && (typeof(string) == currentType)) {
947                         value = Decimal.Parse((string)value, NumberStyles.Currency, (IFormatProvider)null); // WebData 99376
948                     }
949                     else if ((typeof(SqlBytes) == currentType) && (typeof(byte[]) == destinationType.ClassType)) {
950                         typeChanged = false;    // Do nothing
951                     }
952                     else if ((typeof(string) == currentType) && (SqlDbType.Time == destinationType.SqlDbType)) {
953                         value = TimeSpan.Parse((string)value);
954                     }
955                     else if ((typeof(string) == currentType) && (SqlDbType.DateTimeOffset == destinationType.SqlDbType)) {
956                         value = DateTimeOffset.Parse((string)value, (IFormatProvider)null);
957                     }
958                     else if ((typeof(DateTime) == currentType) && (SqlDbType.DateTimeOffset == destinationType.SqlDbType)) {
959                         value = new DateTimeOffset((DateTime)value);
960                     }
961                     else if (TdsEnums.SQLTABLE == destinationType.TDSType &&
962                                 (value is DataTable ||
963                                 value is DbDataReader ||
964                                 value is System.Collections.Generic.IEnumerable<SqlDataRecord>)) {
965                         // no conversion for TVPs.
966                         typeChanged = false;
967                     }
968                     else if (destinationType.ClassType==typeof(byte[]) && value is Stream && allowStreaming) {
969                         coercedToDataFeed = true;        
970                         value = new StreamDataFeed((Stream)value);
971                     }
972                     else {
973                         value = Convert.ChangeType(value, destinationType.ClassType, (IFormatProvider)null);
974                     }
975                 }
976                 catch(Exception e) {
977                     // 
978                     if (!ADP.IsCatchableExceptionType(e)) {
979                         throw;
980                     }
981
982                     throw ADP.ParameterConversionFailed(value, destinationType.ClassType, e); // WebData 75433
983                 }
984             }
985
986             Debug.Assert(allowStreaming || !coercedToDataFeed, "Streaming is not allowed, but type was coerced into a data feed");
987             Debug.Assert(value.GetType() == currentType ^ typeChanged, "Incorrect value for typeChanged");
988             return value;
989         }
990
991         internal void FixStreamDataForNonPLP() {
992             object value = GetCoercedValue();
993             AssertCachedPropertiesAreValid();
994             if (!_coercedValueIsDataFeed) {
995                 return;
996             }
997
998             _coercedValueIsDataFeed = false;
999          
1000             if (value is TextDataFeed) {
1001                 if (Size > 0) {
1002                     char[] buffer = new char[Size];
1003                     int nRead = ((TextDataFeed)value)._source.ReadBlock(buffer, 0, Size);
1004                     CoercedValue = new string(buffer, 0, nRead);
1005                 }
1006                 else {
1007                     CoercedValue = ((TextDataFeed)value)._source.ReadToEnd();
1008                 }
1009                 return;
1010             }
1011
1012             if (value is StreamDataFeed) {
1013                 if (Size > 0) {
1014                     byte[] buffer = new byte[Size];
1015                     int totalRead = 0;
1016                     Stream sourceStream = ((StreamDataFeed)value)._source;
1017                     while (totalRead < Size) {
1018                         int nRead = sourceStream.Read(buffer, totalRead, Size - totalRead);
1019                         if (nRead == 0) {
1020                             break;
1021                         }
1022                         totalRead += nRead;
1023                     }
1024                     if (totalRead < Size) {
1025                         Array.Resize(ref buffer, totalRead);
1026                     }
1027                     CoercedValue = buffer;
1028                 }
1029                 else {
1030                     MemoryStream ms = new MemoryStream();
1031                     ((StreamDataFeed)value)._source.CopyTo(ms);
1032                     CoercedValue = ms.ToArray();
1033                 }
1034                 return;
1035             }
1036
1037             if (value is XmlDataFeed) {
1038                 CoercedValue = MetaType.GetStringFromXml(((XmlDataFeed)value)._source);
1039                 return;
1040             }
1041
1042             // We should have returned before reaching here
1043             Debug.Assert(false, "_coercedValueIsDataFeed was true, but the value was not a known DataFeed type");
1044         }
1045
1046         private void CloneHelper(SqlParameter destination) {
1047             CloneHelperCore(destination);
1048             destination._metaType     = _metaType;
1049             destination._collation    = _collation;
1050             destination._xmlSchemaCollectionDatabase = _xmlSchemaCollectionDatabase;
1051             destination._xmlSchemaCollectionOwningSchema = _xmlSchemaCollectionOwningSchema;
1052             destination._xmlSchemaCollectionName = _xmlSchemaCollectionName;
1053             destination._udtTypeName  = _udtTypeName;
1054             destination._typeName  = _typeName;
1055             destination._udtLoadError = _udtLoadError;
1056
1057             destination._parameterName = _parameterName;
1058             destination._precision = _precision;
1059             destination._scale = _scale;
1060             destination._sqlBufferReturnValue = _sqlBufferReturnValue;
1061             destination._isSqlParameterSqlType = _isSqlParameterSqlType;
1062             destination._internalMetaType = _internalMetaType;
1063             destination.CoercedValue     = CoercedValue; // copy cached value reference because of XmlReader problem
1064             destination._valueAsINullable = _valueAsINullable;
1065             destination._isNull = _isNull;
1066             destination._coercedValueIsDataFeed = _coercedValueIsDataFeed;
1067             destination._coercedValueIsSqlType = _coercedValueIsSqlType;
1068             destination._actualSize = _actualSize;
1069             destination.ForceColumnEncryption = ForceColumnEncryption;
1070         }
1071
1072         internal byte GetActualPrecision() {
1073             return ShouldSerializePrecision() ? PrecisionInternal: ValuePrecision(CoercedValue);
1074         }
1075
1076         internal byte GetActualScale() {
1077             if (ShouldSerializeScale()) {
1078                 return ScaleInternal;
1079             }
1080
1081             // issue: how could a user specify 0 as the actual scale?
1082             if (GetMetaTypeOnly().IsVarTime) {
1083                 return TdsEnums.DEFAULT_VARTIME_SCALE;
1084             }
1085             return ValueScale(CoercedValue);
1086         }
1087
1088         internal int GetParameterSize() {
1089             return ShouldSerializeSize() ? Size : ValueSize(CoercedValue);
1090         }
1091
1092         private void GetActualFieldsAndProperties(out List<MSS.SmiExtendedMetaData> fields, out SmiMetaDataPropertyCollection props, out ParameterPeekAheadValue peekAhead) {
1093             fields = null;
1094             props = null;
1095             peekAhead = null;
1096
1097             object value = GetCoercedValue();
1098             if (value is DataTable) {
1099                 DataTable dt = value as DataTable;
1100                 if (dt.Columns.Count <= 0) {
1101                     throw SQL.NotEnoughColumnsInStructuredType();
1102                 }
1103                 fields = new List<MSS.SmiExtendedMetaData>(dt.Columns.Count);
1104                 bool[] keyCols = new bool[dt.Columns.Count];
1105                 bool hasKey = false;
1106
1107                 // set up primary key as unique key list
1108                 //  do this prior to general metadata loop to favor the primary key
1109                 if (null != dt.PrimaryKey && 0 < dt.PrimaryKey.Length) {
1110                     foreach(DataColumn col in dt.PrimaryKey) {
1111                         keyCols[col.Ordinal] = true;
1112                         hasKey = true;
1113                     }
1114                 }
1115
1116                 for(int i=0; i<dt.Columns.Count; i++) {
1117                     fields.Add(MSS.MetaDataUtilsSmi.SmiMetaDataFromDataColumn(dt.Columns[i], dt));
1118
1119                     // DataColumn uniqueness is only for a single column, so don't add
1120                     //  more than one.  (keyCols.Count first for assumed minimal perf benefit)
1121                     if (!hasKey && dt.Columns[i].Unique) {
1122                         keyCols[i] = true;
1123                         hasKey = true;
1124                     }
1125                 }
1126
1127                 // Add unique key property, if any found.
1128                 if (hasKey) {
1129                     props = new SmiMetaDataPropertyCollection();
1130                     props[MSS.SmiPropertySelector.UniqueKey] = new MSS.SmiUniqueKeyProperty(new List<bool>(keyCols));
1131                 }
1132             }
1133             else if (value is SqlDataReader) {
1134                 fields = new List<MSS.SmiExtendedMetaData>(((SqlDataReader)value).GetInternalSmiMetaData());
1135                 if (fields.Count <= 0) {
1136                     throw SQL.NotEnoughColumnsInStructuredType();
1137                 }
1138
1139                 bool[] keyCols = new bool[fields.Count];
1140                 bool hasKey = false;
1141                 for(int i=0; i<fields.Count; i++) {
1142                     MSS.SmiQueryMetaData qmd = fields[i] as MSS.SmiQueryMetaData;
1143                     if (null != qmd && !qmd.IsKey.IsNull && qmd.IsKey.Value) {
1144                         keyCols[i] = true;
1145                         hasKey = true;
1146                     }
1147                 }
1148
1149                 // Add unique key property, if any found.
1150                 if (hasKey) {
1151                     props = new SmiMetaDataPropertyCollection();
1152                     props[MSS.SmiPropertySelector.UniqueKey] = new MSS.SmiUniqueKeyProperty(new List<bool>(keyCols));
1153                 }
1154             }
1155             else if (value is IEnumerable<SqlDataRecord>) {
1156                 // must grab the first record of the enumerator to get the metadata
1157                 IEnumerator<MSS.SqlDataRecord> enumerator = ((IEnumerable<MSS.SqlDataRecord>) value).GetEnumerator();
1158                 MSS.SqlDataRecord firstRecord = null;
1159                 try {
1160                     // no need for fields if there's no rows or no columns -- we'll be sending a null instance anyway.
1161                     if (enumerator.MoveNext()) {
1162                         firstRecord = enumerator.Current;
1163                         int fieldCount = firstRecord.FieldCount;
1164                         if (0 < fieldCount) {
1165                             // It's valid!  Grab those fields.
1166                             bool[] keyCols = new bool[fieldCount];
1167                             bool[] defaultFields = new bool[fieldCount];
1168                             bool[] sortOrdinalSpecified = new bool[fieldCount];
1169                             int maxSortOrdinal = -1;  // largest sort ordinal seen, used to optimize locating holes in the list
1170                             bool hasKey = false;
1171                             bool hasDefault = false;
1172                             int sortCount = 0;
1173                             SmiOrderProperty.SmiColumnOrder[] sort = new SmiOrderProperty.SmiColumnOrder[fieldCount];
1174                             fields = new List<MSS.SmiExtendedMetaData>(fieldCount);
1175                             for (int i = 0; i < fieldCount; i++) {
1176                                 SqlMetaData colMeta = firstRecord.GetSqlMetaData(i);
1177                                 fields.Add(MSS.MetaDataUtilsSmi.SqlMetaDataToSmiExtendedMetaData(colMeta));
1178                                 if (colMeta.IsUniqueKey) {
1179                                     keyCols[i] = true;
1180                                     hasKey = true;
1181                                 }
1182
1183                                 if (colMeta.UseServerDefault) {
1184                                     defaultFields[i] = true;
1185                                     hasDefault = true;
1186                                 }
1187
1188                                 sort[i].Order = colMeta.SortOrder;
1189                                 if (SortOrder.Unspecified != colMeta.SortOrder) {
1190                                     // SqlMetaData takes care of checking for negative sort ordinals with specified sort order
1191
1192                                     // bail early if there's no way sort order could be monotonically increasing
1193                                     if (fieldCount <= colMeta.SortOrdinal) {
1194                                         throw SQL.SortOrdinalGreaterThanFieldCount(i, colMeta.SortOrdinal);
1195                                     }
1196
1197                                     // Check to make sure we haven't seen this ordinal before
1198                                     if (sortOrdinalSpecified[colMeta.SortOrdinal]) {
1199                                         throw SQL.DuplicateSortOrdinal(colMeta.SortOrdinal);
1200                                     }
1201
1202                                     sort[i].SortOrdinal = colMeta.SortOrdinal;
1203                                     sortOrdinalSpecified[colMeta.SortOrdinal] = true;
1204                                     if (colMeta.SortOrdinal > maxSortOrdinal) {
1205                                         maxSortOrdinal = colMeta.SortOrdinal;
1206                                     }
1207                                     sortCount++;
1208                                 }
1209                             }
1210
1211                             if (hasKey) {
1212                                 props = new SmiMetaDataPropertyCollection();
1213                                 props[MSS.SmiPropertySelector.UniqueKey] = new MSS.SmiUniqueKeyProperty(new List<bool>(keyCols));
1214                             }
1215
1216                             if (hasDefault) {
1217                                 // May have already created props list in unique key handling
1218                                 if (null == props) {
1219                                     props = new SmiMetaDataPropertyCollection();
1220                                 }
1221
1222                                 props[MSS.SmiPropertySelector.DefaultFields] = new MSS.SmiDefaultFieldsProperty(new List<bool>(defaultFields));
1223                             }
1224
1225                             if (0 < sortCount) {
1226                                 // validate monotonically increasing sort order.
1227                                 //  Since we already checked for duplicates, we just need
1228                                 //  to watch for values outside of the sortCount range.
1229                                 if (maxSortOrdinal >= sortCount) {
1230                                     // there is at least one hole, find the first one
1231                                     int i;
1232                                     for (i = 0; i < sortCount; i++) {
1233                                         if (!sortOrdinalSpecified[i]) {
1234                                             break;
1235                                         }
1236                                     }
1237                                     Debug.Assert(i < sortCount, "SqlParameter.GetActualFieldsAndProperties: SortOrdinal hole-finding algorithm failed!");
1238                                     throw SQL.MissingSortOrdinal(i);
1239                                 }
1240
1241                                 // May have already created props list
1242                                 if (null == props) {
1243                                     props = new SmiMetaDataPropertyCollection();
1244                                 }
1245
1246                                 props[MSS.SmiPropertySelector.SortOrder] = new MSS.SmiOrderProperty(
1247                                         new List<SmiOrderProperty.SmiColumnOrder>(sort));
1248                             }
1249
1250                             // pack it up so we don't have to rewind to send the first value
1251                             peekAhead = new ParameterPeekAheadValue();
1252                             peekAhead.Enumerator = enumerator;
1253                             peekAhead.FirstRecord = firstRecord;
1254
1255                             // now that it's all packaged, make sure we don't dispose it.
1256                             enumerator = null;
1257                         }
1258                         else {
1259                             throw SQL.NotEnoughColumnsInStructuredType();
1260                         }
1261                     }
1262                     else {
1263                         throw SQL.IEnumerableOfSqlDataRecordHasNoRows();
1264                     }
1265                 }
1266                 finally {
1267                     if (enumerator != null) {
1268                         enumerator.Dispose();
1269                     }
1270                 }
1271             }
1272             else if (value is DbDataReader) {
1273                 DataTable schema = ((DbDataReader)value).GetSchemaTable();
1274                 if (schema.Rows.Count <= 0) {
1275                     throw SQL.NotEnoughColumnsInStructuredType();
1276                 }
1277
1278                 int fieldCount = schema.Rows.Count;
1279                 fields = new List<MSS.SmiExtendedMetaData>(fieldCount);
1280                 bool[] keyCols = new bool[fieldCount];
1281                 bool hasKey = false;
1282                 int ordinalForIsKey = schema.Columns[SchemaTableColumn.IsKey].Ordinal;
1283                 int ordinalForColumnOrdinal = schema.Columns[SchemaTableColumn.ColumnOrdinal].Ordinal;
1284                 // Extract column metadata
1285                 for(int rowOrdinal=0; rowOrdinal<fieldCount; rowOrdinal++) {
1286                     DataRow row = schema.Rows[rowOrdinal];
1287                     SmiExtendedMetaData candidateMd = MSS.MetaDataUtilsSmi.SmiMetaDataFromSchemaTableRow(row);
1288
1289                     // Determine destination ordinal.  Allow for ordinal not specified by assuming rowOrdinal *is* columnOrdinal
1290                     //  in that case, but don't worry about mix-and-match of the two techniques
1291                     int columnOrdinal = rowOrdinal;
1292                     if (!row.IsNull(ordinalForColumnOrdinal)) {
1293                        columnOrdinal = (int) row[ordinalForColumnOrdinal];
1294                     }
1295
1296                     // After this point, things we are creating (keyCols, fields) should be accessed by columnOrdinal
1297                     //  while the source should just be accessed via "row".
1298
1299                     // Watch for out-of-range ordinals
1300                     if (columnOrdinal >= fieldCount || columnOrdinal < 0) {
1301                         throw SQL.InvalidSchemaTableOrdinals();
1302                     }
1303
1304                     // extend empty space if out-of-order ordinal
1305                     while (columnOrdinal > fields.Count) {
1306                         fields.Add(null);
1307                     }
1308
1309                     // Now add the candidate to the list
1310                     if (fields.Count == columnOrdinal) {
1311                         fields.Add(candidateMd);
1312                     }
1313                     else {
1314                         // Disallow two columns using the same ordinal (even if due to mixing null and non-null columnOrdinals)
1315                         if (fields[columnOrdinal] != null) {
1316                             throw SQL.InvalidSchemaTableOrdinals();
1317                         }
1318
1319                         // Don't use insert, since it shifts all later columns down a notch
1320                         fields[columnOrdinal] = candidateMd;
1321                     }
1322
1323                     // Propogate key information
1324                     if (!row.IsNull(ordinalForIsKey) && (bool)row[ordinalForIsKey]) {
1325                         keyCols[columnOrdinal] = true;
1326                         hasKey = true;
1327                     }
1328                 }
1329
1330 #if DEBUG
1331                 // Check for holes
1332                 //  Above loop logic prevents holes since:
1333                 //      1) loop processes fieldcount # of columns
1334                 //      2) no ordinals outside continuous range from 0 to fieldcount - 1 are allowed
1335                 //      3) no duplicate ordinals are allowed
1336                 // But assert no holes to be sure.
1337                 foreach (SmiExtendedMetaData md in fields) {
1338                     Debug.Assert(null != md, "Shouldn't be able to have holes, since original loop algorithm prevents such.");
1339                 }
1340 #endif
1341
1342                 // Add unique key property, if any defined.
1343                 if (hasKey) {
1344                     props = new SmiMetaDataPropertyCollection();
1345                     props[MSS.SmiPropertySelector.UniqueKey] = new MSS.SmiUniqueKeyProperty(new List<bool>(keyCols));
1346                 }
1347             }
1348         }
1349
1350         internal object GetCoercedValue() {
1351             // NOTE: User can change the Udt at any time
1352             if ((null == _coercedValue) || (_internalMetaType.SqlDbType == Data.SqlDbType.Udt)) {  // will also be set during parameter Validation
1353                 bool isDataFeed = Value is DataFeed;
1354                 if ((IsNull) || (isDataFeed)) {
1355                     // No coercion is done for DataFeeds and Nulls
1356                     _coercedValue = Value;
1357                     _coercedValueIsSqlType = (_coercedValue==null) ? false: _isSqlParameterSqlType; // set to null for output parameters that keeps _isSqlParameterSqlType
1358                     _coercedValueIsDataFeed = isDataFeed;
1359                     _actualSize = IsNull ? 0 : -1;
1360                 }
1361                 else {
1362                     bool typeChanged;
1363                     _coercedValue = CoerceValue(Value, _internalMetaType, out _coercedValueIsDataFeed, out typeChanged);
1364                     _coercedValueIsSqlType = ((_isSqlParameterSqlType) && (!typeChanged));  // Type changed always results in a CLR type
1365                     _actualSize = -1;
1366                 }
1367             }
1368             AssertCachedPropertiesAreValid();
1369             return _coercedValue;
1370         }
1371         
1372         internal bool CoercedValueIsSqlType {
1373             get {
1374                 if (null == _coercedValue) {
1375                     GetCoercedValue();
1376                 }
1377                 AssertCachedPropertiesAreValid();
1378                 return _coercedValueIsSqlType;
1379             }
1380         }
1381
1382         internal bool CoercedValueIsDataFeed {
1383             get {
1384                 if (null == _coercedValue) {
1385                     GetCoercedValue();
1386                 }
1387                 AssertCachedPropertiesAreValid();
1388                 return _coercedValueIsDataFeed;
1389             }
1390         }
1391
1392         [Conditional("DEBUG")]
1393         internal void AssertCachedPropertiesAreValid()
1394         {
1395             AssertPropertiesAreValid(_coercedValue, _coercedValueIsSqlType, _coercedValueIsDataFeed, IsNull);
1396         }
1397
1398         [Conditional("DEBUG")]
1399         internal void AssertPropertiesAreValid(object value, bool? isSqlType = null, bool? isDataFeed = null, bool? isNull = null)
1400         {
1401             Debug.Assert(!isSqlType.HasValue || (isSqlType.Value == (value is INullable)), "isSqlType is incorrect");
1402             Debug.Assert(!isDataFeed.HasValue || (isDataFeed.Value == (value is DataFeed)), "isDataFeed is incorrect");
1403             Debug.Assert(!isNull.HasValue || (isNull.Value == ADP.IsNull(value)), "isNull is incorrect");
1404         }
1405
1406         private SqlDbType GetMetaSqlDbTypeOnly() {
1407             MetaType metaType = _metaType;
1408             if (null == metaType) { // infer the type from the value
1409                 metaType = MetaType.GetDefaultMetaType();
1410             }
1411             return metaType.SqlDbType;
1412         }
1413
1414         // This may not be a good thing to do in case someone overloads the parameter type but I
1415         // don't want to go from SqlDbType -> metaType -> TDSType
1416         private MetaType GetMetaTypeOnly() {
1417             if (null != _metaType) {
1418                 return _metaType;
1419             }
1420             if (null != _value && DBNull.Value != _value) {
1421                   // We have a value set by the user then just use that value
1422                   // char and char[] are not directly supported so we convert those values to string
1423                   Type valueType = _value.GetType ();
1424                   if (typeof(char) == valueType) {
1425                       _value = _value.ToString();
1426                       valueType = typeof (string);
1427                   }
1428                   else if (typeof(char[]) == valueType) {
1429                      _value = new string((char[])_value);
1430                      valueType = typeof (string);
1431                   }
1432                   return MetaType.GetMetaTypeFromType(valueType);
1433             }
1434             else if (null != _sqlBufferReturnValue) {  // value came back from the server
1435                  Type valueType = _sqlBufferReturnValue.GetTypeFromStorageType (_isSqlParameterSqlType);
1436                  if (null != valueType) {
1437                      return MetaType.GetMetaTypeFromType(valueType);
1438                  }
1439             }
1440             return MetaType.GetDefaultMetaType();
1441         }
1442
1443         internal void Prepare(SqlCommand cmd) { // MDAC 67063
1444             if (null == _metaType) {
1445                 throw ADP.PrepareParameterType(cmd);
1446             }
1447             else if (!ShouldSerializeSize() && !_metaType.IsFixed) {
1448                 throw ADP.PrepareParameterSize(cmd);
1449             }
1450             else if ( (!ShouldSerializePrecision() && !ShouldSerializeScale()) &&  (_metaType.SqlDbType == SqlDbType.Decimal) ) {
1451                 throw ADP.PrepareParameterScale(cmd, SqlDbType.ToString());
1452             }
1453         }
1454
1455         private void PropertyChanging () {
1456             _internalMetaType = null;
1457         }
1458
1459         private void PropertyTypeChanging () {
1460             PropertyChanging();
1461             CoercedValue = null;
1462         }
1463
1464         internal void SetSqlBuffer (SqlBuffer buff){
1465             _sqlBufferReturnValue = buff;
1466             _value = null;
1467             _coercedValue = null;
1468             _isNull = _sqlBufferReturnValue.IsNull;
1469             _coercedValueIsDataFeed = false;
1470             _coercedValueIsSqlType = false;
1471             _udtLoadError = null;
1472             _actualSize = -1;
1473         }
1474
1475         internal void SetUdtLoadError(Exception e) { // SQL BU DT 329981
1476             _udtLoadError = e;
1477         }
1478
1479         internal void Validate(int index, bool isCommandProc) {
1480             MetaType metaType = GetMetaTypeOnly();
1481             _internalMetaType = metaType;
1482
1483             // NOTE: (General Criteria): SqlParameter does a Size Validation check and would fail if the size is 0. 
1484             //                           This condition filters all scenarios where we view a valid size 0.
1485             if (ADP.IsDirection(this, ParameterDirection.Output) &&
1486                 !ADP.IsDirection(this, ParameterDirection.ReturnValue) && // SQL BU DT 372370
1487                 (!metaType.IsFixed) && 
1488                 !ShouldSerializeSize() && 
1489                 ((null == _value) || Convert.IsDBNull(_value)) && 
1490                 (SqlDbType != SqlDbType.Timestamp) && 
1491                 (SqlDbType != SqlDbType.Udt) &&
1492                 // 
1493
1494                 (SqlDbType != SqlDbType.Xml) &&
1495                 !metaType.IsVarTime) {
1496
1497                 throw ADP.UninitializedParameterSize(index, metaType.ClassType);
1498             }
1499
1500             if (metaType.SqlDbType != SqlDbType.Udt && Direction != ParameterDirection.Output) {
1501                 GetCoercedValue();
1502             }
1503
1504             //check if the UdtTypeName is specified for Udt params
1505             if (metaType.SqlDbType == SqlDbType.Udt) {
1506                 if (ADP.IsEmpty (UdtTypeName))
1507                     throw SQL.MustSetUdtTypeNameForUdtParams ();
1508             }
1509             else if (!ADP.IsEmpty (UdtTypeName)) {
1510                 throw SQL.UnexpectedUdtTypeNameForNonUdtParams();
1511             }
1512
1513             // Validate structured-type-specific details.
1514             if (metaType.SqlDbType == SqlDbType.Structured) {
1515                 if (!isCommandProc && ADP.IsEmpty (TypeName))
1516                     throw SQL.MustSetTypeNameForParam(metaType.TypeName, this.ParameterName);
1517
1518                 if (ParameterDirection.Input != this.Direction) {
1519                     throw SQL.UnsupportedTVPOutputParameter(this.Direction, this.ParameterName);
1520                 }
1521
1522                 if (DBNull.Value == GetCoercedValue()) {
1523                     throw SQL.DBNullNotSupportedForTVPValues(this.ParameterName);
1524                 }
1525             }
1526             else if (!ADP.IsEmpty (TypeName)) {
1527                 throw SQL.UnexpectedTypeNameForNonStructParams(this.ParameterName);
1528             }
1529         }
1530
1531         // func will change type to that with a 4 byte length if the type has a two
1532         // byte length and a parameter length > than that expressable in 2 bytes
1533         internal MetaType ValidateTypeLengths(bool yukonOrNewer) {
1534             MetaType mt = InternalMetaType;
1535             // MDAC bug #50839 + #52829 : Since the server will automatically reject any
1536             // char, varchar, binary, varbinary, nchar, or nvarchar parameter that has a
1537             // byte sizeInCharacters > 8000 bytes, we promote the parameter to image, text, or ntext.  This
1538             // allows the user to specify a parameter type using a COM+ datatype and be able to
1539             // use that parameter against a BLOB column.
1540             if ((SqlDbType.Udt != mt.SqlDbType) && (false == mt.IsFixed) && (false == mt.IsLong)) { // if type has 2 byte length
1541                 long actualSizeInBytes = this.GetActualSize();
1542                 long sizeInCharacters = this.Size;
1543
1544                 // Bug: VSTFDevDiv #636867
1545                 // Notes:
1546                 // 'actualSizeInBytes' is the size of value passed; 
1547                 // 'sizeInCharacters' is the parameter size;
1548                 // 'actualSizeInBytes' is in bytes; 
1549                 // 'this.Size' is in charaters; 
1550                 // 'sizeInCharacters' is in characters; 
1551                 // 'TdsEnums.TYPE_SIZE_LIMIT' is in bytes;
1552                 // For Non-NCharType and for non-Yukon or greater variables, size should be maintained;
1553                 // Reverting changes from bug VSTFDevDiv # 479739 as it caused an regression;
1554                 // Modifed variable names from 'size' to 'sizeInCharacters', 'actualSize' to 'actualSizeInBytes', and 
1555                 // 'maxSize' to 'maxSizeInBytes'
1556                 // The idea is to
1557                 //  1) revert the regression from bug 479739
1558                 //  2) fix as many scenarios as possible including bug 636867
1559                 //  3) cause no additional regression from 3.5 sp1
1560                 // Keeping these goals in mind - the following are the changes we are making
1561
1562                 long maxSizeInBytes = 0;
1563                 if ((mt.IsNCharType) && (yukonOrNewer))
1564                     maxSizeInBytes = ((sizeInCharacters * sizeof(char)) > actualSizeInBytes) ? sizeInCharacters * sizeof(char) : actualSizeInBytes;
1565                 else
1566                 {
1567                     // Notes:
1568                     // Elevation from (n)(var)char (4001+) to (n)text succeeds without failure only with Yukon and greater.
1569                     // it fails in sql server 2000
1570                     maxSizeInBytes = (sizeInCharacters > actualSizeInBytes) ? sizeInCharacters : actualSizeInBytes;
1571                 }
1572
1573                 if ((maxSizeInBytes > TdsEnums.TYPE_SIZE_LIMIT) || (_coercedValueIsDataFeed) || 
1574                     (sizeInCharacters == -1) || (actualSizeInBytes == -1)) { // is size > size able to be described by 2 bytes
1575                     if (yukonOrNewer) {
1576                         // Convert the parameter to its max type
1577                         mt = MetaType.GetMaxMetaTypeFromMetaType(mt);
1578                         _metaType = mt;
1579                         InternalMetaType = mt;
1580                         if (!mt.IsPlp) {
1581                             if (mt.SqlDbType == SqlDbType.Xml) {
1582                                 throw ADP.InvalidMetaDataValue();     //Xml should always have IsPartialLength = true
1583                             }
1584                             if (mt.SqlDbType == SqlDbType.NVarChar 
1585                              || mt.SqlDbType == SqlDbType.VarChar 
1586                              || mt.SqlDbType == SqlDbType.VarBinary) {
1587                                 Size = (int)(SmiMetaData.UnlimitedMaxLengthIndicator);
1588                             }
1589                         }
1590                     }
1591                     else {
1592                         switch (mt.SqlDbType) { // widening the SqlDbType is automatic
1593                         case SqlDbType.Binary:
1594                         case SqlDbType.VarBinary:
1595                             mt = MetaType.GetMetaTypeFromSqlDbType (SqlDbType.Image, false);
1596                             _metaType = mt; // do not use SqlDbType property which calls PropertyTypeChanging resetting coerced value
1597                             InternalMetaType = mt;
1598                             break;
1599                         case SqlDbType.Char:
1600                         case SqlDbType.VarChar:
1601                             mt = MetaType.GetMetaTypeFromSqlDbType (SqlDbType.Text, false);
1602                             _metaType = mt;
1603                             InternalMetaType = mt;
1604                             break;
1605                         case SqlDbType.NChar:
1606                         case SqlDbType.NVarChar:
1607                             mt = MetaType.GetMetaTypeFromSqlDbType (SqlDbType.NText, false);
1608                             _metaType = mt;
1609                             InternalMetaType = mt;
1610                             break;
1611                         default:
1612                             Debug.Assert(false, "Missed metatype in SqlCommand.BuildParamList()");
1613                             break;
1614                         }
1615                     }
1616                 }
1617             }
1618             return mt;
1619         }
1620
1621         private byte ValuePrecision(object value) {
1622             if (value is SqlDecimal) {
1623                 if (((SqlDecimal) value).IsNull) // MDAC #79648
1624                     return 0;
1625
1626                 return ((SqlDecimal)value).Precision;
1627             }
1628             return ValuePrecisionCore(value);
1629         }
1630
1631         private byte ValueScale(object value) {
1632             if (value is SqlDecimal) {
1633                 if (((SqlDecimal) value).IsNull) // MDAC #79648
1634                     return 0;
1635
1636                 return ((SqlDecimal) value).Scale;
1637             }
1638             return ValueScaleCore(value);
1639         }
1640
1641         private static int StringSize(object value, bool isSqlType) {
1642             if (isSqlType) {
1643                 Debug.Assert(!((INullable)value).IsNull, "Should not call StringSize on null values");
1644                 if (value is SqlString) {
1645                     return ((SqlString)value).Value.Length;
1646                 }
1647                 if (value is SqlChars) {
1648                     return ((SqlChars)value).Value.Length;
1649                 }
1650             }
1651             else {
1652                 string svalue = (value as string);
1653                 if (null != svalue) {
1654                     return svalue.Length;
1655                 }
1656                 char[] cvalue = (value as char[]);
1657                 if (null != cvalue) {
1658                     return cvalue.Length;
1659                 }
1660                 if (value is char) {
1661                     return 1;
1662                 }
1663             }
1664
1665             // Didn't match, unknown size
1666             return 0;
1667         }
1668
1669         private static int BinarySize(object value, bool isSqlType) {
1670             if (isSqlType) {
1671                 Debug.Assert(!((INullable)value).IsNull, "Should not call StringSize on null values");
1672                 if (value is SqlBinary) {
1673                     return ((SqlBinary)value).Length;
1674                 }
1675                 if (value is SqlBytes) {
1676                     return ((SqlBytes)value).Value.Length;
1677                 }
1678             }
1679             else {
1680                 byte[] bvalue = (value as byte[]);
1681                 if (null != bvalue) {
1682                     return bvalue.Length;
1683                 }
1684                 if (value is byte) {
1685                     return 1;
1686                 }
1687             }
1688
1689             // Didn't match, unknown size
1690             return 0;
1691         }
1692
1693         private int ValueSize(object value) {
1694             if (value is SqlString) {
1695                 if (((SqlString) value).IsNull) // MDAC #79648
1696                     return 0;
1697
1698                 return ((SqlString) value).Value.Length;
1699             }
1700             if (value is SqlChars) {
1701                 if (((SqlChars) value).IsNull)
1702                     return 0;
1703
1704                 return ((SqlChars) value).Value.Length;
1705             }
1706
1707             if (value is SqlBinary) {
1708                 if (((SqlBinary) value).IsNull) // MDAC #79648
1709                     return 0;
1710
1711                 return ((SqlBinary) value).Length;
1712             }
1713             if (value is SqlBytes) {
1714                 if (((SqlBytes) value).IsNull)
1715                     return 0;
1716
1717                 return (int)(((SqlBytes) value).Length);
1718             }
1719             if (value is DataFeed)
1720             {
1721                 // Unknown length
1722                 return 0;                
1723             }
1724             return ValueSizeCore(value);
1725         }
1726
1727         // 
1728
1729         // parse an string of the form db.schema.name where any of the three components
1730         // might have "[" "]" and dots within it.
1731         // returns:
1732         //   [0] dbname (or null)
1733         //   [1] schema (or null)
1734         //   [2] name
1735         // NOTE: if perf/space implications of Regex is not a problem, we can get rid
1736         // of this and use a simple regex to do the parsing
1737         internal static string[] ParseTypeName(string typeName, bool isUdtTypeName) {
1738             Debug.Assert(null != typeName, "null typename passed to ParseTypeName");
1739
1740             try {
1741                 string errorMsg;
1742                 if (isUdtTypeName) {
1743                     errorMsg = Res.SQL_UDTTypeName;
1744                 }
1745                 else {
1746                     errorMsg = Res.SQL_TypeName;
1747                 }
1748                 return MultipartIdentifier.ParseMultipartIdentifier(typeName, "[\"", "]\"", '.', 3, true, errorMsg, true);
1749             }
1750             catch (ArgumentException) {
1751                 if (isUdtTypeName) {
1752                     throw SQL.InvalidUdt3PartNameFormat();
1753                 }
1754                 else {
1755                     throw SQL.InvalidParameterTypeNameFormat();
1756                 }
1757             }
1758         }
1759
1760         sealed internal class SqlParameterConverter : ExpandableObjectConverter {
1761
1762             // converter classes should have public ctor
1763             public SqlParameterConverter() {
1764             }
1765
1766             override public bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
1767                 if (typeof(System.ComponentModel.Design.Serialization.InstanceDescriptor) == destinationType) {
1768                     return true;
1769                 }
1770                 return base.CanConvertTo(context, destinationType);
1771             }
1772
1773             override public object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) {
1774                 if (destinationType == null) {
1775                     throw ADP.ArgumentNull("destinationType");
1776                 }
1777                 if ((typeof(System.ComponentModel.Design.Serialization.InstanceDescriptor) == destinationType) && (value is SqlParameter)) {
1778                     return ConvertToInstanceDescriptor(value as SqlParameter);
1779                 }
1780                 return base.ConvertTo(context, culture, value, destinationType);
1781             }
1782
1783             private System.ComponentModel.Design.Serialization.InstanceDescriptor ConvertToInstanceDescriptor(SqlParameter p) {
1784                 // MDAC 67321 - reducing parameter generated code
1785                 int flags = 0; // if part of the collection - the parametername can't be empty
1786
1787                 if (p.ShouldSerializeSqlDbType()) {
1788                     flags |= 1;
1789                 }
1790                 if (p.ShouldSerializeSize()) {
1791                     flags |= 2;
1792                 }
1793                 if (!ADP.IsEmpty(p.SourceColumn)) {
1794                     flags |= 4;
1795                 }
1796                 if (null != p.Value) {
1797                     flags |= 8;
1798                 }
1799                 if ((ParameterDirection.Input != p.Direction) || p.IsNullable
1800                     || p.ShouldSerializePrecision() || p.ShouldSerializeScale()
1801                     || (DataRowVersion.Current != p.SourceVersion)
1802                     ) {
1803                      flags |= 16; // v1.0 everything
1804                 }
1805
1806                 if (p.SourceColumnNullMapping || !ADP.IsEmpty(p.XmlSchemaCollectionDatabase) ||
1807                     !ADP.IsEmpty(p.XmlSchemaCollectionOwningSchema) || !ADP.IsEmpty(p.XmlSchemaCollectionName)) {
1808                     flags |= 32; // v2.0 everything
1809                 }
1810
1811                 Type[] ctorParams;
1812                 object[] ctorValues;
1813                 switch(flags) {
1814                 case  0: // ParameterName
1815                 case  1: // SqlDbType
1816                     ctorParams = new Type[] { typeof(string), typeof(SqlDbType) };
1817                     ctorValues = new object[] { p.ParameterName, p.SqlDbType };
1818                     break;
1819                 case  2: // Size
1820                 case  3: // Size, SqlDbType
1821                     ctorParams = new Type[] { typeof(string), typeof(SqlDbType), typeof(int) };
1822                     ctorValues = new object[] { p.ParameterName, p.SqlDbType, p.Size };
1823                     break;
1824                 case  4: // SourceColumn
1825                 case  5: // SourceColumn, SqlDbType
1826                 case  6: // SourceColumn, Size
1827                 case  7: // SourceColumn, Size, SqlDbType
1828                     ctorParams = new Type[] { typeof(string), typeof(SqlDbType), typeof(int), typeof(string) };
1829                     ctorValues = new object[] { p.ParameterName, p.SqlDbType, p.Size, p.SourceColumn };
1830                     break;
1831                 case  8: // Value
1832                     ctorParams = new Type[] { typeof(string), typeof(object) };
1833                     ctorValues = new object[] { p.ParameterName, p.Value };
1834                     break;
1835                 default:
1836                     if (0 == (32 & flags)) { // v1.0 everything
1837                         ctorParams = new Type[] {
1838                                                     typeof(string), typeof(SqlDbType), typeof(int), typeof(ParameterDirection),
1839                                                     typeof(bool), typeof(byte), typeof(byte),
1840                                                     typeof(string), typeof(DataRowVersion),
1841                                                     typeof(object) };
1842                         ctorValues = new object[] {
1843                                                       p.ParameterName, p.SqlDbType,  p.Size, p.Direction,
1844                                                       p.IsNullable, p.PrecisionInternal, p.ScaleInternal,
1845                                                       p.SourceColumn, p.SourceVersion,
1846                                                       p.Value };
1847                     }
1848                     else { // v2.0 everything - round trip all browsable properties + precision/scale
1849                         ctorParams = new Type[] {
1850                                                     typeof(string), typeof(SqlDbType), typeof(int), typeof(ParameterDirection),
1851                                                     typeof(byte), typeof(byte),
1852                                                     typeof(string), typeof(DataRowVersion), typeof(bool),
1853                                                     typeof(object),
1854                                                     typeof(string), typeof(string),
1855                                                     typeof(string) };
1856                         ctorValues = new object[] {
1857                                                       p.ParameterName, p.SqlDbType,  p.Size, p.Direction,
1858                                                       p.PrecisionInternal, p.ScaleInternal,
1859                                                       p.SourceColumn, p.SourceVersion, p.SourceColumnNullMapping,
1860                                                       p.Value,
1861                                                       p.XmlSchemaCollectionDatabase, p.XmlSchemaCollectionOwningSchema,
1862                                                       p.XmlSchemaCollectionName};
1863                     }
1864                     break;
1865                 }
1866                 System.Reflection.ConstructorInfo ctor = typeof(SqlParameter).GetConstructor(ctorParams);
1867                 return new System.ComponentModel.Design.Serialization.InstanceDescriptor(ctor, ctorValues);
1868             }
1869         }
1870
1871     }
1872 }