Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / DataOracleClient / System / Data / OracleClient / OracleInternalConnection.cs / 2 / 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
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- BuildProvider.cs
- DeclaredTypeValidatorAttribute.cs
- InstanceCompleteException.cs
- DbConnectionStringCommon.cs
- PrtCap_Reader.cs
- ClockGroup.cs
- DecimalStorage.cs
- SafeThreadHandle.cs
- AdRotatorDesigner.cs
- AssemblyBuilder.cs
- NestPullup.cs
- FamilyMapCollection.cs
- XmlUrlResolver.cs
- DisableDpiAwarenessAttribute.cs
- EdmSchemaAttribute.cs
- translator.cs
- OdbcReferenceCollection.cs
- SiteMapSection.cs
- OleCmdHelper.cs
- X509Certificate.cs
- TreeIterator.cs
- RowSpanVector.cs
- CoTaskMemHandle.cs
- ConfigurationManagerHelperFactory.cs
- PreservationFileWriter.cs
- TriggerCollection.cs
- ToolStripContentPanelRenderEventArgs.cs
- ObjectPersistData.cs
- Screen.cs
- SafeNativeMethods.cs
- WindowsListViewScroll.cs
- ResolveMatchesMessage11.cs
- PreProcessInputEventArgs.cs
- ToolTipAutomationPeer.cs
- BaseCodeDomTreeGenerator.cs
- AddInBase.cs
- MdiWindowListItemConverter.cs
- ObjectContext.cs
- XmlNamespaceDeclarationsAttribute.cs
- ClientTargetCollection.cs
- LayoutTable.cs
- DynamicRendererThreadManager.cs
- ExportFileRequest.cs
- ObjectAnimationBase.cs
- JulianCalendar.cs
- StorageAssociationSetMapping.cs
- Directory.cs
- ResourceReferenceKeyNotFoundException.cs
- _Connection.cs
- InternalConfigConfigurationFactory.cs
- FileDialogPermission.cs
- SpeechUI.cs
- CornerRadiusConverter.cs
- AutomationElementCollection.cs
- StringUtil.cs
- WorkItem.cs
- EtwTrace.cs
- GenericNameHandler.cs
- ProfileProvider.cs
- Atom10FeedFormatter.cs
- SkewTransform.cs
- SchemaLookupTable.cs
- OpCodes.cs
- ClientRolePrincipal.cs
- StyleModeStack.cs
- ContainerActivationHelper.cs
- UserControl.cs
- DirectoryInfo.cs
- Matrix3D.cs
- RsaSecurityTokenParameters.cs
- XamlStream.cs
- JoinCqlBlock.cs
- GridViewColumnCollection.cs
- SafeViewOfFileHandle.cs
- MaterialCollection.cs
- Queue.cs
- Size3D.cs
- HelpKeywordAttribute.cs
- ReadOnlyDictionary.cs
- StringFunctions.cs
- XhtmlBasicCalendarAdapter.cs
- DragEvent.cs
- CodeAccessSecurityEngine.cs
- QueueSurrogate.cs
- VectorConverter.cs
- PixelFormatConverter.cs
- MDIClient.cs
- RoutedEventHandlerInfo.cs
- UrlPath.cs
- SchemaMerger.cs
- EventMappingSettingsCollection.cs
- MSG.cs
- DataGridViewCellCollection.cs
- XmlSchemaParticle.cs
- WindowsIPAddress.cs
- ColumnMapProcessor.cs
- SmiEventSink_DeferedProcessing.cs
- PanelStyle.cs
- UnicodeEncoding.cs
- XMLDiffLoader.cs