OleDbConnectionInternal.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / Data / System / Data / OleDb / OleDbConnectionInternal.cs / 1 / OleDbConnectionInternal.cs

                            //------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
//----------------------------------------------------------------------------- 
 
namespace System.Data.OleDb {
 
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Data.Common; 
    using System.Data.ProviderBase;
    using System.Diagnostics; 
    using System.Globalization; 
    using System.IO;
    using System.Runtime.CompilerServices; 
    using System.Runtime.InteropServices;
    using System.Security;
    using System.Security.Permissions;
    using System.Text; 
    using System.Threading;
    using SysES = System.EnterpriseServices; 
    using SysTx = System.Transactions; 

    sealed internal class OleDbConnectionInternal : DbConnectionInternal, IDisposable { 

        static private volatile OleDbServicesWrapper idataInitialize;
        static private object dataInitializeLock = new object();
 
        internal readonly OleDbConnectionString ConnectionString; // parsed connection string attributes
 
        // A SafeHandle is used instead of a RCW because we need to fake the CLR into not marshalling 

        // OLE DB Services is marked apartment thread, but it actually supports/requires free-threading. 
        // However the CLR doesn't know this and attempts to marshal the interfaces back to their original context.
        // But the OLE DB doesn't marshal very well if at all.  Our workaround is based on the fact
        // OLE DB is free-threaded and allows the workaround.
 
        // Creating DataSource/Session would requiring marshalling DataLins to its original context
        // and has a severe performance impact (when working with transactions), hence our workaround to not Marshal. 
 
        // Creating a Command would requiring marshalling Session to its original context and
        // actually doesn't work correctly, without our workaround you must execute the command in 
        // the same context of the connection open.  This doesn't work for pooled objects that contain
        // an open OleDbConnection.

        // We don't do extra work at this time to allow the DataReader to be used in a different context 
        // from which the command was executed in.  See WebData 64320, IRowset.GetNextRows will throw InvalidCastException
 
        // In V1.0, we worked around the performance impact of creating a DataSource/Session using 
        // WrapIUnknownWithComObject which creates a new RCW without searching for existing RCW
        // effectively faking out the CLR into thinking the call is in the correct context. 
        // We also would use Marshal.ReleaseComObject to force the release of the 'temporary' RCW.

        // In V1.1, we worked around the CreateCommand issue with the same WrapIUnknownWithComObject trick.
 
        // In V2.0, the performance of using WrapIUnknownWithComObject & ReleaseComObject severly degraded.
        // Using a SafeHandle (for lifetime control) and a delegate to call the apporiate COM method 
        // offered much better performance. 

        // the "Data Source object". 
        private readonly DataSourceWrapper _datasrcwrp;

        // the "Session object".
        private readonly SessionWrapper _sessionwrp; 

        private WeakReference weakTransaction; 
 
        private bool        _forcedAutomaticEnlistment;
 
        internal OleDbConnectionInternal(OleDbConnectionString constr, OleDbConnection connection) : base () {
#if DEBUG
            try { // use this to help validate this object is only created after the following permission has been previously demanded in the current codepath
                if (null != connection) { 
                    connection.UserConnectionOptions.DemandPermission();
                } 
                else { 
                    constr.DemandPermission();
                } 
            }
            catch(System.Security.SecurityException) {
                System.Diagnostics.Debug.Assert(false, "unexpected SecurityException for current codepath");
                throw; 
            }
#endif 
            Debug.Assert((null != constr) && !constr.IsEmpty, "empty connectionstring"); 
            ConnectionString = constr;
 
            if (constr.PossiblePrompt && !System.Environment.UserInteractive) {
                throw ODB.PossiblePromptNotUserInteractive();
            }
 
            // this is the native DataLinks object which pools the native datasource/session
            OleDbServicesWrapper wrapper = OleDbConnectionInternal.GetObjectPool(); 
            _datasrcwrp = new DataSourceWrapper(); 

            // DataLinks wrapper will call IDataInitialize::GetDataSource to create the DataSource 
            // uses constr.ActualConnectionString, no InfoMessageEvent checking
            wrapper.GetDataSource(constr, ref _datasrcwrp);
            Debug.Assert(!_datasrcwrp.IsInvalid, "bad DataSource");
 
            // initialization is delayed because of OleDbConnectionStringBuilder only wants
            // pre-Initialize IDBPropertyInfo & IDBProperties on the data source 
            if (null != connection) { 
                _sessionwrp = new SessionWrapper();
 
                // From the DataSource object, will call IDBInitialize.Initialize & IDBCreateSession.CreateSession
                // We always need both called so we use a single call for a single DangerousAddRef/DangerousRelease pair.
                OleDbHResult hr = _datasrcwrp.InitializeAndCreateSession(constr, ref _sessionwrp);
 
                // process the HResult here instead of from the SafeHandle because the possibility
                // of an InfoMessageEvent. 
                if ((0 <= hr) && !_sessionwrp.IsInvalid) { // process infonessage events 
                    OleDbConnection.ProcessResults(hr, connection, connection);
                } 
                else {
                    Exception e = OleDbConnection.ProcessResults(hr, null, null);
                    Debug.Assert(null != e, "CreateSessionError");
                    throw e; 
                }
                Debug.Assert(!_sessionwrp.IsInvalid, "bad Session"); 
            } 
        }
 
        internal OleDbConnection Connection {
            get {
                return (OleDbConnection)Owner;
            } 
        }
 
        internal bool HasSession { 
            get {
                return (null != _sessionwrp); 
            }
        }

        internal OleDbTransaction LocalTransaction { 
            get {
                OleDbTransaction result = null; 
                if (null != weakTransaction) { 
                    result = ((OleDbTransaction)weakTransaction.Target);
                } 
                return result;
            }
            set {
                weakTransaction = null; 

                if (null != value) { 
                    weakTransaction = new WeakReference((OleDbTransaction)value); 
                }
            } 
        }

        private string Provider {
            get { return ConnectionString.Provider; } 
        }
 
        override public string ServerVersion { // MDAC 55481 
            // consider making a method, not a property
            get { 
                object value = GetDataSourceValue(OleDbPropertySetGuid.DataSourceInfo, ODB.DBPROP_DBMSVER);
                return Convert.ToString(value, CultureInfo.InvariantCulture);
            }
        } 

        // grouping the native OLE DB casts togther by required interfaces and optional interfaces, connection then session 
        // want these to be methods, not properties otherwise they appear in VS7 managed debugger which attempts to evaluate them 

        // required interface, safe cast 
        internal IDBPropertiesWrapper IDBProperties() {
            Debug.Assert(null != _datasrcwrp, "IDBProperties: null datasource");
            return _datasrcwrp.IDBProperties(this);
        } 

        // required interface, safe cast 
        internal IOpenRowsetWrapper IOpenRowset() { 
            Debug.Assert(null != _datasrcwrp, "IOpenRowset: null datasource");
            Debug.Assert(null != _sessionwrp, "IOpenRowset: null session"); 
            return _sessionwrp.IOpenRowset(this);
        }

        // optional interface, unsafe cast 
        private IDBInfoWrapper IDBInfo() {
            Debug.Assert(null != _datasrcwrp, "IDBInfo: null datasource"); 
            return _datasrcwrp.IDBInfo(this); 
        }
 
