Skip to content

Commit 4448813

Browse files
authored
Merge branch 'ydb-platform:main' into main
2 parents 4cbc310 + ab8fb03 commit 4448813

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+4414
-592
lines changed

.github/scripts/publish.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ then
88
exit 1;
99
fi;
1010

11-
LAST_TAG=$(git tag | tail -n 1);
11+
LAST_TAG=$(git tag --sort=-creatordate | head -n 1);
1212
MAJOR=$(echo $LAST_TAG | sed -E 's/v([0-9]+)\..*/\1/');
1313
MINOR=$(echo $LAST_TAG | sed -E 's/v[0-9]+\.([0-9]+)\..*/\1/');
1414
PATCH=$(echo $LAST_TAG | sed -E 's/v[0-9]+\.[0-9]+\.([0-9]+)($|-rc[0-9]+)/\1/');

.github/workflows/tests.yml

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ jobs:
3838
strategy:
3939
fail-fast: false
4040
matrix:
41-
ydb-version: [ 'trunk' ]
41+
ydb-version: [ 'trunk', 'latest' ]
4242
dotnet-version: [ 6.0.x, 7.0.x ]
4343
include:
4444
- dotnet-version: 6.0.x
@@ -54,7 +54,6 @@ jobs:
5454
- 8765:8765
5555
env:
5656
YDB_LOCAL_SURVIVE_RESTART: true
57-
YDB_USE_IN_MEMORY_PDISKS: true
5857
options: '--name ydb-local -h localhost'
5958
env:
6059
OS: ubuntu-22.04
@@ -72,7 +71,7 @@ jobs:
7271
run: |
7372
docker cp ydb-local:/ydb_certs/ca.pem ~/
7473
cd src
75-
dotnet test --filter "(FullyQualifiedName~Ado) | (FullyQualifiedName~Dapper)" -l "console;verbosity=normal"
74+
dotnet test --filter "(FullyQualifiedName~Ado) | (FullyQualifiedName~Dapper)" -f ${{ matrix.dotnet-target-framework }} -l "console;verbosity=normal"
7675
topic-tests:
7776
runs-on: ubuntu-22.04
7877
strategy:
@@ -94,7 +93,6 @@ jobs:
9493
- 8765:8765
9594
env:
9695
YDB_LOCAL_SURVIVE_RESTART: true
97-
YDB_USE_IN_MEMORY_PDISKS: true
9896
options: '--name ydb-local -h localhost'
9997
env:
10098
OS: ubuntu-22.04
@@ -112,7 +110,7 @@ jobs:
112110
run: |
113111
docker cp ydb-local:/ydb_certs/ca.pem ~/
114112
cd src
115-
dotnet test --filter "FullyQualifiedName~Topic" -l "console;verbosity=normal"
113+
dotnet test --filter "FullyQualifiedName~Topic" -f ${{ matrix.dotnet-target-framework }} -l "console;verbosity=normal"
116114
integration-tests:
117115
runs-on: ubuntu-22.04
118116
strategy:
@@ -134,7 +132,6 @@ jobs:
134132
- 8765:8765
135133
env:
136134
YDB_LOCAL_SURVIVE_RESTART: true
137-
YDB_USE_IN_MEMORY_PDISKS: true
138135
options: '--name ydb-local -h localhost'
139136
env:
140137
OS: ubuntu-22.04

