Skip to content

Commit 27f4273

Browse files
authored
Add query notification support to SqlClient (dotnet#20708)
1 parent 768cd9c commit 27f4273

23 files changed

+3885
-20
lines changed

pkg/Microsoft.Private.PackageBaseline/packageIndex.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1143,7 +1143,7 @@
11431143
"4.1.0.0": "4.1.0",
11441144
"4.1.1.0": "4.3.0",
11451145
"4.2.0.0": "4.4.0",
1146-
"4.2.1.0": "4.5.0"
1146+
"4.3.0.0": "4.5.0"
11471147
}
11481148
},
11491149
"System.Data.SqlXml": {

src/System.Data.SqlClient/dir.props

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
33
<Import Project="..\dir.props" />
44
<PropertyGroup>
5-
<AssemblyVersion>4.2.1.0</AssemblyVersion>
5+
<AssemblyVersion>4.3.0.0</AssemblyVersion>
66
<AssemblyKey>MSFT</AssemblyKey>
77
</PropertyGroup>
88
</Project>

src/System.Data.SqlClient/ref/System.Data.SqlClient.cs

+76
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,17 @@ public SqlMetaData(string name, System.Data.SqlDbType dbType, string database, s
184184
public static Microsoft.SqlServer.Server.SqlMetaData InferFromValue(object value, string name) { throw null; }
185185
}
186186
}
187+
namespace System.Data.Sql
188+
{
189+
public sealed partial class SqlNotificationRequest
190+
{
191+
public SqlNotificationRequest() { }
192+
public SqlNotificationRequest(string userData, string options, int timeout) { }
193+
public string Options { get { throw null; } set { } }
194+
public int Timeout { get { throw null; } set { } }
195+
public string UserData { get { throw null; } set { } }
196+
}
197+
}
187198
namespace System.Data.SqlClient
188199
{
189200
public enum ApplicationIntent
@@ -331,6 +342,7 @@ public override void Cancel() { }
331342
public System.Threading.Tasks.Task<System.Xml.XmlReader> ExecuteXmlReaderAsync() { throw null; }
332343
public System.Threading.Tasks.Task<System.Xml.XmlReader> ExecuteXmlReaderAsync(System.Threading.CancellationToken cancellationToken) { throw null; }
333344
public override void Prepare() { }
345+
public System.Data.Sql.SqlNotificationRequest Notification { get { throw null; } set { } }
334346
}
335347
public sealed partial class SqlConnection : System.Data.Common.DbConnection, System.ICloneable
336348
{
@@ -426,6 +438,70 @@ protected override void OnRowUpdated(System.Data.Common.RowUpdatedEventArgs valu
426438
protected override void OnRowUpdating(System.Data.Common.RowUpdatingEventArgs value) { }
427439
object System.ICloneable.Clone() { throw null; }
428440
}
441+
public sealed partial class SqlDependency
442+
{
443+
public SqlDependency() { }
444+
public SqlDependency(SqlCommand command) { }
445+
public SqlDependency(SqlCommand command, string options, int timeout) { }
446+
public bool HasChanges { get { throw null; } }
447+
public string Id { get { throw null; } }
448+
public event OnChangeEventHandler OnChange { add { } remove { } }
449+
public void AddCommandDependency(SqlCommand command) { }
450+
public static bool Start(string connectionString) { throw null; }
451+
public static bool Start(string connectionString, string queue) { throw null; }
452+
public static bool Stop(string connectionString) { throw null; }
453+
public static bool Stop(string connectionString, string queue) { throw null; }
454+
}
455+
public delegate void OnChangeEventHandler(object sender, SqlNotificationEventArgs e);
456+
public partial class SqlNotificationEventArgs : System.EventArgs
457+
{
458+
public SqlNotificationEventArgs(SqlNotificationType type, SqlNotificationInfo info, SqlNotificationSource source) { }
459+
public SqlNotificationType Type { get { throw null; } }
460+
public SqlNotificationInfo Info { get { throw null; } }
461+
public SqlNotificationSource Source { get { throw null; } }
462+
}
463+
public enum SqlNotificationInfo
464+
{
465+
Truncate = 0,
466+
Insert = 1,
467+
Update = 2,
468+
Delete = 3,
469+
Drop = 4,
470+
Alter = 5,
471+
Restart = 6,
472+
Error = 7,
473+
Query = 8,
474+
Invalid = 9,
475+
Options = 10,
476+
Isolation = 11,
477+
Expired = 12,
478+
Resource = 13,
479+
PreviousFire = 14,
480+
TemplateLimit = 15,
481+
Merge = 16,
482+
Unknown = -1,
483+
AlreadyChanged = -2
484+
}
485+
public enum SqlNotificationSource
486+
{
487+
Data = 0,
488+
Timeout = 1,
489+
Object = 2,
490+
Database = 3,
491+
System = 4,
492+
Statement = 5,
493+
Environment = 6,
494+
Execution = 7,
495+
Owner = 8,
496+
Unknown = -1,
497+
Client = -2
498+
}
499+
public enum SqlNotificationType
500+
{
501+
Change = 0,
502+
Subscribe = 1,
503+
Unknown = -1
504+
}
429505
public sealed partial class SqlRowUpdatedEventArgs : System.Data.Common.RowUpdatedEventArgs
430506
{
431507
public SqlRowUpdatedEventArgs(DataRow row, IDbCommand command, StatementType statementType, System.Data.Common.DataTableMapping tableMapping)

src/System.Data.SqlClient/src/Resources/Strings.resx

+27
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,33 @@
667667
<data name="SQL_EnumeratedRecordFieldCountChanged" xml:space="preserve">
668668
<value>Number of fields in record '{0}' does not match the number in the original record.</value>
669669
</data>
670+
<data name="SQLNotify_AlreadyHasCommand" xml:space="preserve">
671+
<value>This SqlCommand object is already associated with another SqlDependency object.</value>
672+
</data>
673+
<data name="SqlDependency_DatabaseBrokerDisabled" xml:space="preserve">
674+
<value>The SQL Server Service Broker for the current database is not enabled, and as a result query notifications are not supported. Please enable the Service Broker for this database if you wish to use notifications.</value>
675+
</data>
676+
<data name="SqlDependency_DefaultOptionsButNoStart" xml:space="preserve">
677+
<value>When using SqlDependency without providing an options value, SqlDependency.Start() must be called prior to execution of a command added to the SqlDependency instance.</value>
678+
</data>
679+
<data name="SqlDependency_NoMatchingServerStart" xml:space="preserve">
680+
<value>When using SqlDependency without providing an options value, SqlDependency.Start() must be called for each server that is being executed against.</value>
681+
</data>
682+
<data name="SqlDependency_NoMatchingServerDatabaseStart" xml:space="preserve">
683+
<value>SqlDependency.Start has been called for the server the command is executing against more than once, but there is no matching server/user/database Start() call for current command.</value>
684+
</data>
685+
<data name="SqlDependency_EventNoDuplicate" xml:space="preserve">
686+
<value>SqlDependency.OnChange does not support multiple event registrations for the same delegate.</value>
687+
</data>
688+
<data name="SqlDependency_IdMismatch" xml:space="preserve">
689+
<value>No SqlDependency exists for the key.</value>
690+
</data>
691+
<data name="SqlDependency_InvalidTimeout" xml:space="preserve">
692+
<value>Timeout specified is invalid. Timeout cannot be &lt; 0.</value>
693+
</data>
694+
<data name="SqlDependency_DuplicateStart" xml:space="preserve">
695+
<value>SqlDependency does not support calling Start() with different connection strings having the same server, user, and database in the same app domain.</value>
696+
</data>
670697
<data name="SqlMetaData_InvalidSqlDbTypeForConstructorFormat" xml:space="preserve">
671698
<value>The dbType {0} is invalid for this constructor.</value>
672699
</data>

src/System.Data.SqlClient/src/System.Data.SqlClient.csproj

+9
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
<Compile Include="System\Data\ProviderBase\DbReferenceCollection.cs" />
8787
<Compile Include="System\Data\ProviderBase\TimeoutTimer.cs" />
8888
<Compile Include="System\Data\Sql\SqlMetaData.cs" />
89+
<Compile Include="System\Data\Sql\SqlNotificationRequest.cs" />
8990
<Compile Include="System\Data\SqlClient\ApplicationIntent.cs" />
9091
<Compile Include="System\Data\SqlClient\LocalDBAPI.cs" />
9192
<Compile Include="System\Data\SqlClient\ParameterPeekAheadValue.cs" />
@@ -113,6 +114,9 @@
113114
<Compile Include="System\Data\SqlClient\SqlConnectionTimeoutErrorInternal.cs" />
114115
<Compile Include="System\Data\SqlClient\SqlDataAdapter.cs" />
115116
<Compile Include="System\Data\SqlClient\SqlDataReader.cs" />
117+
<Compile Include="System\Data\SqlClient\SqlDependency.cs" />
118+
<Compile Include="System\Data\SqlClient\SqlDependencyListener.cs" />
119+
<Compile Include="System\Data\SqlClient\SqlDependencyUtils.cs" />
116120
<Compile Include="System\Data\SqlClient\SqlEnums.cs" />
117121
<Compile Include="System\Data\SqlClient\SqlError.cs" />
118122
<Compile Include="System\Data\SqlClient\SqlErrorCollection.cs" />
@@ -123,6 +127,11 @@
123127
<Compile Include="System\Data\SqlClient\SqlInternalConnectionTds.cs" />
124128
<Compile Include="System\Data\SqlClient\sqlinternaltransaction.cs" />
125129
<Compile Include="System\Data\SqlClient\SqlMetadataFactory.cs" />
130+
<Compile Include="System\Data\SqlClient\SqlNotificationEventArgs.cs" />
131+
<Compile Include="System\Data\SqlClient\SqlNotificationInfo.cs" />
132+
<Compile Include="System\Data\SqlClient\SqlNotificationSource.cs" />
133+
<Compile Include="System\Data\SqlClient\SqlNotificationType.cs" />
134+
<Compile Include="System\Data\SqlClient\OnChangedEventHandler.cs" />
126135
<Compile Include="System\Data\SqlClient\SqlParameter.cs" />
127136
<Compile Include="System\Data\SqlClient\SqlParameterCollection.cs" />
128137
<Compile Include="System\Data\SqlClient\SqlParameterCollectionHelper.cs" />

src/System.Data.SqlClient/src/System/Data/Common/AdapterUtil.SqlClient.cs

+6
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ internal static Exception ExceptionWithStackTrace(Exception e)
4747
}
4848
}
4949

