Skip to content

Commit 12d9954

Browse files
authored
Merge pull request #184 from ngvtien/master
Address issues 182,183, 185, 186, 187
2 parents 886baa2 + a2e7cbe commit 12d9954

20 files changed

+743
-77
lines changed

AdoNetCore.AseClient.sln

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
3-
# Visual Studio 15
4-
VisualStudioVersion = 15.0.27130.2010
3+
# Visual Studio Version 16
4+
VisualStudioVersion = 16.0.30320.27
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AdoNetCore.AseClient", "src\AdoNetCore.AseClient\AdoNetCore.AseClient.csproj", "{A994B1E4-2B7F-40B8-B045-57E4F324FF67}"
77
EndProject

src/AdoNetCore.AseClient/AdoNetCore.AseClient.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,7 @@
33
<PropertyGroup>
44
<Description>.NET Core data provider for Sybase ASE</Description>
55
</PropertyGroup>
6+
<PropertyGroup>
7+
<LangVersion>7</LangVersion>
8+
</PropertyGroup>
69
</Project>

src/AdoNetCore.AseClient/AseCommand.cs

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public sealed class AseCommand : DbCommand
2727
private string _commandText;
2828
private UpdateRowSource _updatedRowSource;
2929
private bool? _namedParameters;
30+
internal FormatItem FormatItem { get; set; }
3031

3132
/// <summary>
3233
/// Constructor function for an <see cref="AseCommand"/> instance.
@@ -42,10 +43,8 @@ public AseCommand()
4243
/// Note: the instance will not be initialised with an AseConnection; before use this must be supplied.
4344
/// </summary>
4445
/// <param name="commandText">The command text to execute</param>
45-
public AseCommand(string commandText)
46+
public AseCommand(string commandText) : this()
4647
{
47-
AseParameters = new AseParameterCollection();
48-
4948
CommandText = commandText;
5049
}
5150

@@ -54,14 +53,10 @@ public AseCommand(string commandText)
5453
/// </summary>
5554
/// <param name="commandText">The command text to execute</param>
5655
/// <param name="connection">The connection upon which to execute</param>
57-
public AseCommand(string commandText, AseConnection connection)
56+
public AseCommand(string commandText, AseConnection connection) : this(commandText)
5857
{
5958
_connection = connection;
6059
_transaction = connection.Transaction;
61-
62-
AseParameters = new AseParameterCollection();
63-
64-
CommandText = commandText;
6560
}
6661

6762
/// <summary>
@@ -70,23 +65,13 @@ public AseCommand(string commandText, AseConnection connection)
7065
/// <param name="commandText">The command text to execute</param>
7166
/// <param name="connection">The connection upon which to execute</param>
7267
/// <param name="transaction">The transaction within which to execute</param>
73-
public AseCommand(string commandText, AseConnection connection, AseTransaction transaction)
68+
public AseCommand(string commandText, AseConnection connection, AseTransaction transaction) : this (commandText, connection)
7469
{
75-
_connection = connection;
7670
_transaction = transaction;
77-
78-
AseParameters = new AseParameterCollection();
79-
80-
CommandText = commandText;
8171
}
8272

83-
internal AseCommand(AseConnection connection)
84-
{
85-
_connection = connection;
86-
_transaction = connection.Transaction;
87-
88-
AseParameters = new AseParameterCollection();
89-
}
73+
internal AseCommand(AseConnection connection) : this (string.Empty, connection, connection.Transaction)
74+
{ }
9075

9176
/// <summary>
9277
/// Tries to cancel the execution of a <see cref="AseCommand" />.
@@ -131,6 +116,7 @@ protected override DbParameter CreateDbParameter()
131116
return CreateParameter();
132117
}
133118

119+
134120
/// <summary>
135121
/// Executes a Transact-SQL statement against the connection and returns the number of rows affected.
136122
/// </summary>

src/AdoNetCore.AseClient/AseCommandBuilder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#if ENABLE_SYSTEM_DATA_COMMON_EXTENSIONS
1+
#if ENABLE_SYSTEM_DATA_COMMON_EXTENSIONS
22
using System;
33
using System.Collections.Generic;
44
using System.Data;
@@ -484,4 +484,4 @@ private void RowUpdating(object sender, AseRowUpdatingEventArgs args)
484484
}
485485
}
486486
}
487-
#endif
487+
#endif

src/AdoNetCore.AseClient/AseDataReader.cs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010

