/// <summary>
        /// Adds a <see cref="NpgsqlParameter">NpgsqlParameter</see> to the <see cref="NpgsqlParameterCollection">NpgsqlParameterCollection</see> given the specified parameter name and value.
        /// </summary>
        /// <param name="parameterName">The name of the <see cref="NpgsqlParameter">NpgsqlParameter</see>.</param>
        /// <param name="value">The Value of the <see cref="NpgsqlParameter">NpgsqlParameter</see> to add to the collection.</param>
        /// <param name="parameterType">One of the NpgsqlDbType values.</param>
        /// <param name="size">The length of the column.</param>
        /// <param name="sourceColumn">The name of the source column.</param>
        /// <returns>The paramater that was added.</returns>
        public NpgsqlParameter AddWithValue(string parameterName, NpgsqlDbType parameterType, int size, string sourceColumn, object value)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "AddWithValue", parameterName, parameterType, size, sourceColumn, value);

            NpgsqlParameter param = new NpgsqlParameter(parameterName, parameterType, size, sourceColumn);

            param.Value = value;

            return(this.Add(param));
        }
Esempio n. 2
0
 public void PrepareTransaction()
 {
     if (!_prepared)
     {
         NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "PrepareTransaction");
         NpgsqlConnection connection = GetConnection();
         NpgsqlCommand.ExecuteBlind(connection.Connector, string.Format("PREPARE TRANSACTION '{0}'", _txName));
         _prepared = true;
     }
 }
Esempio n. 3
0
        /// <summary>
        /// This method writes a set of bytes to the stream. It also enables logging of them.
        /// </summary>
        public static Stream WriteBytesNullTerminated(this Stream stream, byte[] the_bytes)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteBytes");
            NpgsqlEventLog.LogMsg("Log_BytesWritten", LogLevel.Debug, the_bytes);

            stream.Write(the_bytes, 0, the_bytes.Length);
            stream.WriteByte(0);

            return(stream);
        }
Esempio n. 4
0
        /// <summary>
        /// Initializes a new instance of the <see cref="NpgsqlParameter">NpgsqlParameter</see>
        /// </summary>
        /// <param m_Name="parameterName">The m_Name of the parameter to map.</param>
        /// <param m_Name="parameterType">One of the <see cref="UnityNpgsqlTypes.NpgsqlDbType">NpgsqlDbType</see> values.</param>
        /// <param m_Name="size">The length of the parameter.</param>
        /// <param m_Name="sourceColumn">The m_Name of the source column.</param>
        public NpgsqlParameter(String parameterName, NpgsqlDbType parameterType, Int32 size, String sourceColumn)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME, parameterName, parameterType, size, source_column);

            this.ParameterName = parameterName;

            NpgsqlDbType = parameterType; //Allow the setter to catch any exceptions.

            this.size     = size;
            source_column = sourceColumn;
        }
        /// <summary>
        /// Creates a prepared version of the command on a PostgreSQL server.
        /// </summary>
        public override void Prepare()
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Prepare");

            // Check the connection state.
            CheckConnectionState();

            UnPrepare();

            PrepareInternal();
        }
 /// <summary>
 /// Removes all items from the collection.
 /// </summary>
 public override void Clear()
 {
     NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Clear");
     foreach (NpgsqlParameter toRemove in this.InternalList)
     {
         // clean up the parameter so it can be added to another command if required.
         toRemove.Collection = null;
     }
     this.InternalList.Clear();
     this.InvalidateHashLookups();
 }
Esempio n. 7
0
        ///<summary>
        /// This method writes a string to the network stream.
        /// </summary>
        public static Stream WriteString(this Stream stream, String theString)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteString");

            NpgsqlEventLog.LogMsg("Log_StringWritten", LogLevel.Debug, theString);

            byte[] bytes = BackendEncoding.UTF8Encoding.GetBytes(theString);

            stream.Write(bytes, 0, bytes.Length);

            return(stream);
        }
 /// <summary>
 /// When a connection is closed within an enclosing TransactionScope and the transaction
 /// hasn't been promoted, we defer the actual closing until the scope ends.
 /// </summary>
 internal void PromotableLocalTransactionEnded()
 {
     NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "PromotableLocalTransactionEnded");
     if (_postponingDispose)
     {
         Dispose(true);
     }
     else if (_postponingClose)
     {
         ReallyClose();
     }
 }
        /// <summary>
        /// Removes the specified <see cref="NpgsqlParameter">NpgsqlParameter</see> from the collection.
        /// </summary>
        /// <param name="parameterName">The name of the <see cref="NpgsqlParameter">NpgsqlParameter</see> to remove from the collection.</param>
        public void Remove(string parameterName)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Remove", parameterName);

            int index = IndexOf(parameterName);

            if (index < 0)
            {
                throw new InvalidOperationException("No parameter with the specified name exists in the collection");
            }
            RemoveAt(index);
        }
Esempio n. 10
0
        /// <summary>
        /// Begins a database transaction with the specified isolation level.
        /// </summary>
        /// <param name="level">The <see cref="System.Data.IsolationLevel">isolation level</see> under which the transaction should run.</param>
        /// <returns>A <see cref="NpgsqlTransaction">NpgsqlTransaction</see>
        /// object representing the new transaction.</returns>
        /// <remarks>
        /// Currently the IsolationLevel ReadCommitted and Serializable are supported by the PostgreSQL backend.
        /// There's no support for nested transactions.
        /// </remarks>
        public new NpgsqlTransaction BeginTransaction(IsolationLevel level)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "BeginTransaction", level);

            CheckConnectionOpen();

            if (connector.Transaction != null)
            {
                throw new InvalidOperationException("Exception_NoNestedTransactions");
            }

            return(new NpgsqlTransaction(this, level));
        }
Esempio n. 11
0
        /// <summary>
        /// Opens a database connection with the property settings specified by the
        /// <see cref="NpgsqlConnection.ConnectionString">ConnectionString</see>.
        /// </summary>
        public override void Open()
        {
            // If we're postponing a close (see doc on this variable), the connection is already
            // open and can be silently reused
            if (_postponingClose)
            {
                return;
            }

            CheckConnectionClosed();

            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Open");

            // Check if there is any missing argument.
            if (!settings.ContainsKey(Keywords.Host))
            {
                throw new ArgumentException("Exception_MissingConnStrArg: " + Keywords.Host);
            }
            if (!settings.ContainsKey(Keywords.UserName) && !settings.ContainsKey(Keywords.IntegratedSecurity))
            {
                throw new ArgumentException("Exception_MissingConnStrArg: " + Keywords.UserName);
            }

            // Get a Connector, either from the pool or creating one ourselves.
            if (Pooling)
            {
                connector = NpgsqlConnectorPool.ConnectorPoolMgr.RequestConnector(this);
            }
            else
            {
                connector = new NpgsqlConnector(this);

                connector.Open();
            }

            connector.Notice       += NoticeDelegate;
            connector.Notification += NotificationDelegate;

            if (SyncNotification)
            {
                connector.AddNotificationThread();
            }

            if (Enlist)
            {
                Promotable.Enlist(Transaction.Current);
            }

            OpenCounter++;
            this.OnStateChange(new StateChangeEventArgs(ConnectionState.Closed, ConnectionState.Open));
        }
Esempio n. 12
0
        public void CommitTransaction()
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CommitTransaction");
            NpgsqlConnection connection = GetConnection();

            if (_prepared)
            {
                NpgsqlCommand.ExecuteBlind(connection.Connector, string.Format("COMMIT PREPARED '{0}'", _txName));
            }
            else
            {
                NpgsqlCommand.ExecuteBlind(connection.Connector, NpgsqlQuery.CommitTransaction);
            }
        }
        private byte[] GetExecuteCommandText()
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetPreparedCommandText");

            MemoryStream result = new MemoryStream();

            result.WriteString("EXECUTE {0}", planName);

            if (parameters.Count != 0)
            {
                result.WriteByte((byte)ASCIIBytes.ParenLeft);

                for (int i = 0; i < Parameters.Count; i++)
                {
                    var p = Parameters[i];

                    if (i > 0)
                    {
                        result.WriteByte((byte)ASCIIBytes.Comma);
                    }

                    // Add parentheses wrapping parameter value before the type cast to avoid problems with Int16.MinValue, Int32.MinValue and Int64.MinValue
                    // See bug #1010543
                    result.WriteByte((byte)ASCIIBytes.ParenLeft);

                    byte[] serialization;

                    serialization = p.TypeInfo.ConvertToBackend(p.Value, false, Connector.NativeToBackendTypeConverterOptions);

                    result
                    .WriteBytes(serialization)
                    .WriteBytes((byte)ASCIIBytes.ParenRight);

                    if (p.UseCast)
                    {
                        PGUtil.WriteString(result, string.Format("::{0}", p.TypeInfo.CastName));

                        if (p.TypeInfo.UseSize && (p.Size > 0))
                        {
                            result.WriteString("({0})", p.Size);
                        }
                    }
                }

                result.WriteByte((byte)ASCIIBytes.ParenRight);
            }

            return(result.ToArray());
        }
