Skip to content

Commit 0c95bde

Browse files
dev: Added specification YdbCommandTests and YdbParameterTests
1 parent 340d626 commit 0c95bde

File tree

10 files changed

+265
-47
lines changed

10 files changed

+265
-47
lines changed

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

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,23 @@ namespace Ydb.Sdk.Ado;
99

1010
public sealed class YdbCommand : DbCommand
1111
{
12-
private YdbConnection? YdbConnection { get; set; }
12+
private YdbConnection? _ydbConnection;
13+
private string _commandText = string.Empty;
1314

14-
private string? _commandText = string.Empty;
15+
private YdbConnection YdbConnection =>
16+
_ydbConnection ?? throw new InvalidOperationException("Connection property has not been initialized");
1517

1618
public YdbCommand()
1719
{
1820
}
1921

2022
public YdbCommand(YdbConnection ydbConnection)
2123
{
22-
YdbConnection = ydbConnection;
24+
_ydbConnection = ydbConnection;
2325
}
2426

2527
public override void Cancel()
2628
{
27-
throw new NotImplementedException("Currently not supported");
2829
}
2930

3031
public override int ExecuteNonQuery()
@@ -63,14 +64,37 @@ public override async Task<int> ExecuteNonQueryAsync(CancellationToken cancellat
6364

6465
public override void Prepare()
6566
{
66-
// 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+
}
6781
}
6882

6983
public override string CommandText
7084
{
71-
get => _commandText ?? throw new InvalidOperationException("CommandText property has not been initialized");
85+
get => _commandText;
7286
#pragma warning disable CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes).
73-
[param: AllowNull] set => _commandText = value;
87+
[param: AllowNull]
88+
set
89+
{
90+
if (_ydbConnection?.LastReader?.IsOpen ?? 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;
97+
}
7498
#pragma warning restore CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes).
7599
}
76100

@@ -95,17 +119,22 @@ public override int CommandTimeout
95119

96120
protected override DbConnection? DbConnection
97121
{
98-
get => YdbConnection;
122+
get => _ydbConnection;
99123
set
100124
{
125+
if (_ydbConnection?.IsBusy ?? false)
126+
{
127+
throw new InvalidOperationException("An open data reader exists for this command.");
128+
}
129+
101130
if (value is null or Ado.YdbConnection)
102131
{
103-
YdbConnection = (YdbConnection?)value;
132+
_ydbConnection = (YdbConnection?)value;
104133
}
105134
else
106135
{
107136
throw new ArgumentException(
108-
$"Unsupported DbTransaction type: {value.GetType()}, expected: {typeof(YdbConnection)}");
137+
$"Unsupported DbConnection type: {value.GetType()}, expected: {typeof(YdbConnection)}");
109138
}
110139
}
111140
}
@@ -153,16 +182,19 @@ protected override YdbDataReader ExecuteDbDataReader(CommandBehavior behavior)
153182
protected override async Task<DbDataReader> ExecuteDbDataReaderAsync(CommandBehavior behavior,
154183
CancellationToken cancellationToken)
155184
{
156-
if (YdbConnection?.IsBusy
157-
?? throw new InvalidOperationException("Connection property has not been initialized."))
185+
if (YdbConnection.IsBusy)
158186
{
159187
throw new YdbOperationInProgressException(YdbConnection);
160188
}
161189

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)
@@ -182,9 +214,15 @@ protected override async Task<DbDataReader> ExecuteDbDataReaderAsync(CommandBeha
182214
var execSettings = CommandTimeout > 0
183215
? new ExecuteQuerySettings { TransportTimeout = TimeSpan.FromSeconds(CommandTimeout) }
184216
: new ExecuteQuerySettings();
217+
execSettings.CancellationToken = cancellationToken;
185218

186219
var transaction = YdbConnection.CurrentTransaction;
187220

221+
if (Transaction != null && Transaction != transaction) // assert on legacy DbTransaction property
222+
{
223+
throw new InvalidOperationException("Transaction mismatched! (Maybe using another connection)");
224+
}
225+
188226
var ydbDataReader = await YdbDataReader.CreateYdbDataReader(YdbConnection.Session.ExecuteQuery(
189227
preparedSql.ToString(), ydbParameters, execSettings, transaction?.TransactionControl),
190228
YdbConnection.Session.OnStatus, transaction);

src/Ydb.Sdk/src/Ado/YdbConnection.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,9 +163,7 @@ public override string ConnectionString
163163
}
164164
}
165165

166-
public override string Database => State == ConnectionState.Closed
167-
? string.Empty
168-
: ConnectionStringBuilder.Database;
166+
public override string Database => _connectionStringBuilder?.Database ?? string.Empty;
169167