1111
namespace AdoNetCore.AseClient
1212
{
13+
/// <summary>
14+
/// ASE implementation of <see cref="IDataReader"/>
15+
/// </summary>
1316
public sealed class AseDataReader : DbDataReader
1417
{
1518
private TableResult _currentTable;
@@ -634,15 +637,11 @@ public override bool Read()
634637
}
635638

636639
public override int Depth => 0;
640+
637641
public override bool IsClosed => _currentTable == null;
638642
private int _finalRecordsAffected = -1;
639-
public override int RecordsAffected
640-
{
641-
get
642-
{
643-
return _currentTable != null && _currentResult < _totalResults ? _currentTable.RecordsAffected : _finalRecordsAffected;
644-
}
645-
}
643+
644+
public override int RecordsAffected => _currentTable != null && _currentResult < _totalResults ? _currentTable.RecordsAffected : _finalRecordsAffected;
646645

647646
public void SetRecordsAffected(int value)
648647
{

src/AdoNetCore.AseClient/AseErrorCollection.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ private static int GetIndexOfMostSevereError(AseError[] errors)
6464
var result = 0;
6565
for (var i = 1; i < errors.Length; i++)
6666
{
67-
// The '=' in '<=' means that for equal severity, we take the last error in the list.
68-
if (errors[result].Severity <= errors[i].Severity)
67+
// We will respect the order if they're the same and already sorted and only care for the different ones
68+
if (errors[result].Severity < errors[i].Severity)
6969
{
7070
result = i;
7171
}

src/AdoNetCore.AseClient/AseParameter.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,6 @@ public AseParameter(int parameterIndex, AseDbType dbType, int size, ParameterDir
276276
SourceVersion = sourceVersion;
277277
Value = value;
278278
}
279-
280279
public override void ResetDbType()
281280
{
282281
DbType = default(DbType);

src/AdoNetCore.AseClient/Internal/FormatItem.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,20 +63,22 @@ public string ParameterName
6363
/// </summary>
6464
public SerializationType SerializationType { get; set; }
6565

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

7070
var dbType = parameter.DbType;
71+
7172
var length = TypeMap.GetFormatLength(dbType, parameter, env.Encoding);
73+
7274
var format = new FormatItem
7375
{
7476
ParameterName = parameter.ParameterName,
7577
IsOutput = parameter.IsOutput,
7678
IsNullable = parameter.IsNullable,
7779
Length = length,
7880
DataType = TypeMap.GetTdsDataType(dbType, parameter.SendableValue, length, parameter.ParameterName),
79-
UserType = TypeMap.GetTdsUserType(dbType)
81+
UserType = TypeMap.GetUserType(dbType, parameter.SendableValue, length)
8082
};
8183

8284
//fixup the FormatItem's BlobType for strings and byte arrays
@@ -89,6 +91,15 @@ public static FormatItem CreateForParameter(AseParameter parameter, DbEnvironmen
8991
break;
9092
case DbType.String:
9193
format.BlobType = BlobType.BLOB_UNICHAR;
94+
// This is far less than ideal but at the time of addressing this issue whereby if the
95+
// BlobType is a BLOB_UNICHAR then the UserType would need to be 36 when it
96+
// is a stored proc otherwise it would need to be zero (0).
97+
//
98+
// In the future, we'd need to overhaul how TDS_BLOB is structured especially
99+
// around BLOB_UNICHAR and the UserType that it should return in a more consistent way
100+
if (commandType != CommandType.StoredProcedure)
101+
format.UserType = 0;
102+
92103
break;
93104
case DbType.Binary:
94105
format.BlobType = BlobType.BLOB_LONGBINARY;
@@ -156,6 +167,7 @@ public static FormatItem ReadForRow(Stream stream, Encoding enc, TokenType srcTo
156167
default:
157168
throw new ArgumentException($"Unexpected token type: {srcTokenType}.", nameof(srcTokenType));
158169
}
170+
159171
ReadTypeInfo(format, stream, enc);
160172

161173
Logger.Instance?.WriteLine($" <- {format.ColumnName}: {format.DataType} (len: {format.Length}) (ut:{format.UserType}) (status:{format.RowStatus}) (loc:{format.LocaleInfo}) format names available: ColumnLabel [{format.ColumnLabel}], ColumnName [{format.ColumnName}], CatalogName [{format.CatalogName}], ParameterName [{format.ParameterName}], SchemaName [{format.SchemaName}], TableName [{format.TableName}]");

src/AdoNetCore.AseClient/Internal/Handler/ResponseParameterTokenHandler.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.Collections.Generic;
1+
using System.Collections.Generic;
22
using System.Data;
33
using AdoNetCore.AseClient.Enum;
44
using AdoNetCore.AseClient.Interface;
@@ -33,11 +33,10 @@ public void Handle(IToken token)
3333
foreach (AseParameter parameter in _parameters)
3434
{
3535
if (parameter.Direction == ParameterDirection.ReturnValue)
36-
{
3736
parameter.Value = t.Status;
38-
}
3937
}
4038
break;
39+
4140
case ParametersToken t:
4241
var dict = new Dictionary<string, ParametersToken.Parameter>();
4342

@@ -49,9 +48,7 @@ public void Handle(IToken token)
4948
foreach (AseParameter parameter in _parameters)
5049
{
5150
if (parameter.IsOutput && dict.ContainsKey(parameter.ParameterName))
52-
{
5351
parameter.Value = dict[parameter.ParameterName].Value;
54-
}
5552
}
5653
break;
5754
default:

src/AdoNetCore.AseClient/Internal/InternalConnection.cs

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -297,13 +297,11 @@ public void ChangeDatabase(string databaseName)
297297
HasParameters = false,
298298
CommandText = $"USE {databaseName}"
299299
}));
300-
300+
301301
var messageHandler = new MessageTokenHandler(EventNotifier);
302302
var envChangeTokenHandler = new EnvChangeTokenHandler(_environment, _parameters.Charset);
303303

304-
ReceiveTokens(
305-
envChangeTokenHandler,
306-
messageHandler);
304+
ReceiveTokens(envChangeTokenHandler, messageHandler);
307305

308306
AssertExecutionCompletion();
309307

@@ -393,7 +391,8 @@ private void InternalExecuteQueryAsync(AseCommand command, AseTransaction transa
393391
}
394392
catch (Exception ex)
395393
{
396-
readerSource.TrySetException(ex); // If we have already begun returning data, then this will get lost.
394+
// If we have already begun returning data, then this will get lost.
395+
if (!readerSource.TrySetException(ex)) throw;
397396
}
398397
}
399398

@@ -436,7 +435,7 @@ private void InternalExecuteNonQueryAsync(AseCommand command, AseTransaction tra
436435
}
437436
catch (Exception ex)
438437
{
439-
rowsAffectedSource.TrySetException(ex);
438+
if (!rowsAffectedSource.TrySetException(ex)) throw;
440439
}
441440
}
442441