        // optional interface, unsafe cast
        internal IDBSchemaRowsetWrapper IDBSchemaRowset() {
            Debug.Assert(null != _datasrcwrp, "IDBSchemaRowset: null datasource");
            Debug.Assert(null != _sessionwrp, "IDBSchemaRowset: null session"); 
            return _sessionwrp.IDBSchemaRowset(this);
        } 
 
        // optional interface, unsafe cast
        internal ITransactionJoinWrapper ITransactionJoin() { 
            Debug.Assert(null != _datasrcwrp, "ITransactionJoin: null datasource");
            Debug.Assert(null != _sessionwrp, "ITransactionJoin: null session");
            return _sessionwrp.ITransactionJoin(this);
        } 

        // optional interface, unsafe cast 
        internal UnsafeNativeMethods.ICommandText ICommandText() { 
            Debug.Assert(null != _datasrcwrp, "IDBCreateCommand: null datasource");
            Debug.Assert(null != _sessionwrp, "IDBCreateCommand: null session"); 

            object icommandText = null;
            OleDbHResult hr = _sessionwrp.CreateCommand(ref icommandText);
 
            Debug.Assert((0 <= hr) || (null == icommandText), "CreateICommandText: error with ICommandText");
            if (hr < 0) { 
                if (OleDbHResult.E_NOINTERFACE != hr) { // MDAC 57856 
                    ProcessResults(hr);
                } 
                else {
                    SafeNativeMethods.Wrapper.ClearErrorInfo();
                }
            } 
            return (UnsafeNativeMethods.ICommandText)icommandText;
        } 
 
        override protected void Activate(SysTx.Transaction transaction) {
            throw ADP.NotSupported(); 
        }

        override public DbTransaction BeginTransaction(IsolationLevel isolationLevel) {
            OleDbConnection.ExecutePermission.Demand(); 

            OleDbConnection outerConnection = Connection; 
            if (null != LocalTransaction) { 
                throw ADP.ParallelTransactionsNotSupported(outerConnection);
            } 

            object unknown = null;
            OleDbTransaction transaction;
            try { 
                transaction = new OleDbTransaction(outerConnection, null, isolationLevel);
 
                Bid.Trace(" %d#, ITransactionLocal\n", ObjectID); 
                Debug.Assert(null != _datasrcwrp, "ITransactionLocal: null datasource");
                Debug.Assert(null != _sessionwrp, "ITransactionLocal: null session"); 
                unknown = _sessionwrp.ComWrapper();
                UnsafeNativeMethods.ITransactionLocal value = (unknown as UnsafeNativeMethods.ITransactionLocal);
                if (null == value) {
                    throw ODB.TransactionsNotSupported(Provider, (Exception)null); 
                }
                transaction.BeginInternal(value); 
            } 
            finally {
                if (null != unknown) { 
                    Marshal.ReleaseComObject(unknown);
                }
            }
            LocalTransaction = transaction; 
            return transaction;
        } 
 
        override protected DbReferenceCollection CreateReferenceCollection() {
            return new OleDbReferenceCollection(); 
        }

        override protected void Deactivate() { // used by both managed and native pooling
            NotifyWeakReference(OleDbReferenceCollection.Closing); 

            if (_forcedAutomaticEnlistment) { 
                EnlistTransactionInternal(null, false);     // always un-enlist manually enlisted transaction, because the native pooler doesn't track it... 
            }
            OleDbTransaction transaction = LocalTransaction; 
            if (null != transaction) {
                LocalTransaction = null;
                // required to rollback any transactions on this connection
                // before releasing the back to the oledb connection pool 
                transaction.Dispose();
            } 
        } 

        public override void Dispose() { // MDAC 65459 
            Debug.Assert(null == LocalTransaction, "why was Deactivate not called first");
            if (null != _sessionwrp) {
                _sessionwrp.Dispose();
            } 
            if (null != _datasrcwrp) {
                _datasrcwrp.Dispose(); 
            } 
            base.Dispose();
        } 

        override public void EnlistTransaction(SysTx.Transaction transaction) { // MDAC 78997
            OleDbConnection.VerifyExecutePermission();
 
            OleDbConnection outerConnection = Connection;
            if (null != LocalTransaction) { 
                throw ADP.LocalTransactionPresent(); 
            }
            EnlistTransactionInternal(transaction, false); 
        }

        internal void EnlistTransactionInternal(SysTx.Transaction transaction, bool forcedAutomatic) {
            OleDbConnection.VerifyExecutePermission(); 

            SysTx.IDtcTransaction oleTxTransaction = ADP.GetOletxTransaction(transaction); 
 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); 
            try {
                using(ITransactionJoinWrapper transactionJoin = ITransactionJoin()) {
                    if (null == transactionJoin.Value) {
                        throw ODB.TransactionsNotSupported(Provider, (Exception)null); 
                    }
                    transactionJoin.Value.JoinTransaction(oleTxTransaction, (int) IsolationLevel.Unspecified, 0, IntPtr.Zero); 
                    _forcedAutomaticEnlistment = forcedAutomatic; 
                }
            } 
            finally {
                Bid.ScopeLeave(ref hscp);
            }
            EnlistedTransaction = transaction; 
        }
 
        internal object GetDataSourceValue(Guid propertySet, int propertyID) { 
            object value = GetDataSourcePropertyValue(propertySet, propertyID);
            if ((value is OleDbPropertyStatus) || Convert.IsDBNull(value)) { 
                value = null;
            }
            return value;
        } 

        internal object GetDataSourcePropertyValue(Guid propertySet, int propertyID) { 
            OleDbHResult hr; 
            tagDBPROP[] dbprops;
            using(IDBPropertiesWrapper idbProperties = IDBProperties()) { 
                using(PropertyIDSet propidset = new PropertyIDSet(propertySet, propertyID)) {

                    using(DBPropSet propset = new DBPropSet(idbProperties.Value, propidset, out hr)) {
                        if (hr < 0) { 
                            SafeNativeMethods.Wrapper.ClearErrorInfo();
                        } 
                        dbprops = propset.GetPropertySet(0, out propertySet); 
                    }
                } 
            }
            if (OleDbPropertyStatus.Ok == dbprops[0].dwStatus) {
                return dbprops[0].vValue;
            } 
            return dbprops[0].dwStatus;
        } 
 
