OracleInternalConnection.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / DataOracleClient / System / Data / OracleClient / OracleInternalConnection.cs / 1 / OracleInternalConnection.cs

                            //------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
namespace System.Data.OracleClient 
{
    using System; 
    using System.Collections;
    using System.Collections.Generic;
    using System.Data.Common;
    using System.Data.ProviderBase; 
    using System.Diagnostics;
    using System.Globalization; 
    using System.Runtime.InteropServices; 
    using System.Security;
    using System.Security.Permissions; 
    using System.Text;
    using System.Threading;
    using SysTx = System.Transactions;
 
    sealed internal class OracleInternalConnection : DbConnectionInternal {
 
        private OracleConnectionString  _connectionOptions; 
        private OciEnvironmentHandle    _environmentHandle;         // OCI environment handle -- the root of all handles for this connection.
        private OciErrorHandle          _errorHandle;               // OCI error handle -- every call needs one 
        private OciServerHandle         _serverHandle;              // Not available in MTS transaction connection
        private OciServiceContextHandle _serviceContextHandle;      // OCI service context handle -- defines the connection and transaction.
        private OciSessionHandle        _sessionHandle;             // Not available in MTS transaction connection
        private OciEnlistContext        _enlistContext;             // Only available in MTS transaction connection 

        private bool                    _connectionIsOpen; 
 
        private WeakReference           _transaction;               // weak reference to the local transaction
        private TransactionState        _transactionState;          // our own transacted state 

        private List _deferredInfoMessageCollection;    // where our Success With Info messages go while we connect...

        private long                    _serverVersion;             // server version value,  eg: 0x0801050000 
        private string                  _serverVersionString;       // server version string, eg: "8.1.5.0.0 Oracle8i Enterprise Edition Release 8.1.5.0.0 - Production"
        private string                  _serverVersionStringNormalized;       // server version string, eg: "08.01.05.00.00" 
        private TimeSpan                _serverTimeZoneAdjustment = TimeSpan.MinValue; 

        private NativeBuffer            _scratchBuffer;             // for miscellaneous uses, like error handling, version strings, BFILE names.. 
        private Encoding                _encodingDatabase;          // will encode/decode CHAR/VARCHAR/CLOB strings
        private Encoding                _encodingNational;          // will encode/decode NCHAR/NVARCHAR/NCLOB strings

        // Construct from a compiled connection string 
        internal OracleInternalConnection(OracleConnectionString connectionOptions) {
#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 
                connectionOptions.DemandPermission();
            } 
            catch(System.Security.SecurityException) {
                System.Diagnostics.Debug.Assert(false, "unexpected SecurityException for current codepath");
                throw;
            } 
#endif
            _connectionOptions = connectionOptions; 
 
            //  We test for the presence of a distributed transaction in a function
            //  that is only called when the Enlist connection string attribute is 
            //  false, so we can avoid the overhead of loading enterpriseservices
            //  stuff for local-only transactions.

            string userName             = connectionOptions.UserId; 
            string password             = connectionOptions.Password;
            string serverName           = connectionOptions.DataSource; 
            bool   integratedSecurity   = connectionOptions.IntegratedSecurity; 
            bool   unicode              = connectionOptions.Unicode;
            bool   omitOracleConnectionName = _connectionOptions.OmitOracleConnectionName; 

            _connectionIsOpen = OpenOnLocalTransaction (userName, password, serverName, integratedSecurity, unicode, omitOracleConnectionName);

            if (UnicodeEnabled) 
                _encodingDatabase   = System.Text.Encoding.Unicode; // for environments initialized in UTF16 mode, we can use straight Unicode
            else if (ServerVersionAtLeastOracle8i) 
                _encodingDatabase   = new OracleEncoding(this);     // for Oracle8i or greater we'll use Oracle's conversion routines. 
            else
                _encodingDatabase   = System.Text.Encoding.Default; // anything prior to Oracle8i doesn't work with Oracle's conversion routines. 

            _encodingNational   = System.Text.Encoding.Unicode;     // we use Unicode for the NCHAR/NVARCHAR/NCLOB and let Oracle perform the conversion automatically.

            // SQLBUDT #286430 - we only should be attempting to enlist in a distributed 
            // transaction when we're not a pooled connection.
            if (connectionOptions.Enlist && !connectionOptions.Pooling) { 
                SysTx.Transaction transaction = ADP.GetCurrentTransaction(); 

                if (null != transaction) { 
                    Enlist(userName, password, serverName, transaction, false);
                }
            }
        } 

        internal OciEnvironmentHandle EnvironmentHandle { 
            //  Every handle is allocated from the environment handle in some way, 
            //  so we have to provide access to it internally.
            get { return _environmentHandle; } 
        }

        internal OciErrorHandle ErrorHandle {
            //  Every OCI call needs an error handle, so make it available internally. 
            get { return _errorHandle; }
        } 
 
        internal bool HasTransaction {
            get { 
                TransactionState transactionState = TransactionState;
                bool result = ((TransactionState.LocalStarted == transactionState) || (TransactionState.GlobalStarted == transactionState));
                return result;
            } 
        }
 
        override public string ServerVersion { 
            get {
                if (null == _serverVersionString) { 
                    string  result = "no version available";
                    NativeBuffer    buffer = null;

                    try { 
                        buffer = new NativeBuffer_ServerVersion(500);
 
                        int rc = TracedNativeMethods.OCIServerVersion( 
                                            ServiceContextHandle,       // hndlp
                                            ErrorHandle,                // errhp 
                                            buffer
                                            );

                        if (0 != rc) 
                            throw ADP.OracleError(ErrorHandle, rc);
 
                        if (0 == rc) // in case it was a warning message. 
                            result = ServiceContextHandle.PtrToString(buffer);
 
                        _serverVersion      = ParseServerVersion(result);
                        _serverVersionString= String.Format((IFormatProvider)null, "{0}.{1}.{2}.{3}.{4} {5}",
                                                    (_serverVersion >> 32) & 0xff,
                                                    (_serverVersion >> 24) & 0xff, 
                                                    (_serverVersion >> 16) & 0xff,
                                                    (_serverVersion >> 8)  & 0xff, 
                                                    _serverVersion         & 0xff, 
                                                    result
                                                    ); 
                        _serverVersionStringNormalized= String.Format((IFormatProvider)null, "{0:00}.{1:00}.{2:00}.{3:00}.{4:00} ",
                                                    (_serverVersion >> 32) & 0xff,
                                                    (_serverVersion >> 24) & 0xff,
                                                    (_serverVersion >> 16) & 0xff, 
                                                    (_serverVersion >> 8)  & 0xff,
                                                    _serverVersion         & 0xff 
                                                    ); 
                    }
                    finally { 
                        if (null != buffer) {
                            buffer.Dispose();
                            buffer = null;
                        } 
                    }
                } 
                return _serverVersionString; 
            }
        } 

        override public string ServerVersionNormalized {
            get {
                if (null == _serverVersionStringNormalized) { 
                    string temp = ServerVersion;
                } 
                return _serverVersionStringNormalized; 
            }
        } 

        internal bool ServerVersionAtLeastOracle8 {
            get { return (ServerVersionNumber >= 0x800000000L); }
        } 

        internal bool ServerVersionAtLeastOracle8i { 
            get { return (ServerVersionNumber >= 0x801000000L); } 
        }
 
        internal bool ServerVersionAtLeastOracle9i {
            get { return (ServerVersionNumber >= 0x900000000L); }
        }
 
        internal long ServerVersionNumber {
            get { 
                if (0 == _serverVersion) { 
                    string temp = ServerVersion;    // force the serverversion value to be created
                } 
                return _serverVersion;
            }
        }
 
