diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 637eeeb7..61cb173e 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -31,7 +31,7 @@ jobs:
- name: Restore
run: dotnet restore ${{ matrix.source-dir }}${{ matrix.solutionFile }}
- name: Install ReSharper
- run: dotnet tool install -g JetBrains.ReSharper.GlobalTools
+ run: dotnet tool install -g JetBrains.ReSharper.GlobalTools --version 2025.2.1
- name: format all files with auto-formatter
run: bash ./.github/scripts/format-all-dotnet-code.sh ${{ matrix.source-dir }} ${{ matrix.solutionFile }}
- name: Check repository diff
@@ -63,6 +63,7 @@ jobs:
**.cshtml
minimumReportSeverity: WARNING
dotnetVersion: ${{ steps.setup-dotnet.outputs.dotnet-version }}
+ version: 2025.2.1
ignoreIssueType: |
UnusedField.Compiler,
UnusedVariable.Compiler,
diff --git a/src/Ydb.Sdk/CHANGELOG.md b/src/Ydb.Sdk/CHANGELOG.md
index 2d87d8b8..4fbbcd8a 100644
--- a/src/Ydb.Sdk/CHANGELOG.md
+++ b/src/Ydb.Sdk/CHANGELOG.md
@@ -1,3 +1,5 @@
+- Feat ADO.NET: Added YSON type support (YdbDbType.Yson) with byte[] values.
+
## v0.23.0
- Feat ADO.NET: `YdbDataSource.OpenRetryableConnectionAsync` opens a retryable connection with automatic retries for transient failures.
diff --git a/src/Ydb.Sdk/src/Ado/Internal/YdbTypedValueExtensions.cs b/src/Ydb.Sdk/src/Ado/Internal/YdbTypedValueExtensions.cs
index 6f50f078..29bd7271 100644
--- a/src/Ydb.Sdk/src/Ado/Internal/YdbTypedValueExtensions.cs
+++ b/src/Ydb.Sdk/src/Ado/Internal/YdbTypedValueExtensions.cs
@@ -120,6 +120,9 @@ internal static TypedValue Decimal(this decimal value, byte precision, byte scal
internal static TypedValue Bytes(this byte[] value) => MakePrimitiveTypedValue(Type.Types.PrimitiveTypeId.String,
new Ydb.Value { BytesValue = ByteString.CopyFrom(value) });
+ internal static TypedValue Yson(this byte[] value) => MakePrimitiveTypedValue(Type.Types.PrimitiveTypeId.Yson,
+ new Ydb.Value { BytesValue = ByteString.CopyFrom(value) });
+
internal static TypedValue Json(this string value) => MakeText(Type.Types.PrimitiveTypeId.Json, value);
internal static TypedValue JsonDocument(this string value) =>
diff --git a/src/Ydb.Sdk/src/Ado/Internal/YdbValueExtensions.cs b/src/Ydb.Sdk/src/Ado/Internal/YdbValueExtensions.cs
index fc25d821..4694ea00 100644
--- a/src/Ydb.Sdk/src/Ado/Internal/YdbValueExtensions.cs
+++ b/src/Ydb.Sdk/src/Ado/Internal/YdbValueExtensions.cs
@@ -54,6 +54,8 @@ internal static TimeSpan GetInterval64(this Ydb.Value value) =>
internal static byte[] GetBytes(this Ydb.Value value) => value.BytesValue.ToByteArray();
+ internal static byte[] GetYson(this Ydb.Value value) => value.BytesValue.ToByteArray();
+
internal static string GetText(this Ydb.Value value) => value.TextValue;
internal static string GetJson(this Ydb.Value value) => value.TextValue;
diff --git a/src/Ydb.Sdk/src/Ado/YdbDataReader.cs b/src/Ydb.Sdk/src/Ado/YdbDataReader.cs
index fa4a7141..3077ad34 100644
--- a/src/Ydb.Sdk/src/Ado/YdbDataReader.cs
+++ b/src/Ydb.Sdk/src/Ado/YdbDataReader.cs
@@ -96,6 +96,8 @@ public override byte GetByte(int ordinal) =>
public byte[] GetBytes(int ordinal) => GetPrimitiveValue(Type.Types.PrimitiveTypeId.String, ordinal).GetBytes();
+ public byte[] GetYson(int ordinal) => GetPrimitiveValue(Type.Types.PrimitiveTypeId.Yson, ordinal).GetYson();
+
public override long GetBytes(int ordinal, long dataOffset, byte[]? buffer, int bufferOffset, int length)
{
var bytes = GetBytes(ordinal);
@@ -281,6 +283,7 @@ or Type.Types.PrimitiveTypeId.Timestamp
or Type.Types.PrimitiveTypeId.JsonDocument
or Type.Types.PrimitiveTypeId.Json => typeof(string),
Type.Types.PrimitiveTypeId.String => typeof(byte[]),
+ Type.Types.PrimitiveTypeId.Yson => typeof(byte[]),
Type.Types.PrimitiveTypeId.Uuid => typeof(Guid),
_ => throw new YdbException($"Unsupported ydb type {type}")
};
@@ -440,6 +443,7 @@ public override object GetValue(int ordinal)
Type.Types.PrimitiveTypeId.Utf8 => ydbValue.GetText(),
Type.Types.PrimitiveTypeId.Json => ydbValue.GetJson(),
Type.Types.PrimitiveTypeId.JsonDocument => ydbValue.GetJsonDocument(),
+ Type.Types.PrimitiveTypeId.Yson => ydbValue.GetYson(),
Type.Types.PrimitiveTypeId.String => ydbValue.GetBytes(),
Type.Types.PrimitiveTypeId.Uuid => ydbValue.GetUuid(),
_ => throw new YdbException($"Unsupported ydb type {GetColumnType(ordinal)}")
@@ -707,7 +711,7 @@ private class Metadata : IMetadata
public Metadata(ResultSet resultSet)
{
Columns = resultSet.Columns;
- ColumnNameToOrdinal = ColumnNameToOrdinal = Columns
+ ColumnNameToOrdinal = Columns
.Select((c, idx) => (c.Name, Index: idx))
.ToDictionary(t => t.Name, t => t.Index);
RowsCount = resultSet.Rows.Count;
diff --git a/src/Ydb.Sdk/src/Ado/YdbParameter.cs b/src/Ydb.Sdk/src/Ado/YdbParameter.cs
index 2d4ac898..f7e55d29 100644
--- a/src/Ydb.Sdk/src/Ado/YdbParameter.cs
+++ b/src/Ydb.Sdk/src/Ado/YdbParameter.cs
@@ -33,6 +33,7 @@ public sealed class YdbParameter : DbParameter
{ YdbDbType.Float, Type.Types.PrimitiveTypeId.Float.Null() },
{ YdbDbType.Double, Type.Types.PrimitiveTypeId.Double.Null() },
{ YdbDbType.Uuid, Type.Types.PrimitiveTypeId.Uuid.Null() },
+ { YdbDbType.Yson, Type.Types.PrimitiveTypeId.Yson.Null() },
{ YdbDbType.Json, Type.Types.PrimitiveTypeId.Json.Null() },
{ YdbDbType.JsonDocument, Type.Types.PrimitiveTypeId.JsonDocument.Null() },
{ YdbDbType.Date32, Type.Types.PrimitiveTypeId.Date32.Null() },
@@ -155,6 +156,7 @@ internal TypedValue TypedValue
YdbDbType.Double => MakeDouble(value),
YdbDbType.Decimal when value is decimal decimalValue => Decimal(decimalValue),
YdbDbType.Bytes => MakeBytes(value),
+ YdbDbType.Yson => MakeYson(value),
YdbDbType.Json when value is string stringValue => stringValue.Json(),
YdbDbType.JsonDocument when value is string stringValue => stringValue.JsonDocument(),
YdbDbType.Uuid when value is Guid guidValue => guidValue.Uuid(),
@@ -240,6 +242,13 @@ internal TypedValue TypedValue
_ => throw ValueTypeNotSupportedException
};
+ private TypedValue MakeYson(object value) => value switch
+ {
+ byte[] bytesValue => bytesValue.Yson(),
+ MemoryStream memoryStream => memoryStream.ToArray().Yson(),
+ _ => throw ValueTypeNotSupportedException
+ };
+
private TypedValue MakeDate(object value) => value switch
{
DateTime dateTimeValue => dateTimeValue.Date(),
diff --git a/src/Ydb.Sdk/src/Ado/YdbType/YdbDbType.cs b/src/Ydb.Sdk/src/Ado/YdbType/YdbDbType.cs
index 8a4306b1..6633c00e 100644
--- a/src/Ydb.Sdk/src/Ado/YdbType/YdbDbType.cs
+++ b/src/Ydb.Sdk/src/Ado/YdbType/YdbDbType.cs
@@ -105,6 +105,14 @@ public enum YdbDbType
///
Text,
+ ///
+ /// YSON in binary form (passed/returned as byte[]).
+ ///
+ ///
+ /// Can't be used in the primary key.
+ ///
+ Yson,
+
///
/// JSON represented as text.
///
diff --git a/src/Ydb.Sdk/test/Ydb.Sdk.Ado.Tests/YdbParameterTests.cs b/src/Ydb.Sdk/test/Ydb.Sdk.Ado.Tests/YdbParameterTests.cs
index 51252b73..baa139e4 100644
--- a/src/Ydb.Sdk/test/Ydb.Sdk.Ado.Tests/YdbParameterTests.cs
+++ b/src/Ydb.Sdk/test/Ydb.Sdk.Ado.Tests/YdbParameterTests.cs
@@ -343,6 +343,7 @@ CustomDecimalColumn Decimal(35, 5) NOT NULL,
IntervalColumn Interval NOT NULL,
JsonColumn Json NOT NULL,
JsonDocumentColumn JsonDocument NOT NULL,
+ YsonColumn Yson NOT NULL,
Date32Column Date32 NOT NULL,
Datetime64Column DateTime64 NOT NULL,
Timestamp64Column Timestamp64 NOT NULL,
@@ -359,13 +360,13 @@ PRIMARY KEY (Int32Column)
Int32Column, BoolColumn, Int64Column, Int16Column, Int8Column, FloatColumn, DoubleColumn,
DefaultDecimalColumn, CustomDecimalColumn, Uint8Column, Uint16Column, Uint32Column,
Uint64Column, TextColumn, BytesColumn, DateColumn, DatetimeColumn, TimestampColumn,
- IntervalColumn, JsonColumn, JsonDocumentColumn, Date32Column, Datetime64Column,
+ IntervalColumn, JsonColumn, JsonDocumentColumn, YsonColumn, Date32Column, Datetime64Column,
Timestamp64Column, Interval64Column
) VALUES (
@Int32Column, @BoolColumn, @Int64Column, @Int16Column, @Int8Column, @FloatColumn,
@DoubleColumn, @DefaultDecimalColumn, @CustomDecimalColumn, @Uint8Column, @Uint16Column,
@Uint32Column, @Uint64Column, @TextColumn, @BytesColumn, @DateColumn, @DatetimeColumn,
- @TimestampColumn, @IntervalColumn, @JsonColumn, @JsonDocumentColumn, @Date32Column,
+ @TimestampColumn, @IntervalColumn, @JsonColumn, @JsonDocumentColumn, @YsonColumn, @Date32Column,
@Datetime64Column, @Timestamp64Column, @Interval64Column
);
""",
@@ -392,6 +393,7 @@ PRIMARY KEY (Int32Column)
new YdbParameter("IntervalColumn", YdbDbType.Interval, TimeSpan.Zero),
new YdbParameter("JsonColumn", YdbDbType.Json, "{}"),
new YdbParameter("JsonDocumentColumn", YdbDbType.JsonDocument, "{}"),
+ new YdbParameter("YsonColumn", YdbDbType.Yson, "{a=1u}"u8.ToArray()),
new YdbParameter("Date32Column", YdbDbType.Date32, DateTime.MinValue),
new YdbParameter("Datetime64Column", YdbDbType.Datetime64, DateTime.MinValue),
new YdbParameter("Timestamp64Column", YdbDbType.Timestamp64, DateTime.MinValue),
@@ -407,7 +409,7 @@ PRIMARY KEY (Int32Column)
Int32Column, BoolColumn, Int64Column, Int16Column, Int8Column, FloatColumn, DoubleColumn,
DefaultDecimalColumn, CustomDecimalColumn, Uint8Column, Uint16Column, Uint32Column,
Uint64Column, TextColumn, BytesColumn, DateColumn, DatetimeColumn, TimestampColumn,
- IntervalColumn, JsonColumn, JsonDocumentColumn, Date32Column, Datetime64Column,
+ IntervalColumn, JsonColumn, JsonDocumentColumn, YsonColumn, Date32Column, Datetime64Column,
Timestamp64Column, Interval64Column
FROM {tableName};
"""
@@ -435,10 +437,11 @@ PRIMARY KEY (Int32Column)
Assert.Equal(TimeSpan.Zero, ydbDataReader.GetInterval(18));
Assert.Equal("{}", ydbDataReader.GetJson(19));
Assert.Equal("{}", ydbDataReader.GetJsonDocument(20));
- Assert.Equal(DateTime.MinValue, ydbDataReader.GetDateTime(21));
+ Assert.Equal("{a=1u}"u8.ToArray(), ydbDataReader.GetYson(21));
Assert.Equal(DateTime.MinValue, ydbDataReader.GetDateTime(22));
Assert.Equal(DateTime.MinValue, ydbDataReader.GetDateTime(23));
- Assert.Equal(TimeSpan.FromMilliseconds(TimeSpan.MinValue.Milliseconds), ydbDataReader.GetInterval(24));
+ Assert.Equal(DateTime.MinValue, ydbDataReader.GetDateTime(24));
+ Assert.Equal(TimeSpan.FromMilliseconds(TimeSpan.MinValue.Milliseconds), ydbDataReader.GetInterval(25));
Assert.False(ydbDataReader.Read());
await ydbDataReader.CloseAsync();
diff --git a/src/Ydb.Sdk/test/Ydb.Sdk.Ado.Tests/YdbSchemaTests.cs b/src/Ydb.Sdk/test/Ydb.Sdk.Ado.Tests/YdbSchemaTests.cs
index fb46acb8..1145a84e 100644
--- a/src/Ydb.Sdk/test/Ydb.Sdk.Ado.Tests/YdbSchemaTests.cs
+++ b/src/Ydb.Sdk/test/Ydb.Sdk.Ado.Tests/YdbSchemaTests.cs
@@ -176,8 +176,8 @@ public async Task GetSchema_WhenAllTypesTable_ReturnAllTypes()
var dataTable = await ydbConnection.GetSchemaAsync("Columns", [_allTypesTable, null]);
var dataTableNullable = await ydbConnection.GetSchemaAsync("Columns", [_allTypesTableNullable, null]);
- Assert.Equal(17, dataTable.Rows.Count);
- Assert.Equal(17, dataTableNullable.Rows.Count);
+ Assert.Equal(18, dataTable.Rows.Count);
+ Assert.Equal(18, dataTableNullable.Rows.Count);
CheckAllColumns(dataTable, false);
CheckAllColumns(dataTableNullable, true);
@@ -202,6 +202,7 @@ void CheckAllColumns(DataTable pDataTable, bool isNullableTable)
CheckColumn(pDataTable.Rows[14], "DateColumn", 14, isNullableTable);
CheckColumn(pDataTable.Rows[15], "DatetimeColumn", 15, isNullableTable);
CheckColumn(pDataTable.Rows[16], "TimestampColumn", 16, isNullableTable);
+ CheckColumn(pDataTable.Rows[17], "YsonColumn", 17, isNullableTable, "Yson");
}
void CheckColumn(DataRow column, string columnName, int ordinal, bool isNullable, string? dataType = null)
@@ -243,6 +244,7 @@ DefaultDecimalColumn Decimal(22,9) NOT NULL,
DateColumn Date NOT NULL,
DatetimeColumn Datetime NOT NULL,
TimestampColumn Timestamp NOT NULL,
+ YsonColumn Yson NOT NULL,
PRIMARY KEY (Int32Column)
);
@@ -264,6 +266,7 @@ DefaultDecimalColumn Decimal(22,9),
DateColumn Date,
DatetimeColumn Datetime,
TimestampColumn Timestamp,
+ YsonColumn Yson,
PRIMARY KEY (Int32Column)
);
"""