Skip to content

Commit 253cbb2

Browse files
committed
User Story 34145: Tidy up Bulk Copy unmatched column name work
- Fixed SNI reflection failures when running in NetFX.
1 parent 309faaf commit 253cbb2

File tree

2 files changed

+72
-23
lines changed

2 files changed

+72
-23
lines changed

src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/InternalConnectionWrapper.cs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -126,20 +126,25 @@ public void KillConnection()
126126
{
127127
object tdsParser = ConnectionHelper.GetParser(_internalConnection);
128128
object stateObject = TdsParserHelper.GetStateObject(tdsParser);
129-
object sessionHandle = TdsParserStateObjectHelper.GetSessionHandle(stateObject);
130129

131-
Assembly systemDotData = Assembly.Load(new AssemblyName(typeof(SqlConnection).GetTypeInfo().Assembly.FullName));
132-
Type sniHandleType = systemDotData.GetType("Microsoft.Data.SqlClient.SNI.SNIHandle");
133-
MethodInfo killConn = sniHandleType.GetMethod("KillConnection");
130+
Assembly assembly = Assembly.Load(new AssemblyName(typeof(SqlConnection).GetTypeInfo().Assembly.FullName));
131+
Type sniHandleType = assembly.GetType("Microsoft.Data.SqlClient.SNI.SNIHandle");
134132

135-
if (killConn != null)
133+
MethodInfo killConn = null;
134+
if (sniHandleType is not null)
136135
{
137-
killConn.Invoke(sessionHandle, null);
136+
killConn = sniHandleType.GetMethod("KillConnection");
138137
}
139-
else
138+
139+
if (killConn is null)
140140
{
141141
throw new InvalidOperationException("Error: Could not find SNI KillConnection test hook. This operation is only supported in debug builds.");
142142
}
143+
144+
killConn.Invoke(
145+
TdsParserStateObjectHelper.GetSessionHandle(stateObject),
146+
null);
147+
143148
// Ensure kill occurs outside of check connection window
144149
Thread.Sleep(100);
145150
}

src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/SystemDataInternals/TdsParserStateObjectHelper.cs

Lines changed: 60 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,61 @@
44

55
using System;
66
using System.Reflection;
7+
using Xunit;
78