        internal DataTable BuildInfoLiterals() {
            using(IDBInfoWrapper wrapper = IDBInfo()) { 
                UnsafeNativeMethods.IDBInfo dbInfo = wrapper.Value;
                if (null == dbInfo) {
                    return null;
                } 

                DataTable table = new DataTable("DbInfoLiterals"); 
                table.Locale = CultureInfo.InvariantCulture; 
                DataColumn literalName  = new DataColumn("LiteralName", typeof(String));
                DataColumn literalValue = new DataColumn("LiteralValue", typeof(String)); 
                DataColumn invalidChars = new DataColumn("InvalidChars", typeof(String));
                DataColumn invalidStart = new DataColumn("InvalidStartingChars", typeof(String));
                DataColumn literal      = new DataColumn("Literal", typeof(Int32));
                DataColumn maxlen       = new DataColumn("Maxlen", typeof(Int32)); 

                table.Columns.Add(literalName); 
                table.Columns.Add(literalValue); 
                table.Columns.Add(invalidChars);
                table.Columns.Add(invalidStart); 
                table.Columns.Add(literal);
                table.Columns.Add(maxlen);

                OleDbHResult hr; 
                int literalCount = 0;
                IntPtr literalInfo = ADP.PtrZero; 
                using(DualCoTaskMem handle = new DualCoTaskMem(dbInfo, null, out literalCount, out literalInfo, out hr)) { 
                    // All literals were either invalid or unsupported. The provider allocates memory for *prgLiteralInfo and sets the value of the fSupported element in all of the structures to FALSE. The consumer frees this memory when it no longer needs the information.
                    if (OleDbHResult.DB_E_ERRORSOCCURRED != hr) { 
                        long offset = literalInfo.ToInt64();
                        tagDBLITERALINFO tag = new tagDBLITERALINFO();
                        for (int i = 0; i < literalCount; ++i, offset += ODB.SizeOf_tagDBLITERALINFO) {
                            Marshal.PtrToStructure((IntPtr)offset, tag); 

                            DataRow row = table.NewRow(); 
                            row[literalName ] = ((OleDbLiteral) tag.it).ToString(); 
                            row[literalValue] = tag.pwszLiteralValue;
                            row[invalidChars] = tag.pwszInvalidChars; 
                            row[invalidStart] = tag.pwszInvalidStartingChars;
                            row[literal     ] = tag.it;
                            row[maxlen      ] = tag.cchMaxLen;
 
                            table.Rows.Add(row);
                            row.AcceptChanges(); 
                        } 
                        if (hr < 0) { // ignore infomsg
                            ProcessResults(hr); 
                        }
                    }
                    else {
                        SafeNativeMethods.Wrapper.ClearErrorInfo(); 
                    }
                } 
                return table; 
            }
        } 


        internal DataTable BuildInfoKeywords() {
 
            DataTable table = new DataTable(ODB.DbInfoKeywords);
            table.Locale = CultureInfo.InvariantCulture; 
            DataColumn keyword  = new DataColumn(ODB.Keyword, typeof(String)); 
            table.Columns.Add(keyword);
 
            if(!AddInfoKeywordsToTable(table,keyword)){
                table = null;
            }
 
            return table;
        } 
 
        internal bool AddInfoKeywordsToTable(DataTable table, DataColumn keyword) {
            using(IDBInfoWrapper wrapper = IDBInfo()) { 
                UnsafeNativeMethods.IDBInfo dbInfo = wrapper.Value;
                if (null == dbInfo) {
                    return false;
                } 

                OleDbHResult hr; 
                string keywords; 

                Bid.Trace(" %d#\n", ObjectID); 
                hr = dbInfo.GetKeywords(out keywords);
                Bid.Trace(" %08X{HRESULT}\n", hr);

                if (hr < 0) { // ignore infomsg 
                    ProcessResults(hr);
                } 
 
                if (null != keywords) {
                    string[] values = keywords.Split(new char[1] { ',' }); 
                    for (int i = 0; i < values.Length; ++i) {
                        DataRow row = table.NewRow();
                        row[keyword] = values[i];
 
                        table.Rows.Add(row);
                        row.AcceptChanges(); 
                    } 
                }
                return true; 
            }
        }

        internal DataTable BuildSchemaGuids() { 
            DataTable table = new DataTable(ODB.SchemaGuids);
            table.Locale = CultureInfo.InvariantCulture; 
 
            DataColumn schemaGuid  = new DataColumn(ODB.Schema, typeof(Guid));
            DataColumn restrictionSupport = new DataColumn(ODB.RestrictionSupport, typeof(Int32)); 

            table.Columns.Add(schemaGuid);
            table.Columns.Add(restrictionSupport);
 
            SchemaSupport[] supportedSchemas = GetSchemaRowsetInformation();
 
            if (null != supportedSchemas) { 
                object[] values = new object[2];
                table.BeginLoadData(); 
                for (int i = 0; i < supportedSchemas.Length; ++i) {
                    values[0] = supportedSchemas[i]._schemaRowset;
                    values[1] = supportedSchemas[i]._restrictions;
                    table.LoadDataRow(values, LoadOption.OverwriteChanges); 
                }
                table.EndLoadData(); 
            } 
            return table;
        } 

        internal string GetLiteralInfo(int literal) {
            using(IDBInfoWrapper wrapper = IDBInfo()) {
                UnsafeNativeMethods.IDBInfo dbInfo = wrapper.Value; 
                if (null == dbInfo) {
                    return null; 
                } 
                string literalValue = null;
                IntPtr literalInfo = ADP.PtrZero; 
                int literalCount = 0;
                OleDbHResult hr;

                using(DualCoTaskMem handle = new DualCoTaskMem(dbInfo, new int[1] { literal }, out literalCount, out literalInfo, out hr)) { 
                    // All literals were either invalid or unsupported. The provider allocates memory for *prgLiteralInfo and sets the value of the fSupported element in all of the structures to FALSE. The consumer frees this memory when it no longer needs the information.
                    if (OleDbHResult.DB_E_ERRORSOCCURRED != hr) { 
                        if ((1 == literalCount) && Marshal.ReadInt32(literalInfo, ODB.OffsetOf_tagDBLITERALINFO_it) == literal) { // WebData 98612 
                            literalValue = Marshal.PtrToStringUni(Marshal.ReadIntPtr(literalInfo, 0));
                        } 
                        if (hr < 0) { // ignore infomsg
                            ProcessResults(hr);
                        }
                    } 
                    else {
                        SafeNativeMethods.Wrapper.ClearErrorInfo(); 
                    } 
                }
                return literalValue; 
            }
        }

        internal SchemaSupport[] GetSchemaRowsetInformation() { 
            OleDbConnectionString constr = ConnectionString;
            SchemaSupport[] supportedSchemas = constr.SchemaSupport; 
            if (null != supportedSchemas) { 
                return supportedSchemas;
            } 
            using(IDBSchemaRowsetWrapper wrapper = IDBSchemaRowset()) {
                UnsafeNativeMethods.IDBSchemaRowset dbSchemaRowset = wrapper.Value;
                if (null == dbSchemaRowset) {
                    return null; // IDBSchemaRowset not supported 
                }
 
                OleDbHResult hr; 
                int schemaCount = 0;
                IntPtr schemaGuids = ADP.PtrZero; 
                IntPtr schemaRestrictions = ADP.PtrZero;

                using(DualCoTaskMem safehandle = new DualCoTaskMem(dbSchemaRowset, out schemaCount, out schemaGuids, out schemaRestrictions, out hr)) {
                    dbSchemaRowset = null; 
                    if (hr < 0) { // ignore infomsg
                        ProcessResults(hr); 
                    } 

                    supportedSchemas = new SchemaSupport[schemaCount]; 
                    if (ADP.PtrZero != schemaGuids) {
                        for (int i = 0, offset = 0; i < supportedSchemas.Length; ++i, offset += ODB.SizeOf_Guid) {
                            IntPtr ptr = ADP.IntPtrOffset(schemaGuids, i * ODB.SizeOf_Guid);
                            supportedSchemas[i]._schemaRowset =  (Guid) Marshal.PtrToStructure(ptr, typeof(Guid)); 
                        }
                    } 
                    if (ADP.PtrZero != schemaRestrictions) { 
                        for (int i = 0; i < supportedSchemas.Length; ++i) {
                            supportedSchemas[i]._restrictions = Marshal.ReadInt32(schemaRestrictions, i * 4); 
                        }
                    }
                }
                constr.SchemaSupport = supportedSchemas; 
                return supportedSchemas;
            } 
        } 

