Skip to content

Commit

Permalink
Feature | Add "Command Timeout" connection string option (#722)
Browse files Browse the repository at this point in the history
  • Loading branch information
ErikEJ committed Sep 18, 2020
1 parent 5934db4 commit 81052d6
Show file tree
Hide file tree
Showing 18 changed files with 288 additions and 13 deletions.
1 change: 1 addition & 0 deletions doc/snippets/Microsoft.Data.SqlClient/SqlCommand.xml
Expand Up @@ -1240,6 +1240,7 @@ For example, with a 30 second time out, if <xref:Microsoft.Data.SqlClient.SqlDat
[!code-csharp[SqlCommand CommandTimeout](~/../sqlclient/doc/samples/SqlCommand_CommandTimeout.cs)]
]]></format>
</remarks>
<exception cref="T:System.ArgumentException">The value set is less than 0.</exception>
</CommandTimeout>
<CommandType>
<summary>
Expand Down
18 changes: 18 additions & 0 deletions doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml
Expand Up @@ -472,6 +472,23 @@ The connection string contains <see langword="Context Connection=true" />.
<value>The list of trusted master key paths for the column encryption.</value>
<remarks>To be added.</remarks>
</ColumnEncryptionTrustedMasterKeyPaths>
<CommandTimeout>
<summary>
Gets the default wait time (in seconds) before terminating the attempt to execute a command and generating an error. The default is 30 seconds.
</summary>
<value>
The time in seconds to wait for the command to execute. The default is 30 seconds.
</value>
<remarks>
<format type="text/markdown"><![CDATA[
## Remarks
You can set the default wait time by using the `Command Timeout` keyword in the connection string. A value of 0 indicates no limit (an attempt to execute a command will wait indefinitely).
]]></format>
</remarks>
</CommandTimeout>
<ConnectionString>
<summary>Gets or sets the string used to open a SQL Server database.</summary>
<value>The connection string that includes the source database name, and other parameters needed to establish the initial connection. The default value is an empty string.</value>
Expand Down Expand Up @@ -517,6 +534,7 @@ The connection string contains <see langword="Context Connection=true" />.
|AttachDBFilename<br /><br /> -or-<br /><br /> Extended Properties<br /><br /> -or-<br /><br /> Initial File Name|N/A|The name of the primary database file, including the full path name of an attachable database. AttachDBFilename is only supported for primary data files with an .mdf extension.<br /><br /> If the value of the AttachDBFileName key is specified in the connection string, the database is attached and becomes the default database for the connection.<br /><br /> If this key is not specified and if the database was previously attached, the database will not be reattached. The previously attached database will be used as the default database for the connection.<br /><br /> If this key is specified together with the AttachDBFileName key, the value of this key will be used as the alias. However, if the name is already used in another attached database, the connection will fail.<br /><br /> The path may be absolute or relative by using the DataDirectory substitution string. If DataDirectory is used, the database file must exist within a subdirectory of the directory pointed to by the substitution string. **Note:** Remote server, HTTP, and UNC path names are not supported. <br /><br /> The database name must be specified with the keyword 'database' (or one of its aliases) as in the following:<br /><br /> <code>"AttachDbFileName=&#124;DataDirectory&#124;\data\YourDB.mdf;integrated security=true;database=YourDatabase"</code><br /><br /> An error will be generated if a log file exists in the same directory as the data file and the 'database' keyword is used when attaching the primary data file. In this case, remove the log file. Once the database is attached, a new log file will be automatically generated based on the physical path.|
|Authentication|N/A|The authentication method used for [Connecting to SQL Database By Using Azure Active Directory Authentication](https://azure.microsoft.com/documentation/articles/sql-database-aad-authentication/#7-connect-to-your-database-by-using-azure-active-directory-identities).<br /><br /> Valid values are:<br /><br /> `Active Directory Integrated`, `Active Directory Interactive`, `Active Directory Password`, `Sql Password`. Currently `Active Directory Integrated` and `Active Directory Interactive` modes of authentication are supported only for .NET Framework. |
|Column Encryption Setting|N/A|Enables or disables [Always Encrypted](/sql/relational-databases/security/encryption/always-encrypted-database-engine?view=sql-server-2017) functionality for the connection.|
|Command Timeout|30|The default wait time (in seconds) before terminating the attempt to execute a command and generating an error.<br /><br /> Valid values are greater than or equal to 0 and less than or equal to 2147483647.|
|Connect Timeout<br /><br /> -or-<br /><br /> Connection Timeout<br /><br /> -or-<br /><br /> Timeout|15|The length of time (in seconds) to wait for a connection to the server before terminating the attempt and generating an error.<br /><br /> Valid values are greater than or equal to 0 and less than or equal to 2147483647.<br /><br /> When opening a connection to a Azure SQL Database, set the connection timeout to 30 seconds.|
|Connection Lifetime<br /><br /> -or-<br /><br /> Load Balance Timeout|0|When a connection is returned to the pool, its creation time is compared with the current time, and the connection is destroyed if that time span (in seconds) exceeds the value specified by `Connection Lifetime`. This is useful in clustered configurations to force load balancing between a running server and a server just brought online.<br /><br /> A value of zero (0) causes pooled connections to have the maximum connection timeout.|
|Connect Retry Count<br /><br /> -or-<br /><br />ConnectRetryCount|1|Controls the number of reconnection attempts after the client identifies an idle connection failure. Valid values are 0 to 255. The default is 1. 0 means do not attempt to reconnect (disable connection resiliency).<br /><br /> For additional information about idle connection resiliency, see [Technical Article - Idle Connection Resiliency](https://go.microsoft.com/fwlink/?LinkId=393996).|
Expand Down
Expand Up @@ -195,6 +195,23 @@ Modified: Data Source=(local);Initial Catalog=AdventureWorks;Integrated Security
<value>The column encryption settings for the connection string builder.</value>
<remarks>To be added.</remarks>
</ColumnEncryptionSetting>
<CommandTimeout>
<summary>
The default wait time (in seconds) before terminating the attempt to execute a command and generating an error. The default is 30 seconds.
</summary>
<value>
The time in seconds to wait for the command to execute. The default is 30 seconds.
</value>
<remarks>
<format type="text/markdown"><![CDATA[
## Remarks
This property corresponds to the "Command Timeout" key within the <xref:Microsoft.Data.SqlClient.SqlConnection> connection string.
]]></format>
</remarks>
<exception cref="T:System.ArgumentException">The value set is less than 0.</exception>
</CommandTimeout>
<ConnectionReset>
<summary>Obsolete. Gets or sets a Boolean value that indicates whether the connection is reset when drawn from the connection pool.</summary>
<value>The value of the <see cref="P:Microsoft.Data.SqlClient.SqlConnectionStringBuilder.ConnectionReset" /> property, or true if no value has been supplied.</value>
Expand Down
Expand Up @@ -590,6 +590,9 @@ public sealed partial class SqlConnection : System.Data.Common.DbConnection, Sys
internal string SQLDNSCachingSupportedStateBeforeRedirect { get { throw null; } }

object System.ICloneable.Clone() { throw null; }
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml' path='docs/members[@name="SqlConnection"]/CommandTimeout/*' />
[System.ComponentModel.DesignerSerializationVisibilityAttribute(0)]
public int CommandTimeout { get { throw null; } }
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml' path='docs/members[@name="SqlConnection"]/ConnectionString/*'/>
[System.ComponentModel.DefaultValueAttribute("")]
[System.ComponentModel.EditorAttribute("Microsoft.VSDesigner.Data.SQL.Design.SqlConnectionStringEditor, Microsoft.VSDesigner, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Drawing.Design.UITypeEditor, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
Expand Down Expand Up @@ -712,6 +715,10 @@ public sealed partial class SqlConnectionStringBuilder : System.Data.Common.DbCo
[System.ComponentModel.DisplayNameAttribute("Authentication")]
[System.ComponentModel.RefreshPropertiesAttribute(System.ComponentModel.RefreshProperties.All)]
public Microsoft.Data.SqlClient.SqlAuthenticationMethod Authentication { get { throw null; } set { } }
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/SqlConnectionStringBuilder.xml' path='docs/members[@name="SqlConnectionStringBuilder"]/CommandTimeout/*'/>
[System.ComponentModel.DisplayNameAttribute("Command Timeout")]
[System.ComponentModel.RefreshPropertiesAttribute(System.ComponentModel.RefreshProperties.All)]
public int CommandTimeout { get { throw null; } set { } }
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/SqlConnectionStringBuilder.xml' path='docs/members[@name="SqlConnectionStringBuilder"]/ConnectRetryCount/*'/>
[System.ComponentModel.DisplayNameAttribute("Connect Retry Count")]
[System.ComponentModel.RefreshPropertiesAttribute(System.ComponentModel.RefreshProperties.All)]
Expand Down
Expand Up @@ -487,7 +487,7 @@ internal static ApplicationIntent ConvertToApplicationIntent(string keyword, obj

internal static bool IsValidAuthenticationTypeValue(SqlAuthenticationMethod value)
{
Debug.Assert(Enum.GetNames(typeof(SqlAuthenticationMethod)).Length == 6, "SqlAuthenticationMethod enum has changed, update needed");
Debug.Assert(Enum.GetNames(typeof(SqlAuthenticationMethod)).Length == 7, "SqlAuthenticationMethod enum has changed, update needed");
return value == SqlAuthenticationMethod.SqlPassword
|| value == SqlAuthenticationMethod.ActiveDirectoryPassword
|| value == SqlAuthenticationMethod.ActiveDirectoryIntegrated
Expand Down Expand Up @@ -676,6 +676,7 @@ internal static partial class DbConnectionStringDefaults
internal const ApplicationIntent ApplicationIntent = Microsoft.Data.SqlClient.ApplicationIntent.ReadWrite;
internal const string ApplicationName = "Core Microsoft SqlClient Data Provider";
internal const string AttachDBFilename = "";
internal const int CommandTimeout = 30;
internal const int ConnectTimeout = 15;
internal const string CurrentLanguage = "";
internal const string DataSource = "";
Expand Down Expand Up @@ -719,6 +720,7 @@ internal static partial class DbConnectionStringKeywords
internal const string ApplicationName = "Application Name";
internal const string AsynchronousProcessing = "Asynchronous Processing";
internal const string AttachDBFilename = "AttachDbFilename";
internal const string CommandTimeout = "Command Timeout";
internal const string ConnectTimeout = "Connect Timeout";
internal const string ConnectionReset = "Connection Reset";
internal const string ContextConnection = "Context Connection";
Expand Down
Expand Up @@ -65,7 +65,7 @@ protected override void AfterCleared(SqlCommand owner)
}

private CommandType _commandType;
private int _commandTimeout = ADP.DefaultCommandTimeout;
private int? _commandTimeout;
private UpdateRowSource _updatedRowSource = UpdateRowSource.Both;
private bool _designTimeInvisible;

Expand Down Expand Up @@ -572,7 +572,7 @@ override public int CommandTimeout
{
get
{
return _commandTimeout;
return _commandTimeout ?? DefaultCommandTimeout;
}
set
{
Expand All @@ -592,10 +592,18 @@ override public int CommandTimeout
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlCommand.xml' path='docs/members[@name="SqlCommand"]/ResetCommandTimeout/*'/>
public void ResetCommandTimeout()
{
if (ADP.DefaultCommandTimeout != _commandTimeout)
if (ADP.DefaultCommandTimeout != CommandTimeout)
{
PropertyChanging();
_commandTimeout = ADP.DefaultCommandTimeout;
_commandTimeout = DefaultCommandTimeout;
}
}

private int DefaultCommandTimeout
{
get
{
return _activeConnection?.CommandTimeout ?? ADP.DefaultCommandTimeout;
}
}

Expand Down
Expand Up @@ -505,6 +505,16 @@ public override int ConnectionTimeout
}
}

/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml' path='docs/members[@name="SqlConnection"]/CommandTimeout/*' />
public int CommandTimeout
{
get
{
SqlConnectionString constr = (SqlConnectionString)ConnectionOptions;
return ((null != constr) ? constr.CommandTimeout : SqlConnectionString.DEFAULT.Command_Timeout);
}
}

/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml' path='docs/members[@name="SqlConnection"]/AccessToken/*' />
// AccessToken: To be used for token based authentication
public string AccessToken
Expand Down
Expand Up @@ -23,6 +23,7 @@ internal static partial class DEFAULT
internal const ApplicationIntent ApplicationIntent = DbConnectionStringDefaults.ApplicationIntent;
internal const string Application_Name = TdsEnums.SQL_PROVIDER_NAME;
internal const string AttachDBFilename = "";
internal const int Command_Timeout = ADP.DefaultCommandTimeout;
internal const int Connect_Timeout = ADP.DefaultConnectionTimeout;
internal const string Current_Language = "";
internal const string Data_Source = "";
Expand Down Expand Up @@ -67,6 +68,8 @@ internal static class KEY
internal const string ColumnEncryptionSetting = "column encryption setting";
internal const string EnclaveAttestationUrl = "enclave attestation url";
internal const string AttestationProtocol = "attestation protocol";

internal const string Command_Timeout = "command timeout";
internal const string Connect_Timeout = "connect timeout";
internal const string Connection_Reset = "connection reset";
internal const string Context_Connection = "context connection";
Expand Down Expand Up @@ -210,6 +213,7 @@ internal static class TRANSACTIONBINDING
private readonly string _enclaveAttestationUrl;
private readonly SqlConnectionAttestationProtocol _attestationProtocol;

private readonly int _commandTimeout;
private readonly int _connectTimeout;
private readonly int _loadBalanceTimeout;
private readonly int _maxPoolSize;
Expand Down Expand Up @@ -265,6 +269,7 @@ internal SqlConnectionString(string connectionString) : base(connectionString, G
_userInstance = ConvertValueToBoolean(KEY.User_Instance, DEFAULT.User_Instance);
_multiSubnetFailover = ConvertValueToBoolean(KEY.MultiSubnetFailover, DEFAULT.MultiSubnetFailover);

_commandTimeout = ConvertValueToInt32(KEY.Command_Timeout, DEFAULT.Command_Timeout);
_connectTimeout = ConvertValueToInt32(KEY.Connect_Timeout, DEFAULT.Connect_Timeout);
_loadBalanceTimeout = ConvertValueToInt32(KEY.Load_Balance_Timeout, DEFAULT.Load_Balance_Timeout);
_maxPoolSize = ConvertValueToInt32(KEY.Max_Pool_Size, DEFAULT.Max_Pool_Size);
Expand Down Expand Up @@ -307,6 +312,11 @@ internal SqlConnectionString(string connectionString) : base(connectionString, G
throw ADP.InvalidConnectionOptionValue(KEY.Connect_Timeout);
}

if (_commandTimeout < 0)
{
throw ADP.InvalidConnectionOptionValue(KEY.Command_Timeout);
}

if (_maxPoolSize < 1)
{
throw ADP.InvalidConnectionOptionValue(KEY.Max_Pool_Size);
Expand Down Expand Up @@ -490,6 +500,7 @@ internal SqlConnectionString(SqlConnectionString connectionOptions, string dataS
_pooling = connectionOptions._pooling;
_replication = connectionOptions._replication;
_userInstance = userInstance;
_commandTimeout = connectionOptions._commandTimeout;
_connectTimeout = connectionOptions._connectTimeout;
_loadBalanceTimeout = connectionOptions._loadBalanceTimeout;
#if netcoreapp
Expand Down Expand Up @@ -545,6 +556,7 @@ internal SqlConnectionString(SqlConnectionString connectionOptions, string dataS
internal bool Replication { get { return _replication; } }
internal bool UserInstance { get { return _userInstance; } }

internal int CommandTimeout { get { return _commandTimeout; } }
internal int ConnectTimeout { get { return _connectTimeout; } }
internal int LoadBalanceTimeout { get { return _loadBalanceTimeout; } }
internal int MaxPoolSize { get { return _maxPoolSize; } }
Expand Down Expand Up @@ -633,6 +645,7 @@ private static bool CompareHostName(ref string host, string name, bool fixup)
#if netcoreapp
{ KEY.PoolBlockingPeriod, KEY.PoolBlockingPeriod},
#endif
{ KEY.Command_Timeout, KEY.Command_Timeout },
{ KEY.Connect_Timeout, KEY.Connect_Timeout },
{ KEY.Connection_Reset, KEY.Connection_Reset },
{ KEY.Context_Connection, KEY.Context_Connection },
Expand Down

0 comments on commit 81052d6

Please sign in to comment.