Skip to content

Commit 997af4c

Browse files
authored
Merge pull request #197 from ngvtien/master
Addressing Issues #196, #192 and #205
2 parents 71e0480 + 42ca3f9 commit 997af4c

15 files changed

+235
-73
lines changed

build/common.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
<Project>
22
<PropertyGroup>
33
<TargetFrameworks>netcoreapp1.0;netcoreapp1.1;netcoreapp2.0;netcoreapp2.1;netcoreapp2.2;net46;netstandard2.0</TargetFrameworks>
4-
<VersionPrefix>0.19.1</VersionPrefix>
4+
<VersionPrefix>0.19.2</VersionPrefix>
55
<AssemblyVersion>0.11.0.0</AssemblyVersion>
66
<FileVersion>$(VersionPrefix)</FileVersion>
77
<Authors>dataaction</Authors>
88
<PackageTags>Sybase ASE Adaptive SAP AseClient DbProvider</PackageTags>
99
<PackageIcon>icon.png</PackageIcon>
1010
<PackageProjectUrl>https://github.com/DataAction/AdoNetCore.AseClient</PackageProjectUrl>
1111
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
12-
<PackageReleaseNotes>Refer to GitHub - https://github.com/DataAction/AdoNetCore.AseClient/releases/tag/0.19.1</PackageReleaseNotes>
12+
<PackageReleaseNotes>Refer to GitHub - https://github.com/DataAction/AdoNetCore.AseClient/releases/tag/0.19.2</PackageReleaseNotes>
1313
<RepositoryUrl>https://github.com/DataAction/AdoNetCore.AseClient</RepositoryUrl>
1414
<RepositoryType>git</RepositoryType>
1515
</PropertyGroup>

src/AdoNetCore.AseClient/AseCommandBuilder.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,12 +224,15 @@ private static DataTable GetSchemaTableWithKeyInfo(DbCommand sourceCommand)
224224
if (dataTable != null)
225225
{
226226
// If there is no primary key on the table, then throw MissingPrimaryKeyException.
227-
var isKeyColumn = dataTable.Columns["IsKey"];
227+
var isKeyColumn = dataTable.Columns[SchemaTableColumn.IsKey];
228+
var isUniqueColumn = dataTable.Columns[SchemaTableColumn.IsUnique];
229+
228230
var hasKey = false;
229231

230232
foreach (DataRow columnDescriptorRow in dataTable.Rows)
231233
{
232-
hasKey |= (bool)columnDescriptorRow[isKeyColumn];
234+
hasKey |= (bool)columnDescriptorRow[isKeyColumn] ||
235+
(bool)columnDescriptorRow[isUniqueColumn];
233236

234237
if (hasKey)
235238
{

src/AdoNetCore.AseClient/AseConnection.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections;
33
using System.Data;
44
using System.Data.Common;
5+
using System.Net.Security;
56
using AdoNetCore.AseClient.Interface;
67
using AdoNetCore.AseClient.Internal;
78

@@ -274,7 +275,7 @@ public override void Open()
274275
{
275276
var parameters = ConnectionParameters.Parse(_connectionString);
276277

277-
_internal = _connectionPoolManager.Reserve(_connectionString, parameters, _eventNotifier);
278+
_internal = _connectionPoolManager.Reserve(_connectionString, parameters, _eventNotifier, UserCertificateValidationCallback);
278279

279280
InternalConnectionTimeout = parameters.LoginTimeout;
280281
}
@@ -543,7 +544,10 @@ public bool NamedParameters
543544
#if ENABLE_CLONEABLE_INTERFACE
544545
public object Clone()
545546
{
546-
return new AseConnection(_connectionString, _connectionPoolManager);
547+
return new AseConnection(_connectionString, _connectionPoolManager)
548+
{
549+
UserCertificateValidationCallback = UserCertificateValidationCallback,
550+
};
547551
}
548552
#endif
549553

@@ -621,6 +625,12 @@ public AseTransaction Transaction
621625
return _transaction;
622626
}
623627
}
628+
629+
/// <summary>
630+
/// Allow consumer to override the default certificate validation
631+
/// </summary>
632+
public RemoteCertificateValidationCallback UserCertificateValidationCallback { get; set; }
633+
624634
}
625635