        internal OciServiceContextHandle ServiceContextHandle {
            //  You need to provide the service context handle to things like the 
            //  OCI execute call so a statement handle can be associated with a 
            //  connection.  Better make it available internally, then.
            get { return _serviceContextHandle; } 
        }

        internal OciSessionHandle SessionHandle {
            //  You need to provide the session handle to a few OCI calls.  Better 
            //  make it available internally, then.
            get { return _sessionHandle; } 
        } 

        internal OracleTransaction Transaction { 
            //  In oracle, the session object controls the transaction so we keep
            //  the transaction state here as well.

            get { 
                if (_transaction != null && _transaction.IsAlive) {
                    if (null != ((OracleTransaction)_transaction.Target).Connection) { 
                        return (OracleTransaction)_transaction.Target; 
                    }
                    _transaction.Target = null; 
                }
                return null;
            }
            set { 
                if (value == null)
                { 
                    // SQLHOTFIX# 50003486 - if the set accessor is called with a null value 
                    //   it effectively creates a dead transaction...this is not likely the intent
                    //   and it potentially causes state management problems in error conditions. 
                    _transaction = null;
                }
                else
                { 
                    if (_transaction != null)
                    { 
                        _transaction.Target = (OracleTransaction)value; 
                    }
                    else 
                    {
                        _transaction = new WeakReference((OracleTransaction)value);
                    }
                } 
            }
        } 
 
        internal TransactionState TransactionState {
            //  In oracle, the session object controls the transaction so we keep 
            //  the transaction state here as well.
            get { return _transactionState; }
            set { _transactionState = value; }
        } 

        internal bool UnicodeEnabled { 
            get { return OCI.ClientVersionAtLeastOracle9i && (null == EnvironmentHandle || EnvironmentHandle.IsUnicode); } 
        }
 
        override protected void Activate(SysTx.Transaction transaction) {
            bool isInTransaction = (null != transaction);
            OracleConnectionString connectionOptions = _connectionOptions;
 
            if (isInTransaction && connectionOptions.Enlist) {
                if (!transaction.Equals(EnlistedTransaction)) {     // WebData 20000024 
                    Enlist(connectionOptions.UserId, connectionOptions.Password, connectionOptions.DataSource, transaction, false); 
                }
            } 
            else if (!isInTransaction && null != _enlistContext) {
                UnEnlist();
            }
        } 

        override public DbTransaction BeginTransaction(IsolationLevel il) { 
            return BeginOracleTransaction(il); 
        }
 
        internal OracleTransaction BeginOracleTransaction(IsolationLevel il) {
            OracleConnection.ExecutePermission.Demand();

            //------------------------------------------------------------------------------------- 
            // pre-condition validation
 
            if (TransactionState.AutoCommit != TransactionState) 
                throw ADP.NoParallelTransactions();
 
            //-------------------------------------------------------------------------------------

            // SQLHOTFIX# 50003423: setting isolation levels may require that we execute commands on the server which will,
            //   in turn, rollback any potentially dead transactions and reset our state to auto-commit mode. This typically 
            //   happens when a connection is re-used to execute a new command after a previous command associated with a
            //   transaction has been committed. When we're attempting to begin a new transaction, we need to be sure to 
            //   clear the internal state *before* partially initializing members. 
            Debug.Assert(_transaction == null || _transaction.IsAlive == false);
            RollbackDeadTransaction(); 

            OracleTransaction newTransaction = new OracleTransaction(ProxyConnection(), il);
            Transaction = newTransaction;
 
            //--------------------------------------------------------------------------------------
            // post-condition validation 
 
            Debug.Assert(TransactionState == TransactionState.LocalStarted && newTransaction != null);
 
            //-------------------------------------------------------------------------------------

            return newTransaction;
        } 

        private void CreateDeferredInfoMessage(OciErrorHandle errorHandle, int rc) { 
            // NOTE: You should only call this within the Open() call. 
            Debug.Assert ((int)OCI.RETURNCODE.OCI_SUCCESS_WITH_INFO == rc, "unexpected info message");
 
            OracleException             infoMessage      = OracleException.CreateException(errorHandle, rc);
            OracleInfoMessageEventArgs  infoMessageEvent = new OracleInfoMessageEventArgs(infoMessage);

            List deferredInfoMessageCollection = _deferredInfoMessageCollection; 

            if (null == deferredInfoMessageCollection) { 
                deferredInfoMessageCollection = _deferredInfoMessageCollection = new List(); 
            }
 
            deferredInfoMessageCollection.Add(infoMessageEvent);
        }

        internal void ConnectionIsBroken() { 
            DoomThisConnection();
            OracleConnection owningObject = (OracleConnection)Owner; 
            if (null != owningObject) { 
                owningObject.Close(); // force the closed state on the outer object.
            } 
            else {
                Dispose();
            }
        } 

        internal void Commit() { 
            //  Commits the current local transaction; called by the transaction 
            //  object, because Oracle doesn't have a specific transaction object,
            //  but combines the transaction into the service context. 

            //--------------------------------------------------------------------------------------
            // pre-condition validation
 
            // ensure that we are participating in a local transaction
            Debug.Assert ( TransactionState == TransactionState.LocalStarted && Transaction != null ); 
 
            // NOTE: OCITransCommit will return an error if the connection has been broken/closed,
            //   so not checking that state here. 

            //--------------------------------------------------------------------------------------

 
            int rc = TracedNativeMethods.OCITransCommit(
                                        ServiceContextHandle, 
                                        ErrorHandle, 
                                        OCI.MODE.OCI_DEFAULT
                                        ); 

            if (0 != rc) {
                OracleException.Check(ErrorHandle, rc);
            } 

            // Once we complete the transaction, we're supposed to go back to 
            // autocommit mode. 
            TransactionState = TransactionState.AutoCommit;
 
            // SQLHOTFIX# 50003486: in order to restore the connection's transaction state to what it was prior to beginning
            //   this transaction, ensure that OracleTransaction WeakRef (_transaction) is null. Not doing so, which was the
            //   original behavior of this code, does not appear to serve any purpose and complicates state detection
            //   elsewhere, causing unexpected behavioral complications. As an example, once a transaction was committed or 
            //   rolled back, any subsequent command execution would send a rollback notification to the server when the
            //   transaction no longer existed in the server's context (e.g. already committed/rolled back). 
            Transaction = null; 

        } 

        override protected void Deactivate() {

            // Connection may have been already doomed on a previous call to Deactivate, 
            // in which case the ErrorHandle will have already been nulled out
            if (!IsConnectionDoomed && null != ErrorHandle && ErrorHandle.ConnectionIsBroken) { 
                ConnectionIsBroken(); 
            }
 
            // Before we return the connection to the pool, we rollback any
            // active transaction that may have been created.  Note that we
            // don't bother with distributed transactions because we don't
            // want to them back (it's handled by the TM).  We also don't 
            // worry about implicit transactions (like "select...for update")
            // because we don't want to take the performance hit of the server 
            // round-trip when it isn't very likely. 
            if (TransactionState.LocalStarted == TransactionState) {
                // On the off chance that we have some failure during rollback 
                // we just eat it and make sure that the connection is doomed.

                try {
                    Rollback(); 
                }
                catch (Exception e) { 
                    if (!ADP.IsCatchableExceptionType(e)) { 
                        throw;
                    } 

                    ADP.TraceException(e);
                    base.DoomThisConnection();
                } 
            }
 
        } 

        override public void Dispose() { 
            Deactivate();     // ensure we rollback any transaction...

            //
            OciEnlistContext.SafeDispose(ref _enlistContext); 

            // 
 

            OciHandle.SafeDispose(ref _sessionHandle); 
            OciHandle.SafeDispose(ref _serviceContextHandle);
            OciHandle.SafeDispose(ref _serverHandle);
            OciHandle.SafeDispose(ref _errorHandle);
            OciHandle.SafeDispose(ref _environmentHandle); 

            if (null != _scratchBuffer) { 
                _scratchBuffer.Dispose(); 
            }
 
            _scratchBuffer = null;
            _encodingDatabase = null;
            _encodingNational = null;
            _transaction = null; 
            _serverVersionString = null;
 
            base.Dispose(); 
        }
 