        internal DataTable GetSchemaRowset(Guid schema, object[] restrictions) { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, schema=%p{GUID}, restrictions\n", ObjectID, schema);
            try {
                if (null == restrictions) { // MDAC 62243 
                    restrictions = new object[0];
                } 
                DataTable dataTable = null; 
                using(IDBSchemaRowsetWrapper wrapper = IDBSchemaRowset()) {
                    UnsafeNativeMethods.IDBSchemaRowset dbSchemaRowset = wrapper.Value; 
                    if (null == dbSchemaRowset) {
                        throw ODB.SchemaRowsetsNotSupported(Provider);
                    }
 
                    UnsafeNativeMethods.IRowset rowset = null;
                    OleDbHResult hr; 
 
                    Bid.Trace(" %d#\n", ObjectID);
                    hr = dbSchemaRowset.GetRowset(ADP.PtrZero, ref schema, restrictions.Length, restrictions, ref ODB.IID_IRowset, 0, ADP.PtrZero, out rowset); 
                    Bid.Trace(" %08X{HRESULT}\n", hr);

                    if (hr < 0) { // ignore infomsg
                        ProcessResults(hr); 
                    }
 
                    if (null != rowset) { 
                        using(OleDbDataReader dataReader = new OleDbDataReader(Connection, null, 0, CommandBehavior.Default)) {
                            dataReader.InitializeIRowset(rowset, ChapterHandle.DB_NULL_HCHAPTER, IntPtr.Zero); 
                            dataReader.BuildMetaInfo();
                            dataReader.HasRowsRead();

                            dataTable = new DataTable(); 
                            dataTable.Locale = CultureInfo.InvariantCulture;
                            dataTable.TableName = OleDbSchemaGuid.GetTextFromValue(schema); 
                            OleDbDataAdapter.FillDataTable(dataReader, dataTable); 
                        }
                    } 
                    return dataTable;
                }
            }
            finally { 
                Bid.ScopeLeave(ref hscp);
            } 
        } 

        // returns true if there is an active data reader on the specified command 
        internal bool HasLiveReader(OleDbCommand cmd)  {
            bool result = false;
            DbReferenceCollection referenceCollection = ReferenceCollection;
 
            if (null != referenceCollection) {
                foreach (object weak in referenceCollection.Filter(OleDbReferenceCollection.DataReaderTag)) { 
                    OleDbDataReader dataReader = (OleDbDataReader)weak; // at least one is alive 
                    if  (null != dataReader && cmd == dataReader.Command) {
                        result = true;  // but it's only "live" if the command specified matches... 
                        break;
                    }
                }
            } 
            return result;
        } 
 
        private void ProcessResults(OleDbHResult hr) {
            OleDbConnection connection = Connection; // get value from weakref only once 
            Exception e = OleDbConnection.ProcessResults(hr, connection, connection);
            if (null != e) { throw e; }
        }
 
        internal bool SupportSchemaRowset(Guid schema) {
            SchemaSupport[] schemaSupport = GetSchemaRowsetInformation(); 
            if (null != schemaSupport) { // MDAC 68385 
                for (int i = 0; i < schemaSupport.Length; ++i) {
                    if (schema == schemaSupport[i]._schemaRowset) { 
                        return true;
                    }
                }
            } 
            return false;
        } 
 
        [SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.UnmanagedCode)]
        static private object CreateInstanceDataLinks() { 
            Type datalink = Type.GetTypeFromCLSID(ODB.CLSID_DataLinks, true);
            return Activator.CreateInstance(datalink, System.Reflection.BindingFlags.Public|System.Reflection.BindingFlags.Instance, null, null, CultureInfo.InvariantCulture, null);
        }
 

        // @devnote: should be multithread safe access to OleDbConnection.idataInitialize, 
        // though last one wins for setting variable.  It may be different objects, but 
        // OLE DB will ensure I'll work with just the single pool
        static private OleDbServicesWrapper GetObjectPool() { 
            OleDbServicesWrapper wrapper = OleDbConnectionInternal.idataInitialize;
            if (null == wrapper) {
                lock(dataInitializeLock) {
                    wrapper = OleDbConnectionInternal.idataInitialize; 
                    if (null == wrapper) {
                        VersionCheck(); 
 
                        object datalinks;
                        try { 
                            datalinks = CreateInstanceDataLinks();
                        }
                        catch (Exception e) {
                            // 
                            if (!ADP.IsCatchableExceptionType(e)) {
                                throw; 
                            } 

                            throw ODB.MDACNotAvailable(e); 
                        }
                        if (null == datalinks) {
                            throw ODB.MDACNotAvailable(null);
                        } 
                        wrapper = new OleDbServicesWrapper(datalinks);
                        OleDbConnectionInternal.idataInitialize = wrapper; 
                    } 
                }
            } 
            Debug.Assert(null != wrapper, "GetObjectPool: null dataInitialize");
            return wrapper;
        }
 
        static private void VersionCheck() {
            // $ 
 
            if (ApartmentState.Unknown == Thread.CurrentThread.GetApartmentState()) {
                SetMTAApartmentState(); 
            }

            ADP.CheckVersionMDAC(false);
        } 

        [System.Runtime.CompilerServices.MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] 
        static private void SetMTAApartmentState() { 
            // we are defaulting to a multithread apartment state
            Thread.CurrentThread.SetApartmentState(ApartmentState.MTA); 
        }

        // @devnote: should be multithread safe
        static public void ReleaseObjectPool() { 
            OleDbConnectionInternal.idataInitialize = null;
        } 
 
        internal OleDbTransaction ValidateTransaction(OleDbTransaction transaction, string method) {
            if (null != this.weakTransaction) { 

                OleDbTransaction head = (OleDbTransaction) this.weakTransaction.Target;
                if ((null != head) && this.weakTransaction.IsAlive) {
                    head = OleDbTransaction.TransactionUpdate(head); 

                    // either we are wrong or finalize was called and object still alive 
                    Debug.Assert(null != head, "unexcpted Transaction state"); 
                }
                // else transaction has finalized on user 

                if (null != head) {
                    if (null == transaction) {
                        // valid transaction exists and cmd doesn't have it 
                        throw ADP.TransactionRequired(method);
                    } 
                    else { 
                        OleDbTransaction tail = OleDbTransaction.TransactionLast(head);
                        if (tail != transaction) { 
                            if (tail.Connection != transaction.Connection) {
                                throw ADP.TransactionConnectionMismatch();
                            }
                            // else cmd has incorrect transaction 
                            throw ADP.TransactionCompleted();
                        } 
                        // else cmd has correct transaction 
                        return transaction;
                    } 
                }
                else { // cleanup for Finalized transaction
                    this.weakTransaction = null;
                } 
            }
            else if ((null != transaction) && (null != transaction.Connection)) { // MDAC 72706 
                throw ADP.TransactionConnectionMismatch(); 
            }
            // else no transaction and cmd is correct 

            // MDAC 61649
            // if transactionObject is from this connection but zombied
            // and no transactions currently exists - then ignore the bogus object 
            return null;
        } 
 
        internal Dictionary GetPropertyInfo(Guid[] propertySets) {
            bool isopen = HasSession; 
            OleDbConnectionString constr = ConnectionString;
            Dictionary properties = null;

            if (null == propertySets) { 
                propertySets = new Guid[0];
            } 
            using(PropertyIDSet propidset = new PropertyIDSet(propertySets)) { 
                using(IDBPropertiesWrapper idbProperties = IDBProperties()) {
                    using(PropertyInfoSet infoset = new PropertyInfoSet(idbProperties.Value, propidset)) { 
                        properties = infoset.GetValues();
                    }
                }
            } 
            return properties;
        } 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