50+
internal static void TraceExceptionWithoutRethrow(Exception e)
51+
{
52+
Debug.Assert(ADP.IsCatchableExceptionType(e), "Invalid exception type, should have been re-thrown!");
53+
TraceException("<comm.ADP.TraceException|ERR|CATCH> '%ls'\n", e);
54+
}
55+
5056
//
5157
// COM+ exceptions
5258
//
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Data.Common;
6+
using System.Data.SqlClient;
7+
8+
namespace System.Data.Sql
9+
{
10+
public sealed class SqlNotificationRequest
11+
{
12+
private string _userData;
13+
private string _options;
14+
private int _timeout;
15+
16+
public SqlNotificationRequest()
17+
: this(null, null, SQL.SqlDependencyTimeoutDefault) { }
18+
19+
public SqlNotificationRequest(string userData, string options, int timeout)
20+
{
21+
UserData = userData;
22+
Timeout = timeout;
23+
Options = options;
24+
}
25+
26+
public string Options
27+
{
28+
get
29+
{
30+
return _options;
31+
}
32+
set
33+
{
34+
if ((null != value) && (ushort.MaxValue < value.Length))
35+
{
36+
throw ADP.ArgumentOutOfRange(string.Empty, nameof(Options));
37+
}
38+
_options = value;
39+
}
40+
}
41+
42+
public int Timeout
43+
{
44+
get
45+
{
46+
return _timeout;
47+
}
48+
set
49+
{
50+
if (0 > value)
51+
{
52+
throw ADP.ArgumentOutOfRange(string.Empty, nameof(Timeout));
53+
}
54+
_timeout = value;
55+
}
56+
}
57+
58+
public string UserData
59+
{
60+
get
61+
{
62+
return _userData;
63+
}
64+
set
65+
{
66+
if ((null != value) && (ushort.MaxValue < value.Length))
67+
{
68+
throw ADP.ArgumentOutOfRange(string.Empty, nameof(UserData));
69+
}
70+
_userData = value;
71+
}
72+
}
73+
}
74+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
namespace System.Data.SqlClient
6+
{
7+
public delegate void OnChangeEventHandler(object sender, SqlNotificationEventArgs e);
8+
}

src/System.Data.SqlClient/src/System/Data/SqlClient/SqlBulkCopy.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ private Task<BulkCopySimpleResultSet> CreateAndExecuteInitialQueryAsync(out Bulk
486486
{
487487
string TDSCommand = CreateInitialQuery();
488488

489-
Task executeTask = _parser.TdsExecuteSQLBatch(TDSCommand, this.BulkCopyTimeout, _stateObj, sync: !_isAsyncBulkCopy, callerHasConnectionLock: true);
489+
Task executeTask = _parser.TdsExecuteSQLBatch(TDSCommand, this.BulkCopyTimeout, null, _stateObj, sync: !_isAsyncBulkCopy, callerHasConnectionLock: true);
490490

491491
if (executeTask == null)
492492
{
@@ -743,7 +743,7 @@ private string AnalyzeTargetAndCreateUpdateBulkCommand(BulkCopySimpleResultSet i
743743

744744
private Task SubmitUpdateBulkCommand(string TDSCommand)
745745
{
746-
Task executeTask = _parser.TdsExecuteSQLBatch(TDSCommand, this.BulkCopyTimeout, _stateObj, sync: !_isAsyncBulkCopy, callerHasConnectionLock: true);
746+
Task executeTask = _parser.TdsExecuteSQLBatch(TDSCommand, this.BulkCopyTimeout, null, _stateObj, sync: !_isAsyncBulkCopy, callerHasConnectionLock: true);
747747

748748
if (executeTask == null)
749749
{

0 commit comments

Comments
 (0)