CHANGELOG.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,53 @@
1+
* Fixed: YdbDataReader.GetDataTypeName for optional values.
2+
* Added support for "Columns" collectionName in YdbConnection.GetSchema(Async).
3+
4+
## v0.12.0
5+
* GetUint64(int ordinal) returns a ulong for Uint8, Uint16, Uint32, Uint64 YDB types.
6+
* GetInt64(int ordinal) returns a int for Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32 YDB types.
7+
* GetUint32(int ordinal) returns a uint for Uint8, Uint16, Uint32 YDB types.
8+
* GetInt32(int ordinal) returns a int for Int8, Int16, Int32, Uint8, Uint16 YDB types.
9+
* GetUint16(int ordinal) returns a ushort for Uint8, Uint16 YDB types.
10+
* GetInt16(int ordinal) returns a short for Int8, Int16, Uint8 YDB types.
11+
* GetDouble(int ordinal) returns a double for Float and Double YDB types.
12+
* Throw InvalidCastException on string.Empty in `GetChar(int ordinal)`.
13+
* Changed Ydb.Sdk.Value.InvalidTypeException to InvalidCastException in YdbValueParser.
14+
* Changed InvalidCastException to InvalidOperationException in YdbParameter.
15+
* Added specification tests: YdbCommandTests and YdbParameterTests.
16+
* YdbConnection.Database returns string.Empty if ConnectionStringBuilder is null.
17+
* Propagated cancellationToken in Execute[.*]Async methods.
18+
* When YdbCommand has an open data reader, it throws InvalidOperationException on the setters: CommandText, DbConnection.
19+
* Added checkers to YdbCommand.Prepare().
20+
* CommandText getter doesn't throw an exception if the CommandText property has not been initialized.
21+
22+
## v0.11.0
23+
* Fix bug: GetValue(int ordinal) return DBNull.Value if fetched NULL value.
24+
* Fix: NextResult() moves to the next result and skip the first ResultSet.
25+
* Added specification DbDataReaderTests.
26+
* If dataOffset is larger than the length of data, GetChars and GetBytes methods will return 0.
27+
* If YdbDataReader is closed: `throw new InvalidOperationException("The reader is closed")`.
28+
* InvalidOperationException on ConnectionString property has not been initialized.
29+
* One YdbTransaction per YdbConnection. Otherwise, throw an exception: InvalidOperationException("A transaction is already in progress; nested/concurrent transactions aren't supported.").
30+
* ConnectionString returns an empty.String when it is not set.
31+
* When a YdbDataReader is closed, if stream is not empty, a YdbTransaction fails if it is not null. A session also fails due to a possible error SessionBusy race condition with the server.
32+
* Fixed bug: Fetch txId from the last result set.
33+
* YdbTransaction CheckDisposed() (invoke rollback if transaction hasn't been committed).
34+
* Dev: Added specification tests for YdbTransaction.
35+
36+
## v0.10.0
37+
- Fixed bug in Topic Writer: race condition when session fails, then write operation starts on previous session and new session is created. Messages may be lost.
38+
- Supported in ADO.NET GetSchema(Async). CollectionNames:
39+
* Tables
40+
* TablesWithCollections
41+
* DataSourceInformation
42+
* MetaDataCollections
43+
* Restrictions
44+
- Rename field _onStatus -> _onNotSuccessStatus in YdbDataReader
45+
- If session is not active, do not invoke DeleteNotActiveSession(session)
46+
- AttachStream: connect stream using NodeId
47+
- PoolManager: change pool properties on field
48+
- Delete *Settings.DefaultInstance because it's a singleton object that's changed by tasks when NodeId is set
49+
- DbConnection.Session.OnStatus(status) in YdbTransaction
50+
151
## v0.9.4
252
- Do not pessimize the node on Grpc.Core.StatusCode.Cancelled and Grpc.Core.StatusCode.DeadlineExceeded.
353
- Dispose of WriterSession using dispose CancellationToken.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ Example of using a query client to execute a simple query:
9898

9999
```c#
100100
// Create QueryClient using Driver instance.
101-
using var queryClient = new QueryService(driver);
101+
using var queryClient = new QueryClient(driver);
102102

103103
var row = await queryClient.ReadRow(@"
104104
DECLARE $id AS Uint64;

src/Ydb.Sdk/src/Ado/PoolManager.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ namespace Ydb.Sdk.Ado;
66
internal static class PoolManager
77
{
88
private static readonly SemaphoreSlim SemaphoreSlim = new(1); // async mutex
9+
private static readonly ConcurrentDictionary<string, SessionPool> Pools = new();
910

10-
private static ConcurrentDictionary<string, SessionPool> Pools { get; } = new();
11-
12-
internal static async Task<Session> GetSession(YdbConnectionStringBuilder connectionString)
11+
internal static async Task<Session> GetSession(
12+
YdbConnectionStringBuilder connectionString,
13+
CancellationToken cancellationToken
14+
)
1315
{
1416
if (Pools.TryGetValue(connectionString.ConnectionString, out var sessionPool))
1517
{
@@ -18,7 +20,7 @@ internal static async Task<Session> GetSession(YdbConnectionStringBuilder connec
1820

1921
try
2022
{
21-
await SemaphoreSlim.WaitAsync();
23+
await SemaphoreSlim.WaitAsync(cancellationToken);
2224

2325
if (Pools.TryGetValue(connectionString.ConnectionString, out var pool))
2426
{

src/Ydb.Sdk/src/Ado/ThrowHelper.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using Ydb.Sdk.Value;
2+
3+
namespace Ydb.Sdk.Ado;
4+
5+
internal static class ThrowHelper
6+
{
7+
internal static T ThrowInvalidCast<T>(YdbValue ydbValue)
8+
{
9+
throw new InvalidCastException($"Field YDB type {ydbValue.TypeId} can't be cast to {typeof(T)} type.");
10+
}
11+
12+
internal static void ThrowIndexOutOfRangeException(int columnCount)
13+
{
14+
throw new IndexOutOfRangeException("Ordinal must be between 0 and " + (columnCount - 1));
15+
}
16+
17+
internal static void ThrowInvalidCastException(string expectedType, string actualType)
18+
{
19+
throw new InvalidCastException($"Invalid type of YDB value, expected: {expectedType}, actual: {actualType}.");
20+
}
21+
}

src/Ydb.Sdk/src/Ado/YdbCommand.cs

Lines changed: 59 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Data;
22
using System.Data.Common;
3+
using System.Diagnostics.CodeAnalysis;
34
using System.Text;
45
using Ydb.Sdk.Ado.Internal;
56
using Ydb.Sdk.Services.Query;
@@ -8,18 +9,23 @@ namespace Ydb.Sdk.Ado;
89

910
public sealed class YdbCommand : DbCommand
1011
{
11-
private YdbConnection YdbConnection { get; set; }
12-
12+
private YdbConnection? _ydbConnection;
1313
private string _commandText = string.Empty;
1414

15+
private YdbConnection YdbConnection =>
16+
_ydbConnection ?? throw new InvalidOperationException("Connection property has not been initialized");
17+
18+
public YdbCommand()
19+
{
20+
}
21+
1522
public YdbCommand(YdbConnection ydbConnection)
1623
{
17-
YdbConnection = ydbConnection;
24+
_ydbConnection = ydbConnection;
1825
}
1926

2027
public override void Cancel()
2128
{
22-
throw new NotImplementedException("Currently not supported");
2329
}
2430

2531
public override int ExecuteNonQuery()
@@ -47,9 +53,7 @@ public override async Task<int> ExecuteNonQueryAsync(CancellationToken cancellat
4753
{
4854
await using var dataReader = await ExecuteReaderAsync(CommandBehavior.Default, cancellationToken);
4955

50-
var data = await dataReader.ReadAsync(cancellationToken)
51-
? dataReader.IsDBNull(0) ? null : dataReader.GetValue(0)
52-
: null;
56+
var data = await dataReader.ReadAsync(cancellationToken) ? dataReader.GetValue(0) : null;
5357

5458
while (await dataReader.NextResultAsync(cancellationToken))
5559
{
@@ -60,19 +64,38 @@ public override async Task<int> ExecuteNonQueryAsync(CancellationToken cancellat
6064

6165
public override void Prepare()
6266
{
63-
// Do nothing
67+
if (YdbConnection.State == ConnectionState.Closed)
68+
{
69+
throw new InvalidOperationException("Connection is not open");
70+
}
71+
72+
if (CommandText.Length == 0)
73+
{
74+
throw new InvalidOperationException("CommandText property has not been initialized");
75+
}
76+
77+
if (YdbConnection.IsBusy)
78+
{
79+
throw new YdbOperationInProgressException(YdbConnection);
80+
}
6481
}
6582

6683
public override string CommandText
6784
{
6885
get => _commandText;
6986
#pragma warning disable CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes).
87+
[param: AllowNull]
7088
set
71-
#pragma warning restore CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes).
7289
{
73-
_commandText = value ?? throw new ArgumentNullException(nameof(value));
74-
DbParameterCollection.Clear();
90+
if (_ydbConnection?.IsBusy ?? false)
91+
{
92+
throw new InvalidOperationException("An open data reader exists for this command");
93+
}
94+
95+
// ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract
96+
_commandText = value ?? string.Empty;
7597
}
98+
#pragma warning restore CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes).
7699
}
77100

78101
public override int CommandTimeout
@@ -96,17 +119,22 @@ public override int CommandTimeout
96119

97120
protected override DbConnection? DbConnection
98121
{
99-
get => YdbConnection;
122+
get => _ydbConnection;
100123
set
101124
{
102-
if (value is YdbConnection ydbConnection)
125+
if (_ydbConnection?.IsBusy ?? false)
103126
{
104-
YdbConnection = ydbConnection;
127+
throw new InvalidOperationException("An open data reader exists for this command.");
128+
}
129+
130+
if (value is null or Ado.YdbConnection)
131+
{
132+
_ydbConnection = (YdbConnection?)value;
105133
}
106134
else
107135
{
108136
throw new ArgumentException(
109-
$"Unsupported DbTransaction type: {value?.GetType()}, expected: {typeof(YdbConnection)}");
137+
$"Unsupported DbConnection type: {value.GetType()}, expected: {typeof(YdbConnection)}");
110138
}
111139
}
112140
}
@@ -162,7 +190,11 @@ protected override async Task<DbDataReader> ExecuteDbDataReaderAsync(CommandBeha
162190
YdbConnection.EnsureConnectionOpen();
163191

164192
var ydbParameters = DbParameterCollection.YdbParameters;
165-
var (sql, paramNames) = SqlParser.Parse(CommandText);
193+
var (sql, paramNames) = SqlParser.Parse(
194+
CommandText.Length > 0
195+
? CommandText
196+
: throw new InvalidOperationException("CommandText property has not been initialized")
197+
);
166198
var preparedSql = new StringBuilder();
167199

168200
foreach (var paramName in paramNames)
@@ -181,15 +213,22 @@ protected override async Task<DbDataReader> ExecuteDbDataReaderAsync(CommandBeha
181213

182214
var execSettings = CommandTimeout > 0
183215
? new ExecuteQuerySettings { TransportTimeout = TimeSpan.FromSeconds(CommandTimeout) }
184-
: ExecuteQuerySettings.DefaultInstance;
216+
: new ExecuteQuerySettings();
217+
execSettings.CancellationToken = cancellationToken;
218+
219+
var transaction = YdbConnection.CurrentTransaction;
220+
221+
if (Transaction != null && Transaction != transaction) // assert on legacy DbTransaction property
222+
{
223+
throw new InvalidOperationException("Transaction mismatched! (Maybe using another connection)");
224+
}
185225

186226
var ydbDataReader = await YdbDataReader.CreateYdbDataReader(YdbConnection.Session.ExecuteQuery(
187-
preparedSql.ToString(), ydbParameters, execSettings, Transaction?.TransactionControl),
188-
YdbConnection.Session.OnStatus, Transaction);
227+
preparedSql.ToString(), ydbParameters, execSettings, transaction?.TransactionControl),
228+
YdbConnection.Session.OnStatus, transaction);
189229

190230
YdbConnection.LastReader = ydbDataReader;
191231
YdbConnection.LastCommand = CommandText;
192-
YdbConnection.LastTransaction = Transaction;
193232

194233
return ydbDataReader;
195234
}

0 commit comments

Comments
 (0)