DbMetaDataFactory.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / fx / src / Data / System / Data / ProviderBase / DbMetaDataFactory.cs / 1 / DbMetaDataFactory.cs

                            //------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
//----------------------------------------------------------------------------- 
 
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; 
        }

#if !ORACLE
        protected DataSet CollectionDataSet  { 
            get {
                return _metaDataCollectionsDataSet; 
            } 
        }
 
        protected string ServerVersion  {
            get {
                return _serverVersionString;
            } 
        }
 
 
        protected string ServerVersionNormalized  {
            get { 
                return _normalizedServerVersion;
            }
        }
#endif 

        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)) {
                        // new error messages are not allowed for beta 2
                        // will add a more descriptive error in RTM 
                        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;
        }
    }
} 

 
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK