public static void ResetCommandTimeout(this ICancellableCommand command)
        {
            var session = command.Connection?.Session;

            if (session is not null)
            {
                if (command.CommandTimeout == 0 || session.CancellationTimeout == 0)
                {
                    session.SetTimeout(Constants.InfiniteTimeout);
                }
                else
                {
                    var commandTimeUntilCanceled = command.GetCommandTimeUntilCanceled() * 1000;
                    if (session.CancellationTimeout > 0)
                    {
                        // try to cancel first, then close socket
                        command.SetTimeout(commandTimeUntilCanceled);
                        session.SetTimeout(commandTimeUntilCanceled + session.CancellationTimeout * 1000);
                    }
                    else
                    {
                        // close socket once the timeout is reached
                        session.SetTimeout(commandTimeUntilCanceled);
                    }
                }
            }
        }
        public static int GetCommandTimeUntilCanceled(this ICancellableCommand command)
        {
            var commandTimeout = command.CommandTimeout;
            var session        = command.Connection?.Session;

            if (commandTimeout == 0 || session is null)
            {
                return(0);
            }

            // the total cancellation period (graphically) is [===CommandTimeout===][=CancellationTimeout=], which can't
            // exceed int.MaxValue/1000 because it has to be multiplied by 1000 to be converted to milliseconds
            return(Math.Min(commandTimeout, Math.Max(1, (int.MaxValue / 1000) - session.CancellationTimeout)));
        }
        /// <summary>
        /// Causes the effective command timeout to be reset back to the value specified by <see cref="CommandTimeout"/>.
        /// </summary>
        /// <remarks>As per the <a href="https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.commandtimeout.aspx">MSDN documentation</a>,
        /// "This property is the cumulative time-out (for all network packets that are read during the invocation of a method) for all network reads during command
        /// execution or processing of the results. A time-out can still occur after the first row is returned, and does not include user processing time, only network
        /// read time. For example, with a 30 second time out, if Read requires two network packets, then it has 30 seconds to read both network packets. If you call
        /// Read again, it will have another 30 seconds to read any data that it requires."
        /// The <see cref="ResetCommandTimeout"/> method is called by public ADO.NET API methods to reset the effective time remaining at the beginning of a new
        /// method call.</remarks>
        public static void ResetCommandTimeout(this ICancellableCommand command)
        {
            var commandTimeout = command.CommandTimeout;

            command.Connection?.Session?.SetTimeout(commandTimeout == 0 ? Constants.InfiniteTimeout : commandTimeout * 1000);
        }
 /// <summary>
 /// Creates a new instance that cancels <paramref name="command"/>.
 /// </summary>
 /// <param name="command">A command to cancel.</param>
 public CancelCommand(ICancellableCommand command)
 {
     Ensure.NotNull(command, "command");
     this.command = command;
     this.command.CanExecuteChanged += OnCanExecuteChanged;
 }