1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System;
6 using System.Data;
7 using System.Data.Common;
8 using System.Diagnostics;
9 using System.Globalization;
10 using System.Data.SqlTypes;
11 using System.Data.SqlClient;
12 
13 namespace Microsoft.SqlServer.Server
14 {
15     // class SqlMetaData
16     //   Simple immutable implementation of the a metadata-holding class.  Only
17     //    complexities are:
18     //        1) enforcing immutability.
19     //        2) Inferring type from a value.
20     //        3) Adjusting a value to match the metadata.
21 
22     public sealed partial class SqlMetaData
23     {
24         private string _strName;
25         private long _lMaxLength;
26         private SqlDbType _sqlDbType;
27         private byte _bPrecision;
28         private byte _bScale;
29         private long _lLocale;
30         private SqlCompareOptions _eCompareOptions;
31         private string _xmlSchemaCollectionDatabase;
32         private string _xmlSchemaCollectionOwningSchema;
33         private string _xmlSchemaCollectionName;
34         private string _serverTypeName;
35         private bool _bPartialLength;
36         private Type _udtType;
37         private bool _useServerDefault;
38         private bool _isUniqueKey;
39         private SortOrder _columnSortOrder;
40         private int _sortOrdinal;
41 
42         // unlimited (except by implementation) max-length.
43         private const long x_lMax = -1;
44         private const long x_lServerMaxUnicode = 4000;
45         private const long x_lServerMaxANSI = 8000;
46         private const long x_lServerMaxBinary = 8000;
47         private const bool x_defaultUseServerDefault = false;
48         private const bool x_defaultIsUniqueKey = false;
49         private const SortOrder x_defaultColumnSortOrder = SortOrder.Unspecified;
50         private const int x_defaultSortOrdinal = -1;
51 
52         private const SqlCompareOptions x_eDefaultStringCompareOptions = SqlCompareOptions.IgnoreCase
53                                         | SqlCompareOptions.IgnoreKanaType | SqlCompareOptions.IgnoreWidth;
54 
55         // scalar types constructor without tvp extended properties
SqlMetaData(String name, SqlDbType dbType)56         public SqlMetaData(String name, SqlDbType dbType)
57         {
58             Construct(name, dbType, x_defaultUseServerDefault,
59                     x_defaultIsUniqueKey, x_defaultColumnSortOrder, x_defaultSortOrdinal);
60         }
61 
62         // scalar types constructor
SqlMetaData(String name, SqlDbType dbType, bool useServerDefault, bool isUniqueKey, SortOrder columnSortOrder, int sortOrdinal)63         public SqlMetaData(String name, SqlDbType dbType, bool useServerDefault,
64                     bool isUniqueKey, SortOrder columnSortOrder, int sortOrdinal)
65         {
66             Construct(name, dbType, useServerDefault,
67                     isUniqueKey, columnSortOrder, sortOrdinal);
68         }
69 
70         // binary or string constructor with only max length
71         // (for string types, locale and compare options will be picked up from the thread.
SqlMetaData(String name, SqlDbType dbType, long maxLength)72         public SqlMetaData(String name, SqlDbType dbType, long maxLength)
73         {
74             Construct(name, dbType, maxLength, x_defaultUseServerDefault,
75                     x_defaultIsUniqueKey, x_defaultColumnSortOrder, x_defaultSortOrdinal);
76         }
77 
78         // binary or string constructor with only max length and tvp extended properties
79         // (for string types, locale and compare options will be picked up from the thread.
SqlMetaData(String name, SqlDbType dbType, long maxLength, bool useServerDefault, bool isUniqueKey, SortOrder columnSortOrder, int sortOrdinal)80         public SqlMetaData(String name, SqlDbType dbType, long maxLength, bool useServerDefault,
81                     bool isUniqueKey, SortOrder columnSortOrder, int sortOrdinal)
82         {
83             Construct(name, dbType, maxLength, useServerDefault,
84                     isUniqueKey, columnSortOrder, sortOrdinal);
85         }
86 
87         // udt ctor without tvp extended properties
SqlMetaData(String name, SqlDbType dbType, Type userDefinedType)88         public SqlMetaData(String name, SqlDbType dbType, Type userDefinedType)
89         {
90             Construct(name, dbType, userDefinedType, null, x_defaultUseServerDefault,
91                     x_defaultIsUniqueKey, x_defaultColumnSortOrder, x_defaultSortOrdinal);
92         }
93 
94         // udt ctor without tvp extended properties
SqlMetaData(String name, SqlDbType dbType, Type userDefinedType, string serverTypeName)95         public SqlMetaData(String name, SqlDbType dbType, Type userDefinedType, string serverTypeName)
96         {
97             Construct(name, dbType, userDefinedType, serverTypeName, x_defaultUseServerDefault,
98                     x_defaultIsUniqueKey, x_defaultColumnSortOrder, x_defaultSortOrdinal);
99         }
100 
101         // udt ctor
SqlMetaData(String name, SqlDbType dbType, Type userDefinedType, string serverTypeName, bool useServerDefault, bool isUniqueKey, SortOrder columnSortOrder, int sortOrdinal)102         public SqlMetaData(String name, SqlDbType dbType, Type userDefinedType, string serverTypeName,
103                     bool useServerDefault, bool isUniqueKey, SortOrder columnSortOrder, int sortOrdinal)
104         {
105             Construct(name, dbType, userDefinedType, serverTypeName, useServerDefault,
106                     isUniqueKey, columnSortOrder, sortOrdinal);
107         }
108 
109         // decimal ctor without tvp extended properties
SqlMetaData(String name, SqlDbType dbType, byte precision, byte scale)110         public SqlMetaData(String name, SqlDbType dbType, byte precision, byte scale)
111         {
112             Construct(name, dbType, precision, scale, x_defaultUseServerDefault,
113                     x_defaultIsUniqueKey, x_defaultColumnSortOrder, x_defaultSortOrdinal);
114         }
115 
116         // decimal ctor
SqlMetaData(string name, SqlDbType dbType, byte precision, byte scale, bool useServerDefault, bool isUniqueKey, SortOrder columnSortOrder, int sortOrdinal)117         public SqlMetaData(string name, SqlDbType dbType, byte precision, byte scale, bool useServerDefault,
118                     bool isUniqueKey, SortOrder columnSortOrder, int sortOrdinal)
119         {
120             Construct(name, dbType, precision, scale, useServerDefault,
121                     isUniqueKey, columnSortOrder, sortOrdinal);
122         }
123 
124         // string type constructor with locale and compare options, no tvp extended properties
SqlMetaData(String name, SqlDbType dbType, long maxLength, long locale, SqlCompareOptions compareOptions)125         public SqlMetaData(String name, SqlDbType dbType, long maxLength, long locale,
126                            SqlCompareOptions compareOptions)
127         {
128             Construct(name, dbType, maxLength, locale, compareOptions, x_defaultUseServerDefault,
129                     x_defaultIsUniqueKey, x_defaultColumnSortOrder, x_defaultSortOrdinal);
130         }
131 
132         // string type constructor with locale and compare options
SqlMetaData(String name, SqlDbType dbType, long maxLength, long locale, SqlCompareOptions compareOptions, bool useServerDefault, bool isUniqueKey, SortOrder columnSortOrder, int sortOrdinal)133         public SqlMetaData(String name, SqlDbType dbType, long maxLength, long locale,
134                            SqlCompareOptions compareOptions, bool useServerDefault,
135                            bool isUniqueKey, SortOrder columnSortOrder, int sortOrdinal)
136         {
137             Construct(name, dbType, maxLength, locale, compareOptions, useServerDefault,
138                     isUniqueKey, columnSortOrder, sortOrdinal);
139         }
140 
141         // typed xml ctor
SqlMetaData(String name, SqlDbType dbType, string database, string owningSchema, string objectName, bool useServerDefault, bool isUniqueKey, SortOrder columnSortOrder, int sortOrdinal)142         public SqlMetaData(String name, SqlDbType dbType, string database, string owningSchema,
143                            string objectName, bool useServerDefault, bool isUniqueKey,
144                            SortOrder columnSortOrder, int sortOrdinal)
145         {
146             Construct(name, dbType, database, owningSchema, objectName, useServerDefault,
147                         isUniqueKey, columnSortOrder, sortOrdinal);
148         }
149 
150         // everything except xml schema and tvp properties ctor
SqlMetaData(String name, SqlDbType dbType, long maxLength, byte precision, byte scale, long locale, SqlCompareOptions compareOptions, Type userDefinedType)151         public SqlMetaData(String name, SqlDbType dbType, long maxLength, byte precision,
152                            byte scale, long locale, SqlCompareOptions compareOptions,
153                            Type userDefinedType) :
154                            this(name, dbType, maxLength, precision, scale, locale, compareOptions,
155                                 userDefinedType, x_defaultUseServerDefault, x_defaultIsUniqueKey,
156                                 x_defaultColumnSortOrder, x_defaultSortOrdinal)
157         {
158         }
159 
160         // everything except xml schema ctor
SqlMetaData(String name, SqlDbType dbType, long maxLength, byte precision, byte scale, long localeId, SqlCompareOptions compareOptions, Type userDefinedType, bool useServerDefault, bool isUniqueKey, SortOrder columnSortOrder, int sortOrdinal)161         public SqlMetaData(String name, SqlDbType dbType, long maxLength, byte precision,
162                            byte scale, long localeId, SqlCompareOptions compareOptions,
163                            Type userDefinedType, bool useServerDefault,
164                            bool isUniqueKey, SortOrder columnSortOrder, int sortOrdinal)
165         {
166             switch (dbType)
167             {
168                 case SqlDbType.BigInt:
169                 case SqlDbType.Image:
170                 case SqlDbType.Timestamp:
171                 case SqlDbType.Bit:
172                 case SqlDbType.DateTime:
173                 case SqlDbType.SmallDateTime:
174                 case SqlDbType.Real:
175                 case SqlDbType.Int:
176                 case SqlDbType.Money:
177                 case SqlDbType.SmallMoney:
178                 case SqlDbType.Float:
179                 case SqlDbType.UniqueIdentifier:
180                 case SqlDbType.SmallInt:
181                 case SqlDbType.TinyInt:
182                 case SqlDbType.Xml:
183                 case SqlDbType.Date:
184                     Construct(name, dbType, useServerDefault, isUniqueKey, columnSortOrder, sortOrdinal);
185                     break;
186                 case SqlDbType.Binary:
187                 case SqlDbType.VarBinary:
188                     Construct(name, dbType, maxLength, useServerDefault, isUniqueKey, columnSortOrder, sortOrdinal);
189                     break;
190                 case SqlDbType.Char:
191                 case SqlDbType.NChar:
192                 case SqlDbType.NVarChar:
193                 case SqlDbType.VarChar:
194                     Construct(name, dbType, maxLength, localeId, compareOptions, useServerDefault, isUniqueKey, columnSortOrder, sortOrdinal);
195                     break;
196                 case SqlDbType.NText:
197                 case SqlDbType.Text:
198                     // We should ignore user's max length and use Max instead to avoid exception
199                     Construct(name, dbType, Max, localeId, compareOptions, useServerDefault, isUniqueKey, columnSortOrder, sortOrdinal);
200                     break;
201                 case SqlDbType.Decimal:
202                 case SqlDbType.Time:
203                 case SqlDbType.DateTime2:
204                 case SqlDbType.DateTimeOffset:
205                     Construct(name, dbType, precision, scale, useServerDefault, isUniqueKey, columnSortOrder, sortOrdinal);
206                     break;
207                 case SqlDbType.Variant:
208                     Construct(name, dbType, useServerDefault, isUniqueKey, columnSortOrder, sortOrdinal);
209                     break;
210                 case SqlDbType.Udt:
211                     Construct(name, dbType, userDefinedType, "", useServerDefault, isUniqueKey, columnSortOrder, sortOrdinal);
212                     break;
213                 default:
214                     SQL.InvalidSqlDbTypeForConstructor(dbType);
215                     break;
216             }
217         }
218 
SqlMetaData(String name, SqlDbType dbType, string database, string owningSchema, string objectName)219         public SqlMetaData(String name, SqlDbType dbType, string database, string owningSchema, string objectName)
220         {
221             Construct(name, dbType, database, owningSchema, objectName, x_defaultUseServerDefault, x_defaultIsUniqueKey,
222                     x_defaultColumnSortOrder, x_defaultSortOrdinal);
223         }
224 
225         // Most general constructor, should be able to initialize all SqlMetaData fields.(Used by SqlParameter)
SqlMetaData(String name, SqlDbType sqlDBType, long maxLength, byte precision, byte scale, long localeId, SqlCompareOptions compareOptions, string xmlSchemaCollectionDatabase, string xmlSchemaCollectionOwningSchema, string xmlSchemaCollectionName, bool partialLength, Type udtType)226         internal SqlMetaData(String name,
227                               SqlDbType sqlDBType,
228                               long maxLength,
229                               byte precision,
230                               byte scale,
231                               long localeId,
232                               SqlCompareOptions compareOptions,
233                               string xmlSchemaCollectionDatabase,
234                               string xmlSchemaCollectionOwningSchema,
235                               string xmlSchemaCollectionName,
236                               bool partialLength,
237                               Type udtType)
238         {
239             AssertNameIsValid(name);
240 
241             _strName = name;
242             _sqlDbType = sqlDBType;
243             _lMaxLength = maxLength;
244             _bPrecision = precision;
245             _bScale = scale;
246             _lLocale = localeId;
247             _eCompareOptions = compareOptions;
248             _xmlSchemaCollectionDatabase = xmlSchemaCollectionDatabase;
249             _xmlSchemaCollectionOwningSchema = xmlSchemaCollectionOwningSchema;
250             _xmlSchemaCollectionName = xmlSchemaCollectionName;
251             _bPartialLength = partialLength;
252 
253             _udtType = udtType;
254         }
255 
256         // Private constructor used to initialize default instance array elements.
257         // DO NOT EXPOSE OUTSIDE THIS CLASS!  It performs no validation.
SqlMetaData(String name, SqlDbType sqlDbType, long maxLength, byte precision, byte scale, long localeId, SqlCompareOptions compareOptions, bool partialLength)258         private SqlMetaData(String name,
259                              SqlDbType sqlDbType,
260                              long maxLength,
261                              byte precision,
262                              byte scale,
263                              long localeId,
264                              SqlCompareOptions compareOptions,
265                              bool partialLength)
266         {
267             AssertNameIsValid(name);
268 
269             _strName = name;
270             _sqlDbType = sqlDbType;
271             _lMaxLength = maxLength;
272             _bPrecision = precision;
273             _bScale = scale;
274             _lLocale = localeId;
275             _eCompareOptions = compareOptions;
276             _bPartialLength = partialLength;
277             _udtType = null;
278         }
279 
280         public SqlCompareOptions CompareOptions
281         {
282             get => _eCompareOptions;
283         }
284 
285         public DbType DbType
286         {
287             get => sxm_rgSqlDbTypeToDbType[(int)_sqlDbType];
288         }
289 
290         public bool IsUniqueKey
291         {
292             get => _isUniqueKey;
293         }
294 
295         public long LocaleId
296         {
297             get => _lLocale;
298         }
299 
300         public static long Max
301         {
302             get => x_lMax;
303         }
304 
305         public long MaxLength
306         {
307             get => _lMaxLength;
308         }
309 
310         public string Name
311         {
312             get => _strName;
313         }
314 
315         public byte Precision
316         {
317             get => _bPrecision;
318         }
319 
320         public byte Scale
321         {
322             get => _bScale;
323         }
324 
325         public SortOrder SortOrder
326         {
327             get => _columnSortOrder;
328         }
329 
330         public int SortOrdinal
331         {
332             get => _sortOrdinal;
333         }
334 
335         public SqlDbType SqlDbType
336         {
337             get => _sqlDbType;
338         }
339 
340         public Type Type
341         {
342             get => _udtType;
343         }
344 
345         public string TypeName
346         {
347             get
348             {
349                 if (_serverTypeName != null)
350                 {
351                     return _serverTypeName;
352                 }
353                 else if (SqlDbType == SqlDbType.Udt)
354                 {
355                     return UdtTypeName;
356                 }
357                 else
358                 {
359                     return sxm_rgDefaults[(int)SqlDbType].Name;
360                 }
361             }
362         }
363 
364         internal string ServerTypeName
365         {
366             get => _serverTypeName;
367         }
368 
369         public bool UseServerDefault
370         {
371             get => _useServerDefault;
372         }
373 
374         public string XmlSchemaCollectionDatabase
375         {
376             get => _xmlSchemaCollectionDatabase;
377         }
378 
379         public string XmlSchemaCollectionName
380         {
381             get => _xmlSchemaCollectionName;
382         }
383 
384         public string XmlSchemaCollectionOwningSchema
385         {
386             get => _xmlSchemaCollectionOwningSchema;
387         }
388 
389         internal bool IsPartialLength
390         {
391             get => _bPartialLength;
392         }
393 
394         internal string UdtTypeName
395         {
396             get
397             {
398                 if (SqlDbType != SqlDbType.Udt)
399                 {
400                     return null;
401                 }
402                 else if (_udtType == null)
403                 {
404                     return null;
405                 }
406                 else
407                 {
408                     return _udtType.FullName;
409                 }
410             }
411         }
412 
413         // Construction for all types that do not have variable attributes
Construct(String name, SqlDbType dbType, bool useServerDefault, bool isUniqueKey, SortOrder columnSortOrder, int sortOrdinal)414         private void Construct(String name, SqlDbType dbType, bool useServerDefault,
415                     bool isUniqueKey, SortOrder columnSortOrder, int sortOrdinal)
416         {
417             AssertNameIsValid(name);
418 
419             ValidateSortOrder(columnSortOrder, sortOrdinal);
420 
421             // Check for absence of explicitly-allowed types to avoid unexpected additions when new types are added
422             if (!(SqlDbType.BigInt == dbType ||
423                     SqlDbType.Bit == dbType ||
424                     SqlDbType.DateTime == dbType ||
425                     SqlDbType.Date == dbType ||
426                     SqlDbType.DateTime2 == dbType ||
427                     SqlDbType.DateTimeOffset == dbType ||
428                     SqlDbType.Decimal == dbType ||
429                     SqlDbType.Float == dbType ||
430                     SqlDbType.Image == dbType ||
431                     SqlDbType.Int == dbType ||
432                     SqlDbType.Money == dbType ||
433                     SqlDbType.NText == dbType ||
434                     SqlDbType.Real == dbType ||
435                     SqlDbType.SmallDateTime == dbType ||
436                     SqlDbType.SmallInt == dbType ||
437                     SqlDbType.SmallMoney == dbType ||
438                     SqlDbType.Text == dbType ||
439                     SqlDbType.Time == dbType ||
440                     SqlDbType.Timestamp == dbType ||
441                     SqlDbType.TinyInt == dbType ||
442                     SqlDbType.UniqueIdentifier == dbType ||
443                     SqlDbType.Variant == dbType ||
444                     SqlDbType.Xml == dbType))
445                 throw SQL.InvalidSqlDbTypeForConstructor(dbType);
446 
447             SetDefaultsForType(dbType);
448 
449             if (SqlDbType.NText == dbType || SqlDbType.Text == dbType)
450             {
451                 _lLocale = CultureInfo.CurrentCulture.LCID;
452             }
453 
454 
455             _strName = name;
456             _useServerDefault = useServerDefault;
457             _isUniqueKey = isUniqueKey;
458             _columnSortOrder = columnSortOrder;
459             _sortOrdinal = sortOrdinal;
460         }
461 
462         // Construction for all types that vary by user-specified length (not Udts)
Construct(String name, SqlDbType dbType, long maxLength, bool useServerDefault, bool isUniqueKey, SortOrder columnSortOrder, int sortOrdinal)463         private void Construct(String name, SqlDbType dbType, long maxLength, bool useServerDefault,
464                     bool isUniqueKey, SortOrder columnSortOrder, int sortOrdinal)
465         {
466             AssertNameIsValid(name);
467 
468             ValidateSortOrder(columnSortOrder, sortOrdinal);
469 
470             long lLocale = 0;
471             if (SqlDbType.Char == dbType)
472             {
473                 if (maxLength > x_lServerMaxANSI || maxLength < 0)
474                     throw ADP.Argument(SR.GetString(SR.ADP_InvalidDataLength2, maxLength.ToString(CultureInfo.InvariantCulture)), nameof(maxLength));
475                 lLocale = CultureInfo.CurrentCulture.LCID;
476             }
477             else if (SqlDbType.VarChar == dbType)
478             {
479                 if ((maxLength > x_lServerMaxANSI || maxLength < 0) && maxLength != Max)
480                     throw ADP.Argument(SR.GetString(SR.ADP_InvalidDataLength2, maxLength.ToString(CultureInfo.InvariantCulture)), nameof(maxLength));
481                 lLocale = CultureInfo.CurrentCulture.LCID;
482             }
483             else if (SqlDbType.NChar == dbType)
484             {
485                 if (maxLength > x_lServerMaxUnicode || maxLength < 0)
486                     throw ADP.Argument(SR.GetString(SR.ADP_InvalidDataLength2, maxLength.ToString(CultureInfo.InvariantCulture)), nameof(maxLength));
487                 lLocale = CultureInfo.CurrentCulture.LCID;
488             }
489             else if (SqlDbType.NVarChar == dbType)
490             {
491                 if ((maxLength > x_lServerMaxUnicode || maxLength < 0) && maxLength != Max)
492                     throw ADP.Argument(SR.GetString(SR.ADP_InvalidDataLength2, maxLength.ToString(CultureInfo.InvariantCulture)), nameof(maxLength));
493                 lLocale = CultureInfo.CurrentCulture.LCID;
494             }
495             else if (SqlDbType.NText == dbType || SqlDbType.Text == dbType)
496             {
497                 // old-style lobs only allowed with Max length
498                 if (SqlMetaData.Max != maxLength)
499                     throw ADP.Argument(SR.GetString(SR.ADP_InvalidDataLength2, maxLength.ToString(CultureInfo.InvariantCulture)), nameof(maxLength));
500                 lLocale = CultureInfo.CurrentCulture.LCID;
501             }
502             else if (SqlDbType.Binary == dbType)
503             {
504                 if (maxLength > x_lServerMaxBinary || maxLength < 0)
505                     throw ADP.Argument(SR.GetString(SR.ADP_InvalidDataLength2, maxLength.ToString(CultureInfo.InvariantCulture)), nameof(maxLength));
506             }
507             else if (SqlDbType.VarBinary == dbType)
508             {
509                 if ((maxLength > x_lServerMaxBinary || maxLength < 0) && maxLength != Max)
510                     throw ADP.Argument(SR.GetString(SR.ADP_InvalidDataLength2, maxLength.ToString(CultureInfo.InvariantCulture)), nameof(maxLength));
511             }
512             else if (SqlDbType.Image == dbType)
513             {
514                 // old-style lobs only allowed with Max length
515                 if (SqlMetaData.Max != maxLength)
516                     throw ADP.Argument(SR.GetString(SR.ADP_InvalidDataLength2, maxLength.ToString(CultureInfo.InvariantCulture)), nameof(maxLength));
517             }
518             else
519                 throw SQL.InvalidSqlDbTypeForConstructor(dbType);
520 
521             SetDefaultsForType(dbType);
522 
523             _strName = name;
524             _lMaxLength = maxLength;
525             _lLocale = lLocale;
526             _useServerDefault = useServerDefault;
527             _isUniqueKey = isUniqueKey;
528             _columnSortOrder = columnSortOrder;
529             _sortOrdinal = sortOrdinal;
530         }
531 
532         // Construction for string types with specified locale/compare options
Construct(String name, SqlDbType dbType, long maxLength, long locale, SqlCompareOptions compareOptions, bool useServerDefault, bool isUniqueKey, SortOrder columnSortOrder, int sortOrdinal)533         private void Construct(String name,
534                                SqlDbType dbType,
535                                long maxLength,
536                                long locale,
537                                SqlCompareOptions compareOptions,
538                                bool useServerDefault,
539                                bool isUniqueKey,
540                                SortOrder columnSortOrder,
541                                int sortOrdinal)
542         {
543             AssertNameIsValid(name);
544 
545             ValidateSortOrder(columnSortOrder, sortOrdinal);
546 
547             // Validate type and max length.
548             if (SqlDbType.Char == dbType)
549             {
550                 if (maxLength > x_lServerMaxANSI || maxLength < 0)
551                     throw ADP.Argument(SR.GetString(SR.ADP_InvalidDataLength2, maxLength.ToString(CultureInfo.InvariantCulture)), nameof(maxLength));
552             }
553             else if (SqlDbType.VarChar == dbType)
554             {
555                 if ((maxLength > x_lServerMaxANSI || maxLength < 0) && maxLength != Max)
556                     throw ADP.Argument(SR.GetString(SR.ADP_InvalidDataLength2, maxLength.ToString(CultureInfo.InvariantCulture)), nameof(maxLength));
557             }
558             else if (SqlDbType.NChar == dbType)
559             {
560                 if (maxLength > x_lServerMaxUnicode || maxLength < 0)
561                     throw ADP.Argument(SR.GetString(SR.ADP_InvalidDataLength2, maxLength.ToString(CultureInfo.InvariantCulture)), nameof(maxLength));
562             }
563             else if (SqlDbType.NVarChar == dbType)
564             {
565                 if ((maxLength > x_lServerMaxUnicode || maxLength < 0) && maxLength != Max)
566                     throw ADP.Argument(SR.GetString(SR.ADP_InvalidDataLength2, maxLength.ToString(CultureInfo.InvariantCulture)), nameof(maxLength));
567             }
568             else if (SqlDbType.NText == dbType || SqlDbType.Text == dbType)
569             {
570                 // old-style lobs only allowed with Max length
571                 if (SqlMetaData.Max != maxLength)
572                     throw ADP.Argument(SR.GetString(SR.ADP_InvalidDataLength2, maxLength.ToString(CultureInfo.InvariantCulture)), nameof(maxLength));
573             }
574             else
575                 throw SQL.InvalidSqlDbTypeForConstructor(dbType);
576 
577             // Validate locale?
578 
579             // Validate compare options
580             //    Binary sort must be by itself.
581             //    Nothing else but the Ignore bits is allowed.
582             if (SqlCompareOptions.BinarySort != compareOptions &&
583                     0 != (~((int)SqlCompareOptions.IgnoreCase | (int)SqlCompareOptions.IgnoreNonSpace |
584                             (int)SqlCompareOptions.IgnoreKanaType | (int)SqlCompareOptions.IgnoreWidth) &
585                         (int)compareOptions))
586                 throw ADP.InvalidEnumerationValue(typeof(SqlCompareOptions), (int)compareOptions);
587 
588             SetDefaultsForType(dbType);
589 
590             _strName = name;
591             _lMaxLength = maxLength;
592             _lLocale = locale;
593             _eCompareOptions = compareOptions;
594             _useServerDefault = useServerDefault;
595             _isUniqueKey = isUniqueKey;
596             _columnSortOrder = columnSortOrder;
597             _sortOrdinal = sortOrdinal;
598         }
599 
600 
601         private static byte[] s_maxLenFromPrecision = new byte[] {5,5,5,5,5,5,5,5,5,9,9,9,9,9,
602         9,9,9,9,9,13,13,13,13,13,13,13,13,13,17,17,17,17,17,17,17,17,17,17};
603 
604         private const byte MaxTimeScale = 7;
605 
606         private static byte[] s_maxVarTimeLenOffsetFromScale = new byte[] { 2, 2, 2, 1, 1, 0, 0, 0 };
607 
608         // Construction for Decimal type and new Katmai Date/Time types
Construct(String name, SqlDbType dbType, byte precision, byte scale, bool useServerDefault, bool isUniqueKey, SortOrder columnSortOrder, int sortOrdinal)609         private void Construct(String name, SqlDbType dbType, byte precision, byte scale, bool useServerDefault,
610                     bool isUniqueKey, SortOrder columnSortOrder, int sortOrdinal)
611         {
612             AssertNameIsValid(name);
613 
614             ValidateSortOrder(columnSortOrder, sortOrdinal);
615 
616             if (SqlDbType.Decimal == dbType)
617             {
618                 if (precision > SqlDecimal.MaxPrecision || scale > precision)
619                     throw SQL.PrecisionValueOutOfRange(precision);
620 
621                 if (scale > SqlDecimal.MaxScale)
622                     throw SQL.ScaleValueOutOfRange(scale);
623             }
624             else if (SqlDbType.Time == dbType || SqlDbType.DateTime2 == dbType || SqlDbType.DateTimeOffset == dbType)
625             {
626                 if (scale > MaxTimeScale)
627                 {
628                     throw SQL.TimeScaleValueOutOfRange(scale);
629                 }
630             }
631             else
632             {
633                 throw SQL.InvalidSqlDbTypeForConstructor(dbType);
634             }
635             SetDefaultsForType(dbType);
636 
637             _strName = name;
638             _bPrecision = precision;
639             _bScale = scale;
640             if (SqlDbType.Decimal == dbType)
641             {
642                 _lMaxLength = s_maxLenFromPrecision[precision - 1];
643             }
644             else
645             {
646                 _lMaxLength -= s_maxVarTimeLenOffsetFromScale[scale];
647             }
648             _useServerDefault = useServerDefault;
649             _isUniqueKey = isUniqueKey;
650             _columnSortOrder = columnSortOrder;
651             _sortOrdinal = sortOrdinal;
652         }
653 
654         // Construction for Udt type
Construct(String name, SqlDbType dbType, Type userDefinedType, string serverTypeName, bool useServerDefault, bool isUniqueKey, SortOrder columnSortOrder, int sortOrdinal)655         private void Construct(String name, SqlDbType dbType, Type userDefinedType, string serverTypeName, bool useServerDefault,
656                     bool isUniqueKey, SortOrder columnSortOrder, int sortOrdinal)
657         {
658             AssertNameIsValid(name);
659 
660             ValidateSortOrder(columnSortOrder, sortOrdinal);
661 
662             if (SqlDbType.Udt != dbType)
663                 throw SQL.InvalidSqlDbTypeForConstructor(dbType);
664 
665             if (null == userDefinedType)
666                 throw ADP.ArgumentNull(nameof(userDefinedType));
667 
668             SetDefaultsForType(SqlDbType.Udt);
669 
670             _strName = name;
671             _lMaxLength = SerializationHelperSql9.GetUdtMaxLength(userDefinedType);
672             _udtType = userDefinedType;
673             _serverTypeName = serverTypeName;
674             _useServerDefault = useServerDefault;
675             _isUniqueKey = isUniqueKey;
676             _columnSortOrder = columnSortOrder;
677             _sortOrdinal = sortOrdinal;
678         }
679 
680         // Construction for Xml type
Construct(String name, SqlDbType dbType, string database, string owningSchema, string objectName, bool useServerDefault, bool isUniqueKey, SortOrder columnSortOrder, int sortOrdinal)681         private void Construct(String name, SqlDbType dbType, string database, string owningSchema,
682                     string objectName, bool useServerDefault, bool isUniqueKey, SortOrder columnSortOrder,
683                     int sortOrdinal)
684         {
685             AssertNameIsValid(name);
686 
687             ValidateSortOrder(columnSortOrder, sortOrdinal);
688 
689             if (SqlDbType.Xml != dbType)
690                 throw SQL.InvalidSqlDbTypeForConstructor(dbType);
691 
692             if (null != database || null != owningSchema)
693             {
694                 if (null == objectName)
695                 {
696                     throw ADP.ArgumentNull(nameof(objectName));
697                 }
698             }
699 
700             SetDefaultsForType(SqlDbType.Xml);
701             _strName = name;
702 
703             _xmlSchemaCollectionDatabase = database;
704             _xmlSchemaCollectionOwningSchema = owningSchema;
705             _xmlSchemaCollectionName = objectName;
706             _useServerDefault = useServerDefault;
707             _isUniqueKey = isUniqueKey;
708             _columnSortOrder = columnSortOrder;
709             _sortOrdinal = sortOrdinal;
710         }
711 
AssertNameIsValid(string name)712         private void AssertNameIsValid(string name)
713         {
714             if (null == name)
715                 throw ADP.ArgumentNull(nameof(name));
716 
717             if (Microsoft.SqlServer.Server.SmiMetaData.MaxNameLength < name.Length)
718                 throw SQL.NameTooLong(nameof(name));
719         }
720 
ValidateSortOrder(SortOrder columnSortOrder, int sortOrdinal)721         private void ValidateSortOrder(SortOrder columnSortOrder, int sortOrdinal)
722         {
723             // Check that sort order is valid enum value.
724             if (SortOrder.Unspecified != columnSortOrder &&
725                     SortOrder.Ascending != columnSortOrder &&
726                     SortOrder.Descending != columnSortOrder)
727             {
728                 throw SQL.InvalidSortOrder(columnSortOrder);
729             }
730 
731             // Must specify both sort order and ordinal, or neither
732             if ((SortOrder.Unspecified == columnSortOrder) != (x_defaultSortOrdinal == sortOrdinal))
733             {
734                 throw SQL.MustSpecifyBothSortOrderAndOrdinal(columnSortOrder, sortOrdinal);
735             }
736         }
737 
738 
Adjust(Int16 value)739         public Int16 Adjust(Int16 value)
740         {
741             if (SqlDbType.SmallInt != SqlDbType)
742                 ThrowInvalidType();
743             return value;
744         }
745 
Adjust(Int32 value)746         public Int32 Adjust(Int32 value)
747         {
748             if (SqlDbType.Int != SqlDbType)
749                 ThrowInvalidType();
750             return value;
751         }
752 
Adjust(Int64 value)753         public Int64 Adjust(Int64 value)
754         {
755             if (SqlDbType.BigInt != SqlDbType)
756                 ThrowInvalidType();
757             return value;
758         }
759 
Adjust(float value)760         public float Adjust(float value)
761         {
762             if (SqlDbType.Real != SqlDbType)
763                 ThrowInvalidType();
764             return value;
765         }
766 
Adjust(double value)767         public double Adjust(double value)
768         {
769             if (SqlDbType.Float != SqlDbType)
770                 ThrowInvalidType();
771             return value;
772         }
773 
Adjust(string value)774         public string Adjust(string value)
775         {
776             if (SqlDbType.Char == SqlDbType || SqlDbType.NChar == SqlDbType)
777             {
778                 // Don't pad null values
779                 if (null != value)
780                 {
781                     // Pad if necessary
782                     if (value.Length < MaxLength)
783                         value = value.PadRight((int)MaxLength);
784                 }
785             }
786             else if (SqlDbType.VarChar != SqlDbType &&
787                      SqlDbType.NVarChar != SqlDbType &&
788                      SqlDbType.Text != SqlDbType &&
789                      SqlDbType.NText != SqlDbType)
790             {
791                 ThrowInvalidType();
792             }
793 
794             // Handle null values after type check
795             if (null == value)
796             {
797                 return null;
798             }
799 
800             if (value.Length > MaxLength && Max != MaxLength)
801                 value = value.Remove((int)MaxLength, (int)(value.Length - MaxLength));
802 
803             return value;
804         }
805 
Adjust(decimal value)806         public decimal Adjust(decimal value)
807         {
808             if (SqlDbType.Decimal != SqlDbType &&
809                 SqlDbType.Money != SqlDbType &&
810                 SqlDbType.SmallMoney != SqlDbType)
811             {
812                 ThrowInvalidType();
813             }
814 
815             if (SqlDbType.Decimal != SqlDbType)
816             {
817                 VerifyMoneyRange(new SqlMoney(value));
818                 return value;
819             }
820             else
821             {
822                 SqlDecimal sdValue = InternalAdjustSqlDecimal(new SqlDecimal(value));
823                 return sdValue.Value;
824             }
825         }
826 
Adjust(DateTime value)827         public DateTime Adjust(DateTime value)
828         {
829             if (SqlDbType.DateTime == SqlDbType || SqlDbType.SmallDateTime == SqlDbType)
830             {
831                 VerifyDateTimeRange(value);
832             }
833             else if (SqlDbType.DateTime2 == SqlDbType)
834             {
835                 return new DateTime(InternalAdjustTimeTicks(value.Ticks));
836             }
837             else if (SqlDbType.Date == SqlDbType)
838             {
839                 return value.Date;
840             }
841             else
842             {
843                 ThrowInvalidType();
844             }
845             return value;
846         }
847 
Adjust(Guid value)848         public Guid Adjust(Guid value)
849         {
850             if (SqlDbType.UniqueIdentifier != SqlDbType)
851                 ThrowInvalidType();
852             return value;
853         }
854 
Adjust(SqlBoolean value)855         public SqlBoolean Adjust(SqlBoolean value)
856         {
857             if (SqlDbType.Bit != SqlDbType)
858                 ThrowInvalidType();
859             return value;
860         }
861 
Adjust(SqlByte value)862         public SqlByte Adjust(SqlByte value)
863         {
864             if (SqlDbType.TinyInt != SqlDbType)
865                 ThrowInvalidType();
866             return value;
867         }
868 
Adjust(SqlInt16 value)869         public SqlInt16 Adjust(SqlInt16 value)
870         {
871             if (SqlDbType.SmallInt != SqlDbType)
872                 ThrowInvalidType();
873             return value;
874         }
875 
Adjust(SqlInt32 value)876         public SqlInt32 Adjust(SqlInt32 value)
877         {
878             if (SqlDbType.Int != SqlDbType)
879                 ThrowInvalidType();
880             return value;
881         }
882 
Adjust(SqlInt64 value)883         public SqlInt64 Adjust(SqlInt64 value)
884         {
885             if (SqlDbType.BigInt != SqlDbType)
886                 ThrowInvalidType();
887             return value;
888         }
889 
Adjust(SqlSingle value)890         public SqlSingle Adjust(SqlSingle value)
891         {
892             if (SqlDbType.Real != SqlDbType)
893                 ThrowInvalidType();
894             return value;
895         }
896 
Adjust(SqlDouble value)897         public SqlDouble Adjust(SqlDouble value)
898         {
899             if (SqlDbType.Float != SqlDbType)
900                 ThrowInvalidType();
901             return value;
902         }
903 
Adjust(SqlMoney value)904         public SqlMoney Adjust(SqlMoney value)
905         {
906             if (SqlDbType.Money != SqlDbType &&
907                 SqlDbType.SmallMoney != SqlDbType)
908                 ThrowInvalidType();
909 
910             if (!value.IsNull)
911                 VerifyMoneyRange(value);
912 
913             return value;
914         }
915 
Adjust(SqlDateTime value)916         public SqlDateTime Adjust(SqlDateTime value)
917         {
918             if (SqlDbType.DateTime != SqlDbType &&
919                 SqlDbType.SmallDateTime != SqlDbType)
920                 ThrowInvalidType();
921 
922             if (!value.IsNull)
923                 VerifyDateTimeRange(value.Value);
924 
925             return value;
926         }
927 
Adjust(SqlDecimal value)928         public SqlDecimal Adjust(SqlDecimal value)
929         {
930             if (SqlDbType.Decimal != SqlDbType)
931                 ThrowInvalidType();
932             return InternalAdjustSqlDecimal(value);
933         }
934 
Adjust(SqlString value)935         public SqlString Adjust(SqlString value)
936         {
937             if (SqlDbType.Char == SqlDbType || SqlDbType.NChar == SqlDbType)
938             {
939                 //DBG.Assert(Max!=MaxLength, "SqlMetaData.Adjust(SqlString): Fixed-length type with Max length!");
940                 // Don't pad null values
941                 if (!value.IsNull)
942                 {
943                     // Pad fixed-length types
944                     if (value.Value.Length < MaxLength)
945                         return new SqlString(value.Value.PadRight((int)MaxLength));
946                 }
947             }
948             else if (SqlDbType.VarChar != SqlDbType && SqlDbType.NVarChar != SqlDbType &&
949                     SqlDbType.Text != SqlDbType && SqlDbType.NText != SqlDbType)
950                 ThrowInvalidType();
951 
952             // Handle null values after type check
953             if (value.IsNull)
954             {
955                 return value;
956             }
957 
958             // trim all types
959             if (value.Value.Length > MaxLength && Max != MaxLength)
960                 value = new SqlString(value.Value.Remove((int)MaxLength, (int)(value.Value.Length - MaxLength)));
961 
962             return value;
963         }
964 
Adjust(SqlBinary value)965         public SqlBinary Adjust(SqlBinary value)
966         {
967             if (SqlDbType.Binary == SqlDbType ||
968                 SqlDbType.Timestamp == SqlDbType)
969             {
970                 if (!value.IsNull)
971                 {
972                     // Pad fixed-length types
973                     if (value.Length < MaxLength)
974                     {
975                         byte[] rgbValue = value.Value;
976                         byte[] rgbNewValue = new byte[MaxLength];
977                         Buffer.BlockCopy(rgbValue, 0, rgbNewValue, 0, rgbValue.Length);
978                         Array.Clear(rgbNewValue, rgbValue.Length, rgbNewValue.Length - rgbValue.Length);
979                         return new SqlBinary(rgbNewValue);
980                     }
981                 }
982             }
983             else if (SqlDbType.VarBinary != SqlDbType &&
984                     SqlDbType.Image != SqlDbType)
985                 ThrowInvalidType();
986 
987             // Handle null values
988             if (value.IsNull)
989             {
990                 return value;
991             }
992 
993             // trim all types
994             if (value.Length > MaxLength && Max != MaxLength)
995             {
996                 byte[] rgbValue = value.Value;
997                 byte[] rgbNewValue = new byte[MaxLength];
998                 Buffer.BlockCopy(rgbValue, 0, rgbNewValue, 0, (int)MaxLength);
999                 value = new SqlBinary(rgbNewValue);
1000             }
1001 
1002             return value;
1003         }
1004 
Adjust(SqlGuid value)1005         public SqlGuid Adjust(SqlGuid value)
1006         {
1007             if (SqlDbType.UniqueIdentifier != SqlDbType)
1008                 ThrowInvalidType();
1009             return value;
1010         }
1011 
Adjust(SqlChars value)1012         public SqlChars Adjust(SqlChars value)
1013         {
1014             if (SqlDbType.Char == SqlDbType || SqlDbType.NChar == SqlDbType)
1015             {
1016                 //DBG.Assert(Max!=MaxLength, "SqlMetaData.Adjust(SqlChars): Fixed-length type with Max length!");
1017                 // Don't pad null values
1018                 if (null != value && !value.IsNull)
1019                 {
1020                     // Pad fixed-length types
1021                     long oldLength = value.Length;
1022                     if (oldLength < MaxLength)
1023                     {
1024                         // Make sure buffer is long enough
1025                         if (value.MaxLength < MaxLength)
1026                         {
1027                             char[] rgchNew = new char[(int)MaxLength];
1028                             Buffer.BlockCopy(value.Buffer, 0, rgchNew, 0, (int)oldLength);
1029                             value = new SqlChars(rgchNew);
1030                         }
1031 
1032                         // pad extra space
1033                         char[] rgchTemp = value.Buffer;
1034                         for (long i = oldLength; i < MaxLength; i++)
1035                             rgchTemp[i] = ' ';
1036 
1037                         value.SetLength(MaxLength);
1038                         return value;
1039                     }
1040                 }
1041             }
1042             else if (SqlDbType.VarChar != SqlDbType && SqlDbType.NVarChar != SqlDbType &&
1043                     SqlDbType.Text != SqlDbType && SqlDbType.NText != SqlDbType)
1044                 ThrowInvalidType();
1045 
1046             // Handle null values after type check.
1047             if (null == value || value.IsNull)
1048             {
1049                 return value;
1050             }
1051 
1052             // trim all types
1053             if (value.Length > MaxLength && Max != MaxLength)
1054                 value.SetLength(MaxLength);
1055 
1056             return value;
1057         }
1058 
Adjust(SqlBytes value)1059         public SqlBytes Adjust(SqlBytes value)
1060         {
1061             if (SqlDbType.Binary == SqlDbType || SqlDbType.Timestamp == SqlDbType)
1062             {
1063                 //DBG.Assert(Max!=MaxLength, "SqlMetaData.Adjust(SqlBytes): Fixed-length type with Max length!");
1064                 // Don't pad null values
1065                 if (null != value && !value.IsNull)
1066                 {
1067                     // Pad fixed-length types
1068                     int oldLength = (int)value.Length;
1069                     if (oldLength < MaxLength)
1070                     {
1071                         // Make sure buffer is long enough
1072                         if (value.MaxLength < MaxLength)
1073                         {
1074                             byte[] rgbNew = new byte[MaxLength];
1075                             Buffer.BlockCopy(value.Buffer, 0, rgbNew, 0, (int)oldLength);
1076                             value = new SqlBytes(rgbNew);
1077                         }
1078 
1079                         // pad extra space
1080                         byte[] rgbTemp = value.Buffer;
1081                         Array.Clear(rgbTemp, oldLength, rgbTemp.Length - oldLength);
1082                         value.SetLength(MaxLength);
1083                         return value;
1084                     }
1085                 }
1086             }
1087             else if (SqlDbType.VarBinary != SqlDbType &&
1088                      SqlDbType.Image != SqlDbType)
1089                 ThrowInvalidType();
1090 
1091             // Handle null values after type check.
1092             if (null == value || value.IsNull)
1093             {
1094                 return value;
1095             }
1096 
1097             // trim all types
1098             if (value.Length > MaxLength && Max != MaxLength)
1099                 value.SetLength(MaxLength);
1100 
1101             return value;
1102         }
1103 
Adjust(SqlXml value)1104         public SqlXml Adjust(SqlXml value)
1105         {
1106             if (SqlDbType.Xml != SqlDbType)
1107                 ThrowInvalidType();
1108             return value;
1109         }
1110 
Adjust(TimeSpan value)1111         public TimeSpan Adjust(TimeSpan value)
1112         {
1113             if (SqlDbType.Time != SqlDbType)
1114                 ThrowInvalidType();
1115             VerifyTimeRange(value);
1116             return new TimeSpan(InternalAdjustTimeTicks(value.Ticks));
1117         }
1118 
Adjust(DateTimeOffset value)1119         public DateTimeOffset Adjust(DateTimeOffset value)
1120         {
1121             if (SqlDbType.DateTimeOffset != SqlDbType)
1122                 ThrowInvalidType();
1123             return new DateTimeOffset(InternalAdjustTimeTicks(value.Ticks), value.Offset);
1124         }
1125 
Adjust(object value)1126         public object Adjust(object value)
1127         {
1128             // Pass null references through
1129             if (null == value)
1130                 return null;
1131 
1132             Type dataType = value.GetType();
1133             switch (Type.GetTypeCode(dataType))
1134             {
1135                 case TypeCode.Boolean: value = this.Adjust((Boolean)value); break;
1136                 case TypeCode.Byte: value = this.Adjust((Byte)value); break;
1137                 case TypeCode.Char: value = this.Adjust((Char)value); break;
1138                 case TypeCode.DateTime: value = this.Adjust((DateTime)value); break;
1139                 case TypeCode.DBNull:    /* DBNull passes through as is for all types */   break;
1140                 case TypeCode.Decimal: value = this.Adjust((Decimal)value); break;
1141                 case TypeCode.Double: value = this.Adjust((Double)value); break;
1142                 case TypeCode.Empty: throw ADP.InvalidDataType(TypeCode.Empty);
1143                 case TypeCode.Int16: value = this.Adjust((Int16)value); break;
1144                 case TypeCode.Int32: value = this.Adjust((Int32)value); break;
1145                 case TypeCode.Int64: value = this.Adjust((Int64)value); break;
1146                 case TypeCode.SByte: throw ADP.InvalidDataType(TypeCode.SByte);
1147                 case TypeCode.Single: value = this.Adjust((Single)value); break;
1148                 case TypeCode.String: value = this.Adjust((String)value); break;
1149                 case TypeCode.UInt16: throw ADP.InvalidDataType(TypeCode.UInt16);
1150                 case TypeCode.UInt32: throw ADP.InvalidDataType(TypeCode.UInt32);
1151                 case TypeCode.UInt64: throw ADP.InvalidDataType(TypeCode.UInt64);
1152                 case TypeCode.Object:
1153                     if (dataType == typeof(System.Byte[]))
1154                         value = this.Adjust((System.Byte[])value);
1155                     else if (dataType == typeof(System.Char[]))
1156                         value = this.Adjust((System.Char[])value);
1157                     else if (dataType == typeof(System.Guid))
1158                         value = this.Adjust((System.Guid)value);
1159                     else if (dataType == typeof(System.Object))
1160                     {
1161                         throw ADP.InvalidDataType(TypeCode.UInt64);
1162                     }
1163                     else if (dataType == typeof(SqlBinary))
1164                         value = this.Adjust((SqlBinary)value);
1165                     else if (dataType == typeof(SqlBoolean))
1166                         value = this.Adjust((SqlBoolean)value);
1167                     else if (dataType == typeof(SqlByte))
1168                         value = this.Adjust((SqlByte)value);
1169                     else if (dataType == typeof(SqlDateTime))
1170                         value = this.Adjust((SqlDateTime)value);
1171                     else if (dataType == typeof(SqlDouble))
1172                         value = this.Adjust((SqlDouble)value);
1173                     else if (dataType == typeof(SqlGuid))
1174                         value = this.Adjust((SqlGuid)value);
1175                     else if (dataType == typeof(SqlInt16))
1176                         value = this.Adjust((SqlInt16)value);
1177                     else if (dataType == typeof(SqlInt32))
1178                         value = this.Adjust((SqlInt32)value);
1179                     else if (dataType == typeof(SqlInt64))
1180                         value = this.Adjust((SqlInt64)value);
1181                     else if (dataType == typeof(SqlMoney))
1182                         value = this.Adjust((SqlMoney)value);
1183                     else if (dataType == typeof(SqlDecimal))
1184                         value = this.Adjust((SqlDecimal)value);
1185                     else if (dataType == typeof(SqlSingle))
1186                         value = this.Adjust((SqlSingle)value);
1187                     else if (dataType == typeof(SqlString))
1188                         value = this.Adjust((SqlString)value);
1189                     else if (dataType == typeof(SqlChars))
1190                         value = this.Adjust((SqlChars)value);
1191                     else if (dataType == typeof(SqlBytes))
1192                         value = this.Adjust((SqlBytes)value);
1193                     else if (dataType == typeof(SqlXml))
1194                         value = this.Adjust((SqlXml)value);
1195                     else if (dataType == typeof(TimeSpan))
1196                         value = this.Adjust((TimeSpan)value);
1197                     else if (dataType == typeof(DateTimeOffset))
1198                         value = this.Adjust((DateTimeOffset)value);
1199                     else
1200                     {
1201                         // Handle UDTs?
1202                         throw ADP.UnknownDataType(dataType);
1203                     }
1204                     break;
1205 
1206 
1207                 default: throw ADP.UnknownDataTypeCode(dataType, Type.GetTypeCode(dataType));
1208             }
1209 
1210             return value;
1211         }
1212 
InferFromValue(object value, String name)1213         public static SqlMetaData InferFromValue(object value, String name)
1214         {
1215             if (value == null)
1216                 throw ADP.ArgumentNull(nameof(value));
1217             SqlMetaData smd = null;
1218             Type dataType = value.GetType();
1219             switch (Type.GetTypeCode(dataType))
1220             {
1221                 case TypeCode.Boolean: smd = new SqlMetaData(name, SqlDbType.Bit); break;
1222                 case TypeCode.Byte: smd = new SqlMetaData(name, SqlDbType.TinyInt); break;
1223                 case TypeCode.Char: smd = new SqlMetaData(name, SqlDbType.NVarChar, 1); break;
1224                 case TypeCode.DateTime: smd = new SqlMetaData(name, SqlDbType.DateTime); break;
1225                 case TypeCode.DBNull: throw ADP.InvalidDataType(TypeCode.DBNull);
1226                 case TypeCode.Decimal:
1227                     {  // Add brackets in order to contain scope declare local variable "sd"
1228                        // use logic inside SqlDecimal to infer precision and scale.
1229                         SqlDecimal sd = new SqlDecimal((Decimal)value);
1230                         smd = new SqlMetaData(name, SqlDbType.Decimal, sd.Precision, sd.Scale);
1231                     }
1232                     break;
1233                 case TypeCode.Double: smd = new SqlMetaData(name, SqlDbType.Float); break;
1234                 case TypeCode.Empty: throw ADP.InvalidDataType(TypeCode.Empty);
1235                 case TypeCode.Int16: smd = new SqlMetaData(name, SqlDbType.SmallInt); break;
1236                 case TypeCode.Int32: smd = new SqlMetaData(name, SqlDbType.Int); break;
1237                 case TypeCode.Int64: smd = new SqlMetaData(name, SqlDbType.BigInt); break;
1238                 case TypeCode.SByte: throw ADP.InvalidDataType(TypeCode.SByte);
1239                 case TypeCode.Single: smd = new SqlMetaData(name, SqlDbType.Real); break;
1240                 case TypeCode.String:
1241                     {
1242                         long maxLen = ((String)value).Length;
1243                         if (maxLen < 1) maxLen = 1;
1244 
1245                         if (x_lServerMaxUnicode < maxLen)
1246                             maxLen = Max;
1247 
1248                         smd = new SqlMetaData(name, SqlDbType.NVarChar, maxLen);
1249                     }
1250                     break;
1251                 case TypeCode.UInt16: throw ADP.InvalidDataType(TypeCode.UInt16);
1252                 case TypeCode.UInt32: throw ADP.InvalidDataType(TypeCode.UInt32);
1253                 case TypeCode.UInt64: throw ADP.InvalidDataType(TypeCode.UInt64);
1254                 case TypeCode.Object:
1255                     if (dataType == typeof(System.Byte[]))
1256                     {
1257                         long maxLen = ((System.Byte[])value).Length;
1258                         if (maxLen < 1) maxLen = 1;
1259 
1260                         if (x_lServerMaxBinary < maxLen)
1261                             maxLen = Max;
1262 
1263                         smd = new SqlMetaData(name, SqlDbType.VarBinary, maxLen);
1264                     }
1265                     else if (dataType == typeof(System.Char[]))
1266                     {
1267                         long maxLen = ((System.Char[])value).Length;
1268                         if (maxLen < 1) maxLen = 1;
1269 
1270                         if (x_lServerMaxUnicode < maxLen)
1271                             maxLen = Max;
1272 
1273                         smd = new SqlMetaData(name, SqlDbType.NVarChar, maxLen);
1274                     }
1275                     else if (dataType == typeof(System.Guid))
1276                         smd = new SqlMetaData(name, SqlDbType.UniqueIdentifier);
1277                     else if (dataType == typeof(System.Object))
1278                         smd = new SqlMetaData(name, SqlDbType.Variant);
1279                     else if (dataType == typeof(SqlBinary))
1280                     {
1281                         long maxLen;
1282                         SqlBinary sb = ((SqlBinary)value);
1283                         if (!sb.IsNull)
1284                         {
1285                             maxLen = sb.Length;
1286                             if (maxLen < 1) maxLen = 1;
1287 
1288                             if (x_lServerMaxBinary < maxLen)
1289                                 maxLen = Max;
1290                         }
1291                         else
1292                             maxLen = sxm_rgDefaults[(int)SqlDbType.VarBinary].MaxLength;
1293 
1294                         smd = new SqlMetaData(name, SqlDbType.VarBinary, maxLen);
1295                     }
1296                     else if (dataType == typeof(SqlBoolean))
1297                         smd = new SqlMetaData(name, SqlDbType.Bit);
1298                     else if (dataType == typeof(SqlByte))
1299                         smd = new SqlMetaData(name, SqlDbType.TinyInt);
1300                     else if (dataType == typeof(SqlDateTime))
1301                         smd = new SqlMetaData(name, SqlDbType.DateTime);
1302                     else if (dataType == typeof(SqlDouble))
1303                         smd = new SqlMetaData(name, SqlDbType.Float);
1304                     else if (dataType == typeof(SqlGuid))
1305                         smd = new SqlMetaData(name, SqlDbType.UniqueIdentifier);
1306                     else if (dataType == typeof(SqlInt16))
1307                         smd = new SqlMetaData(name, SqlDbType.SmallInt);
1308                     else if (dataType == typeof(SqlInt32))
1309                         smd = new SqlMetaData(name, SqlDbType.Int);
1310                     else if (dataType == typeof(SqlInt64))
1311                         smd = new SqlMetaData(name, SqlDbType.BigInt);
1312                     else if (dataType == typeof(SqlMoney))
1313                         smd = new SqlMetaData(name, SqlDbType.Money);
1314                     else if (dataType == typeof(SqlDecimal))
1315                     {
1316                         byte bPrec;
1317                         byte scale;
1318                         SqlDecimal sd = (SqlDecimal)value;
1319                         if (!sd.IsNull)
1320                         {
1321                             bPrec = sd.Precision;
1322                             scale = sd.Scale;
1323                         }
1324                         else
1325                         {
1326                             bPrec = sxm_rgDefaults[(int)SqlDbType.Decimal].Precision;
1327                             scale = sxm_rgDefaults[(int)SqlDbType.Decimal].Scale;
1328                         }
1329                         smd = new SqlMetaData(name, SqlDbType.Decimal, bPrec, scale);
1330                     }
1331                     else if (dataType == typeof(SqlSingle))
1332                         smd = new SqlMetaData(name, SqlDbType.Real);
1333                     else if (dataType == typeof(SqlString))
1334                     {
1335                         SqlString ss = (SqlString)value;
1336                         if (!ss.IsNull)
1337                         {
1338                             long maxLen = ss.Value.Length;
1339                             if (maxLen < 1) maxLen = 1;
1340 
1341                             if (maxLen > x_lServerMaxUnicode)
1342                                 maxLen = Max;
1343 
1344                             smd = new SqlMetaData(name, SqlDbType.NVarChar, maxLen, ss.LCID, ss.SqlCompareOptions);
1345                         }
1346                         else
1347                         {
1348                             smd = new SqlMetaData(name, SqlDbType.NVarChar, sxm_rgDefaults[(int)SqlDbType.NVarChar].MaxLength);
1349                         }
1350                     }
1351                     else if (dataType == typeof(SqlChars))
1352                     {
1353                         long maxLen;
1354                         SqlChars sch = (SqlChars)value;
1355                         if (!sch.IsNull)
1356                         {
1357                             maxLen = sch.Length;
1358                             if (maxLen < 1) maxLen = 1;
1359 
1360                             if (maxLen > x_lServerMaxUnicode)
1361                                 maxLen = Max;
1362                         }
1363                         else
1364                             maxLen = sxm_rgDefaults[(int)SqlDbType.NVarChar].MaxLength;
1365 
1366                         smd = new SqlMetaData(name, SqlDbType.NVarChar, maxLen);
1367                     }
1368                     else if (dataType == typeof(SqlBytes))
1369                     {
1370                         long maxLen;
1371                         SqlBytes sb = (SqlBytes)value;
1372                         if (!sb.IsNull)
1373                         {
1374                             maxLen = sb.Length;
1375                             if (maxLen < 1) maxLen = 1;
1376                             else if (x_lServerMaxBinary < maxLen) maxLen = Max;
1377                         }
1378                         else
1379                             maxLen = sxm_rgDefaults[(int)SqlDbType.VarBinary].MaxLength;
1380 
1381                         smd = new SqlMetaData(name, SqlDbType.VarBinary, maxLen);
1382                     }
1383                     else if (dataType == typeof(SqlXml))
1384                         smd = new SqlMetaData(name, SqlDbType.Xml);
1385                     else if (dataType == typeof(TimeSpan))
1386                         smd = new SqlMetaData(name, SqlDbType.Time, 0, InferScaleFromTimeTicks(((TimeSpan)value).Ticks));
1387                     else if (dataType == typeof(DateTimeOffset))
1388                         smd = new SqlMetaData(name, SqlDbType.DateTimeOffset, 0, InferScaleFromTimeTicks(((DateTimeOffset)value).Ticks));
1389                     else
1390                         throw ADP.UnknownDataType(dataType);
1391                     break;
1392 
1393 
1394                 default: throw ADP.UnknownDataTypeCode(dataType, Type.GetTypeCode(dataType));
1395             }
1396 
1397             return smd;
1398         }
1399 
Adjust(bool value)1400         public bool Adjust(bool value)
1401         {
1402             if (SqlDbType.Bit != SqlDbType)
1403                 ThrowInvalidType();
1404             return value;
1405         }
1406 
Adjust(byte value)1407         public byte Adjust(byte value)
1408         {
1409             if (SqlDbType.TinyInt != SqlDbType)
1410                 ThrowInvalidType();
1411             return value;
1412         }
1413 
Adjust(byte[] value)1414         public byte[] Adjust(byte[] value)
1415         {
1416             if (SqlDbType.Binary == SqlDbType || SqlDbType.Timestamp == SqlDbType)
1417             {
1418                 // Don't pad null values
1419                 if (null != value)
1420                 {
1421                     // Pad fixed-length types
1422                     if (value.Length < MaxLength)
1423                     {
1424                         byte[] rgbNewValue = new byte[MaxLength];
1425                         Buffer.BlockCopy(value, 0, rgbNewValue, 0, value.Length);
1426                         Array.Clear(rgbNewValue, value.Length, (int)rgbNewValue.Length - value.Length);
1427                         return rgbNewValue;
1428                     }
1429                 }
1430             }
1431             else if (SqlDbType.VarBinary != SqlDbType &&
1432                     SqlDbType.Image != SqlDbType)
1433                 ThrowInvalidType();
1434 
1435             // Handle null values after type check
1436             if (null == value)
1437             {
1438                 return null;
1439             }
1440 
1441             // trim all types
1442             if (value.Length > MaxLength && Max != MaxLength)
1443             {
1444                 byte[] rgbNewValue = new byte[MaxLength];
1445                 Buffer.BlockCopy(value, 0, rgbNewValue, 0, (int)MaxLength);
1446                 value = rgbNewValue;
1447             }
1448 
1449             return value;
1450         }
1451 
Adjust(char value)1452         public char Adjust(char value)
1453         {
1454             if (SqlDbType.Char == SqlDbType || SqlDbType.NChar == SqlDbType)
1455             {
1456                 if (1 != MaxLength)
1457                     ThrowInvalidType();
1458             }
1459             else if ((1 > MaxLength) ||  // char must have max length of at least 1
1460                     (SqlDbType.VarChar != SqlDbType && SqlDbType.NVarChar != SqlDbType &&
1461                     SqlDbType.Text != SqlDbType && SqlDbType.NText != SqlDbType)
1462                     )
1463                 ThrowInvalidType();
1464 
1465             return value;
1466         }
1467 
Adjust(char[] value)1468         public char[] Adjust(char[] value)
1469         {
1470             if (SqlDbType.Char == SqlDbType || SqlDbType.NChar == SqlDbType)
1471             {
1472                 // Don't pad null values
1473                 if (null != value)
1474                 {
1475                     // Pad fixed-length types
1476                     long oldLength = value.Length;
1477                     if (oldLength < MaxLength)
1478                     {
1479                         char[] rgchNew = new char[(int)MaxLength];
1480                         Buffer.BlockCopy(value, 0, rgchNew, 0, (int)oldLength);
1481 
1482                         // pad extra space
1483                         for (long i = oldLength; i < rgchNew.Length; i++)
1484                             rgchNew[i] = ' ';
1485 
1486                         return rgchNew;
1487                     }
1488                 }
1489             }
1490             else if (SqlDbType.VarChar != SqlDbType && SqlDbType.NVarChar != SqlDbType &&
1491                     SqlDbType.Text != SqlDbType && SqlDbType.NText != SqlDbType)
1492                 ThrowInvalidType();
1493 
1494             // Handle null values after type check
1495             if (null == value)
1496             {
1497                 return null;
1498             }
1499 
1500             // trim all types
1501             if (value.Length > MaxLength && Max != MaxLength)
1502             {
1503                 char[] rgchNewValue = new char[MaxLength];
1504                 Buffer.BlockCopy(value, 0, rgchNewValue, 0, (int)MaxLength);
1505                 value = rgchNewValue;
1506             }
1507 
1508 
1509             return value;
1510         }
1511 
1512 
GetPartialLengthMetaData(SqlMetaData md)1513         internal static SqlMetaData GetPartialLengthMetaData(SqlMetaData md)
1514         {
1515             if (md.IsPartialLength == true)
1516             {
1517                 return md;
1518             }
1519             if (md.SqlDbType == SqlDbType.Xml)
1520                 ThrowInvalidType();     //Xml should always have IsPartialLength = true
1521 
1522             if (md.SqlDbType == SqlDbType.NVarChar || md.SqlDbType == SqlDbType.VarChar ||
1523                     md.SqlDbType == SqlDbType.VarBinary)
1524             {
1525                 SqlMetaData mdnew = new SqlMetaData(md.Name, md.SqlDbType, SqlMetaData.Max, 0, 0, md.LocaleId,
1526                     md.CompareOptions, null, null, null, true, md.Type);
1527                 return mdnew;
1528             }
1529             else
1530                 return md;
1531         }
1532 
1533 
ThrowInvalidType()1534         private static void ThrowInvalidType()
1535         {
1536             throw ADP.InvalidMetaDataValue();
1537         }
1538 
1539         // Hard coding smalldatetime limits...
1540         private static readonly DateTime s_dtSmallMax = new DateTime(2079, 06, 06, 23, 59, 29, 998);
1541         private static readonly DateTime s_dtSmallMin = new DateTime(1899, 12, 31, 23, 59, 29, 999);
VerifyDateTimeRange(DateTime value)1542         private void VerifyDateTimeRange(DateTime value)
1543         {
1544             if (SqlDbType.SmallDateTime == SqlDbType && (s_dtSmallMax < value || s_dtSmallMin > value))
1545                 ThrowInvalidType();
1546         }
1547 
1548         private static readonly SqlMoney s_smSmallMax = new SqlMoney(((Decimal)Int32.MaxValue) / 10000);
1549         private static readonly SqlMoney s_smSmallMin = new SqlMoney(((Decimal)Int32.MinValue) / 10000);
VerifyMoneyRange(SqlMoney value)1550         private void VerifyMoneyRange(SqlMoney value)
1551         {
1552             if (SqlDbType.SmallMoney == SqlDbType && ((s_smSmallMax < value).Value || (s_smSmallMin > value).Value))
1553                 ThrowInvalidType();
1554         }
1555 
InternalAdjustSqlDecimal(SqlDecimal value)1556         private SqlDecimal InternalAdjustSqlDecimal(SqlDecimal value)
1557         {
1558             if (!value.IsNull && (value.Precision != Precision || value.Scale != Scale))
1559             {
1560                 // Force truncation if target scale is smaller than actual scale.
1561                 if (value.Scale != Scale)
1562                 {
1563                     value = SqlDecimal.AdjustScale(value, Scale - value.Scale, false /* Don't round, truncate. */);
1564                 }
1565                 return SqlDecimal.ConvertToPrecScale(value, Precision, Scale);
1566             }
1567 
1568             return value;
1569         }
1570 
1571         private static readonly TimeSpan s_timeMin = TimeSpan.Zero;
1572         private static readonly TimeSpan s_timeMax = new TimeSpan(TimeSpan.TicksPerDay - 1);
VerifyTimeRange(TimeSpan value)1573         private void VerifyTimeRange(TimeSpan value)
1574         {
1575             if (SqlDbType.Time == SqlDbType && (s_timeMin > value || value > s_timeMax))
1576             {
1577                 ThrowInvalidType();
1578             }
1579         }
1580 
1581         private static readonly Int64[] s_unitTicksFromScale = {
1582             10000000,
1583             1000000,
1584             100000,
1585             10000,
1586             1000,
1587             100,
1588             10,
1589             1,
1590         };
1591 
InternalAdjustTimeTicks(Int64 ticks)1592         private Int64 InternalAdjustTimeTicks(Int64 ticks)
1593         {
1594             return (ticks / s_unitTicksFromScale[Scale] * s_unitTicksFromScale[Scale]);
1595         }
1596 
InferScaleFromTimeTicks(Int64 ticks)1597         private static byte InferScaleFromTimeTicks(Int64 ticks)
1598         {
1599             for (byte scale = 0; scale < MaxTimeScale; ++scale)
1600             {
1601                 if ((ticks / s_unitTicksFromScale[scale] * s_unitTicksFromScale[scale]) == ticks)
1602                 {
1603                     return scale;
1604                 }
1605             }
1606             return MaxTimeScale;
1607         }
1608 
1609         private static DbType[] sxm_rgSqlDbTypeToDbType = {
1610             DbType.Int64,           // SqlDbType.BigInt
1611             DbType.Binary,          // SqlDbType.Binary
1612             DbType.Boolean,         // SqlDbType.Bit
1613             DbType.AnsiString,      // SqlDbType.Char
1614             DbType.DateTime,        // SqlDbType.DateTime
1615             DbType.Decimal,         // SqlDbType.Decimal
1616             DbType.Double,          // SqlDbType.Float
1617             DbType.Binary,          // SqlDbType.Image
1618             DbType.Int32,           // SqlDbType.Int
1619             DbType.Currency,        // SqlDbType.Money
1620             DbType.String,          // SqlDbType.NChar
1621             DbType.String,          // SqlDbType.NText
1622             DbType.String,          // SqlDbType.NVarChar
1623             DbType.Single,          // SqlDbType.Real
1624             DbType.Guid,            // SqlDbType.UniqueIdentifier
1625             DbType.DateTime,        // SqlDbType.SmallDateTime
1626             DbType.Int16,           // SqlDbType.SmallInt
1627             DbType.Currency,        // SqlDbType.SmallMoney
1628             DbType.AnsiString,      // SqlDbType.Text
1629             DbType.Binary,          // SqlDbType.Timestamp
1630             DbType.Byte,            // SqlDbType.TinyInt
1631             DbType.Binary,          // SqlDbType.VarBinary
1632             DbType.AnsiString,      // SqlDbType.VarChar
1633             DbType.Object,          // SqlDbType.Variant
1634             DbType.Object,          // SqlDbType.Row
1635             DbType.Xml,             // SqlDbType.Xml
1636             DbType.String,          // SqlDbType.NVarChar, place holder
1637             DbType.String,          // SqlDbType.NVarChar, place holder
1638             DbType.String,          // SqlDbType.NVarChar, place holder
1639             DbType.Object,          // SqlDbType.Udt
1640             DbType.Object,          // SqlDbType.Structured
1641             DbType.Date,            // SqlDbType.Date
1642             DbType.Time,            // SqlDbType.Time
1643             DbType.DateTime2,       // SqlDbType.DateTime2
1644             DbType.DateTimeOffset   // SqlDbType.DateTimeOffset
1645         };
1646 
SetDefaultsForType(SqlDbType dbType)1647         private void SetDefaultsForType(SqlDbType dbType)
1648         {
1649             if (SqlDbType.BigInt <= dbType && SqlDbType.DateTimeOffset >= dbType)
1650             {
1651                 SqlMetaData smdDflt = sxm_rgDefaults[(int)dbType];
1652                 _sqlDbType = dbType;
1653                 _lMaxLength = smdDflt.MaxLength;
1654                 _bPrecision = smdDflt.Precision;
1655                 _bScale = smdDflt.Scale;
1656                 _lLocale = smdDflt.LocaleId;
1657                 _eCompareOptions = smdDflt.CompareOptions;
1658             }
1659         }
1660 
1661         // Array of default-valued metadata ordered by corresponding SqlDbType.
1662         internal static SqlMetaData[] sxm_rgDefaults =
1663             {
1664             //    new SqlMetaData(name, DbType, SqlDbType, MaxLen, Prec, Scale, Locale, DatabaseName, SchemaName, isPartialLength)
1665             new SqlMetaData("bigint", SqlDbType.BigInt,
1666                     8, 19, 0, 0, SqlCompareOptions.None,  false),            // SqlDbType.BigInt
1667             new SqlMetaData("binary", SqlDbType.Binary,
1668                     1, 0, 0, 0, SqlCompareOptions.None,  false),                // SqlDbType.Binary
1669             new SqlMetaData("bit", SqlDbType.Bit,
1670                     1, 1, 0, 0, SqlCompareOptions.None, false),                // SqlDbType.Bit
1671             new SqlMetaData("char", SqlDbType.Char,
1672                     1, 0, 0, 0, x_eDefaultStringCompareOptions,  false),                // SqlDbType.Char
1673             new SqlMetaData("datetime", SqlDbType.DateTime,
1674                     8, 23, 3, 0, SqlCompareOptions.None, false),            // SqlDbType.DateTime
1675             new SqlMetaData("decimal", SqlDbType.Decimal,
1676                     9, 18, 0, 0, SqlCompareOptions.None,  false),            // SqlDbType.Decimal
1677             new SqlMetaData("float", SqlDbType.Float,
1678                     8, 53, 0, 0, SqlCompareOptions.None, false),            // SqlDbType.Float
1679             new SqlMetaData("image", SqlDbType.Image,
1680                     x_lMax, 0, 0, 0, SqlCompareOptions.None, false),                // SqlDbType.Image
1681             new SqlMetaData("int", SqlDbType.Int,
1682                     4, 10, 0, 0, SqlCompareOptions.None, false),            // SqlDbType.Int
1683             new SqlMetaData("money", SqlDbType.Money,
1684                     8, 19, 4, 0, SqlCompareOptions.None, false),            // SqlDbType.Money
1685             new SqlMetaData("nchar", SqlDbType.NChar,
1686                     1, 0, 0, 0, x_eDefaultStringCompareOptions, false),                // SqlDbType.NChar
1687             new SqlMetaData("ntext", SqlDbType.NText,
1688                     x_lMax, 0, 0, 0, x_eDefaultStringCompareOptions, false),                // SqlDbType.NText
1689             new SqlMetaData("nvarchar", SqlDbType.NVarChar,
1690                     x_lServerMaxUnicode, 0, 0, 0, x_eDefaultStringCompareOptions, false),                // SqlDbType.NVarChar
1691             new SqlMetaData("real", SqlDbType.Real,
1692                     4, 24, 0, 0, SqlCompareOptions.None, false),            // SqlDbType.Real
1693             new SqlMetaData("uniqueidentifier", SqlDbType.UniqueIdentifier,
1694                     16, 0, 0, 0, SqlCompareOptions.None, false),            // SqlDbType.UniqueIdentifier
1695             new SqlMetaData("smalldatetime", SqlDbType.SmallDateTime,
1696                     4, 16, 0, 0, SqlCompareOptions.None, false),            // SqlDbType.SmallDateTime
1697             new SqlMetaData("smallint", SqlDbType.SmallInt,
1698                     2, 5, 0, 0, SqlCompareOptions.None, false),                                    // SqlDbType.SmallInt
1699             new SqlMetaData("smallmoney", SqlDbType.SmallMoney,
1700                     4, 10, 4, 0, SqlCompareOptions.None, false),                // SqlDbType.SmallMoney
1701             new SqlMetaData("text", SqlDbType.Text,
1702                     x_lMax, 0, 0, 0, x_eDefaultStringCompareOptions, false),                // SqlDbType.Text
1703             new SqlMetaData("timestamp", SqlDbType.Timestamp,
1704                     8, 0, 0, 0, SqlCompareOptions.None, false),                // SqlDbType.Timestamp
1705             new SqlMetaData("tinyint", SqlDbType.TinyInt,
1706                     1, 3, 0, 0, SqlCompareOptions.None, false),                // SqlDbType.TinyInt
1707             new SqlMetaData("varbinary", SqlDbType.VarBinary,
1708                     x_lServerMaxBinary, 0, 0, 0, SqlCompareOptions.None, false),                // SqlDbType.VarBinary
1709             new SqlMetaData("varchar", SqlDbType.VarChar,
1710                     x_lServerMaxANSI, 0, 0, 0, x_eDefaultStringCompareOptions, false),                // SqlDbType.VarChar
1711             new SqlMetaData("sql_variant", SqlDbType.Variant,
1712                     8016, 0, 0, 0, SqlCompareOptions.None, false),            // SqlDbType.Variant
1713             new SqlMetaData("nvarchar", SqlDbType.NVarChar,
1714                     1, 0, 0, 0, x_eDefaultStringCompareOptions, false),                // Placeholder for value 24
1715             new SqlMetaData("xml", SqlDbType.Xml,
1716                     x_lMax, 0, 0, 0, x_eDefaultStringCompareOptions, true),                // SqlDbType.Xml
1717             new SqlMetaData("nvarchar", SqlDbType.NVarChar,
1718                     1, 0, 0, 0, x_eDefaultStringCompareOptions, false),                // Placeholder for value 26
1719             new SqlMetaData("nvarchar", SqlDbType.NVarChar,
1720                     x_lServerMaxUnicode, 0, 0, 0, x_eDefaultStringCompareOptions, false),                // Placeholder for value 27
1721             new SqlMetaData("nvarchar", SqlDbType.NVarChar,
1722                     x_lServerMaxUnicode, 0, 0, 0, x_eDefaultStringCompareOptions, false),                // Placeholder for value 28
1723             new SqlMetaData("udt", SqlDbType.Udt,
1724                     0, 0, 0, 0, SqlCompareOptions.None, false),            // SqlDbType.Udt = 29
1725             new SqlMetaData("table", SqlDbType.Structured,
1726                     0, 0, 0, 0, SqlCompareOptions.None, false),                // SqlDbType.Structured
1727             new SqlMetaData("date", SqlDbType.Date,
1728                     3, 10,0, 0, SqlCompareOptions.None, false),                // SqlDbType.Date
1729             new SqlMetaData("time", SqlDbType.Time,
1730                     5, 0, 7, 0, SqlCompareOptions.None, false),                // SqlDbType.Time
1731             new SqlMetaData("datetime2", SqlDbType.DateTime2,
1732                     8, 0, 7, 0, SqlCompareOptions.None, false),                // SqlDbType.DateTime2
1733             new SqlMetaData("datetimeoffset", SqlDbType.DateTimeOffset,
1734                    10, 0, 7, 0, SqlCompareOptions.None, false),                // SqlDbType.DateTimeOffset
1735             };
1736     }
1737 }
1738