Esempio n. 14
0
        ///<summary>
        /// This method writes a C NULL terminated string to the network stream.
        /// It appends a NULL terminator to the end of the String.
        /// </summary>
        public static Stream WriteStringNullTerminated(this Stream stream, String format, params object[] parameters)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteStringNullTerminated");

            string theString = string.Format(format, parameters);

            NpgsqlEventLog.LogMsg("Log_StringWritten", LogLevel.Debug, theString);

            byte[] bytes = BackendEncoding.UTF8Encoding.GetBytes(theString);

            stream.Write(bytes, 0, bytes.Length);
            stream.WriteByte(0);

            return(stream);
        }
Esempio n. 15
0
        /// <summary>
        /// Rolls back a transaction from a pending state.
        /// </summary>
        public override void Rollback()
        {
            CheckDisposed();

            if (_conn == null)
            {
                throw new InvalidOperationException("Exception_NoTransaction");
            }

            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Rollback");

            NpgsqlCommand.ExecuteBlindSuppressTimeout(_conn.Connector, NpgsqlQuery.RollbackTransaction);
            _conn.Connector.Transaction = null;
            _conn = null;
        }
Esempio n. 16
0
        /// <summary>
        /// Used to execute internal commands.
        /// </summary>
        internal NpgsqlCommand(String cmdText, NpgsqlConnector connector, int CommandTimeout = 20)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);

            planName            = String.Empty;
            commandText         = cmdText;
            this.m_Connector    = connector;
            this.CommandTimeout = CommandTimeout;
            commandType         = CommandType.Text;

            // Removed this setting. It was causing too much problem.
            // Do internal commands really need different timeout setting?
            // Internal commands aren't affected by command timeout value provided by user.
            // timeout = 20;
        }
        ///<summary>
        /// This method checks the connection state to see if the connection
        /// is set or it is open. If one of this conditions is not met, throws
        /// an InvalidOperationException
        ///</summary>
        private void CheckConnectionState()
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CheckConnectionState");

            // Check the connection state.
            if (Connector == null || Connector.State == ConnectionState.Closed)
            {
                throw new InvalidOperationException("Exception_ConnectionNotOpen");
            }
            if (Connector.State != ConnectionState.Open)
            {
                throw new InvalidOperationException(
                          "There is already an open DataReader associated with this Command which must be closed first.");
            }
        }
Esempio n. 18
0
        /// <summary>
        /// Releases the connection to the database.  If the connection is pooled, it will be
        ///    made available for re-use.  If it is non-pooled, the actual connection will be shutdown.
        /// </summary>
        public override void Close()
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Close");

            if (connector == null)
            {
                return;
            }

            if (promotable != null && promotable.InLocalTransaction)
            {
                _postponingClose = true;
                return;
            }

            ReallyClose();
        }
        /// <summary>
        /// Inserts a <see cref="NpgsqlParameter">NpgsqlParameter</see> into the collection at the specified index.
        /// </summary>
        /// <param name="index">The zero-based index where the parameter is to be inserted within the collection.</param>
        /// <param name="oValue">The <see cref="NpgsqlParameter">NpgsqlParameter</see> to add to the collection.</param>
        public override void Insert(int index, object oValue)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Insert", index, oValue);

            CheckType(oValue);

            NpgsqlParameter value = oValue as NpgsqlParameter;

            if (value.Collection != null)
            {
                throw new InvalidOperationException("The parameter already belongs to a collection");
            }

            value.Collection = this;
            this.InternalList.Insert(index, value);
            this.InvalidateHashLookups();
        }