89
namespace Microsoft.Data.SqlClient.ManualTesting.Tests.SystemDataInternals
910
{
1011
internal static class TdsParserStateObjectHelper
1112
{
12-
private static readonly Assembly s_systemDotData = typeof(Microsoft.Data.SqlClient.SqlConnection).GetTypeInfo().Assembly;
13-
private static readonly Type s_tdsParserStateObject = s_systemDotData.GetType("Microsoft.Data.SqlClient.TdsParserStateObject");
14-
private static readonly FieldInfo s_forceAllPends = s_tdsParserStateObject.GetField("s_forceAllPends", BindingFlags.Static | BindingFlags.NonPublic);
15-
private static readonly FieldInfo s_skipSendAttention = s_tdsParserStateObject.GetField("s_skipSendAttention", BindingFlags.Static | BindingFlags.NonPublic);
16-
private static readonly FieldInfo s_forceSyncOverAsyncAfterFirstPend = s_tdsParserStateObject.GetField("s_forceSyncOverAsyncAfterFirstPend", BindingFlags.Static | BindingFlags.NonPublic);
17-
private static readonly FieldInfo s_failAsyncPends = s_tdsParserStateObject.GetField("s_failAsyncPends", BindingFlags.Static | BindingFlags.NonPublic);
18-
private static readonly FieldInfo s_forcePendingReadsToWaitForUser = s_tdsParserStateObject.GetField("s_forcePendingReadsToWaitForUser", BindingFlags.Static | BindingFlags.NonPublic);
19-
private static readonly Type s_tdsParserStateObjectManaged = s_systemDotData.GetType("Microsoft.Data.SqlClient.SNI.TdsParserStateObjectManaged");
20-
private static readonly FieldInfo s_tdsParserStateObjectManagedSessionHandle = s_tdsParserStateObjectManaged.GetField("_sessionHandle", BindingFlags.Instance | BindingFlags.NonPublic);
13+
private static readonly FieldInfo s_forceAllPends;
14+
private static readonly FieldInfo s_skipSendAttention;
15+
private static readonly FieldInfo s_forceSyncOverAsyncAfterFirstPend;
16+
private static readonly FieldInfo s_failAsyncPends;
17+
private static readonly FieldInfo s_forcePendingReadsToWaitForUser;
18+
private static readonly Type s_tdsParserStateObjectManaged;
19+
private static readonly FieldInfo s_tdsParserStateObjectManagedSessionHandle;
20+
21+
static TdsParserStateObjectHelper()
22+
{
23+
Assembly assembly = typeof(Microsoft.Data.SqlClient.SqlConnection).GetTypeInfo().Assembly;
24+
Assert.True(assembly is not null, nameof(assembly));
25+
26+
Type tdsParserStateObject = assembly.GetType("Microsoft.Data.SqlClient.TdsParserStateObject");
27+
Assert.True(tdsParserStateObject is not null, nameof(tdsParserStateObject));
28+
29+
s_forceAllPends = tdsParserStateObject.GetField("s_forceAllPends", BindingFlags.Static | BindingFlags.NonPublic);
30+
Assert.True(s_forceAllPends is not null, nameof(s_forceAllPends));
31+
32+
s_skipSendAttention = tdsParserStateObject.GetField("s_skipSendAttention", BindingFlags.Static | BindingFlags.NonPublic);
33+
Assert.True(s_skipSendAttention is not null, nameof(s_skipSendAttention));
34+
35+
s_forceSyncOverAsyncAfterFirstPend = tdsParserStateObject.GetField("s_forceSyncOverAsyncAfterFirstPend", BindingFlags.Static | BindingFlags.NonPublic);
36+
Assert.True(s_forceSyncOverAsyncAfterFirstPend is not null, nameof(s_forceSyncOverAsyncAfterFirstPend));
37+
38+
s_failAsyncPends = tdsParserStateObject.GetField("s_failAsyncPends", BindingFlags.Static | BindingFlags.NonPublic);
39+
Assert.True(s_failAsyncPends is not null, nameof(s_failAsyncPends));
40+
41+
s_forcePendingReadsToWaitForUser = tdsParserStateObject.GetField("s_forcePendingReadsToWaitForUser", BindingFlags.Static | BindingFlags.NonPublic);
42+
Assert.True(s_forcePendingReadsToWaitForUser is not null, nameof(s_forcePendingReadsToWaitForUser));
43+
44+
// These managed SNI handles are allowed to be null, since they
45+
// won't exist in .NET Framework builds.
46+
s_tdsParserStateObjectManaged =
47+
assembly.GetType("Microsoft.Data.SqlClient.SNI.TdsParserStateObjectManaged");
48+
s_tdsParserStateObjectManagedSessionHandle = null;
49+
if (s_tdsParserStateObjectManaged is not null)
50+
{
51+
s_tdsParserStateObjectManagedSessionHandle =
52+
s_tdsParserStateObjectManaged.GetField(
53+
"_sessionHandle",
54+
BindingFlags.Instance | BindingFlags.NonPublic);
55+
// If we have the managed SNI type, we must have the session
56+
// handle field.
57+
Assert.True(
58+
s_tdsParserStateObjectManagedSessionHandle is not null,
59+
nameof(s_tdsParserStateObjectManagedSessionHandle));
60+
}
61+
}
2162

2263
internal static bool ForceAllPends
2364
{
@@ -49,17 +90,20 @@ internal static bool FailAsyncPends
4990
set { s_failAsyncPends.SetValue(null, value); }
5091
}
5192

52-
private static void VerifyObjectIsTdsParserStateObject(object stateObject)
93+
internal static object GetSessionHandle(object stateObject)
5394
{
5495
if (stateObject == null)
96+
{
5597
throw new ArgumentNullException(nameof(stateObject));
56-
if (!s_tdsParserStateObjectManaged.IsInstanceOfType(stateObject))
98+
}
99+
if (s_tdsParserStateObjectManaged is null)
100+
{
101+
throw new InvalidOperationException("This method is not supported on this platform.");
102+
}
103+
if (! s_tdsParserStateObjectManaged.IsInstanceOfType(stateObject))
104+
{
57105
throw new ArgumentException("Object provided was not a TdsParserStateObjectManaged", nameof(stateObject));
58-
}
59-
60-
internal static object GetSessionHandle(object stateObject)
61-
{
62-
VerifyObjectIsTdsParserStateObject(stateObject);
106+
}
63107
return s_tdsParserStateObjectManagedSessionHandle.GetValue(stateObject);
64108
}
65109
}

0 commit comments

Comments
 (0)