//----------------------------------------------------------------------------- 
 
namespace System.Data.OleDb {
 
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Data.Common; 
    using System.Data.ProviderBase;
    using System.Diagnostics; 
    using System.Globalization; 
    using System.IO;
    using System.Runtime.CompilerServices; 
    using System.Runtime.InteropServices;
    using System.Security;
    using System.Security.Permissions;
    using System.Text; 
    using System.Threading;
    using SysES = System.EnterpriseServices; 
    using SysTx = System.Transactions; 

    sealed internal class OleDbConnectionInternal : DbConnectionInternal, IDisposable { 

        static private volatile OleDbServicesWrapper idataInitialize;
        static private object dataInitializeLock = new object();
 
        internal readonly OleDbConnectionString ConnectionString; // parsed connection string attributes
 
        // A SafeHandle is used instead of a RCW because we need to fake the CLR into not marshalling 

        // OLE DB Services is marked apartment thread, but it actually supports/requires free-threading. 
        // However the CLR doesn't know this and attempts to marshal the interfaces back to their original context.
        // But the OLE DB doesn't marshal very well if at all.  Our workaround is based on the fact
        // OLE DB is free-threaded and allows the workaround.
 
        // Creating DataSource/Session would requiring marshalling DataLins to its original context
        // and has a severe performance impact (when working with transactions), hence our workaround to not Marshal. 
 
        // Creating a Command would requiring marshalling Session to its original context and
        // actually doesn't work correctly, without our workaround you must execute the command in 
        // the same context of the connection open.  This doesn't work for pooled objects that contain
        // an open OleDbConnection.

        // We don't do extra work at this time to allow the DataReader to be used in a different context 
        // from which the command was executed in.  See WebData 64320, IRowset.GetNextRows will throw InvalidCastException
 
        // In V1.0, we worked around the performance impact of creating a DataSource/Session using 
        // WrapIUnknownWithComObject which creates a new RCW without searching for existing RCW
        // effectively faking out the CLR into thinking the call is in the correct context. 
        // We also would use Marshal.ReleaseComObject to force the release of the 'temporary' RCW.

        // In V1.1, we worked around the CreateCommand issue with the same WrapIUnknownWithComObject trick.
 
        // In V2.0, the performance of using WrapIUnknownWithComObject & ReleaseComObject severly degraded.
        // Using a SafeHandle (for lifetime control) and a delegate to call the apporiate COM method 
        // offered much better performance. 

        // the "Data Source object". 
        private readonly DataSourceWrapper _datasrcwrp;

        // the "Session object".
        private readonly SessionWrapper _sessionwrp; 

        private WeakReference weakTransaction; 
 
        private bool        _forcedAutomaticEnlistment;
 
        internal OleDbConnectionInternal(OleDbConnectionString constr, OleDbConnection connection) : base () {
#if DEBUG
            try { // use this to help validate this object is only created after the following permission has been previously demanded in the current codepath
                if (null != connection) { 
                    connection.UserConnectionOptions.DemandPermission();
                } 
                else { 
                    constr.DemandPermission();
                } 
            }
            catch(System.Security.SecurityException) {
                System.Diagnostics.Debug.Assert(false, "unexpected SecurityException for current codepath");
                throw; 
            }
#endif 
            Debug.Assert((null != constr) && !constr.IsEmpty, "empty connectionstring"); 
            ConnectionString = constr;
 
            if (constr.PossiblePrompt && !System.Environment.UserInteractive) {
                throw ODB.PossiblePromptNotUserInteractive();
            }
 
            // this is the native DataLinks object which pools the native datasource/session
            OleDbServicesWrapper wrapper = OleDbConnectionInternal.GetObjectPool(); 
            _datasrcwrp = new DataSourceWrapper(); 

            // DataLinks wrapper will call IDataInitialize::GetDataSource to create the DataSource 
            // uses constr.ActualConnectionString, no InfoMessageEvent checking
            wrapper.GetDataSource(constr, ref _datasrcwrp);
            Debug.Assert(!_datasrcwrp.IsInvalid, "bad DataSource");
 
            // initialization is delayed because of OleDbConnectionStringBuilder only wants
            // pre-Initialize IDBPropertyInfo & IDBProperties on the data source 
            if (null != connection) { 
                _sessionwrp = new SessionWrapper();
 
                // From the DataSource object, will call IDBInitialize.Initialize & IDBCreateSession.CreateSession
                // We always need both called so we use a single call for a single DangerousAddRef/DangerousRelease pair.
                OleDbHResult hr = _datasrcwrp.InitializeAndCreateSession(constr, ref _sessionwrp);
 
                // process the HResult here instead of from the SafeHandle because the possibility
                // of an InfoMessageEvent. 
                if ((0 <= hr) && !_sessionwrp.IsInvalid) { // process infonessage events 
                    OleDbConnection.ProcessResults(hr, connection, connection);
                } 
                else {
                    Exception e = OleDbConnection.ProcessResults(hr, null, null);
                    Debug.Assert(null != e, "CreateSessionError");
                    throw e; 
                }
                Debug.Assert(!_sessionwrp.IsInvalid, "bad Session"); 
            } 
        }
 
        internal OleDbConnection Connection {
            get {
                return (OleDbConnection)Owner;
            } 
        }
 
        internal bool HasSession { 
            get {
                return (null != _sessionwrp); 
            }
        }

        internal OleDbTransaction LocalTransaction { 
            get {
                OleDbTransaction result = null; 
                if (null != weakTransaction) { 
                    result = ((OleDbTransaction)weakTransaction.Target);
                } 
                return result;
            }
            set {
                weakTransaction = null; 

                if (null != value) { 
                    weakTransaction = new WeakReference((OleDbTransaction)value); 
                }
            } 
        }

        private string Provider {
            get { return ConnectionString.Provider; } 
        }
 
        override public string ServerVersion { // MDAC 55481 
            // consider making a method, not a property
            get { 
                object value = GetDataSourceValue(OleDbPropertySetGuid.DataSourceInfo, ODB.DBPROP_DBMSVER);
                return Convert.ToString(value, CultureInfo.InvariantCulture);
            }
        } 

        // grouping the native OLE DB casts togther by required interfaces and optional interfaces, connection then session 
        // want these to be methods, not properties otherwise they appear in VS7 managed debugger which attempts to evaluate them 

        // required interface, safe cast 
        internal IDBPropertiesWrapper IDBProperties() {
            Debug.Assert(null != _datasrcwrp, "IDBProperties: null datasource");
            return _datasrcwrp.IDBProperties(this);
        } 

        // required interface, safe cast 
        internal IOpenRowsetWrapper IOpenRowset() { 
            Debug.Assert(null != _datasrcwrp, "IOpenRowset: null datasource");
            Debug.Assert(null != _sessionwrp, "IOpenRowset: null session"); 
            return _sessionwrp.IOpenRowset(this);
        }

        // optional interface, unsafe cast 
        private IDBInfoWrapper IDBInfo() {
            Debug.Assert(null != _datasrcwrp, "IDBInfo: null datasource"); 
            return _datasrcwrp.IDBInfo(this); 
        }
 
        // optional interface, unsafe cast
        internal IDBSchemaRowsetWrapper IDBSchemaRowset() {
            Debug.Assert(null != _datasrcwrp, "IDBSchemaRowset: null datasource");
            Debug.Assert(null != _sessionwrp, "IDBSchemaRowset: null session"); 
            return _sessionwrp.IDBSchemaRowset(this);
        } 
 