Esempio n. 20
0
        /// <summary>
        /// Initializes a new instance of the <see cref="NpgsqlParameter">NpgsqlParameter</see>
        /// class with the parameter m_Name and a value of the new <b>NpgsqlParameter</b>.
        /// </summary>
        /// <param m_Name="parameterName">The m_Name of the parameter to map.</param>
        /// <param m_Name="value">An <see cref="System.Object">Object</see> that is the value of the <see cref="NpgsqlParameter">NpgsqlParameter</see>.</param>
        /// <remarks>
        /// <p>When you specify an <see cref="System.Object">Object</see>
        /// in the value parameter, the <see cref="System.Data.DbType">DbType</see> is
        /// inferred from the .NET Framework type of the <b>Object</b>.</p>
        /// <p>When using this constructor, you must be aware of a possible misuse of the constructor which takes a DbType parameter.
        /// This happens when calling this constructor passing an int 0 and the compiler thinks you are passing a value of DbType.
        /// Use <code> Convert.ToInt32(value) </code> for example to have compiler calling the correct constructor.</p>
        /// </remarks>
        public NpgsqlParameter(String parameterName, object value)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME, parameterName, value);

            this.ParameterName = parameterName;
            this.Value         = value;

            /*if ((this.value == null) || (this.value == DBNull.Value))
             * {
             *  // don't really know what to do - leave default and do further exploration
             *  // Default type for null values is String.
             *  this.value = DBNull.Value;
             *  type_info = NpgsqlTypesHelper.GetNativeTypeInfo(typeof(String));
             * }
             * else if (!NpgsqlTypesHelper.TryGetNativeTypeInfo(value.GetType(), out type_info))
             * {
             *  throw new InvalidCastException(String.Format(resman.GetString("Exception_ImpossibleToCast"), value.GetType()));
             * }*/
        }
Esempio n. 21
0
        /// <summary>
        /// Initializes a new instance of the <see cref="NpgsqlCommand">NpgsqlCommand</see> class with the text of the query, a <see cref="NpgsqlConnection">NpgsqlConnection</see>, and the <see cref="NpgsqlTransaction">NpgsqlTransaction</see>.
        /// </summary>
        /// <param name="cmdText">The text of the query.</param>
        /// <param name="connection">A <see cref="NpgsqlConnection">NpgsqlConnection</see> that represents the connection to a PostgreSQL server.</param>
        /// <param name="transaction">The <see cref="NpgsqlTransaction">NpgsqlTransaction</see> in which the <see cref="NpgsqlCommand">NpgsqlCommand</see> executes.</param>
        public NpgsqlCommand(String cmdText, NpgsqlConnection connection, NpgsqlTransaction transaction)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);

            planName    = String.Empty;
            commandText = cmdText;
            Connection  = connection;
            if (connection != null && m_Connector != null)
            {
                // Note: DefaultCommandTimeout currently only gets read from the very first connection's connector.
                // If we later change the command's connection with the Connection property, we don't read it again.
                // Need a better mechanism.
                CommandTimeout = m_Connector.DefaultCommandTimeout;
            }
            commandType      = CommandType.Text;
            this.Transaction = transaction;

            SetCommandTimeout();
        }
        /// <summary>
        /// Gets a value indicating whether a <see cref="NpgsqlParameter">NpgsqlParameter</see> with the specified parameter name exists in the collection.
        /// </summary>
        /// <param name="parameterName">The name of the <see cref="NpgsqlParameter">NpgsqlParameter</see> object to find.</param>
        /// <param name="parameter">A reference to the requested parameter is returned in this out param if it is found in the list.  This value is null if the parameter is not found.</param>
        /// <returns><b>true</b> if the collection contains the parameter and param will contain the parameter; otherwise, <b>false</b>.</returns>
        public bool TryGetValue(string parameterName, out NpgsqlParameter parameter)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "TryGetValue", parameterName);

            int index = IndexOf(parameterName);

            if (index != -1)
            {
                parameter = InternalList[index];

                return(true);
            }
            else
            {
                parameter = null;

                return(false);
            }
        }
Esempio n. 23
0
        ///<summary>
        /// This method writes a C NULL terminated byte[] limited in length to the
        /// backend server.
        /// It pads the string with null bytes to the size specified.
        /// </summary>
        public static Stream WriteLimBytes(this Stream network_stream, byte[] bytes, Int32 n)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteLimBytes");

            if (bytes.Length > n)
            {
                throw new ArgumentOutOfRangeException("bytes", bytes, "LimStringWriteTooLarge");
            }

            network_stream.Write(bytes, 0, bytes.Length);

            //pad with zeros.
            if (bytes.Length < n)
            {
                bytes = new byte[n - bytes.Length];
                network_stream.Write(bytes, 0, bytes.Length);
            }

            return(network_stream);
        }
        /// <summary>
        /// Executes a SQL statement against the connection and returns the number of rows affected.
        /// </summary>
        /// <returns>The number of rows affected if known; -1 otherwise.</returns>
        public override Int32 ExecuteNonQuery()
        {
            //We treat this as a simple wrapper for calling ExecuteReader() and then
            //update the records affected count at every call to NextResult();
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ExecuteNonQuery");
            int?ret = null;

            using (NpgsqlDataReader rdr = GetReader(CommandBehavior.SequentialAccess))
            {
                do
                {
                    int thisRecord = rdr.RecordsAffected;
                    if (thisRecord != -1)
                    {
                        ret = (ret ?? 0) + thisRecord;
                    }
                    lastInsertedOID = rdr.LastInsertedOID ?? lastInsertedOID;
                }while (rdr.NextResult());
            }
            return(ret ?? -1);
        }