        private void Enlist(string userName, string password, string serverName, SysTx.Transaction transaction, bool manualEnlistment) {
            // No matter what happened before, we need to reset this connection
            // to an unenlisted state.
            UnEnlist(); 

            // Oracle only implemented OraMTS for 9i. 
            if (!OCI.ClientVersionAtLeastOracle9i) 
                throw ADP.DistribTxRequiresOracle9i();
 
#if ALLOWTRACING
            ADP.TraceObjectPoolActivity("Enlist", this, transactionGuid);
#endif //ALLOWTRACING
            if (null != transaction) { 
//Console.WriteLine(String.Format((IFormatProvider)null, "connection {0}: Enlisting: {1}", _uniqueConnectionId, transactionGuid));
                if (HasTransaction) { 
                    throw ADP.TransactionPresent(); 
                }
 
                // To construct a SafeHandle, we have to use a CER, which can't
                // allocate memory, so we have to do our own marshalling to avoid
                // the allocates...
                byte[]  passwordBytes = System.Text.Encoding.Default.GetBytes(password); 
                byte[]  userNameBytes = System.Text.Encoding.Default.GetBytes(userName);
                byte[]  serverNameBytes = System.Text.Encoding.Default.GetBytes(serverName); 
 
                _enlistContext = new OciEnlistContext(userNameBytes, passwordBytes, serverNameBytes, ServiceContextHandle, ErrorHandle);
                _enlistContext.Join(this, transaction); 

                TransactionState = TransactionState.GlobalStarted;
            }
            else { 
                Debug.Assert(null == _enlistContext, "Enlisting a null transaction?");
                TransactionState = TransactionState.AutoCommit; 
            } 

            // Tell the base class about our enlistment 
            EnlistedTransaction = transaction;
        }

        override public void EnlistTransaction(SysTx.Transaction transaction) { 
            OracleConnection.VerifyExecutePermission();
 
            OracleConnectionString  connectionOptions = _connectionOptions;   // prevent race condition 

            // We need to rollback any existing local transaction, so we need to make sure 
            // that there isn't a local transaction before we wipe it out.  Of course, if
            // the local transaction is dead, we can roll it back first.
            RollbackDeadTransaction();
 
            Enlist( connectionOptions.UserId,
                    connectionOptions.Password, 
                    connectionOptions.DataSource, 
                    transaction,
                    true); 
        }

        internal void FireDeferredInfoMessageEvents(OracleConnection outerConnection) {
            List deferredInfoMessageCollection = _deferredInfoMessageCollection; 
            _deferredInfoMessageCollection = null;
 
            if (null != deferredInfoMessageCollection) { 
                foreach (OracleInfoMessageEventArgs deferredInfoMessage in deferredInfoMessageCollection) {
                    if (null != deferredInfoMessage) { 
                        outerConnection.OnInfoMessage(deferredInfoMessage);
                    }
                }
            } 
        }
 
        internal byte[] GetBytes(string value, bool useNationalCharacterSet) { 
            // Return a byte array containing the value in the appropriate
            // character set form. 
            byte[] result;

            if (useNationalCharacterSet)
                result = _encodingNational.GetBytes(value); 
            else
                result = _encodingDatabase.GetBytes(value); 
 
            return result;
        } 

        internal NativeBuffer GetScratchBuffer(int minSize) {
            NativeBuffer scratchBuffer = _scratchBuffer;
            if (null == scratchBuffer || scratchBuffer.Length < minSize) { 
                if (null != scratchBuffer) {
                    scratchBuffer.Dispose(); 
                } 
                scratchBuffer = new NativeBuffer_ScratchBuffer(minSize);
                _scratchBuffer = scratchBuffer; 
            }
            return scratchBuffer;
        }
 
        internal string GetString(byte[] bytearray) {
            return _encodingDatabase.GetString(bytearray); 
        } 

        internal string GetString(byte[] bytearray, bool useNationalCharacterSet) { 
            if (useNationalCharacterSet)
                return _encodingNational.GetString(bytearray);
            else
                return _encodingDatabase.GetString(bytearray); 
        }
 
        internal TimeSpan GetServerTimeZoneAdjustmentToUTC(OracleConnection connection) { 
            TimeSpan serverTimeZoneAdjustment = _serverTimeZoneAdjustment;
 
            if (TimeSpan.MinValue == serverTimeZoneAdjustment) {
                Debug.Assert(TimeSpan.Zero != TimeSpan.MinValue, "TimeSpan.Zero == TimeSpan.MinValue"); // we're assuming TimeSpan.Zero != TimeSpan.MinValue in this code

                if ( ServerVersionAtLeastOracle9i ) { // Oracle8i doesn't have server timezones. 
                    OracleCommand tempCommand;
                    tempCommand = new OracleCommand(); 
                    tempCommand.Connection = connection; 
                    tempCommand.Transaction = Transaction;
                    tempCommand.CommandText = "select tz_offset(dbtimezone) from dual"; 

                    string adjust = ((string)tempCommand.ExecuteScalar());
                    int tzh = Int32.Parse(adjust.Substring(0,3),CultureInfo.InvariantCulture);   // -hh
                    int tzm = Int32.Parse(adjust.Substring(4,2),CultureInfo.InvariantCulture);   // mm 

                    serverTimeZoneAdjustment = new TimeSpan(tzh, tzm, 0); 
                } 
                else {
                    serverTimeZoneAdjustment = TimeSpan.Zero; 
                }
                _serverTimeZoneAdjustment = serverTimeZoneAdjustment;
            }
            return _serverTimeZoneAdjustment; 
        }
 