        // optional interface, unsafe cast
        internal ITransactionJoinWrapper ITransactionJoin() { 
            Debug.Assert(null != _datasrcwrp, "ITransactionJoin: null datasource");
            Debug.Assert(null != _sessionwrp, "ITransactionJoin: null session");
            return _sessionwrp.ITransactionJoin(this);
        } 

        // optional interface, unsafe cast 
        internal UnsafeNativeMethods.ICommandText ICommandText() { 
            Debug.Assert(null != _datasrcwrp, "IDBCreateCommand: null datasource");
            Debug.Assert(null != _sessionwrp, "IDBCreateCommand: null session"); 

            object icommandText = null;
            OleDbHResult hr = _sessionwrp.CreateCommand(ref icommandText);
 
            Debug.Assert((0 <= hr) || (null == icommandText), "CreateICommandText: error with ICommandText");
            if (hr < 0) { 
                if (OleDbHResult.E_NOINTERFACE != hr) { // MDAC 57856 
                    ProcessResults(hr);
                } 
                else {
                    SafeNativeMethods.Wrapper.ClearErrorInfo();
                }
            } 
            return (UnsafeNativeMethods.ICommandText)icommandText;
        } 
 
        override protected void Activate(SysTx.Transaction transaction) {
            throw ADP.NotSupported(); 
        }

        override public DbTransaction BeginTransaction(IsolationLevel isolationLevel) {
            OleDbConnection.ExecutePermission.Demand(); 

            OleDbConnection outerConnection = Connection; 
            if (null != LocalTransaction) { 
                throw ADP.ParallelTransactionsNotSupported(outerConnection);
            } 

            object unknown = null;
            OleDbTransaction transaction;
            try { 
                transaction = new OleDbTransaction(outerConnection, null, isolationLevel);
 
                Bid.Trace(" %d#, ITransactionLocal\n", ObjectID); 
                Debug.Assert(null != _datasrcwrp, "ITransactionLocal: null datasource");
                Debug.Assert(null != _sessionwrp, "ITransactionLocal: null session"); 
                unknown = _sessionwrp.ComWrapper();
                UnsafeNativeMethods.ITransactionLocal value = (unknown as UnsafeNativeMethods.ITransactionLocal);
                if (null == value) {
                    throw ODB.TransactionsNotSupported(Provider, (Exception)null); 
                }
                transaction.BeginInternal(value); 
            } 
            finally {
                if (null != unknown) { 
                    Marshal.ReleaseComObject(unknown);
                }
            }
            LocalTransaction = transaction; 
            return transaction;
        } 
 
        override protected DbReferenceCollection CreateReferenceCollection() {
            return new OleDbReferenceCollection(); 
        }

        override protected void Deactivate() { // used by both managed and native pooling
            NotifyWeakReference(OleDbReferenceCollection.Closing); 

            if (_forcedAutomaticEnlistment) { 
                EnlistTransactionInternal(null, false);     // always un-enlist manually enlisted transaction, because the native pooler doesn't track it... 
            }
            OleDbTransaction transaction = LocalTransaction; 
            if (null != transaction) {
                LocalTransaction = null;
                // required to rollback any transactions on this connection
                // before releasing the back to the oledb connection pool 
                transaction.Dispose();
            } 
        } 

        public override void Dispose() { // MDAC 65459 
            Debug.Assert(null == LocalTransaction, "why was Deactivate not called first");
            if (null != _sessionwrp) {
                _sessionwrp.Dispose();
            } 
            if (null != _datasrcwrp) {
                _datasrcwrp.Dispose(); 
            } 
            base.Dispose();
        } 

        override public void EnlistTransaction(SysTx.Transaction transaction) { // MDAC 78997
            OleDbConnection.VerifyExecutePermission();
 
            OleDbConnection outerConnection = Connection;
            if (null != LocalTransaction) { 
                throw ADP.LocalTransactionPresent(); 
            }
            EnlistTransactionInternal(transaction, false); 
        }

        internal void EnlistTransactionInternal(SysTx.Transaction transaction, bool forcedAutomatic) {
            OleDbConnection.VerifyExecutePermission(); 

            SysTx.IDtcTransaction oleTxTransaction = ADP.GetOletxTransaction(transaction); 
 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); 
            try {
                using(ITransactionJoinWrapper transactionJoin = ITransactionJoin()) {
                    if (null == transactionJoin.Value) {
                        throw ODB.TransactionsNotSupported(Provider, (Exception)null); 
                    }
                    transactionJoin.Value.JoinTransaction(oleTxTransaction, (int) IsolationLevel.Unspecified, 0, IntPtr.Zero); 
                    _forcedAutomaticEnlistment = forcedAutomatic; 
                }
            } 
            finally {
                Bid.ScopeLeave(ref hscp);
            }
            EnlistedTransaction = transaction; 
        }
 
        internal object GetDataSourceValue(Guid propertySet, int propertyID) { 
            object value = GetDataSourcePropertyValue(propertySet, propertyID);
            if ((value is OleDbPropertyStatus) || Convert.IsDBNull(value)) { 
                value = null;
            }
            return value;
        } 

        internal object GetDataSourcePropertyValue(Guid propertySet, int propertyID) { 
            OleDbHResult hr; 
            tagDBPROP[] dbprops;
            using(IDBPropertiesWrapper idbProperties = IDBProperties()) { 
                using(PropertyIDSet propidset = new PropertyIDSet(propertySet, propertyID)) {

                    using(DBPropSet propset = new DBPropSet(idbProperties.Value, propidset, out hr)) {
                        if (hr < 0) { 
                            SafeNativeMethods.Wrapper.ClearErrorInfo();
                        } 
                        dbprops = propset.GetPropertySet(0, out propertySet); 
                    }
                } 
            }
            if (OleDbPropertyStatus.Ok == dbprops[0].dwStatus) {
                return dbprops[0].vValue;
            } 
            return dbprops[0].dwStatus;
        } 
 
        internal DataTable BuildInfoLiterals() {
            using(IDBInfoWrapper wrapper = IDBInfo()) { 
                UnsafeNativeMethods.IDBInfo dbInfo = wrapper.Value;
                if (null == dbInfo) {
                    return null;
                } 

                DataTable table = new DataTable("DbInfoLiterals"); 
                table.Locale = CultureInfo.InvariantCulture; 
                DataColumn literalName  = new DataColumn("LiteralName", typeof(String));
                DataColumn literalValue = new DataColumn("LiteralValue", typeof(String)); 
                DataColumn invalidChars = new DataColumn("InvalidChars", typeof(String));
                DataColumn invalidStart = new DataColumn("InvalidStartingChars", typeof(String));
                DataColumn literal      = new DataColumn("Literal", typeof(Int32));
                DataColumn maxlen       = new DataColumn("Maxlen", typeof(Int32)); 

                table.Columns.Add(literalName); 
                table.Columns.Add(literalValue); 
                table.Columns.Add(invalidChars);
                table.Columns.Add(invalidStart); 
                table.Columns.Add(literal);
                table.Columns.Add(maxlen);

                OleDbHResult hr; 
                int literalCount = 0;
                IntPtr literalInfo = ADP.PtrZero; 
                using(DualCoTaskMem handle = new DualCoTaskMem(dbInfo, null, out literalCount, out literalInfo, out hr)) { 
                    // All literals were either invalid or unsupported. The provider allocates memory for *prgLiteralInfo and sets the value of the fSupported element in all of the structures to FALSE. The consumer frees this memory when it no longer needs the information.
                    if (OleDbHResult.DB_E_ERRORSOCCURRED != hr) { 
                        long offset = literalInfo.ToInt64();
                        tagDBLITERALINFO tag = new tagDBLITERALINFO();
                        for (int i = 0; i < literalCount; ++i, offset += ODB.SizeOf_tagDBLITERALINFO) {
                            Marshal.PtrToStructure((IntPtr)offset, tag); 

                            DataRow row = table.NewRow(); 
                            row[literalName ] = ((OleDbLiteral) tag.it).ToString(); 
                            row[literalValue] = tag.pwszLiteralValue;
                            row[invalidChars] = tag.pwszInvalidChars; 
                            row[invalidStart] = tag.pwszInvalidStartingChars;
                            row[literal     ] = tag.it;
                            row[maxlen      ] = tag.cchMaxLen;
 
                            table.Rows.Add(row);
                            row.AcceptChanges(); 
                        } 
                        if (hr < 0) { // ignore infomsg
                            ProcessResults(hr); 
                        }
                    }
                    else {
                        SafeNativeMethods.Wrapper.ClearErrorInfo(); 
                    }
                } 
                return table; 
            }
        } 


