X Tutup
#if NET45 || NET452 || DNX452 #region License // The PostgreSQL License // // Copyright (C) 2015 The Npgsql Development Team // // Permission to use, copy, modify, and distribute this software and its // documentation for any purpose, without fee, and without a written // agreement is hereby granted, provided that the above copyright notice // and this paragraph and the following two paragraphs appear in all copies. // // IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY // FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, // INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS // DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF // THE POSSIBILITY OF SUCH DAMAGE. // // THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES, // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY // AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS // ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS // TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. #endregion using System; using System.Data; using System.Reflection; using Npgsql.Logging; using Npgsql.FrontendMessages; namespace Npgsql { internal interface INpgsqlTransactionCallbacks : IDisposable { string GetName(); void PrepareTransaction(); void CommitTransaction(); void RollbackTransaction(); } internal class NpgsqlTransactionCallbacks : MarshalByRefObject, INpgsqlTransactionCallbacks { private NpgsqlConnection _connection; private readonly string _connectionString; private bool _closeConnectionRequired; private bool _prepared; private readonly string _txName = Guid.NewGuid().ToString(); private static readonly NpgsqlLogger Log = NpgsqlLogManager.GetCurrentClassLogger(); public NpgsqlTransactionCallbacks(NpgsqlConnection connection) { _connection = connection; _connectionString = _connection.ConnectionString; _connection.Disposed += new EventHandler(_connection_Disposed); } private void _connection_Disposed(object sender, EventArgs e) { // TODO: what happens if this is called from another thread? // connections should not be shared across threads while in a transaction _connection.Disposed -= new EventHandler(_connection_Disposed); _connection = null; } private NpgsqlConnection GetConnection() { if (_connection == null || (_connection.FullState & ConnectionState.Open) != ConnectionState.Open) { _connection = new NpgsqlConnection(_connectionString); _connection.Open(); _closeConnectionRequired = true; return _connection; } else { return _connection; } } #region INpgsqlTransactionCallbacks Members public string GetName() { return _txName; } public void CommitTransaction() { Log.Debug("Commit transaction"); var connection = GetConnection(); if (_prepared) { connection.Connector.ExecuteInternalCommand($"COMMIT PREPARED '{_txName}'"); } else { connection.Connector.ExecuteInternalCommand(PregeneratedMessage.CommitTransaction); } } public void PrepareTransaction() { if (!_prepared) { Log.Debug("Prepare transaction"); NpgsqlConnection connection = GetConnection(); connection.Connector.ExecuteInternalCommand($"PREPARE TRANSACTION '{_txName}'"); _prepared = true; } } public void RollbackTransaction() { Log.Debug("Rollback transaction"); NpgsqlConnection connection = GetConnection(); try { if (_prepared) { connection.Connector.ExecuteInternalCommand($"ROLLBACK PREPARED '{_txName}'"); } else { connection.Connector.ExecuteInternalCommand(PregeneratedMessage.RollbackTransaction); } } finally { // The rollback may change the value of statement_value, set to unknown connection.Connector.SetBackendTimeoutToUnknown(); } } #endregion #region IDisposable Members public void Dispose() { if (_closeConnectionRequired) { _connection.Close(); } _closeConnectionRequired = false; } #endregion } } #endif
X Tutup