626636
/// <summary>

src/AdoNetCore.AseClient/AseParameterCollection.cs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -263,10 +263,10 @@ public AseParameter Add(string parameterName, AseDbType dbType, int size, Parame
263263
/// <returns>A new <see cref="AseParameter" /> object.</returns>
264264
public AseParameter Add(AseParameter parameter)
265265
{
266-
if (parameter != null)
267-
{
268-
_parameters.Add(parameter);
269-
}
266+
if (parameter == null) throw new ArgumentNullException(nameof(parameter));
267+
if (Contains(parameter)) throw new ArgumentException($"parameter name '{parameter.ParameterName}' is already in the collection");
268+
269+
_parameters.Add(parameter);
270270
return parameter;
271271
}
272272

@@ -379,6 +379,7 @@ public override int Add(object value)
379379
{
380380
if (value is AseParameter p)
381381
{
382+
if (Contains(p)) throw new ArgumentException($"Parameter name: '{p.ParameterName}' is already registered", nameof(value));
382383
return ((IList)_parameters).Add(p);
383384
}
384385
return -1;
@@ -438,15 +439,23 @@ public override int IndexOf(object value)
438439
/// Returns -1 when the object does not exist in the <see cref="AseParameterCollection" />.</returns>
439440
public int IndexOf(AseParameter value)
440441
{
441-
if (value != null)
442+
if (value == null) return -1;
443+
for (var i = 0; i < _parameters.Count; i++)
442444
{
443-
for (var i = 0; i < _parameters.Count; i++)
445+
if (string.IsNullOrWhiteSpace(value.ParameterName))
444446
{
445447
if (value == _parameters[i])
446448
{
447449
return i;
448450
}
449451
}
452+
else
453+
{
454+
if (value == _parameters[i] || value.ParameterName == _parameters[i].ParameterName)
455+
{
456+
return i;
457+
}
458+
}
450459
}
451460

452461
return -1;
@@ -459,6 +468,7 @@ public int IndexOf(AseParameter value)
459468
/// <param name="parameter">The <see cref="AseParameter" /> object to add to the collection.</param>
460469
public override void Insert(int index, object parameter)
461470
{
471+
if (Contains(parameter)) throw new ArgumentException($"parameter name '{parameter}' is already in the collection");
462472
((IList)_parameters).Insert(index, parameter);
463473
}
464474

@@ -469,6 +479,7 @@ public override void Insert(int index, object parameter)
469479
/// <param name="parameter">The <see cref="AseParameter" /> object to add to the collection.</param>
470480
public void Insert(int index, AseParameter parameter)
471481
{
482+
if (Contains(parameter)) throw new ArgumentException($"parameter name '{parameter.ParameterName}' is already in the collection");
472483
((IList)_parameters).Insert(index, parameter);
473484
}
474485

@@ -521,10 +532,7 @@ public override void RemoveAt(int index)
521532
/// <param name="index">The starting index of the array.</param>
522533
public override void CopyTo(Array array, int index)
523534
{
524-
if (array != null)
525-
{
526-
((IList)_parameters).CopyTo(array, index);
527-
}
535+
((IList)_parameters).CopyTo(array, index);
528536
}
529537

530538
/// <summary>

src/AdoNetCore.AseClient/Interface/IConnectionPoolManager.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
using System.Net.Security;
2+
13
namespace AdoNetCore.AseClient.Interface
24
{
35
internal interface IConnectionPoolManager
46
{
5-
IInternalConnection Reserve(string connectionString, IConnectionParameters parameters, IInfoMessageEventNotifier eventNotifier);
7+
IInternalConnection Reserve(string connectionString, IConnectionParameters parameters, IInfoMessageEventNotifier eventNotifier, RemoteCertificateValidationCallback userCertificateValidationCallback = null);
68
void Release(string connectionString, IInternalConnection connection);
79
void ClearPool(string connectionString);
810
void ClearPools();

src/AdoNetCore.AseClient/Internal/ConnectionPoolManager.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections;
33
using System.Collections.Concurrent;
44
using System.Collections.Generic;
5+
using System.Net.Security;
56
using AdoNetCore.AseClient.Interface;
67

78
namespace AdoNetCore.AseClient.Internal
@@ -14,14 +15,14 @@ internal sealed class ConnectionPoolManager : IConnectionPoolManager, IEnumerabl
1415

1516
private static readonly ConcurrentDictionary<string, IConnectionPool> Pools = new ConcurrentDictionary<string, IConnectionPool>(StringComparer.OrdinalIgnoreCase);
1617

17-
public IInternalConnection Reserve(string connectionString, IConnectionParameters parameters, IInfoMessageEventNotifier eventNotifier)
18+
public IInternalConnection Reserve(string connectionString, IConnectionParameters parameters, IInfoMessageEventNotifier eventNotifier, RemoteCertificateValidationCallback userCertificateValidationCallback = null)
1819
{
1920
return Pools.GetOrAdd(connectionString, _ =>
2021
{
2122
#if ENABLE_ARRAY_POOL
22-
var internalConnectionFactory = new InternalConnectionFactory(parameters, BufferPool);
23+
var internalConnectionFactory = new InternalConnectionFactory(parameters, BufferPool, userCertificateValidationCallback);
2324
#else
24-
var internalConnectionFactory = new InternalConnectionFactory(parameters);
25+
var internalConnectionFactory = new InternalConnectionFactory(parameters, userCertificateValidationCallback);
2526
#endif
2627

2728
return new ConnectionPool(parameters, internalConnectionFactory);

src/AdoNetCore.AseClient/Internal/FormatItem.cs

Lines changed: 42 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -64,50 +64,60 @@ public string ParameterName
6464
/// </summary>
6565
public SerializationType SerializationType { get; set; }
6666

67-
public static FormatItem CreateForParameter(AseParameter parameter, DbEnvironment env, CommandType commandType)
67+
public static FormatItem CreateForParameter(AseParameter parameter, DbEnvironment env, AseCommand command)
6868
{
6969
parameter.AseDbType = TypeMap.InferType(parameter);
7070

7171
var dbType = parameter.DbType;
72-
7372
var length = TypeMap.GetFormatLength(dbType, parameter, env.Encoding);
7473

75-
var format = new FormatItem
74+
var format = command.FormatItem;
75+
var parameterName = parameter.ParameterName ?? command.Parameters.IndexOf(parameter).ToString();
76+
if (!(command.FormatItem != null && command.FormatItem.ParameterName == parameterName &&
77+
command.FormatItem.AseDbType == parameter.AseDbType))
7678
{
77-
AseDbType = parameter.AseDbType,
78-
ParameterName = parameter.ParameterName,
79-
IsOutput = parameter.IsOutput,
80-
IsNullable = parameter.IsNullable,
81-
Length = length,
82-
DataType = TypeMap.GetTdsDataType(dbType, parameter.SendableValue, length, parameter.ParameterName),
83-
UserType = TypeMap.GetUserType(dbType, parameter.SendableValue, length)
84-
};
79+
format = new FormatItem
80+
{
81+
AseDbType = parameter.AseDbType,
82+
ParameterName = parameter.ParameterName,
83+
IsOutput = parameter.IsOutput,
84+
IsNullable = parameter.IsNullable,
85+
Length = length,
86+
DataType = TypeMap.GetTdsDataType(dbType, parameter.SendableValue, length, parameter.ParameterName),
87+
UserType = TypeMap.GetUserType(dbType, parameter.SendableValue, length)
88+
};
8589

86-
//fixup the FormatItem's BlobType for strings and byte arrays
87-
if (format.DataType == TdsDataType.TDS_BLOB)
88-
{
89-
switch (parameter.DbType)
90+
//fixup the FormatItem's BlobType for strings and byte arrays
91+
if (format.DataType == TdsDataType.TDS_BLOB)
9092
{
91-
case DbType.AnsiString:
92-
format.BlobType = BlobType.BLOB_LONGCHAR;
93-
break;
94-
case DbType.String:
95-
format.BlobType = BlobType.BLOB_UNICHAR;
96-
// This is far less than ideal but at the time of addressing this issue whereby if the
97-
// BlobType is a BLOB_UNICHAR then the UserType would need to be 36 when it
98-
// is a stored proc otherwise it would need to be zero (0).
99-
//
100-
// In the future, we'd need to overhaul how TDS_BLOB is structured especially
101-
// around BLOB_UNICHAR and the UserType that it should return in a more consistent way
102-
if (commandType != CommandType.StoredProcedure)
103-
format.UserType = 0;
93+
switch (parameter.DbType)
94+
{
95+
case DbType.AnsiString:
96+
format.BlobType = BlobType.BLOB_LONGCHAR;
97+
break;
98+
case DbType.String:
99+
format.BlobType = BlobType.BLOB_UNICHAR;
100+
// This is far less than ideal but at the time of addressing this issue whereby if the
101+
// BlobType is a BLOB_UNICHAR then the UserType would need to be 36 when it
102+
// is a stored proc otherwise it would need to be zero (0).
103+
//
104+
// In the future, we'd need to overhaul how TDS_BLOB is structured especially
105+
// around BLOB_UNICHAR and the UserType that it should return in a more consistent way
106+
if (command.CommandType != CommandType.StoredProcedure)
107+
format.UserType = 0;
104108

105-
break;
106-
case DbType.Binary:
107-
format.BlobType = BlobType.BLOB_LONGBINARY;
108-
break;
109+
break;
110+
case DbType.Binary:
111+
format.BlobType = BlobType.BLOB_LONGBINARY;
112+
break;
113+
}
109114
}
110115
}
116+
else
117+
{
118+
format.DataType = TypeMap.GetTdsDataType(dbType, parameter.SendableValue, length, parameter.ParameterName);
119+
format.UserType = TypeMap.GetUserType(dbType, parameter.SendableValue, length);
120+
}
111121

112122
//fixup the FormatItem's length,scale,precision for decimals
113123
if (format.IsDecimalType)

src/AdoNetCore.AseClient/Internal/InternalConnection.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -669,11 +669,7 @@ private IToken[] BuildParameterTokens(AseCommand command)
669669

670670
foreach (var parameter in command.Parameters.SendableParameters)
671671
{
672-
var parameterName = parameter.ParameterName ?? command.Parameters.IndexOf(parameter).ToString();
673-
if (!(command.FormatItem != null && command.FormatItem.ParameterName == parameterName && command.FormatItem.AseDbType == parameter.AseDbType))
674-
{
675-
command.FormatItem = FormatItem.CreateForParameter(parameter, _environment, command.CommandType);
676-
}
672+
command.FormatItem = FormatItem.CreateForParameter(parameter, _environment, command);
677673

678674
formatItems.Add(command.FormatItem);
679675
parameterItems.Add(new ParametersToken.Parameter

src/AdoNetCore.AseClient/Internal/InternalConnectionFactory.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,23 @@ namespace AdoNetCore.AseClient.Internal
1919
internal class InternalConnectionFactory : IInternalConnectionFactory
2020
{
2121
private readonly IConnectionParameters _parameters;
22+
private readonly RemoteCertificateValidationCallback _userCertificateValidationCallback;
23+
24+
2225
#if ENABLE_ARRAY_POOL
2326
private readonly System.Buffers.ArrayPool<byte> _arrayPool;
2427
#endif
2528
private IPEndPoint _endpoint;
2629

2730
#if ENABLE_ARRAY_POOL
28-
public InternalConnectionFactory(IConnectionParameters parameters, System.Buffers.ArrayPool<byte> arrayPool)
31+
public InternalConnectionFactory(IConnectionParameters parameters, System.Buffers.ArrayPool<byte> arrayPool, RemoteCertificateValidationCallback userCertificateValidationCallback)
2932
#else
30-
public InternalConnectionFactory(IConnectionParameters parameters)
33+
public InternalConnectionFactory(IConnectionParameters parameters, RemoteCertificateValidationCallback userCertificateValidationCallback)
3134
#endif
3235
{
3336
_parameters = parameters;
37+
_userCertificateValidationCallback = userCertificateValidationCallback ?? UserCertificateValidationCallback;
38+
3439
#if ENABLE_ARRAY_POOL
3540
_arrayPool = arrayPool;
3641
#endif
@@ -109,7 +114,7 @@ private InternalConnection CreateConnection(Socket socket, CancellationToken tok
109114

110115
if (_parameters.Encryption)
111116
{
112-
sslStream = new SslStream(networkStream, false, UserCertificateValidationCallback);
117+
sslStream = new SslStream(networkStream, false, _userCertificateValidationCallback);
113118

114119
var authenticate = sslStream.AuthenticateAsClientAsync(_parameters.Server);
115120

@@ -175,10 +180,11 @@ private InternalConnection CreateConnectionInternal(Stream networkStream)
175180
#if ENABLE_ARRAY_POOL
176181
return new InternalConnection(_parameters, networkStream, reader, environment, _arrayPool);
177182
#else
178-
return new InternalConnection(_parameters, networkStream, reader, environment);
183+
return new InternalConnection(_parameters, networkStream, reader, environment);
179184
#endif
180185
}
181186

187+
182188
private bool UserCertificateValidationCallback(object sender, X509Certificate serverCertificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
183189
{
184190
var certificateChainPolicyErrors = (sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors) == SslPolicyErrors.RemoteCertificateChainErrors;

src/AdoNetCore.AseClient/Internal/SchemaTableBuilder.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,17 +130,12 @@ private FillTableResults FillTableFromFormats(DataTable table)
130130
private void TryLoadKeyInfo(DataTable table, string baseTableNameValue, string baseSchemaNameValue, string baseCatalogNameValue)
131131
{
132132
if (_connection == null)
133-
{
134133
throw new InvalidOperationException("Invalid AseCommand.Connection");
135-
}
136134

137135
if (_connection.State != ConnectionState.Open)
138-
{
139136
throw new InvalidOperationException("Invalid AseCommand.Connection.ConnectionState");
140-
}
141137

142-
if (!string.IsNullOrWhiteSpace(baseTableNameValue) &&
143-
!string.IsNullOrWhiteSpace(baseCatalogNameValue))
138+
if (string.IsNullOrWhiteSpace(baseTableNameValue))
144139
return;
145140

146141
using (var command = _connection.CreateCommand())

test/AdoNetCore.AseClient.Tests/AdoNetCore.AseClient.Tests.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
1111
<PackageReference Include="NUnit" Version="3.12.0" />
1212
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
13+
1314
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.5.1" />
1415
</ItemGroup>
1516
<ItemGroup>
@@ -34,9 +35,11 @@
3435
</PropertyGroup>
3536
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">
3637
<PackageReference Include="System.Data.Common" Version="4.3.0" />
38+
<PackageReference Include="System.Net.Security" Version="4.3.2" />
3739
</ItemGroup>
3840
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp1.1' ">
3941
<PackageReference Include="System.Data.Common" Version="4.3.0" />
42+
<PackageReference Include="System.Net.Security" Version="4.3.2" />
4043
</ItemGroup>
4144
<ItemGroup Condition="'$(TargetFramework)' == 'net46'">
4245
<PackageReference Include="Sybase.AdoNet4.AseClient">

0 commit comments

Comments
 (0)