Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature | Add "Command Timeout" connection string property #722

Merged
merged 7 commits into from Sep 18, 2020
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
17 changes: 17 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 @@ -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
Expand Up @@ -69,6 +69,8 @@ private enum Keywords
EnclaveAttestationUrl,
AttestationProtocol,

CommandTimeout,

// keep the count value last
KeywordsCount
}
Expand All @@ -93,6 +95,7 @@ private enum Keywords
private string _userID = DbConnectionStringDefaults.UserID;
private string _workstationID = DbConnectionStringDefaults.WorkstationID;

private int _commandTimeout = DbConnectionStringDefaults.CommandTimeout;
private int _connectTimeout = DbConnectionStringDefaults.ConnectTimeout;
private int _loadBalanceTimeout = DbConnectionStringDefaults.LoadBalanceTimeout;
private int _maxPoolSize = DbConnectionStringDefaults.MaxPoolSize;
Expand Down Expand Up @@ -125,6 +128,7 @@ private static string[] CreateValidKeywords()
#if netcoreapp
validKeywords[(int)Keywords.PoolBlockingPeriod] = DbConnectionStringKeywords.PoolBlockingPeriod;
#endif
validKeywords[(int)Keywords.CommandTimeout] = DbConnectionStringKeywords.CommandTimeout;
validKeywords[(int)Keywords.ConnectTimeout] = DbConnectionStringKeywords.ConnectTimeout;
validKeywords[(int)Keywords.CurrentLanguage] = DbConnectionStringKeywords.CurrentLanguage;
validKeywords[(int)Keywords.DataSource] = DbConnectionStringKeywords.DataSource;
Expand Down Expand Up @@ -168,6 +172,7 @@ private static string[] CreateValidKeywords()
#if netcoreapp
hash.Add(DbConnectionStringKeywords.PoolBlockingPeriod, Keywords.PoolBlockingPeriod);
#endif
hash.Add(DbConnectionStringKeywords.CommandTimeout, Keywords.CommandTimeout);
hash.Add(DbConnectionStringKeywords.ConnectTimeout, Keywords.ConnectTimeout);
hash.Add(DbConnectionStringKeywords.CurrentLanguage, Keywords.CurrentLanguage);
hash.Add(DbConnectionStringKeywords.DataSource, Keywords.DataSource);
Expand Down Expand Up @@ -298,6 +303,9 @@ public SqlConnectionStringBuilder(string connectionString) : base()
WorkstationID = ConvertToString(value);
break;

case Keywords.CommandTimeout:
CommandTimeout = ConvertToInt32(value);
break;
case Keywords.ConnectTimeout:
ConnectTimeout = ConvertToInt32(value);
break;
Expand Down Expand Up @@ -416,6 +424,21 @@ public string AttachDBFilename
}
}

/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlConnectionStringBuilder.xml' path='docs/members[@name="SqlConnectionStringBuilder"]/CommandTimeout/*' />
public int CommandTimeout
{
get { return _commandTimeout; }
set
{
if (value < 0)
{
throw ADP.InvalidConnectionOptionValue(DbConnectionStringKeywords.CommandTimeout);
}
SetValue(DbConnectionStringKeywords.CommandTimeout, value);
_commandTimeout = value;
}
}

/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlConnectionStringBuilder.xml' path='docs/members[@name="SqlConnectionStringBuilder"]/ConnectTimeout/*' />
public int ConnectTimeout
{
Expand Down Expand Up @@ -905,6 +928,8 @@ private object GetAt(Keywords index)
#if netcoreapp
case Keywords.PoolBlockingPeriod: return PoolBlockingPeriod;
#endif
case Keywords.CommandTimeout:
return CommandTimeout;
case Keywords.ConnectTimeout:
return ConnectTimeout;
case Keywords.CurrentLanguage:
Expand Down Expand Up @@ -1021,6 +1046,9 @@ private void Reset(Keywords index)
_poolBlockingPeriod = DbConnectionStringDefaults.PoolBlockingPeriod;
break;
#endif
case Keywords.CommandTimeout:
_commandTimeout = DbConnectionStringDefaults.CommandTimeout;
break;
case Keywords.ConnectTimeout:
_connectTimeout = DbConnectionStringDefaults.ConnectTimeout;
break;
Expand Down
Expand Up @@ -744,6 +744,9 @@ public sealed partial class SqlConnection : System.Data.Common.DbConnection, Sys
/// <include file='../../../../doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml' path='docs/members[@name="SqlConnection"]/ColumnEncryptionTrustedMasterKeyPaths/*'/>
[System.ComponentModel.DefaultValueAttribute(null)]
public static System.Collections.Generic.IDictionary<string, System.Collections.Generic.IList<string>> ColumnEncryptionTrustedMasterKeyPaths { get { 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 @@ -912,6 +915,10 @@ public sealed partial class SqlConnectionStringBuilder : System.Data.Common.DbCo
[System.ComponentModel.DisplayNameAttribute("Column Encryption Setting")]
[System.ComponentModel.RefreshPropertiesAttribute(System.ComponentModel.RefreshProperties.All)]
public Microsoft.Data.SqlClient.SqlConnectionColumnEncryptionSetting ColumnEncryptionSetting { 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"]/ConnectionReset/*'/>
[System.ComponentModel.BrowsableAttribute(false)]
[System.ComponentModel.DisplayNameAttribute("Connection Reset")]
Expand Down