Esempio n. 25
0
        /// <summary>
        /// Attempts to cancel the execution of a <see cref="NpgsqlCommand">NpgsqlCommand</see>.
        /// </summary>
        /// <remarks>This Method isn't implemented yet.</remarks>
        public override void Cancel()
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Cancel");

            try
            {
                // get copy for thread safety of null test
                NpgsqlConnector connector = Connector;
                if (connector != null)
                {
                    connector.CancelRequest();
                }
            }
            catch (IOException)
            {
                Connection.ClearPool();
            }
            catch (NpgsqlException)
            {
                // Cancel documentation says the Cancel doesn't throw on failure
            }
        }
Esempio n. 26
0
        /// <summary>
        /// Releases all resources used by the
        /// <see cref="NpgsqlConnection">NpgsqlConnection</see>.
        /// </summary>
        /// <param name="disposing"><b>true</b> when called from Dispose();
        /// <b>false</b> when being called from the finalizer.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposed)
            {
                return;
            }

            _postponingDispose = false;
            if (disposing)
            {
                NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Dispose");
                Close();
                if (_postponingClose)
                {
                    _postponingDispose = true;
                    return;
                }
            }

            base.Dispose(disposing);
            disposed = true;
        }
Esempio n. 27
0
        ///<summary>
        /// This method writes a C NULL terminated string limited in length to the
        /// backend server.
        /// It pads the string with null bytes to the size specified.
        /// </summary>
        public static Stream WriteLimString(this Stream network_stream, String the_string, Int32 n)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteLimString");

            //Note: We do not know the size in bytes until after we have converted the string.
            byte[] bytes = BackendEncoding.UTF8Encoding.GetBytes(the_string);
            if (bytes.Length > n)
            {
                throw new ArgumentOutOfRangeException("the_string", the_string, "LimStringWriteTooLarge");
            }

            network_stream.Write(bytes, 0, bytes.Length);

            //pad with zeros.
            if (bytes.Length < n)
            {
                bytes = new byte[n - bytes.Length];
                network_stream.Write(bytes, 0, bytes.Length);
            }

            return(network_stream);
        }
 /// <summary>
 /// Used when a connection is closed
 /// </summary>
 public void Prepare()
 {
     NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Prepare");
     if (_inTransaction)
     {
         // may not be null if Promote or Enlist is called first
         if (_callbacks == null)
         {
             _callbacks = new NpgsqlTransactionCallbacks(_connection);
         }
         _callbacks.PrepareTransaction();
         if (_npgsqlTx != null)
         {
             // cancel the NpgsqlTransaction since this will
             // be handled by a two phase commit.
             _npgsqlTx.Cancel();
             _npgsqlTx.Dispose();
             _npgsqlTx = null;
             _connection.PromotableLocalTransactionEnded();
         }
     }
 }
 public byte[] Promote()
 {
     NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Promote");
     _rm = CreateResourceManager();
     // may not be null if Prepare or Enlist is called first
     if (_callbacks == null)
     {
         _callbacks = new NpgsqlTransactionCallbacks(_connection);
     }
     byte[] token = _rm.Promote(_callbacks);
     // mostly likely case for this is the transaction has been prepared.
     if (_npgsqlTx != null)
     {
         // cancel the NpgsqlTransaction since this will
         // be handled by a two phase commit.
         _npgsqlTx.Cancel();
         _npgsqlTx.Dispose();
         _npgsqlTx = null;
         _connection.PromotableLocalTransactionEnded();
     }
     return(token);
 }
 public void Enlist(Transaction tx)
 {
     NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Enlist");
     if (tx != null)
     {
         _isolationLevel = tx.IsolationLevel;
         if (!tx.EnlistPromotableSinglePhase(this))
         {
             // must already have a durable resource
             // start transaction
             _npgsqlTx      = _connection.BeginTransaction(ConvertIsolationLevel(_isolationLevel));
             _inTransaction = true;
             _rm            = CreateResourceManager();
             _callbacks     = new NpgsqlTransactionCallbacks(_connection);
             _rm.Enlist(_callbacks, TransactionInterop.GetTransmitterPropagationToken(tx));
             // enlisted in distributed transaction
             // disconnect and cleanup local transaction
             _npgsqlTx.Cancel();
             _npgsqlTx.Dispose();
             _npgsqlTx = null;
         }
     }
 }