        internal DataTable BuildInfoKeywords() {
 
            DataTable table = new DataTable(ODB.DbInfoKeywords);
            table.Locale = CultureInfo.InvariantCulture; 
            DataColumn keyword  = new DataColumn(ODB.Keyword, typeof(String)); 
            table.Columns.Add(keyword);
 
            if(!AddInfoKeywordsToTable(table,keyword)){
                table = null;
            }
 
            return table;
        } 
 
        internal bool AddInfoKeywordsToTable(DataTable table, DataColumn keyword) {
            using(IDBInfoWrapper wrapper = IDBInfo()) { 
                UnsafeNativeMethods.IDBInfo dbInfo = wrapper.Value;
                if (null == dbInfo) {
                    return false;
                } 

                OleDbHResult hr; 
                string keywords; 

                Bid.Trace(" %d#\n", ObjectID); 
                hr = dbInfo.GetKeywords(out keywords);
                Bid.Trace(" %08X{HRESULT}\n", hr);

                if (hr < 0) { // ignore infomsg 
                    ProcessResults(hr);
                } 
 
                if (null != keywords) {
                    string[] values = keywords.Split(new char[1] { ',' }); 
                    for (int i = 0; i < values.Length; ++i) {
                        DataRow row = table.NewRow();
                        row[keyword] = values[i];
 
                        table.Rows.Add(row);
                        row.AcceptChanges(); 
                    } 
                }
                return true; 
            }
        }

        internal DataTable BuildSchemaGuids() { 
            DataTable table = new DataTable(ODB.SchemaGuids);
            table.Locale = CultureInfo.InvariantCulture; 
 
            DataColumn schemaGuid  = new DataColumn(ODB.Schema, typeof(Guid));
            DataColumn restrictionSupport = new DataColumn(ODB.RestrictionSupport, typeof(Int32)); 

            table.Columns.Add(schemaGuid);
            table.Columns.Add(restrictionSupport);
 
            SchemaSupport[] supportedSchemas = GetSchemaRowsetInformation();
 
            if (null != supportedSchemas) { 
                object[] values = new object[2];
                table.BeginLoadData(); 
                for (int i = 0; i < supportedSchemas.Length; ++i) {
                    values[0] = supportedSchemas[i]._schemaRowset;
                    values[1] = supportedSchemas[i]._restrictions;
                    table.LoadDataRow(values, LoadOption.OverwriteChanges); 
                }
                table.EndLoadData(); 
            } 
            return table;
        } 

        internal string GetLiteralInfo(int literal) {
            using(IDBInfoWrapper wrapper = IDBInfo()) {
                UnsafeNativeMethods.IDBInfo dbInfo = wrapper.Value; 
                if (null == dbInfo) {
                    return null; 
                } 
                string literalValue = null;
                IntPtr literalInfo = ADP.PtrZero; 
                int literalCount = 0;
                OleDbHResult hr;

                using(DualCoTaskMem handle = new DualCoTaskMem(dbInfo, new int[1] { literal }, out literalCount, out literalInfo, out hr)) { 
                    // All literals were either invalid or unsupported. The provider allocates memory for *prgLiteralInfo and sets the value of the fSupported element in all of the structures to FALSE. The consumer frees this memory when it no longer needs the information.
                    if (OleDbHResult.DB_E_ERRORSOCCURRED != hr) { 
                        if ((1 == literalCount) && Marshal.ReadInt32(literalInfo, ODB.OffsetOf_tagDBLITERALINFO_it) == literal) { // WebData 98612 
                            literalValue = Marshal.PtrToStringUni(Marshal.ReadIntPtr(literalInfo, 0));
                        } 
                        if (hr < 0) { // ignore infomsg
                            ProcessResults(hr);
                        }
                    } 
                    else {
                        SafeNativeMethods.Wrapper.ClearErrorInfo(); 
                    } 
                }
                return literalValue; 
            }
        }

        internal SchemaSupport[] GetSchemaRowsetInformation() { 
            OleDbConnectionString constr = ConnectionString;
            SchemaSupport[] supportedSchemas = constr.SchemaSupport; 
            if (null != supportedSchemas) { 
                return supportedSchemas;
            } 
            using(IDBSchemaRowsetWrapper wrapper = IDBSchemaRowset()) {
                UnsafeNativeMethods.IDBSchemaRowset dbSchemaRowset = wrapper.Value;
                if (null == dbSchemaRowset) {
                    return null; // IDBSchemaRowset not supported 
                }
 
                OleDbHResult hr; 
                int schemaCount = 0;
                IntPtr schemaGuids = ADP.PtrZero; 
                IntPtr schemaRestrictions = ADP.PtrZero;

                using(DualCoTaskMem safehandle = new DualCoTaskMem(dbSchemaRowset, out schemaCount, out schemaGuids, out schemaRestrictions, out hr)) {
                    dbSchemaRowset = null; 
                    if (hr < 0) { // ignore infomsg
                        ProcessResults(hr); 
                    } 

                    supportedSchemas = new SchemaSupport[schemaCount]; 
                    if (ADP.PtrZero != schemaGuids) {
                        for (int i = 0, offset = 0; i < supportedSchemas.Length; ++i, offset += ODB.SizeOf_Guid) {
                            IntPtr ptr = ADP.IntPtrOffset(schemaGuids, i * ODB.SizeOf_Guid);
                            supportedSchemas[i]._schemaRowset =  (Guid) Marshal.PtrToStructure(ptr, typeof(Guid)); 
                        }
                    } 
                    if (ADP.PtrZero != schemaRestrictions) { 
                        for (int i = 0; i < supportedSchemas.Length; ++i) {
                            supportedSchemas[i]._restrictions = Marshal.ReadInt32(schemaRestrictions, i * 4); 
                        }
                    }
                }
                constr.SchemaSupport = supportedSchemas; 
                return supportedSchemas;
            } 
        } 