170168
public override ConnectionState State => ConnectionState;
171169

src/Ydb.Sdk/src/Ado/YdbDataReader.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,8 @@ private async Task<State> NextExecPart()
597597

598598
private void OnFailReadStream()
599599
{
600-
ReaderState = State.IsConsumed;
600+
ReaderState = State.Close;
601+
601602
if (_ydbTransaction != null)
602603
{
603604
_ydbTransaction.Failed = true;

src/Ydb.Sdk/src/Ado/YdbException.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public YdbException(Status status) : base(status.ToString())
2929
public StatusCode Code { get; }
3030
}
3131

32-
public class YdbOperationInProgressException : YdbException
32+
public class YdbOperationInProgressException : InvalidOperationException
3333
{
3434
public YdbOperationInProgressException(YdbConnection ydbConnection)
3535
: base("A command is already in progress: " + ydbConnection.LastCommand)

src/Ydb.Sdk/src/Ado/YdbParameter.cs

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ public override void ResetDbType()
6161
}
6262

6363
public override DbType DbType { get; set; } = DbType.Object;
64-
public override ParameterDirection Direction { get; set; } = ParameterDirection.InputOutput;
64+
public override ParameterDirection Direction { get; set; } = ParameterDirection.Input;
65+
public override DataRowVersion SourceVersion { get; set; } = DataRowVersion.Current;
6566
public override bool IsNullable { get; set; }
6667

6768
[AllowNull]
@@ -73,15 +74,24 @@ public override string ParameterName
7374
{
7475
_parameterName = value switch
7576
{
76-
null => throw new YdbException("ParameterName must not be null!"),
77+
null => string.Empty,
7778
_ when value.StartsWith("$") => value,
7879
_ when value.StartsWith("@") && value.Length > 1 => $"${value[1..]}",
7980
_ => $"${value}"
8081
};
8182
}
8283
}
8384