        private bool OpenOnLocalTransaction(string userName, string password, string serverName, bool integratedSecurity, bool unicode, bool omitOracleConnectionName) { 
            //  This method attempts to perform a local connection that may not
            //  be enlisted in a distributed transaction.  It only returns true 
            //  when the connection is successful.

            int         rc = 0;
            OCI.CRED    authMode; 

            // Create an OCI environmentHandle handle 
 
            IntPtr      environmentHandle = IntPtr.Zero;
            OCI.MODE    environmentMode = (OCI.MODE.OCI_THREADED | OCI.MODE.OCI_OBJECT);    // Bug 79521 - removing OCI.MODE.OCI_NO_MUTEX to verify 

            OCI.DetermineClientVersion();

            if (unicode) { 
                if (OCI.ClientVersionAtLeastOracle9i)
                    environmentMode |= OCI.MODE.OCI_UTF16; 
                else 
                    unicode = false;
 
            }
            _environmentHandle      = new OciEnvironmentHandle(environmentMode, unicode);
            if (_environmentHandle.IsInvalid)
                throw ADP.CouldNotCreateEnvironment("OCIEnvCreate", rc); 

            // Now create a bunch of other handles, and attach to the server 
 
            _errorHandle            = new OciErrorHandle(_environmentHandle);
            _serverHandle           = new OciServerHandle(_errorHandle); 
            _sessionHandle          = new OciSessionHandle(_serverHandle);
            _serviceContextHandle   = new OciServiceContextHandle(_sessionHandle);

            try { 
                rc = TracedNativeMethods.OCIServerAttach(
                                        _serverHandle,          // srvhp 
                                        _errorHandle,           // errhp 
                                        serverName,             // dblink
                                        serverName.Length,      // dblink_len 
                                        OCI.MODE.OCI_DEFAULT    // mode
                                        );

                if (0 != rc) { 
                    if ((int)OCI.RETURNCODE.OCI_SUCCESS_WITH_INFO == rc) {
                        CreateDeferredInfoMessage(ErrorHandle, rc); 
                    } 
                    else {
                        OracleException.Check(ErrorHandle, rc); 
                    }
                }
                _serviceContextHandle.SetAttribute(OCI.ATTR.OCI_ATTR_SERVER, _serverHandle, _errorHandle);
 
                if (integratedSecurity) {
                    authMode = OCI.CRED.OCI_CRED_EXT; 
                } 
                else {
                    authMode = OCI.CRED.OCI_CRED_RDBMS; 
                    _sessionHandle.SetAttribute(OCI.ATTR.OCI_ATTR_USERNAME, userName, _errorHandle);

                    if (null != password) {
                        _sessionHandle.SetAttribute(OCI.ATTR.OCI_ATTR_PASSWORD, password, _errorHandle); 
                    }
                } 
 
                if (!omitOracleConnectionName) {
                    string shortName = _connectionOptions.DataSource; // WebData 102713/102714 need to use no more than 16 bytes here 
                    if (shortName.Length > 16) {
                        shortName = shortName.Substring(0,16);
                    }
                    _serverHandle.SetAttribute(OCI.ATTR.OCI_ATTR_EXTERNAL_NAME, shortName, _errorHandle); 
                    _serverHandle.SetAttribute(OCI.ATTR.OCI_ATTR_INTERNAL_NAME, shortName, _errorHandle);
                } 
 
                rc = TracedNativeMethods.OCISessionBegin(
                                        _serviceContextHandle,  // svchp 
                                        _errorHandle,           // errhp
                                        _sessionHandle,         // usrhp
                                        authMode,               // credt
                                        OCI.MODE.OCI_DEFAULT    // mode 
                                        );
 
                if (0 != rc) { 
                    if ((int)OCI.RETURNCODE.OCI_SUCCESS_WITH_INFO == rc) {
                        CreateDeferredInfoMessage(ErrorHandle, rc); 
                    }
                    else {
                        OracleException.Check(ErrorHandle, rc);
                    } 
                }
                _serviceContextHandle.SetAttribute(OCI.ATTR.OCI_ATTR_SESSION, _sessionHandle, _errorHandle); 
            } 
            catch (OracleException) {
                // To avoid leaking processes on the server, we ensure that if we 
                // fail to connect for any reason, the handles are disposed right
                // away, instead of waiting on GC.
                OciHandle.SafeDispose(ref _serviceContextHandle);
                OciHandle.SafeDispose(ref _sessionHandle); 
                OciHandle.SafeDispose(ref _serverHandle);
                OciHandle.SafeDispose(ref _errorHandle); 
                OciHandle.SafeDispose(ref _environmentHandle); 
                throw;
            } 
            return true;
        }

        // transistion states used for parsing 
        internal enum PARSERSTATE {
            NOTHINGYET=1,   //start point 
            PERIOD, 
            DIGIT,
        }; 

        static internal long ParseServerVersion (string versionString) {
            //  parse the native version string returned from the server and returns
            //  a 64 bit integer value that represents it.  For example, Oracle's 
            //  version strings typically look like:
            // 
            //      Oracle8i Enterprise Edition Release 8.1.5.0.0 - Production 
            //
            //  this method will take the 8.1.5.0.0 and return 0x0801050000, using 
            //  8 bits for each dot found.

            PARSERSTATE     parserState = PARSERSTATE.NOTHINGYET;
            int             current; 
            int             start = 0;
            int             periodCount = 0; 
            long            version = 0; 

            // make sure we have 4 periods, at the end of the string to force 
            // the state machine to have the correct number of periods.
            versionString = String.Concat(versionString, "0.0.0.0.0 ");

            //Console.WriteLine(versionString); 

            for (current = 0; current < versionString.Length; current++) { 
                //Console.WriteLine(String.Format((IFormatProvider)null, "versionString[{0}]={1} version=0x{2:x10} periodCount={3} parserState={4}", current, versionString.Substring(current,1), version, periodCount, parserState.ToString(CultureInfo.CurrentCulture) )); 

                switch(parserState) { 
                case PARSERSTATE.NOTHINGYET:
                    if (Char.IsDigit(versionString, current)) {
                        parserState = PARSERSTATE.DIGIT;
                        start = current; 
                    }
                    break; 
 
                case PARSERSTATE.PERIOD:
                    if (Char.IsDigit(versionString, current)) { 
                        parserState = PARSERSTATE.DIGIT;
                        start = current;
                    }
                    else { 
                        parserState = PARSERSTATE.NOTHINGYET;
                        periodCount = 0; 
                        version = 0; 
                    }
                    break; 

                case PARSERSTATE.DIGIT:
                    if ("." == versionString.Substring(current,1) || 4 == periodCount) {
                        periodCount++; 
                        parserState = PARSERSTATE.PERIOD;
 
                        long versionPart = (long)Int32.Parse(versionString.Substring(start,current-start),CultureInfo.InvariantCulture); 

                        Debug.Assert(versionPart >= 0 && versionPart < 256, "version part out of range!"); 

                        version = (version << 8) + versionPart;
                        if (5 == periodCount) {
                            return version; 
                        }
                    } 
                    else if (!Char.IsDigit(versionString, current)) { 
                        parserState = PARSERSTATE.NOTHINGYET;
                        periodCount = 0; 
                        version =0;
                    }
                    break;
 
                default:
                    Debug.Assert (false, "no state defined!!!!we should never be here!!!"); 
                    break; 
                }
            } 

            Debug.Assert (false, "didn't find a complete version number in the string");
            return 0;
        } 

        private OracleConnection ProxyConnection() { 
            OracleConnection proxyConnection = (OracleConnection)Owner; 

            if (null == proxyConnection) { 
                throw ADP.InvalidOperation("internal connection without a proxy?");    //
            }
            return proxyConnection;
        } 

        internal void Rollback() { 
            //  Rolls back the current local transaction; called by the transaction 
            //  object, because Oracle doesn't have a specific transaction object,
            //  but combines the transaction into the service context. 

            if (TransactionState.GlobalStarted != _transactionState) {
                int rc = TracedNativeMethods.OCITransRollback(
                                            ServiceContextHandle, 
                                            ErrorHandle,
                                            OCI.MODE.OCI_DEFAULT 
                                            ); 

                if (0 != rc) { 
                    OracleException.Check(ErrorHandle, rc);
                }
                // Once we complete the transaction, we're supposed to go back to
                // autocommit mode. 
                TransactionState = TransactionState.AutoCommit;
            } 
 
            // SQLHOTFIX# 50003486: in order to restore the connection's transaction state to what it was prior to beginning
            //   this transaction, ensure that OracleTransaction WeakRef (_transaction) is null. Not doing so, which was the 
            //   original behavior of this code, does not appear to serve any purpose and complicates state detection
            //   elsewhere, causing unexpected behavioral complications. As an example, once a transaction was committed or
            //   rolled back, any subsequent command execution would send a rollback notification to the server when the
            //   transaction no longer existed in the server's context (e.g. already committed/rolled back). 
            Transaction = null;
        } 
 
        internal void RollbackDeadTransaction() {
            // If our transaction has gone out of scope and has been GC'd, then we 
            // have to roll back the transaction.
            if (null != _transaction && !_transaction.IsAlive) {
                Rollback();
            } 
        }
 
        private void UnEnlist() { 
            if (null != _enlistContext) {
#if ALLOWTRACING 
                ADP.TraceObjectPoolActivity("UnEnlist", this);
#endif //ALLOWTRACING
//Console.WriteLine(String.Format((IFormatProvider)null, "connection {0}: Unenlisting", _uniqueConnectionId));
 
                TransactionState = TransactionState.AutoCommit;
 
                _enlistContext.Join(this, null); 

                OciEnlistContext.SafeDispose(ref _enlistContext); 

                // Tell the base class about our enlistment
                Transaction = null;
            } 
        }
    } 
} 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
namespace System.Data.OracleClient 
{
    using System; 
    using System.Collections;
    using System.Collections.Generic;
    using System.Data.Common;
    using System.Data.ProviderBase; 
    using System.Diagnostics;
    using System.Globalization; 
    using System.Runtime.InteropServices; 
    using System.Security;
    using System.Security.Permissions; 
    using System.Text;
    using System.Threading;
    using SysTx = System.Transactions;
 
