Skip to content

Commit da602cb

Browse files
[Hotfix 4.0.2] | Remove union overlay design and use reflection in SqlTypeWorkarounds (#1647) (#1723)
1 parent 79de344 commit da602cb

File tree

5 files changed

+501
-139
lines changed

5 files changed

+501
-139
lines changed

src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,7 @@
626626
<Compile Include="Interop\SNINativeMethodWrapper.Common.cs" />
627627
<Compile Include="Microsoft\Data\SqlClient\AlwaysEncryptedHelperClasses.cs" />
628628
<Compile Include="Microsoft\Data\SqlClient\SqlColumnEncryptionEnclaveProvider.cs" />
629+
<Compile Include="Microsoft\Data\SqlTypes\SqlTypeWorkarounds.netcore.cs" />
629630
</ItemGroup>
630631
<!-- Windows only -->
631632
<ItemGroup Condition="'$(TargetsWindows)' == 'true'">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
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.SqlTypes;
6+
using System.Runtime.InteropServices;
7+
8+
namespace Microsoft.Data.SqlTypes
9+
{
10+
/// <summary>
11+
/// This type provides workarounds for the separation between System.Data.Common
12+
/// and Microsoft.Data.SqlClient. The latter wants to access internal members of the former, and
13+
/// this class provides ways to do that. We must review and update this implementation any time the
14+
/// implementation of the corresponding types in System.Data.Common change.
15+
/// </summary>
16+
internal static partial class SqlTypeWorkarounds
17+
{
18+
#region Work around inability to access SqlMoney.ctor(long, int) and SqlMoney.ToSqlInternalRepresentation
19+
/// <summary>
20+
/// Constructs a SqlMoney from a long value without scaling. The ignored parameter exists
21+
/// only to distinguish this constructor from the constructor that takes a long.
22+
/// Used only internally.
23+
/// </summary>
24+
internal static SqlMoney SqlMoneyCtor(long value, int ignored)
25+
{
26+
var c = default(SqlMoneyCaster);
27+
28+
// Same behavior as the internal SqlMoney.ctor(long, bool) overload
29+
c.Fake._fNotNull = true;
30+
c.Fake._value = value;
31+
32+
return c.Real;
33+
}
34+
35+
internal static long SqlMoneyToSqlInternalRepresentation(SqlMoney money)
36+
{
37+
var c = default(SqlMoneyCaster);
38+
c.Real = money;
39+
40+
// Same implementation as the internal SqlMoney.ToSqlInternalRepresentation implementation
41+
if (money.IsNull)
42+
{
43+
throw new SqlNullValueException();
44+
}
45+
return c.Fake._value;
46+
}
47+
48+
[StructLayout(LayoutKind.Sequential)]
49+
private struct SqlMoneyLookalike // exact same shape as SqlMoney, but with accessible fields
50+
{
51+
internal bool _fNotNull;
52+
internal long _value;
53+
}
54+
55+
[StructLayout(LayoutKind.Explicit)]
56+
private struct SqlMoneyCaster
57+
{
58+
[FieldOffset(0)]
59+
internal SqlMoney Real;
60+
[FieldOffset(0)]
61+
internal SqlMoneyLookalike Fake;
62+
}
63+
#endregion
64+
65+
#region Work around inability to access SqlDecimal._data1/2/3/4
66+
internal static void SqlDecimalExtractData(SqlDecimal d, out uint data1, out uint data2, out uint data3, out uint data4)
67+
{
68+
// Extract the four data elements from SqlDecimal.
69+
var c = default(SqlDecimalCaster);
70+
c.Real = d;
71+
data1 = c.Fake._data1;
72+
data2 = c.Fake._data2;
73+
data3 = c.Fake._data3;
74+
data4 = c.Fake._data4;
75+
}
76+
77+
[StructLayout(LayoutKind.Sequential)]
78+
private struct SqlDecimalLookalike // exact same shape as SqlDecimal, but with accessible fields
79+
{
80+
internal byte _bStatus;
81+
internal byte _bLen;
82+
internal byte _bPrec;
83+
internal byte _bScale;
84+
internal uint _data1;
85+
internal uint _data2;
86+
internal uint _data3;
87+
internal uint _data4;
88+
}
89+
90+
[StructLayout(LayoutKind.Explicit)]
91+
private struct SqlDecimalCaster
92+
{
93+
[FieldOffset(0)]
94+
internal SqlDecimal Real;
95+
[FieldOffset(0)]
96+
internal SqlDecimalLookalike Fake;
97+
}
98+
#endregion
99+
100+
#region Work around inability to access SqlBinary.ctor(byte[], bool)
101+
internal static SqlBinary SqlBinaryCtor(byte[] value, bool ignored)
102+
{
103+
// Construct a SqlBinary without allocating/copying the byte[]. This provides
104+
// the same behavior as SqlBinary.ctor(byte[], bool).
105+
var c = default(SqlBinaryCaster);
106+
c.Fake._value = value;
107+
return c.Real;
108+
}
109+
110+
[StructLayout(LayoutKind.Sequential)]
111+
private struct SqlBinaryLookalike
112+
{
113+
internal byte[] _value;
114+
}
115+
116+
[StructLayout(LayoutKind.Explicit)]
117+
private struct SqlBinaryCaster
118+
{
119+
[FieldOffset(0)]
120+
internal SqlBinary Real;
121+
[FieldOffset(0)]
122+
internal SqlBinaryLookalike Fake;
123+
}
124+
#endregion
125+
126+
#region Work around inability to access SqlGuid.ctor(byte[], bool)
127+
internal static SqlGuid SqlGuidCtor(byte[] value, bool ignored)
128+
{
129+
// Construct a SqlGuid without allocating/copying the byte[]. This provides
130+
// the same behavior as SqlGuid.ctor(byte[], bool).
131+
var c = default(SqlGuidCaster);
132+
c.Fake._value = value;
133+
return c.Real;
134+
}
135+
136+
[StructLayout(LayoutKind.Sequential)]
137+
private struct SqlGuidLookalike
138+
{
139+
internal byte[] _value;
140+
}
141+
142+
[StructLayout(LayoutKind.Explicit)]
143+
private struct SqlGuidCaster
144+
{
145+
[FieldOffset(0)]
146+
internal SqlGuid Real;
147+
[FieldOffset(0)]
148+
internal SqlGuidLookalike Fake;
149+
}
150+
#endregion
151+
}
152+
}

src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,7 @@
627627
<Compile Include="Microsoft\Data\SqlClient\Server\SmiRequestExecutor.cs" />
628628
<Compile Include="Microsoft\Data\SqlClient\Server\SmiStream.cs" />
629629
<Compile Include="Microsoft\Data\SqlClient\Server\sqlser.cs" />
630+
<Compile Include="Microsoft\Data\SqlTypes\SqlTypeWorkarounds.netfx.cs" />
630631
<Compile Include="Microsoft\Data\Sql\SqlGenericUtil.cs" />
631632
</ItemGroup>
632633
<ItemGroup Condition="'$(BuildSimulator)' == 'true'">

0 commit comments

Comments
 (0)