84-
[AllowNull] [DefaultValue("")] public override string SourceColumn { get; set; } = string.Empty;
85+
private string _sourceColumn = string.Empty;
86+
87+
[AllowNull]
88+
[DefaultValue("")]
89+
public override string SourceColumn
90+
{
91+
get => _sourceColumn;
92+
set => _sourceColumn = value ?? string.Empty;
93+
}
94+
8595
public override object? Value { get; set; }
8696
public override bool SourceColumnNullMapping { get; set; }
8797
public override int Size { get; set; }
@@ -102,22 +112,22 @@ string valueString when DbType is DbType.String or DbType.AnsiString or DbType.A
102112
DbType.Date => YdbValue.MakeDate(dateTimeValue),
103113
DbType.DateTime => YdbValue.MakeDatetime(dateTimeValue),
104114
DbType.DateTime2 or DbType.Object => YdbValue.MakeTimestamp(dateTimeValue),
105-
_ => ThrowInvalidCast()
115+
_ => ThrowInvalidOperation()
106116
},
107117
DateTimeOffset dateTimeOffset when DbType is DbType.DateTimeOffset or DbType.Object =>
108118
YdbValue.MakeTimestamp(dateTimeOffset.UtcDateTime),
109119
float floatValue => DbType switch
110120
{
111121
DbType.Single or DbType.Object => YdbValue.MakeFloat(floatValue),
112122
DbType.Double => YdbValue.MakeDouble(floatValue),
113-
_ => ThrowInvalidCast()
123+
_ => ThrowInvalidOperation()
114124
},
115125
double doubleValue when DbType is DbType.Double or DbType.Object => YdbValue.MakeDouble(doubleValue),
116126
int intValue => DbType switch
117127
{
118128
DbType.Int32 or DbType.Object => YdbValue.MakeInt32(intValue),
119129
DbType.Int64 => YdbValue.MakeInt64(intValue),
120-
_ => ThrowInvalidCast()
130+
_ => ThrowInvalidOperation()
121131
},
122132
long longValue when DbType is DbType.Int64 or DbType.Object => YdbValue.MakeInt64(longValue),
123133
decimal decimalValue when DbType is DbType.Decimal or DbType.Currency or DbType.Object =>
@@ -128,7 +138,7 @@ string valueString when DbType is DbType.String or DbType.AnsiString or DbType.A
128138
DbType.UInt32 or DbType.Object => YdbValue.MakeUint32(uintValue),
129139
DbType.UInt64 => YdbValue.MakeUint64(uintValue),
130140
DbType.Int64 => YdbValue.MakeInt64(uintValue),
131-
_ => ThrowInvalidCast()
141+
_ => ThrowInvalidOperation()
132142
},
133143
byte byteValue => DbType switch
134144
{
@@ -139,15 +149,15 @@ string valueString when DbType is DbType.String or DbType.AnsiString or DbType.A
139149
DbType.UInt64 => YdbValue.MakeUint64(byteValue),
140150
DbType.UInt32 => YdbValue.MakeUint32(byteValue),
141151
DbType.UInt16 => YdbValue.MakeUint16(byteValue),
142-
_ => ThrowInvalidCast()
152+
_ => ThrowInvalidOperation()
143153
},
144154
sbyte sbyteValue => DbType switch
145155
{
146156
DbType.SByte or DbType.Object => YdbValue.MakeInt8(sbyteValue),
147157
DbType.Int64 => YdbValue.MakeInt64(sbyteValue),
148158
DbType.Int32 => YdbValue.MakeInt32(sbyteValue),
149159
DbType.Int16 => YdbValue.MakeInt16(sbyteValue),
150-
_ => ThrowInvalidCast()
160+
_ => ThrowInvalidOperation()
151161
},
152162
ushort ushortValue => DbType switch
153163
{
@@ -156,27 +166,29 @@ string valueString when DbType is DbType.String or DbType.AnsiString or DbType.A
156166
DbType.Int32 => YdbValue.MakeInt32(ushortValue),
157167
DbType.UInt64 => YdbValue.MakeUint64(ushortValue),
158168
DbType.UInt32 => YdbValue.MakeUint32(ushortValue),
159-
_ => ThrowInvalidCast()
169+
_ => ThrowInvalidOperation()
160170
},
161171
short shortValue => DbType switch
162172
{
163173
DbType.Int16 or DbType.Object => YdbValue.MakeInt16(shortValue),
164174
DbType.Int64 => YdbValue.MakeInt64(shortValue),
165175
DbType.Int32 => YdbValue.MakeInt32(shortValue),
166-
_ => ThrowInvalidCast()
176+
_ => ThrowInvalidOperation()
167177
},
168178
byte[] bytesValue when DbType is DbType.Binary or DbType.Object => YdbValue.MakeString(bytesValue),
169179
Guid guidValue when DbType is DbType.Guid or DbType.Object => YdbValue.MakeUuid(guidValue),
180+
MemoryStream memoryStream when DbType is DbType.Binary or DbType.Object => YdbValue.MakeString(
181+
memoryStream.ToArray()),
170182
_ when DbType is DbType.VarNumeric or DbType.Xml or DbType.Time =>
171183
throw new YdbException($"Ydb don't supported this DbType: {DbType}"),
172-
_ => ThrowInvalidCast()
184+
_ => ThrowInvalidOperation()
173185
};
174186
}
175187
}
176188

177-
private YdbValue ThrowInvalidCast()
189+
private YdbValue ThrowInvalidOperation()
178190
{
179-
throw new InvalidCastException(
191+
throw new InvalidOperationException(
180192
$"Writing value of '{Value?.GetType().ToString() ?? "null"}' is not supported for parameters having DbType '{DbType}'");
181193
}
182194
}

src/Ydb.Sdk/src/Ado/YdbParameterCollection.cs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,15 +104,15 @@ public bool Remove(YdbParameter item)
104104
}
105105

106106
/// <inheritdoc />
107-
public override int IndexOf(object value)
107+
public override int IndexOf(object? value)
108108
{
109109
return _parameters.IndexOf(Cast(value));
110110
}
111111

112112
/// <inheritdoc />
113113
public override void Insert(int index, object value)
114114
{
115-
_parameters[index] = Cast(value);
115+
_parameters.Insert(index, Cast(value));
116116
}
117117

118118
/// <summary>
@@ -175,6 +175,7 @@ protected override void SetParameter(int index, DbParameter value)
175175
/// <inheritdoc />
176176
protected override void SetParameter(string parameterName, DbParameter value)
177177
{
178+
ArgumentNullException.ThrowIfNull(value);
178179
var index = IndexOf(parameterName);
179180

180181
if (index == -1)
@@ -258,12 +259,9 @@ public override void AddRange(Array values)
258259

259260
private static YdbParameter Cast(object? value)
260261
{
261-
if (value is YdbParameter ydbParameter)
262-
{
263-
return ydbParameter;
264-
}
262+
ArgumentNullException.ThrowIfNull(value);
265263

266-
throw new InvalidCastException(
264+
return value as YdbParameter ?? throw new InvalidCastException(
267265
$"The value \"{value}\" is not of type \"{nameof(YdbParameter)}\" and cannot be used in this parameter collection.");
268266
}
269267
}

0 commit comments

Comments
 (0)