@@ -611,10 +610,11 @@ private IEnumerable<IToken> BuildCommandTokens(AseCommand command, CommandBehavi
611610
? BuildRpcToken(command, behavior)
612611
: BuildLanguageToken(command, behavior);
613612

614-
foreach (var token in BuildParameterTokens(command.AseParameters))
613+
foreach (var token in BuildParameterTokens(command))
615614
{
616615
yield return token;
617616
}
617+
618618
}
619619

620620
private IToken BuildLanguageToken(AseCommand command, CommandBehavior behavior)
@@ -662,18 +662,23 @@ private string MakeCommand(string commandText, CommandBehavior behavior, bool na
662662
return result;
663663
}
664664

665-
private IToken[] BuildParameterTokens(AseParameterCollection parameters)
665+
private IToken[] BuildParameterTokens(AseCommand command)
666666
{
667667
var formatItems = new List<FormatItem>();
668668
var parameterItems = new List<ParametersToken.Parameter>();
669669

670-
foreach (var parameter in parameters.SendableParameters)
670+
foreach (var parameter in command.Parameters.SendableParameters)
671671
{
672-
var formatItem = FormatItem.CreateForParameter(parameter, _environment);
673-
formatItems.Add(formatItem);
672+
var parameterName = parameter.ParameterName ?? command.Parameters.IndexOf(parameter).ToString();
673+
if (command.FormatItem == null || command.FormatItem.ParameterName != parameterName)
674+
{
675+
command.FormatItem = FormatItem.CreateForParameter(parameter, _environment, command.CommandType);
676+
}
677+
678+
formatItems.Add(command.FormatItem);
674679
parameterItems.Add(new ParametersToken.Parameter
675680
{
676-
Format = formatItem,
681+
Format = command.FormatItem,
677682
Value = parameter.SendableValue
678683
});
679684
}

0 commit comments

Comments
 (0)