| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528 |
- //------------------------------------------------------------------------------
- // <copyright file="dbmetadatafactory.cs" company="Microsoft">
- // Copyright (c) Microsoft Corporation. All rights reserved.
- // </copyright>
- // <owner current="true" primary="true">[....]</owner>
- // <owner current="true" primary="false">[....]</owner>
- //------------------------------------------------------------------------------
- namespace System.Data.ProviderBase {
- using System;
- using System.Collections;
- using System.Data;
- using System.Data.Common;
- using System.Diagnostics;
- using System.Globalization;
- using System.IO;
- using System.Xml;
- using System.Xml.Schema;
-
- internal class DbMetaDataFactory{ // V1.2.3300
- private DataSet _metaDataCollectionsDataSet;
- private string _normalizedServerVersion;
- private string _serverVersionString;
- // well known column names
- private const string _collectionName = "CollectionName";
- private const string _populationMechanism = "PopulationMechanism";
- private const string _populationString = "PopulationString";
- private const string _maximumVersion = "MaximumVersion";
- private const string _minimumVersion = "MinimumVersion";
- private const string _dataSourceProductVersionNormalized = "DataSourceProductVersionNormalized";
- private const string _dataSourceProductVersion = "DataSourceProductVersion";
- private const string _restrictionDefault = "RestrictionDefault";
- private const string _restrictionNumber = "RestrictionNumber";
- private const string _numberOfRestrictions = "NumberOfRestrictions";
- private const string _restrictionName = "RestrictionName";
- private const string _parameterName = "ParameterName";
- // population mechanisms
- private const string _dataTable = "DataTable";
- private const string _sqlCommand = "SQLCommand";
- private const string _prepareCollection = "PrepareCollection";
-
- public DbMetaDataFactory(Stream xmlStream, string serverVersion, string normalizedServerVersion) {
- ADP.CheckArgumentNull(xmlStream, "xmlStream");
- ADP.CheckArgumentNull(serverVersion, "serverVersion");
- ADP.CheckArgumentNull(normalizedServerVersion, "normalizedServerVersion");
-
- LoadDataSetFromXml(xmlStream);
- _serverVersionString = serverVersion;
- _normalizedServerVersion = normalizedServerVersion;
- }
- protected DataSet CollectionDataSet {
- get {
- return _metaDataCollectionsDataSet;
- }
- }
- protected string ServerVersion {
- get {
- return _serverVersionString;
- }
- }
- protected string ServerVersionNormalized {
- get {
- return _normalizedServerVersion;
- }
- }
- protected DataTable CloneAndFilterCollection(string collectionName, string[] hiddenColumnNames) {
- DataTable sourceTable;
- DataTable destinationTable;
- DataColumn[] filteredSourceColumns;
- DataColumnCollection destinationColumns;
- DataRow newRow;
- sourceTable = _metaDataCollectionsDataSet.Tables[collectionName];
- if ((sourceTable == null) || (collectionName != sourceTable.TableName)) {
- throw ADP.DataTableDoesNotExist(collectionName);
- }
-
- destinationTable = new DataTable(collectionName);
- destinationTable.Locale = CultureInfo.InvariantCulture;
- destinationColumns = destinationTable.Columns;
- filteredSourceColumns = FilterColumns(sourceTable,hiddenColumnNames,destinationColumns);
- foreach (DataRow row in sourceTable.Rows) {
- if (SupportedByCurrentVersion(row) == true) {
- newRow = destinationTable.NewRow();
- for(int i = 0; i < destinationColumns.Count; i++) {
- newRow[destinationColumns[i]] = row[filteredSourceColumns[i],DataRowVersion.Current];
- }
- destinationTable.Rows.Add(newRow);
- newRow.AcceptChanges();
- }
- }
- return destinationTable;
- }
- public void Dispose() {
- Dispose(true);
- }
- virtual protected void Dispose(bool disposing) {
- if (disposing) {
- _normalizedServerVersion = null;
- _serverVersionString = null;
- _metaDataCollectionsDataSet.Dispose();
- }
- }
- private DataTable ExecuteCommand(DataRow requestedCollectionRow, String[] restrictions, DbConnection connection){
- DataTable metaDataCollectionsTable = _metaDataCollectionsDataSet.Tables[DbMetaDataCollectionNames.MetaDataCollections];
- DataColumn populationStringColumn = metaDataCollectionsTable.Columns[_populationString];
- DataColumn numberOfRestrictionsColumn = metaDataCollectionsTable.Columns[_numberOfRestrictions];
- DataColumn collectionNameColumn = metaDataCollectionsTable.Columns[_collectionName];
- //DataColumn restrictionNameColumn = metaDataCollectionsTable.Columns[_restrictionName];
-
- DataTable resultTable = null;
- DbCommand command = null;
- DataTable schemaTable = null;
- Debug.Assert(requestedCollectionRow != null);
- String sqlCommand = requestedCollectionRow[populationStringColumn,DataRowVersion.Current] as string;
- int numberOfRestrictions = (int)requestedCollectionRow[numberOfRestrictionsColumn,DataRowVersion.Current] ;
- String collectionName = requestedCollectionRow[collectionNameColumn,DataRowVersion.Current] as string;
- if ((restrictions != null) && (restrictions.Length > numberOfRestrictions)) {
- throw ADP.TooManyRestrictions(collectionName);
- }
- command = connection.CreateCommand();
- command.CommandText = sqlCommand;
- command.CommandTimeout = System.Math.Max(command.CommandTimeout,180);
- for (int i = 0; i < numberOfRestrictions; i++) {
-
- DbParameter restrictionParameter = command.CreateParameter();
-
-
- if ((restrictions != null) && (restrictions.Length > i ) && (restrictions[i] != null)) {
-
- restrictionParameter.Value = restrictions[i];
- }
- else {
- // This is where we have to assign null to the value of the parameter.
- restrictionParameter.Value = DBNull.Value;
- }
- restrictionParameter.ParameterName = GetParameterName(collectionName, i+1);
- restrictionParameter.Direction = ParameterDirection.Input;
- command.Parameters.Add(restrictionParameter);
- }
-
- DbDataReader reader = null;
- try {
-
- try {
- reader = command.ExecuteReader();
- }
- catch (Exception e) {
- if (!ADP.IsCatchableExceptionType(e)) {
- throw;
- }
- throw ADP.QueryFailed(collectionName,e);
- }
-
- //
- // Build a DataTable from the reader
- resultTable = new DataTable(collectionName);
- resultTable.Locale = CultureInfo.InvariantCulture;
-
- schemaTable = reader.GetSchemaTable();
- foreach (DataRow row in schemaTable.Rows){
- resultTable.Columns.Add(row["ColumnName"] as string, (Type)row["DataType"] as Type);
- }
- object[] values = new object[resultTable.Columns.Count];
- while (reader.Read()) {
- reader.GetValues(values);
- resultTable.Rows.Add(values);
- }
- }
- finally {
- if (reader != null) {
- reader.Dispose();
- reader = null;
- }
- }
- return resultTable;
- }
- private DataColumn[] FilterColumns(DataTable sourceTable, string[] hiddenColumnNames, DataColumnCollection destinationColumns) {
- DataColumn newDestinationColumn;
- int currentColumn;
- DataColumn[] filteredSourceColumns = null;
- int columnCount = 0;
- foreach (DataColumn sourceColumn in sourceTable.Columns){
- if (IncludeThisColumn(sourceColumn,hiddenColumnNames) == true) {
- columnCount++;
- }
- }
- if (columnCount == 0) {
- throw ADP.NoColumns();
- }
- currentColumn= 0;
- filteredSourceColumns = new DataColumn[columnCount];
- foreach(DataColumn sourceColumn in sourceTable.Columns){
- if (IncludeThisColumn(sourceColumn,hiddenColumnNames) == true) {
- newDestinationColumn = new DataColumn(sourceColumn.ColumnName,sourceColumn.DataType);
- destinationColumns.Add(newDestinationColumn);
- filteredSourceColumns[currentColumn] = sourceColumn;
- currentColumn++;
- }
- }
- return filteredSourceColumns;
- }
- internal DataRow FindMetaDataCollectionRow(string collectionName) {
- bool versionFailure;
- bool haveExactMatch;
- bool haveMultipleInexactMatches;
- string candidateCollectionName;
- DataTable metaDataCollectionsTable = _metaDataCollectionsDataSet.Tables[DbMetaDataCollectionNames.MetaDataCollections];
- if (metaDataCollectionsTable == null) {
- throw ADP.InvalidXml();
- }
-
- DataColumn collectionNameColumn = metaDataCollectionsTable.Columns[DbMetaDataColumnNames.CollectionName];
- if ((null == collectionNameColumn) || (typeof(System.String) != collectionNameColumn.DataType)) {
- throw ADP.InvalidXmlMissingColumn(DbMetaDataCollectionNames.MetaDataCollections, DbMetaDataColumnNames.CollectionName);
- }
- DataRow requestedCollectionRow = null;
- String exactCollectionName = null;
-
- // find the requested collection
- versionFailure = false;
- haveExactMatch = false;
- haveMultipleInexactMatches = false;
-
- foreach (DataRow row in metaDataCollectionsTable.Rows){
- candidateCollectionName = row[collectionNameColumn,DataRowVersion.Current] as string;
- if (ADP.IsEmpty(candidateCollectionName)) {
- throw ADP.InvalidXmlInvalidValue(DbMetaDataCollectionNames.MetaDataCollections,DbMetaDataColumnNames.CollectionName);
- }
- if (ADP.CompareInsensitiveInvariant(candidateCollectionName, collectionName)){
- if (SupportedByCurrentVersion(row) == false) {
- versionFailure = true;
- }
- else{
- if (collectionName == candidateCollectionName) {
- if (haveExactMatch == true) {
- throw ADP.CollectionNameIsNotUnique(collectionName);
- }
- requestedCollectionRow = row;
- exactCollectionName = candidateCollectionName;
- haveExactMatch = true;
- }
- else {
- // have an inexact match - ok only if it is the only one
- if (exactCollectionName != null) {
- // can't fail here becasue we may still find an exact match
- haveMultipleInexactMatches = true;
- }
- requestedCollectionRow = row;
- exactCollectionName = candidateCollectionName;
- }
- }
- }
- }
- if (requestedCollectionRow == null){
- if (versionFailure == false) {
- throw ADP.UndefinedCollection(collectionName);
- }
- else {
- throw ADP.UnsupportedVersion(collectionName);
- }
- }
-
- if ((haveExactMatch == false) && (haveMultipleInexactMatches == true)) {
- throw ADP.AmbigousCollectionName(collectionName);
- }
- return requestedCollectionRow;
-
- }
- private void FixUpVersion(DataTable dataSourceInfoTable){
- Debug.Assert(dataSourceInfoTable.TableName == DbMetaDataCollectionNames.DataSourceInformation);
- DataColumn versionColumn = dataSourceInfoTable.Columns[_dataSourceProductVersion];
- DataColumn normalizedVersionColumn = dataSourceInfoTable.Columns[_dataSourceProductVersionNormalized];
- if ((versionColumn == null) || (normalizedVersionColumn == null)) {
- throw ADP.MissingDataSourceInformationColumn();
- }
- if (dataSourceInfoTable.Rows.Count != 1) {
- throw ADP.IncorrectNumberOfDataSourceInformationRows();
- }
- DataRow dataSourceInfoRow = dataSourceInfoTable.Rows[0];
- dataSourceInfoRow[versionColumn] = _serverVersionString;
- dataSourceInfoRow[normalizedVersionColumn] = _normalizedServerVersion;
- dataSourceInfoRow.AcceptChanges();
- }
- private string GetParameterName(string neededCollectionName, int neededRestrictionNumber) {
- DataTable restrictionsTable = null;
- DataColumnCollection restrictionColumns = null;
- DataColumn collectionName = null;
- DataColumn parameterName = null;
- DataColumn restrictionName = null;
- DataColumn restrictionNumber = null;;
- string result = null;
- restrictionsTable = _metaDataCollectionsDataSet.Tables[DbMetaDataCollectionNames.Restrictions];
- if (restrictionsTable != null) {
- restrictionColumns = restrictionsTable.Columns;
- if (restrictionColumns != null) {
- collectionName = restrictionColumns[_collectionName];
- parameterName = restrictionColumns[_parameterName];
- restrictionName = restrictionColumns[_restrictionName];
- restrictionNumber = restrictionColumns[_restrictionNumber];
- }
- }
- if ((parameterName == null) ||(collectionName == null) || (restrictionName == null) || (restrictionNumber == null)) {
- throw ADP.MissingRestrictionColumn();
- }
- foreach (DataRow restriction in restrictionsTable.Rows) {
- if (((string)restriction[collectionName] == neededCollectionName) &&
- ((int)restriction[restrictionNumber] == neededRestrictionNumber) &&
- (SupportedByCurrentVersion(restriction))) {
- result = (string)restriction[parameterName];
- break;
- }
- }
- if (result == null) {
- throw ADP.MissingRestrictionRow();
- }
- return result;
- }
- virtual public DataTable GetSchema(DbConnection connection, string collectionName, string[] restrictions) {
- Debug.Assert (_metaDataCollectionsDataSet != null);
- //
- DataTable metaDataCollectionsTable = _metaDataCollectionsDataSet.Tables[DbMetaDataCollectionNames.MetaDataCollections];
- DataColumn populationMechanismColumn = metaDataCollectionsTable.Columns[_populationMechanism];
- DataColumn collectionNameColumn = metaDataCollectionsTable.Columns[DbMetaDataColumnNames.CollectionName];
- DataRow requestedCollectionRow = null;
- DataTable requestedSchema = null;
- string[] hiddenColumns;
- string exactCollectionName = null;
- requestedCollectionRow = FindMetaDataCollectionRow(collectionName);
- exactCollectionName = requestedCollectionRow[collectionNameColumn,DataRowVersion.Current] as string;
- if (ADP.IsEmptyArray(restrictions) == false){
-
- for (int i = 0; i < restrictions.Length; i++) {
- if ((restrictions[i] != null) && (restrictions[i].Length > 4096)) {
- // use a non-specific error because no new beta 2 error messages are allowed
- //
- throw ADP.NotSupported();
- }
- }
- }
- string populationMechanism = requestedCollectionRow[populationMechanismColumn,DataRowVersion.Current] as string;
- switch (populationMechanism) {
- case _dataTable:
- if (exactCollectionName == DbMetaDataCollectionNames.MetaDataCollections) {
- hiddenColumns = new string[2];
- hiddenColumns[0] = _populationMechanism;
- hiddenColumns[1] = _populationString;
- }
- else {
- hiddenColumns = null;
- }
- // none of the datatable collections support restrictions
- if (ADP.IsEmptyArray(restrictions) == false){
- throw ADP.TooManyRestrictions(exactCollectionName);
- }
- requestedSchema = CloneAndFilterCollection(exactCollectionName,hiddenColumns);
- //
- // for the data source infomation table we need to fix up the version columns at run time
- // since the version is determined at run time
- if (exactCollectionName == DbMetaDataCollectionNames.DataSourceInformation) {
- FixUpVersion(requestedSchema);
- }
- break;
- case _sqlCommand:
- requestedSchema = ExecuteCommand(requestedCollectionRow,restrictions,connection);
- break;
- case _prepareCollection:
- requestedSchema = PrepareCollection(exactCollectionName,restrictions, connection);
- break;
- default:
- throw ADP.UndefinedPopulationMechanism(populationMechanism);
- }
- return requestedSchema;
- }
- private bool IncludeThisColumn(DataColumn sourceColumn, string[] hiddenColumnNames) {
- bool result = true;
- string sourceColumnName = sourceColumn.ColumnName;
- switch (sourceColumnName) {
- case _minimumVersion:
- case _maximumVersion:
- result = false;
- break;
- default:
- if (hiddenColumnNames == null) {
- break;
- }
- for (int i = 0 ; i < hiddenColumnNames.Length; i++) {
- if (hiddenColumnNames[i] == sourceColumnName){
- result = false;
- break;
- }
- }
- break;
- }
- return result;
- }
- private void LoadDataSetFromXml(Stream XmlStream){
- _metaDataCollectionsDataSet = new DataSet();
- _metaDataCollectionsDataSet.Locale = System.Globalization.CultureInfo.InvariantCulture;
- _metaDataCollectionsDataSet.ReadXml(XmlStream);
- }
- virtual protected DataTable PrepareCollection(String collectionName, String[] restrictions,DbConnection connection){
- throw ADP.NotSupported();
- }
- private bool SupportedByCurrentVersion(DataRow requestedCollectionRow){
- bool result = true;
- DataColumnCollection tableColumns = requestedCollectionRow.Table.Columns;
- DataColumn versionColumn;
- Object version;
- // check the minimum version first
- versionColumn = tableColumns[_minimumVersion];
- if (versionColumn != null) {
- version = requestedCollectionRow[versionColumn];
- if (version != null) {
- if (version != DBNull.Value) {
- if (0 > string.Compare( _normalizedServerVersion,(string)version, StringComparison.OrdinalIgnoreCase)){
- result = false;
- }
- }
- }
- }
- // if the minmum version was ok what about the maximum version
- if (result == true) {
- versionColumn = tableColumns[_maximumVersion];
- if (versionColumn != null) {
- version = requestedCollectionRow[versionColumn];
- if (version != null) {
- if (version != DBNull.Value) {
- if (0 < string.Compare( _normalizedServerVersion,(string)version, StringComparison.OrdinalIgnoreCase)){
- result = false;
- }
- }
- }
- }
- }
- return result;
- }
- }
- }
|