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