    sealed internal class OracleInternalConnection : DbConnectionInternal {
 
        private OracleConnectionString  _connectionOptions; 
        private OciEnvironmentHandle    _environmentHandle;         // OCI environment handle -- the root of all handles for this connection.
        private OciErrorHandle          _errorHandle;               // OCI error handle -- every call needs one 
        private OciServerHandle         _serverHandle;              // Not available in MTS transaction connection
        private OciServiceContextHandle _serviceContextHandle;      // OCI service context handle -- defines the connection and transaction.
        private OciSessionHandle        _sessionHandle;             // Not available in MTS transaction connection
        private OciEnlistContext        _enlistContext;             // Only available in MTS transaction connection 

        private bool                    _connectionIsOpen; 
 
        private WeakReference           _transaction;               // weak reference to the local transaction
        private TransactionState        _transactionState;          // our own transacted state 

        private List _deferredInfoMessageCollection;    // where our Success With Info messages go while we connect...

        private long                    _serverVersion;             // server version value,  eg: 0x0801050000 
        private string                  _serverVersionString;       // server version string, eg: "8.1.5.0.0 Oracle8i Enterprise Edition Release 8.1.5.0.0 - Production"
        private string                  _serverVersionStringNormalized;       // server version string, eg: "08.01.05.00.00" 
        private TimeSpan                _serverTimeZoneAdjustment = TimeSpan.MinValue; 

        private NativeBuffer            _scratchBuffer;             // for miscellaneous uses, like error handling, version strings, BFILE names.. 
        private Encoding                _encodingDatabase;          // will encode/decode CHAR/VARCHAR/CLOB strings
        private Encoding                _encodingNational;          // will encode/decode NCHAR/NVARCHAR/NCLOB strings

        // Construct from a compiled connection string 
        internal OracleInternalConnection(OracleConnectionString connectionOptions) {
#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 
                connectionOptions.DemandPermission();
            } 
            catch(System.Security.SecurityException) {
                System.Diagnostics.Debug.Assert(false, "unexpected SecurityException for current codepath");
                throw;
            } 
#endif
            _connectionOptions = connectionOptions; 
 
            //  We test for the presence of a distributed transaction in a function
            //  that is only called when the Enlist connection string attribute is 
            //  false, so we can avoid the overhead of loading enterpriseservices
            //  stuff for local-only transactions.

            string userName             = connectionOptions.UserId; 
            string password             = connectionOptions.Password;
            string serverName           = connectionOptions.DataSource; 
            bool   integratedSecurity   = connectionOptions.IntegratedSecurity; 
            bool   unicode              = connectionOptions.Unicode;
            bool   omitOracleConnectionName = _connectionOptions.OmitOracleConnectionName; 

            _connectionIsOpen = OpenOnLocalTransaction (userName, password, serverName, integratedSecurity, unicode, omitOracleConnectionName);

            if (UnicodeEnabled) 
                _encodingDatabase   = System.Text.Encoding.Unicode; // for environments initialized in UTF16 mode, we can use straight Unicode
            else if (ServerVersionAtLeastOracle8i) 
                _encodingDatabase   = new OracleEncoding(this);     // for Oracle8i or greater we'll use Oracle's conversion routines. 
            else
                _encodingDatabase   = System.Text.Encoding.Default; // anything prior to Oracle8i doesn't work with Oracle's conversion routines. 

            _encodingNational   = System.Text.Encoding.Unicode;     // we use Unicode for the NCHAR/NVARCHAR/NCLOB and let Oracle perform the conversion automatically.

            // SQLBUDT #286430 - we only should be attempting to enlist in a distributed 
            // transaction when we're not a pooled connection.
            if (connectionOptions.Enlist && !connectionOptions.Pooling) { 
                SysTx.Transaction transaction = ADP.GetCurrentTransaction(); 

                if (null != transaction) { 
                    Enlist(userName, password, serverName, transaction, false);
                }
            }
        } 

        internal OciEnvironmentHandle EnvironmentHandle { 
            //  Every handle is allocated from the environment handle in some way, 
            //  so we have to provide access to it internally.
            get { return _environmentHandle; } 
        }

        internal OciErrorHandle ErrorHandle {
            //  Every OCI call needs an error handle, so make it available internally. 
            get { return _errorHandle; }
        } 
 
        internal bool HasTransaction {
            get { 
                TransactionState transactionState = TransactionState;
                bool result = ((TransactionState.LocalStarted == transactionState) || (TransactionState.GlobalStarted == transactionState));
                return result;
            } 
        }
 
        override public string ServerVersion { 
            get {
                if (null == _serverVersionString) { 
                    string  result = "no version available";
                    NativeBuffer    buffer = null;

                    try { 
                        buffer = new NativeBuffer_ServerVersion(500);
 
                        int rc = TracedNativeMethods.OCIServerVersion( 
                                            ServiceContextHandle,       // hndlp
                                            ErrorHandle,                // errhp 
                                            buffer
                                            );

                        if (0 != rc) 
                            throw ADP.OracleError(ErrorHandle, rc);
 
                        if (0 == rc) // in case it was a warning message. 
                            result = ServiceContextHandle.PtrToString(buffer);
 
                        _serverVersion      = ParseServerVersion(result);
                        _serverVersionString= String.Format((IFormatProvider)null, "{0}.{1}.{2}.{3}.{4} {5}",
                                                    (_serverVersion >> 32) & 0xff,
                                                    (_serverVersion >> 24) & 0xff, 
                                                    (_serverVersion >> 16) & 0xff,
                                                    (_serverVersion >> 8)  & 0xff, 
                                                    _serverVersion         & 0xff, 
                                                    result
                                                    ); 
                        _serverVersionStringNormalized= String.Format((IFormatProvider)null, "{0:00}.{1:00}.{2:00}.{3:00}.{4:00} ",
                                                    (_serverVersion >> 32) & 0xff,
                                                    (_serverVersion >> 24) & 0xff,
                                                    (_serverVersion >> 16) & 0xff, 
                                                    (_serverVersion >> 8)  & 0xff,
                                                    _serverVersion         & 0xff 
                                                    ); 
                    }
                    finally { 
                        if (null != buffer) {
                            buffer.Dispose();
                            buffer = null;
                        } 
                    }
                } 
                return _serverVersionString; 
            }
        } 

        override public string ServerVersionNormalized {
            get {
                if (null == _serverVersionStringNormalized) { 
                    string temp = ServerVersion;
                } 
                return _serverVersionStringNormalized; 
            }
        } 

        internal bool ServerVersionAtLeastOracle8 {
            get { return (ServerVersionNumber >= 0x800000000L); }
        } 

        internal bool ServerVersionAtLeastOracle8i { 
            get { return (ServerVersionNumber >= 0x801000000L); } 
        }
 
        internal bool ServerVersionAtLeastOracle9i {
            get { return (ServerVersionNumber >= 0x900000000L); }
        }
 
        internal long ServerVersionNumber {
            get { 
                if (0 == _serverVersion) { 
                    string temp = ServerVersion;    // force the serverversion value to be created
                } 
                return _serverVersion;
            }
        }
 
        internal OciServiceContextHandle ServiceContextHandle {
            //  You need to provide the service context handle to things like the 
            //  OCI execute call so a statement handle can be associated with a 
            //  connection.  Better make it available internally, then.
            get { return _serviceContextHandle; } 
        }

