|
16 | 16 | using System.Xml; |
17 | 17 |
|
18 | 18 | using Microsoft.SqlServer.Server; |
| 19 | +using System.Globalization; |
19 | 20 |
|
20 | 21 | namespace System.Data.SqlClient |
21 | 22 | { |
@@ -395,6 +396,266 @@ internal void Bind(TdsParserStateObject stateObj) |
395 | 396 | _defaultLCID = _parser.DefaultLCID; |
396 | 397 | } |
397 | 398 |
|
| 399 | + internal DataTable BuildSchemaTable() |
| 400 | + { |
| 401 | + _SqlMetaDataSet md = this.MetaData; |
| 402 | + Debug.Assert(null != md, "BuildSchemaTable - unexpected null metadata information"); |
| 403 | + |
| 404 | + DataTable schemaTable = new DataTable("SchemaTable"); |
| 405 | + schemaTable.Locale = CultureInfo.InvariantCulture; |
| 406 | + schemaTable.MinimumCapacity = md.Length; |
| 407 | + |
| 408 | + DataColumn columnName = new DataColumn(SchemaTableColumn.ColumnName, typeof(System.String)); |
| 409 | + DataColumn ordinal = new DataColumn(SchemaTableColumn.ColumnOrdinal, typeof(System.Int32)); |
| 410 | + DataColumn size = new DataColumn(SchemaTableColumn.ColumnSize, typeof(System.Int32)); |
| 411 | + DataColumn precision = new DataColumn(SchemaTableColumn.NumericPrecision, typeof(System.Int16)); |
| 412 | + DataColumn scale = new DataColumn(SchemaTableColumn.NumericScale, typeof(System.Int16)); |
| 413 | + |
| 414 | + DataColumn dataType = new DataColumn(SchemaTableColumn.DataType, typeof(System.Type)); |
| 415 | + DataColumn providerSpecificDataType = new DataColumn(SchemaTableOptionalColumn.ProviderSpecificDataType, typeof(System.Type)); |
| 416 | + DataColumn nonVersionedProviderType = new DataColumn(SchemaTableColumn.NonVersionedProviderType, typeof(System.Int32)); |
| 417 | + DataColumn providerType = new DataColumn(SchemaTableColumn.ProviderType, typeof(System.Int32)); |
| 418 | + |
| 419 | + DataColumn isLong = new DataColumn(SchemaTableColumn.IsLong, typeof(System.Boolean)); |
| 420 | + DataColumn allowDBNull = new DataColumn(SchemaTableColumn.AllowDBNull, typeof(System.Boolean)); |
| 421 | + DataColumn isReadOnly = new DataColumn(SchemaTableOptionalColumn.IsReadOnly, typeof(System.Boolean)); |
| 422 | + DataColumn isRowVersion = new DataColumn(SchemaTableOptionalColumn.IsRowVersion, typeof(System.Boolean)); |
| 423 | + |
| 424 | + DataColumn isUnique = new DataColumn(SchemaTableColumn.IsUnique, typeof(System.Boolean)); |
| 425 | + DataColumn isKey = new DataColumn(SchemaTableColumn.IsKey, typeof(System.Boolean)); |
| 426 | + DataColumn isAutoIncrement = new DataColumn(SchemaTableOptionalColumn.IsAutoIncrement, typeof(System.Boolean)); |
| 427 | + DataColumn isHidden = new DataColumn(SchemaTableOptionalColumn.IsHidden, typeof(System.Boolean)); |
| 428 | + |
| 429 | + DataColumn baseCatalogName = new DataColumn(SchemaTableOptionalColumn.BaseCatalogName, typeof(System.String)); |
| 430 | + DataColumn baseSchemaName = new DataColumn(SchemaTableColumn.BaseSchemaName, typeof(System.String)); |
| 431 | + DataColumn baseTableName = new DataColumn(SchemaTableColumn.BaseTableName, typeof(System.String)); |
| 432 | + DataColumn baseColumnName = new DataColumn(SchemaTableColumn.BaseColumnName, typeof(System.String)); |
| 433 | + |
| 434 | + // unique to SqlClient |
| 435 | + DataColumn baseServerName = new DataColumn(SchemaTableOptionalColumn.BaseServerName, typeof(System.String)); |
| 436 | + DataColumn isAliased = new DataColumn(SchemaTableColumn.IsAliased, typeof(System.Boolean)); |
| 437 | + DataColumn isExpression = new DataColumn(SchemaTableColumn.IsExpression, typeof(System.Boolean)); |
| 438 | + DataColumn isIdentity = new DataColumn("IsIdentity", typeof(System.Boolean)); |
| 439 | + DataColumn dataTypeName = new DataColumn("DataTypeName", typeof(System.String)); |
| 440 | + DataColumn udtAssemblyQualifiedName = new DataColumn("UdtAssemblyQualifiedName", typeof(System.String)); |
| 441 | + // Xml metadata specific |
| 442 | + DataColumn xmlSchemaCollectionDatabase = new DataColumn("XmlSchemaCollectionDatabase", typeof(System.String)); |
| 443 | + DataColumn xmlSchemaCollectionOwningSchema = new DataColumn("XmlSchemaCollectionOwningSchema", typeof(System.String)); |
| 444 | + DataColumn xmlSchemaCollectionName = new DataColumn("XmlSchemaCollectionName", typeof(System.String)); |
| 445 | + // SparseColumnSet |
| 446 | + DataColumn isColumnSet = new DataColumn("IsColumnSet", typeof(System.Boolean)); |
| 447 | + |
| 448 | + ordinal.DefaultValue = 0; |
| 449 | + isLong.DefaultValue = false; |
| 450 | + |
| 451 | + DataColumnCollection columns = schemaTable.Columns; |
| 452 | + |
| 453 | + // must maintain order for backward compatibility |
| 454 | + columns.Add(columnName); |
| 455 | + columns.Add(ordinal); |
| 456 | + columns.Add(size); |
| 457 | + columns.Add(precision); |
| 458 | + columns.Add(scale); |
| 459 | + columns.Add(isUnique); |
| 460 | + columns.Add(isKey); |
| 461 | + columns.Add(baseServerName); |
| 462 | + columns.Add(baseCatalogName); |
| 463 | + columns.Add(baseColumnName); |
| 464 | + columns.Add(baseSchemaName); |
| 465 | + columns.Add(baseTableName); |
| 466 | + columns.Add(dataType); |
| 467 | + columns.Add(allowDBNull); |
| 468 | + columns.Add(providerType); |
| 469 | + columns.Add(isAliased); |
| 470 | + columns.Add(isExpression); |
| 471 | + columns.Add(isIdentity); |
| 472 | + columns.Add(isAutoIncrement); |
| 473 | + columns.Add(isRowVersion); |
| 474 | + columns.Add(isHidden); |
| 475 | + columns.Add(isLong); |
| 476 | + columns.Add(isReadOnly); |
| 477 | + columns.Add(providerSpecificDataType); |
| 478 | + columns.Add(dataTypeName); |
| 479 | + columns.Add(xmlSchemaCollectionDatabase); |
| 480 | + columns.Add(xmlSchemaCollectionOwningSchema); |
| 481 | + columns.Add(xmlSchemaCollectionName); |
| 482 | + columns.Add(udtAssemblyQualifiedName); |
| 483 | + columns.Add(nonVersionedProviderType); |
| 484 | + columns.Add(isColumnSet); |
| 485 | + |
| 486 | + for (int i = 0; i < md.Length; i++) |
| 487 | + { |
| 488 | + _SqlMetaData col = md[i]; |
| 489 | + DataRow schemaRow = schemaTable.NewRow(); |
| 490 | + |
| 491 | + schemaRow[columnName] = col.column; |
| 492 | + schemaRow[ordinal] = col.ordinal; |
| 493 | + // |
| 494 | + // be sure to return character count for string types, byte count otherwise |
| 495 | + // col.length is always byte count so for unicode types, half the length |
| 496 | + // |
| 497 | + // For MAX and XML datatypes, we get 0x7fffffff from the server. Do not divide this. |
| 498 | + schemaRow[size] = (col.metaType.IsSizeInCharacters && (col.length != 0x7fffffff)) ? (col.length / 2) : col.length; |
| 499 | + |
| 500 | + |
| 501 | + schemaRow[dataType] = GetFieldTypeInternal(col); |
| 502 | + schemaRow[providerSpecificDataType] = GetProviderSpecificFieldTypeInternal(col); |
| 503 | + schemaRow[nonVersionedProviderType] = (int)col.type; // SqlDbType enum value - does not change with TypeSystem. |
| 504 | + schemaRow[dataTypeName] = GetDataTypeNameInternal(col); |
| 505 | + |
| 506 | + if (_typeSystem <= SqlConnectionString.TypeSystem.SQLServer2005 && col.IsNewKatmaiDateTimeType) |
| 507 | + { |
| 508 | + schemaRow[providerType] = SqlDbType.NVarChar; |
| 509 | + switch (col.type) |
| 510 | + { |
| 511 | + case SqlDbType.Date: |
| 512 | + schemaRow[size] = TdsEnums.WHIDBEY_DATE_LENGTH; |
| 513 | + break; |
| 514 | + case SqlDbType.Time: |
| 515 | + Debug.Assert(TdsEnums.UNKNOWN_PRECISION_SCALE == col.scale || (0 <= col.scale && col.scale <= 7), "Invalid scale for Time column: " + col.scale); |
| 516 | + schemaRow[size] = TdsEnums.WHIDBEY_TIME_LENGTH[TdsEnums.UNKNOWN_PRECISION_SCALE != col.scale ? col.scale : col.metaType.Scale]; |
| 517 | + break; |
| 518 | + case SqlDbType.DateTime2: |
| 519 | + Debug.Assert(TdsEnums.UNKNOWN_PRECISION_SCALE == col.scale || (0 <= col.scale && col.scale <= 7), "Invalid scale for DateTime2 column: " + col.scale); |
| 520 | + schemaRow[size] = TdsEnums.WHIDBEY_DATETIME2_LENGTH[TdsEnums.UNKNOWN_PRECISION_SCALE != col.scale ? col.scale : col.metaType.Scale]; |
| 521 | + break; |
| 522 | + case SqlDbType.DateTimeOffset: |
| 523 | + Debug.Assert(TdsEnums.UNKNOWN_PRECISION_SCALE == col.scale || (0 <= col.scale && col.scale <= 7), "Invalid scale for DateTimeOffset column: " + col.scale); |
| 524 | + schemaRow[size] = TdsEnums.WHIDBEY_DATETIMEOFFSET_LENGTH[TdsEnums.UNKNOWN_PRECISION_SCALE != col.scale ? col.scale : col.metaType.Scale]; |
| 525 | + break; |
| 526 | + } |
| 527 | + } |
| 528 | + else if (_typeSystem <= SqlConnectionString.TypeSystem.SQLServer2005 && col.IsLargeUdt) |
| 529 | + { |
| 530 | + if (_typeSystem == SqlConnectionString.TypeSystem.SQLServer2005) |
| 531 | + { |
| 532 | + schemaRow[providerType] = SqlDbType.VarBinary; |
| 533 | + } |
| 534 | + else |
| 535 | + { |
| 536 | + // TypeSystem.SQLServer2000 |
| 537 | + schemaRow[providerType] = SqlDbType.Image; |
| 538 | + } |
| 539 | + } |
| 540 | + else if (_typeSystem != SqlConnectionString.TypeSystem.SQLServer2000) |
| 541 | + { |
| 542 | + // TypeSystem.SQLServer2005 and above |
| 543 | + |
| 544 | + // SqlDbType enum value - always the actual type for SQLServer2005. |
| 545 | + schemaRow[providerType] = (int)col.type; |
| 546 | + |
| 547 | + if (col.type == SqlDbType.Udt) |
| 548 | + { // Additional metadata for UDTs. |
| 549 | + Debug.Assert(Connection.IsKatmaiOrNewer, "Invalid Column type received from the server"); |
| 550 | + schemaRow[udtAssemblyQualifiedName] = col.udtAssemblyQualifiedName; |
| 551 | + } |
| 552 | + else if (col.type == SqlDbType.Xml) |
| 553 | + { // Additional metadata for Xml. |
| 554 | + Debug.Assert(Connection.IsKatmaiOrNewer, "Invalid DataType (Xml) for the column"); |
| 555 | + schemaRow[xmlSchemaCollectionDatabase] = col.xmlSchemaCollectionDatabase; |
| 556 | + schemaRow[xmlSchemaCollectionOwningSchema] = col.xmlSchemaCollectionOwningSchema; |
| 557 | + schemaRow[xmlSchemaCollectionName] = col.xmlSchemaCollectionName; |
| 558 | + } |
| 559 | + } |
| 560 | + else |
| 561 | + { |
| 562 | + // TypeSystem.SQLServer2000 |
| 563 | + |
| 564 | + // SqlDbType enum value - variable for certain types when SQLServer2000. |
| 565 | + schemaRow[providerType] = GetVersionedMetaType(col.metaType).SqlDbType; |
| 566 | + } |
| 567 | + |
| 568 | + if (TdsEnums.UNKNOWN_PRECISION_SCALE != col.precision) |
| 569 | + { |
| 570 | + schemaRow[precision] = col.precision; |
| 571 | + } |
| 572 | + else |
| 573 | + { |
| 574 | + schemaRow[precision] = col.metaType.Precision; |
| 575 | + } |
| 576 | + |
| 577 | + if (_typeSystem <= SqlConnectionString.TypeSystem.SQLServer2005 && col.IsNewKatmaiDateTimeType) |
| 578 | + { |
| 579 | + schemaRow[scale] = MetaType.MetaNVarChar.Scale; |
| 580 | + } |
| 581 | + else if (TdsEnums.UNKNOWN_PRECISION_SCALE != col.scale) |
| 582 | + { |
| 583 | + schemaRow[scale] = col.scale; |
| 584 | + } |
| 585 | + else |
| 586 | + { |
| 587 | + schemaRow[scale] = col.metaType.Scale; |
| 588 | + } |
| 589 | + |
| 590 | + schemaRow[allowDBNull] = col.isNullable; |
| 591 | + |
| 592 | + // If no ColInfo token received, do not set value, leave as null. |
| 593 | + if (_browseModeInfoConsumed) |
| 594 | + { |
| 595 | + schemaRow[isAliased] = col.isDifferentName; |
| 596 | + schemaRow[isKey] = col.isKey; |
| 597 | + schemaRow[isHidden] = col.isHidden; |
| 598 | + schemaRow[isExpression] = col.isExpression; |
| 599 | + } |
| 600 | + |
| 601 | + schemaRow[isIdentity] = col.isIdentity; |
| 602 | + schemaRow[isAutoIncrement] = col.isIdentity; |
| 603 | + |
| 604 | + |
| 605 | + schemaRow[isLong] = col.metaType.IsLong; |
| 606 | + |
| 607 | + // mark unique for timestamp columns |
| 608 | + if (SqlDbType.Timestamp == col.type) |
| 609 | + { |
| 610 | + schemaRow[isUnique] = true; |
| 611 | + schemaRow[isRowVersion] = true; |
| 612 | + } |
| 613 | + else |
| 614 | + { |
| 615 | + schemaRow[isUnique] = false; |
| 616 | + schemaRow[isRowVersion] = false; |
| 617 | + } |
| 618 | + |
| 619 | + schemaRow[isReadOnly] = (0 == col.updatability); |
| 620 | + schemaRow[isColumnSet] = col.isColumnSet; |
| 621 | + |
| 622 | + if (!string.IsNullOrEmpty(col.serverName)) |
| 623 | + { |
| 624 | + schemaRow[baseServerName] = col.serverName; |
| 625 | + } |
| 626 | + if (!string.IsNullOrEmpty(col.catalogName)) |
| 627 | + { |
| 628 | + schemaRow[baseCatalogName] = col.catalogName; |
| 629 | + } |
| 630 | + if (!string.IsNullOrEmpty(col.schemaName)) |
| 631 | + { |
| 632 | + schemaRow[baseSchemaName] = col.schemaName; |
| 633 | + } |
| 634 | + if (!string.IsNullOrEmpty(col.tableName)) |
| 635 | + { |
| 636 | + schemaRow[baseTableName] = col.tableName; |
| 637 | + } |
| 638 | + if (!string.IsNullOrEmpty(col.baseColumn)) |
| 639 | + { |
| 640 | + schemaRow[baseColumnName] = col.baseColumn; |
| 641 | + } |
| 642 | + else if (!string.IsNullOrEmpty(col.column)) |
| 643 | + { |
| 644 | + schemaRow[baseColumnName] = col.column; |
| 645 | + } |
| 646 | + |
| 647 | + schemaTable.Rows.Add(schemaRow); |
| 648 | + schemaRow.AcceptChanges(); |
| 649 | + } |
| 650 | + |
| 651 | + // mark all columns as readonly |
| 652 | + foreach (DataColumn column in columns) |
| 653 | + { |
| 654 | + column.ReadOnly = true; // MDAC 70943 |
| 655 | + } |
| 656 | + |
| 657 | + return schemaTable; |
| 658 | + } |
398 | 659 |
|
399 | 660 | internal void Cancel(SqlCommand command) |
400 | 661 | { |
@@ -1063,6 +1324,27 @@ override public int GetProviderSpecificValues(object[] values) |
1063 | 1324 | return GetSqlValues(values); |
1064 | 1325 | } |
1065 | 1326 |
|
| 1327 | + public override DataTable GetSchemaTable() |
| 1328 | + { |
| 1329 | + SqlStatistics statistics = null; |
| 1330 | + try |
| 1331 | + { |
| 1332 | + statistics = SqlStatistics.StartTimer(Statistics); |
| 1333 | + if (null == _metaData || null == _metaData.schemaTable) |
| 1334 | + { |
| 1335 | + if (null != this.MetaData) |
| 1336 | + { |
| 1337 | + _metaData.schemaTable = BuildSchemaTable(); |
| 1338 | + Debug.Assert(null != _metaData.schemaTable, "No schema information yet!"); |
| 1339 | + } |
| 1340 | + } |
| 1341 | + return _metaData?.schemaTable; |
| 1342 | + } |
| 1343 | + finally |
| 1344 | + { |
| 1345 | + SqlStatistics.StopTimer(statistics); |
| 1346 | + } |
| 1347 | + } |
1066 | 1348 |
|
1067 | 1349 | override public bool GetBoolean(int i) |
1068 | 1350 | { |
|
0 commit comments