        internal DataTable GetSchemaRowset(Guid schema, object[] restrictions) { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, schema=%p{GUID}, restrictions\n", ObjectID, schema);
            try {
                if (null == restrictions) { // MDAC 62243 
                    restrictions = new object[0];
                } 
                DataTable dataTable = null; 
                using(IDBSchemaRowsetWrapper wrapper = IDBSchemaRowset()) {
                    UnsafeNativeMethods.IDBSchemaRowset dbSchemaRowset = wrapper.Value; 
                    if (null == dbSchemaRowset) {
                        throw ODB.SchemaRowsetsNotSupported(Provider);
                    }
 
                    UnsafeNativeMethods.IRowset rowset = null;
                    OleDbHResult hr; 
 
                    Bid.Trace(" %d#\n", ObjectID);
                    hr = dbSchemaRowset.GetRowset(ADP.PtrZero, ref schema, restrictions.Length, restrictions, ref ODB.IID_IRowset, 0, ADP.PtrZero, out rowset); 
                    Bid.Trace(" %08X{HRESULT}\n", hr);

                    if (hr < 0) { // ignore infomsg
                        ProcessResults(hr); 
                    }
 
                    if (null != rowset) { 
                        using(OleDbDataReader dataReader = new OleDbDataReader(Connection, null, 0, CommandBehavior.Default)) {
                            dataReader.InitializeIRowset(rowset, ChapterHandle.DB_NULL_HCHAPTER, IntPtr.Zero); 
                            dataReader.BuildMetaInfo();
                            dataReader.HasRowsRead();

                            dataTable = new DataTable(); 
                            dataTable.Locale = CultureInfo.InvariantCulture;
                            dataTable.TableName = OleDbSchemaGuid.GetTextFromValue(schema); 
                            OleDbDataAdapter.FillDataTable(dataReader, dataTable); 
                        }
                    } 
                    return dataTable;
                }
            }
            finally { 
                Bid.ScopeLeave(ref hscp);
            } 
        } 

        // returns true if there is an active data reader on the specified command 
        internal bool HasLiveReader(OleDbCommand cmd)  {
            bool result = false;
            DbReferenceCollection referenceCollection = ReferenceCollection;
 
            if (null != referenceCollection) {
                foreach (object weak in referenceCollection.Filter(OleDbReferenceCollection.DataReaderTag)) { 
                    OleDbDataReader dataReader = (OleDbDataReader)weak; // at least one is alive 
                    if  (null != dataReader && cmd == dataReader.Command) {
                        result = true;  // but it's only "live" if the command specified matches... 
                        break;
                    }
                }
            } 
            return result;
        } 
 
        private void ProcessResults(OleDbHResult hr) {
            OleDbConnection connection = Connection; // get value from weakref only once 
            Exception e = OleDbConnection.ProcessResults(hr, connection, connection);
            if (null != e) { throw e; }
        }
 
        internal bool SupportSchemaRowset(Guid schema) {
            SchemaSupport[] schemaSupport = GetSchemaRowsetInformation(); 
            if (null != schemaSupport) { // MDAC 68385 
                for (int i = 0; i < schemaSupport.Length; ++i) {
                    if (schema == schemaSupport[i]._schemaRowset) { 
                        return true;
                    }
                }
            } 
            return false;
        } 
 
        [SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.UnmanagedCode)]
        static private object CreateInstanceDataLinks() { 
            Type datalink = Type.GetTypeFromCLSID(ODB.CLSID_DataLinks, true);
            return Activator.CreateInstance(datalink, System.Reflection.BindingFlags.Public|System.Reflection.BindingFlags.Instance, null, null, CultureInfo.InvariantCulture, null);
        }
 

        // @devnote: should be multithread safe access to OleDbConnection.idataInitialize, 
        // though last one wins for setting variable.  It may be different objects, but 
        // OLE DB will ensure I'll work with just the single pool
        static private OleDbServicesWrapper GetObjectPool() { 
            OleDbServicesWrapper wrapper = OleDbConnectionInternal.idataInitialize;
            if (null == wrapper) {
                lock(dataInitializeLock) {
                    wrapper = OleDbConnectionInternal.idataInitialize; 
                    if (null == wrapper) {
                        VersionCheck(); 
 
                        object datalinks;
                        try { 
                            datalinks = CreateInstanceDataLinks();
                        }
                        catch (Exception e) {
                            // 
                            if (!ADP.IsCatchableExceptionType(e)) {
                                throw; 
                            } 

                            throw ODB.MDACNotAvailable(e); 
                        }
                        if (null == datalinks) {
                            throw ODB.MDACNotAvailable(null);
                        } 
                        wrapper = new OleDbServicesWrapper(datalinks);
                        OleDbConnectionInternal.idataInitialize = wrapper; 
                    } 
                }
            } 
            Debug.Assert(null != wrapper, "GetObjectPool: null dataInitialize");
            return wrapper;
        }
 
        static private void VersionCheck() {
            // $ 
 
            if (ApartmentState.Unknown == Thread.CurrentThread.GetApartmentState()) {
                SetMTAApartmentState(); 
            }

            ADP.CheckVersionMDAC(false);
        } 

        [System.Runtime.CompilerServices.MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] 
        static private void SetMTAApartmentState() { 
            // we are defaulting to a multithread apartment state
            Thread.CurrentThread.SetApartmentState(ApartmentState.MTA); 
        }

        // @devnote: should be multithread safe
        static public void ReleaseObjectPool() { 
            OleDbConnectionInternal.idataInitialize = null;
        } 
 
        internal OleDbTransaction ValidateTransaction(OleDbTransaction transaction, string method) {
            if (null != this.weakTransaction) { 

                OleDbTransaction head = (OleDbTransaction) this.weakTransaction.Target;
                if ((null != head) && this.weakTransaction.IsAlive) {
                    head = OleDbTransaction.TransactionUpdate(head); 

                    // either we are wrong or finalize was called and object still alive 
                    Debug.Assert(null != head, "unexcpted Transaction state"); 
                }
                // else transaction has finalized on user 

                if (null != head) {
                    if (null == transaction) {
                        // valid transaction exists and cmd doesn't have it 
                        throw ADP.TransactionRequired(method);
                    } 
                    else { 
                        OleDbTransaction tail = OleDbTransaction.TransactionLast(head);
                        if (tail != transaction) { 
                            if (tail.Connection != transaction.Connection) {
                                throw ADP.TransactionConnectionMismatch();
                            }
                            // else cmd has incorrect transaction 
                            throw ADP.TransactionCompleted();
                        } 
                        // else cmd has correct transaction 
                        return transaction;
                    } 
                }
                else { // cleanup for Finalized transaction
                    this.weakTransaction = null;
                } 
            }
            else if ((null != transaction) && (null != transaction.Connection)) { // MDAC 72706 
                throw ADP.TransactionConnectionMismatch(); 
            }
            // else no transaction and cmd is correct 

            // MDAC 61649
            // if transactionObject is from this connection but zombied
            // and no transactions currently exists - then ignore the bogus object 
            return null;
        } 
 
        internal Dictionary GetPropertyInfo(Guid[] propertySets) {
            bool isopen = HasSession; 
            OleDbConnectionString constr = ConnectionString;
            Dictionary properties = null;

            if (null == propertySets) { 
                propertySets = new Guid[0];
            } 
            using(PropertyIDSet propidset = new PropertyIDSet(propertySets)) { 
                using(IDBPropertiesWrapper idbProperties = IDBProperties()) {
                    using(PropertyInfoSet infoset = new PropertyInfoSet(idbProperties.Value, propidset)) { 
                        properties = infoset.GetValues();
                    }
                }
            } 
            return properties;
        } 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

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