        internal OciSessionHandle SessionHandle {
            //  You need to provide the session handle to a few OCI calls.  Better 
            //  make it available internally, then.
            get { return _sessionHandle; } 
        } 

        internal OracleTransaction Transaction { 
            //  In oracle, the session object controls the transaction so we keep
            //  the transaction state here as well.

            get { 
                if (_transaction != null && _transaction.IsAlive) {
                    if (null != ((OracleTransaction)_transaction.Target).Connection) { 
                        return (OracleTransaction)_transaction.Target; 
                    }
                    _transaction.Target = null; 
                }
                return null;
            }
            set { 
                if (value == null)
                { 
                    // SQLHOTFIX# 50003486 - if the set accessor is called with a null value 
                    //   it effectively creates a dead transaction...this is not likely the intent
                    //   and it potentially causes state management problems in error conditions. 
                    _transaction = null;
                }
                else
                { 
                    if (_transaction != null)
                    { 
                        _transaction.Target = (OracleTransaction)value; 
                    }
                    else 
                    {
                        _transaction = new WeakReference((OracleTransaction)value);
                    }
                } 
            }
        } 
 
        internal TransactionState TransactionState {
            //  In oracle, the session object controls the transaction so we keep 
            //  the transaction state here as well.
            get { return _transactionState; }
            set { _transactionState = value; }
        } 

        internal bool UnicodeEnabled { 
            get { return OCI.ClientVersionAtLeastOracle9i && (null == EnvironmentHandle || EnvironmentHandle.IsUnicode); } 
        }
 
        override protected void Activate(SysTx.Transaction transaction) {
            bool isInTransaction = (null != transaction);
            OracleConnectionString connectionOptions = _connectionOptions;
 
            if (isInTransaction && connectionOptions.Enlist) {
                if (!transaction.Equals(EnlistedTransaction)) {     // WebData 20000024 
                    Enlist(connectionOptions.UserId, connectionOptions.Password, connectionOptions.DataSource, transaction, false); 
                }
            } 
            else if (!isInTransaction && null != _enlistContext) {
                UnEnlist();
            }
        } 

        override public DbTransaction BeginTransaction(IsolationLevel il) { 
            return BeginOracleTransaction(il); 
        }
 
        internal OracleTransaction BeginOracleTransaction(IsolationLevel il) {
            OracleConnection.ExecutePermission.Demand();

            //------------------------------------------------------------------------------------- 
            // pre-condition validation
 
            if (TransactionState.AutoCommit != TransactionState) 
                throw ADP.NoParallelTransactions();
 
            //-------------------------------------------------------------------------------------

            // SQLHOTFIX# 50003423: setting isolation levels may require that we execute commands on the server which will,
            //   in turn, rollback any potentially dead transactions and reset our state to auto-commit mode. This typically 
            //   happens when a connection is re-used to execute a new command after a previous command associated with a
            //   transaction has been committed. When we're attempting to begin a new transaction, we need to be sure to 
            //   clear the internal state *before* partially initializing members. 
            Debug.Assert(_transaction == null || _transaction.IsAlive == false);
            RollbackDeadTransaction(); 

            OracleTransaction newTransaction = new OracleTransaction(ProxyConnection(), il);
            Transaction = newTransaction;
 
            //--------------------------------------------------------------------------------------
            // post-condition validation 
 
            Debug.Assert(TransactionState == TransactionState.LocalStarted && newTransaction != null);
 
            //-------------------------------------------------------------------------------------

            return newTransaction;
        } 

        private void CreateDeferredInfoMessage(OciErrorHandle errorHandle, int rc) { 
            // NOTE: You should only call this within the Open() call. 
            Debug.Assert ((int)OCI.RETURNCODE.OCI_SUCCESS_WITH_INFO == rc, "unexpected info message");
 
            OracleException             infoMessage      = OracleException.CreateException(errorHandle, rc);
            OracleInfoMessageEventArgs  infoMessageEvent = new OracleInfoMessageEventArgs(infoMessage);

            List deferredInfoMessageCollection = _deferredInfoMessageCollection; 

            if (null == deferredInfoMessageCollection) { 
                deferredInfoMessageCollection = _deferredInfoMessageCollection = new List(); 
            }
 
            deferredInfoMessageCollection.Add(infoMessageEvent);
        }

        internal void ConnectionIsBroken() { 
            DoomThisConnection();
            OracleConnection owningObject = (OracleConnection)Owner; 
            if (null != owningObject) { 
                owningObject.Close(); // force the closed state on the outer object.
            } 
            else {
                Dispose();
            }
        } 

        internal void Commit() { 
            //  Commits the current local transaction; called by the transaction 
            //  object, because Oracle doesn't have a specific transaction object,
            //  but combines the transaction into the service context. 

            //--------------------------------------------------------------------------------------
            // pre-condition validation
 
            // ensure that we are participating in a local transaction
            Debug.Assert ( TransactionState == TransactionState.LocalStarted && Transaction != null ); 
 
            // NOTE: OCITransCommit will return an error if the connection has been broken/closed,
            //   so not checking that state here. 

            //--------------------------------------------------------------------------------------

 
            int rc = TracedNativeMethods.OCITransCommit(
                                        ServiceContextHandle, 
                                        ErrorHandle, 
                                        OCI.MODE.OCI_DEFAULT
                                        ); 

            if (0 != rc) {
                OracleException.Check(ErrorHandle, rc);
            } 

            // Once we complete the transaction, we're supposed to go back to 
            // autocommit mode. 
            TransactionState = TransactionState.AutoCommit;
 
            // SQLHOTFIX# 50003486: in order to restore the connection's transaction state to what it was prior to beginning
            //   this transaction, ensure that OracleTransaction WeakRef (_transaction) is null. Not doing so, which was the
            //   original behavior of this code, does not appear to serve any purpose and complicates state detection
            //   elsewhere, causing unexpected behavioral complications. As an example, once a transaction was committed or 
            //   rolled back, any subsequent command execution would send a rollback notification to the server when the
            //   transaction no longer existed in the server's context (e.g. already committed/rolled back). 
            Transaction = null; 

        } 

        override protected void Deactivate() {

            // Connection may have been already doomed on a previous call to Deactivate, 
            // in which case the ErrorHandle will have already been nulled out
            if (!IsConnectionDoomed && null != ErrorHandle && ErrorHandle.ConnectionIsBroken) { 
                ConnectionIsBroken(); 
            }
 
            // Before we return the connection to the pool, we rollback any
            // active transaction that may have been created.  Note that we
            // don't bother with distributed transactions because we don't
            // want to them back (it's handled by the TM).  We also don't 
            // worry about implicit transactions (like "select...for update")
            // because we don't want to take the performance hit of the server 
            // round-trip when it isn't very likely. 
            if (TransactionState.LocalStarted == TransactionState) {
                // On the off chance that we have some failure during rollback 
                // we just eat it and make sure that the connection is doomed.

                try {
                    Rollback(); 
                }
                catch (Exception e) { 
                    if (!ADP.IsCatchableExceptionType(e)) { 
                        throw;
                    } 

                    ADP.TraceException(e);
                    base.DoomThisConnection();
                } 
            }
 
        } 

        override public void Dispose() { 
            Deactivate();     // ensure we rollback any transaction...

            //
            OciEnlistContext.SafeDispose(ref _enlistContext); 

            // 
 

            OciHandle.SafeDispose(ref _sessionHandle); 
            OciHandle.SafeDispose(ref _serviceContextHandle);
            OciHandle.SafeDispose(ref _serverHandle);
            OciHandle.SafeDispose(ref _errorHandle);
            OciHandle.SafeDispose(ref _environmentHandle); 

            if (null != _scratchBuffer) { 
                _scratchBuffer.Dispose(); 
            }
 
            _scratchBuffer = null;
            _encodingDatabase = null;
            _encodingNational = null;
            _transaction = null; 
            _serverVersionString = null;
 
            base.Dispose(); 
        }
 
        private void Enlist(string userName, string password, string serverName, SysTx.Transaction transaction, bool manualEnlistment) {
            // No matter what happened before, we need to reset this connection
            // to an unenlisted state.
            UnEnlist(); 

            // Oracle only implemented OraMTS for 9i. 
            if (!OCI.ClientVersionAtLeastOracle9i) 
                throw ADP.DistribTxRequiresOracle9i();
 
#if ALLOWTRACING
            ADP.TraceObjectPoolActivity("Enlist", this, transactionGuid);
#endif //ALLOWTRACING
            if (null != transaction) { 
//Console.WriteLine(String.Format((IFormatProvider)null, "connection {0}: Enlisting: {1}", _uniqueConnectionId, transactionGuid));
                if (HasTransaction) { 
                    throw ADP.TransactionPresent(); 
                }
 
                // To construct a SafeHandle, we have to use a CER, which can't
                // allocate memory, so we have to do our own marshalling to avoid
                // the allocates...
                byte[]  passwordBytes = System.Text.Encoding.Default.GetBytes(password); 
                byte[]  userNameBytes = System.Text.Encoding.Default.GetBytes(userName);
                byte[]  serverNameBytes = System.Text.Encoding.Default.GetBytes(serverName); 
 
                _enlistContext = new OciEnlistContext(userNameBytes, passwordBytes, serverNameBytes, ServiceContextHandle, ErrorHandle);
                _enlistContext.Join(this, transaction); 

                TransactionState = TransactionState.GlobalStarted;
            }
            else { 
                Debug.Assert(null == _enlistContext, "Enlisting a null transaction?");
                TransactionState = TransactionState.AutoCommit; 
            } 

            // Tell the base class about our enlistment 
            EnlistedTransaction = transaction;
        }

        override public void EnlistTransaction(SysTx.Transaction transaction) { 
            OracleConnection.VerifyExecutePermission();
 
            OracleConnectionString  connectionOptions = _connectionOptions;   // prevent race condition 

            // We need to rollback any existing local transaction, so we need to make sure 
            // that there isn't a local transaction before we wipe it out.  Of course, if
            // the local transaction is dead, we can roll it back first.
            RollbackDeadTransaction();
 
            Enlist( connectionOptions.UserId,
                    connectionOptions.Password, 
                    connectionOptions.DataSource, 
                    transaction,
                    true); 
        }

        internal void FireDeferredInfoMessageEvents(OracleConnection outerConnection) {
            List deferredInfoMessageCollection = _deferredInfoMessageCollection; 
            _deferredInfoMessageCollection = null;
 
            if (null != deferredInfoMessageCollection) { 
                foreach (OracleInfoMessageEventArgs deferredInfoMessage in deferredInfoMessageCollection) {
                    if (null != deferredInfoMessage) { 
                        outerConnection.OnInfoMessage(deferredInfoMessage);
                    }
                }
            } 
        }
 
        internal byte[] GetBytes(string value, bool useNationalCharacterSet) { 
            // Return a byte array containing the value in the appropriate
            // character set form. 
            byte[] result;

            if (useNationalCharacterSet)
                result = _encodingNational.GetBytes(value); 
            else
                result = _encodingDatabase.GetBytes(value); 
 
            return result;
        } 

        internal NativeBuffer GetScratchBuffer(int minSize) {
            NativeBuffer scratchBuffer = _scratchBuffer;
            if (null == scratchBuffer || scratchBuffer.Length < minSize) { 
                if (null != scratchBuffer) {
                    scratchBuffer.Dispose(); 
                } 
                scratchBuffer = new NativeBuffer_ScratchBuffer(minSize);
                _scratchBuffer = scratchBuffer; 
            }
            return scratchBuffer;
        }
 
        internal string GetString(byte[] bytearray) {
            return _encodingDatabase.GetString(bytearray); 
        } 

        internal string GetString(byte[] bytearray, bool useNationalCharacterSet) { 
            if (useNationalCharacterSet)
                return _encodingNational.GetString(bytearray);
            else
                return _encodingDatabase.GetString(bytearray); 
        }
 
        internal TimeSpan GetServerTimeZoneAdjustmentToUTC(OracleConnection connection) { 
            TimeSpan serverTimeZoneAdjustment = _serverTimeZoneAdjustment;
 
            if (TimeSpan.MinValue == serverTimeZoneAdjustment) {
                Debug.Assert(TimeSpan.Zero != TimeSpan.MinValue, "TimeSpan.Zero == TimeSpan.MinValue"); // we're assuming TimeSpan.Zero != TimeSpan.MinValue in this code

                if ( ServerVersionAtLeastOracle9i ) { // Oracle8i doesn't have server timezones. 
                    OracleCommand tempCommand;
                    tempCommand = new OracleCommand(); 
                    tempCommand.Connection = connection; 
                    tempCommand.Transaction = Transaction;
                    tempCommand.CommandText = "select tz_offset(dbtimezone) from dual"; 

                    string adjust = ((string)tempCommand.ExecuteScalar());
                    int tzh = Int32.Parse(adjust.Substring(0,3),CultureInfo.InvariantCulture);   // -hh
                    int tzm = Int32.Parse(adjust.Substring(4,2),CultureInfo.InvariantCulture);   // mm 

                    serverTimeZoneAdjustment = new TimeSpan(tzh, tzm, 0); 
                } 
                else {
                    serverTimeZoneAdjustment = TimeSpan.Zero; 
                }
                _serverTimeZoneAdjustment = serverTimeZoneAdjustment;
            }
            return _serverTimeZoneAdjustment; 
        }
 
        private bool OpenOnLocalTransaction(string userName, string password, string serverName, bool integratedSecurity, bool unicode, bool omitOracleConnectionName) { 
            //  This method attempts to perform a local connection that may not
            //  be enlisted in a distributed transaction.  It only returns true 
            //  when the connection is successful.

            int         rc = 0;
            OCI.CRED    authMode; 

            // Create an OCI environmentHandle handle 
 
            IntPtr      environmentHandle = IntPtr.Zero;
            OCI.MODE    environmentMode = (OCI.MODE.OCI_THREADED | OCI.MODE.OCI_OBJECT);    // Bug 79521 - removing OCI.MODE.OCI_NO_MUTEX to verify 

            OCI.DetermineClientVersion();

            if (unicode) { 
                if (OCI.ClientVersionAtLeastOracle9i)
                    environmentMode |= OCI.MODE.OCI_UTF16; 
                else 
                    unicode = false;
 
            }
            _environmentHandle      = new OciEnvironmentHandle(environmentMode, unicode);
            if (_environmentHandle.IsInvalid)
                throw ADP.CouldNotCreateEnvironment("OCIEnvCreate", rc); 

            // Now create a bunch of other handles, and attach to the server 
 
            _errorHandle            = new OciErrorHandle(_environmentHandle);
            _serverHandle           = new OciServerHandle(_errorHandle); 
            _sessionHandle          = new OciSessionHandle(_serverHandle);
            _serviceContextHandle   = new OciServiceContextHandle(_sessionHandle);

            try { 
                rc = TracedNativeMethods.OCIServerAttach(
                                        _serverHandle,          // srvhp 
                                        _errorHandle,           // errhp 
                                        serverName,             // dblink
                                        serverName.Length,      // dblink_len 
                                        OCI.MODE.OCI_DEFAULT    // mode
                                        );

                if (0 != rc) { 
                    if ((int)OCI.RETURNCODE.OCI_SUCCESS_WITH_INFO == rc) {
                        CreateDeferredInfoMessage(ErrorHandle, rc); 
                    } 
                    else {
                        OracleException.Check(ErrorHandle, rc); 
                    }
                }
                _serviceContextHandle.SetAttribute(OCI.ATTR.OCI_ATTR_SERVER, _serverHandle, _errorHandle);
 
                if (integratedSecurity) {
                    authMode = OCI.CRED.OCI_CRED_EXT; 
                } 
                else {
                    authMode = OCI.CRED.OCI_CRED_RDBMS; 
                    _sessionHandle.SetAttribute(OCI.ATTR.OCI_ATTR_USERNAME, userName, _errorHandle);

                    if (null != password) {
                        _sessionHandle.SetAttribute(OCI.ATTR.OCI_ATTR_PASSWORD, password, _errorHandle); 
                    }
                } 
 
                if (!omitOracleConnectionName) {
                    string shortName = _connectionOptions.DataSource; // WebData 102713/102714 need to use no more than 16 bytes here 
                    if (shortName.Length > 16) {
                        shortName = shortName.Substring(0,16);
                    }
                    _serverHandle.SetAttribute(OCI.ATTR.OCI_ATTR_EXTERNAL_NAME, shortName, _errorHandle); 
                    _serverHandle.SetAttribute(OCI.ATTR.OCI_ATTR_INTERNAL_NAME, shortName, _errorHandle);
                } 
 
                rc = TracedNativeMethods.OCISessionBegin(
                                        _serviceContextHandle,  // svchp 
                                        _errorHandle,           // errhp
                                        _sessionHandle,         // usrhp
                                        authMode,               // credt
                                        OCI.MODE.OCI_DEFAULT    // mode 
                                        );
 
                if (0 != rc) { 
                    if ((int)OCI.RETURNCODE.OCI_SUCCESS_WITH_INFO == rc) {
                        CreateDeferredInfoMessage(ErrorHandle, rc); 
                    }
                    else {
                        OracleException.Check(ErrorHandle, rc);
                    } 
                }
                _serviceContextHandle.SetAttribute(OCI.ATTR.OCI_ATTR_SESSION, _sessionHandle, _errorHandle); 
            } 
            catch (OracleException) {
                // To avoid leaking processes on the server, we ensure that if we 
                // fail to connect for any reason, the handles are disposed right
                // away, instead of waiting on GC.
                OciHandle.SafeDispose(ref _serviceContextHandle);
                OciHandle.SafeDispose(ref _sessionHandle); 
                OciHandle.SafeDispose(ref _serverHandle);
                OciHandle.SafeDispose(ref _errorHandle); 
                OciHandle.SafeDispose(ref _environmentHandle); 
                throw;
            } 
            return true;
        }

        // transistion states used for parsing 
        internal enum PARSERSTATE {
            NOTHINGYET=1,   //start point 
            PERIOD, 
            DIGIT,
        }; 

        static internal long ParseServerVersion (string versionString) {
            //  parse the native version string returned from the server and returns
            //  a 64 bit integer value that represents it.  For example, Oracle's 
            //  version strings typically look like:
            // 
            //      Oracle8i Enterprise Edition Release 8.1.5.0.0 - Production 
            //
            //  this method will take the 8.1.5.0.0 and return 0x0801050000, using 
            //  8 bits for each dot found.

            PARSERSTATE     parserState = PARSERSTATE.NOTHINGYET;
            int             current; 
            int             start = 0;
            int             periodCount = 0; 
            long            version = 0; 

            // make sure we have 4 periods, at the end of the string to force 
            // the state machine to have the correct number of periods.
            versionString = String.Concat(versionString, "0.0.0.0.0 ");

            //Console.WriteLine(versionString); 

            for (current = 0; current < versionString.Length; current++) { 
                //Console.WriteLine(String.Format((IFormatProvider)null, "versionString[{0}]={1} version=0x{2:x10} periodCount={3} parserState={4}", current, versionString.Substring(current,1), version, periodCount, parserState.ToString(CultureInfo.CurrentCulture) )); 

                switch(parserState) { 
                case PARSERSTATE.NOTHINGYET:
                    if (Char.IsDigit(versionString, current)) {
                        parserState = PARSERSTATE.DIGIT;
                        start = current; 
                    }
                    break; 
 
                case PARSERSTATE.PERIOD:
                    if (Char.IsDigit(versionString, current)) { 
                        parserState = PARSERSTATE.DIGIT;
                        start = current;
                    }
                    else { 
                        parserState = PARSERSTATE.NOTHINGYET;
                        periodCount = 0; 
                        version = 0; 
                    }
                    break; 

                case PARSERSTATE.DIGIT:
                    if ("." == versionString.Substring(current,1) || 4 == periodCount) {
                        periodCount++; 
                        parserState = PARSERSTATE.PERIOD;
 
                        long versionPart = (long)Int32.Parse(versionString.Substring(start,current-start),CultureInfo.InvariantCulture); 

                        Debug.Assert(versionPart >= 0 && versionPart < 256, "version part out of range!"); 

                        version = (version << 8) + versionPart;
                        if (5 == periodCount) {
                            return version; 
                        }
                    } 
                    else if (!Char.IsDigit(versionString, current)) { 
                        parserState = PARSERSTATE.NOTHINGYET;
                        periodCount = 0; 
                        version =0;
                    }
                    break;
 
                default:
                    Debug.Assert (false, "no state defined!!!!we should never be here!!!"); 
                    break; 
                }
            } 

            Debug.Assert (false, "didn't find a complete version number in the string");
            return 0;
        } 

        private OracleConnection ProxyConnection() { 
            OracleConnection proxyConnection = (OracleConnection)Owner; 

            if (null == proxyConnection) { 
                throw ADP.InvalidOperation("internal connection without a proxy?");    //
            }
            return proxyConnection;
        } 

        internal void Rollback() { 
            //  Rolls back the current local transaction; called by the transaction 
            //  object, because Oracle doesn't have a specific transaction object,
            //  but combines the transaction into the service context. 

            if (TransactionState.GlobalStarted != _transactionState) {
                int rc = TracedNativeMethods.OCITransRollback(
                                            ServiceContextHandle, 
                                            ErrorHandle,
                                            OCI.MODE.OCI_DEFAULT 
                                            ); 

                if (0 != rc) { 
                    OracleException.Check(ErrorHandle, rc);
                }
                // Once we complete the transaction, we're supposed to go back to
                // autocommit mode. 
                TransactionState = TransactionState.AutoCommit;
            } 
 
            // SQLHOTFIX# 50003486: in order to restore the connection's transaction state to what it was prior to beginning
            //   this transaction, ensure that OracleTransaction WeakRef (_transaction) is null. Not doing so, which was the 
            //   original behavior of this code, does not appear to serve any purpose and complicates state detection
            //   elsewhere, causing unexpected behavioral complications. As an example, once a transaction was committed or
            //   rolled back, any subsequent command execution would send a rollback notification to the server when the
            //   transaction no longer existed in the server's context (e.g. already committed/rolled back). 
            Transaction = null;
        } 
 
        internal void RollbackDeadTransaction() {
            // If our transaction has gone out of scope and has been GC'd, then we 
            // have to roll back the transaction.
            if (null != _transaction && !_transaction.IsAlive) {
                Rollback();
            } 
        }
 
        private void UnEnlist() { 
            if (null != _enlistContext) {
#if ALLOWTRACING 
                ADP.TraceObjectPoolActivity("UnEnlist", this);
#endif //ALLOWTRACING
//Console.WriteLine(String.Format((IFormatProvider)null, "connection {0}: Unenlisting", _uniqueConnectionId));
 
                TransactionState = TransactionState.AutoCommit;
 
                _enlistContext.Join(this, null); 

                OciEnlistContext.SafeDispose(ref _enlistContext); 

                // Tell the base class about our enlistment
                Transaction = null;
            } 
        }
    } 
} 


// 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