Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ public static class DataTestUtility
// SQL Server capabilities
private static bool? s_isDataClassificationSupported;
private static bool? s_isVectorSupported;
private static bool? s_isVectorFloat16Supported;

// Azure Synapse EngineEditionId == 6
// More could be read at https://learn.microsoft.com/en-us/sql/t-sql/functions/serverproperty-transact-sql?view=sql-server-ver16#propertyname
Expand Down Expand Up @@ -156,6 +157,68 @@ public static string SQLServerVersion
s_isVectorSupported ??= IsTCPConnStringSetup() &&
IsTypePresent("vector");

/// <summary>
/// Determines whether the SQL Server supports the 'float16' base type for the 'vector' data type.
/// </summary>
/// <remarks>
/// Probes the server by first executing
/// <c>ALTER DATABASE SCOPED CONFIGURATION SET PREVIEW_FEATURES = ON;</c> and then executing
/// <c>DECLARE @v AS VECTOR(5, float16) = '[1.0, 1.0, 1.0, 1.0, 1.0]'; SELECT @v;</c>.
/// As a side effect, this enables preview features for the current database. If the server does not
/// recognize <c>float16</c> as a vector base type, if the server does not support the required syntax,
/// if the current principal lacks permission to change the database scoped configuration, or if another
/// server-side error occurs while running the probe, this method returns
/// <see langword="false"/>. Implies <see cref="IsSqlVectorSupported"/>.
/// </remarks>
/// <returns><see langword="true"/> if the 'float16' vector base type is supported; otherwise, <see langword="false"/>.</returns>
public static bool IsSqlVectorFloat16Supported =>
s_isVectorFloat16Supported ??= IsTCPConnStringSetup() &&
IsSqlVectorSupported &&
CheckVectorFloat16Supported();

private static bool CheckVectorFloat16Supported()
{
try
{
using SqlConnection connection = new(TCPConnectionString);
// Enable preview features (required while float16 is in preview), then declare a
// float16 vector and select it back. Without a negotiated float16 feature extension,
// the server returns the value as a varchar(max) JSON string, which the client can
// safely read. We use 1.0 (exactly representable in IEEE-754 binary16) so the
// round-tripped JSON matches the input bit-for-bit. Any failure (server parse
// error such as Msg 195 "'float16' is not a recognized vector base type.", lack of
// permission to set PREVIEW_FEATURES, etc.) means we cannot exercise the float16
// path.
float[] expected = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
using SqlCommand command = new(
"ALTER DATABASE SCOPED CONFIGURATION SET PREVIEW_FEATURES = ON;" +
"DECLARE @v AS VECTOR(5, float16) = '[1.0, 1.0, 1.0, 1.0, 1.0]'; SELECT @v;",
connection);
connection.Open();
using SqlDataReader reader = command.ExecuteReader();
if (!reader.Read())
{
return false;
}
string json = reader.GetString(0);
float[] actual = System.Text.Json.JsonSerializer.Deserialize<float[]>(json);
return actual != null && actual.Length == expected.Length
&& actual.AsSpan().SequenceEqual(expected);
}
catch (SqlException)
{
// Server-side failure (e.g. Msg 195 "'float16' is not a recognized vector base
// type.", Msg 102 syntax errors on older servers, lack of permission to set
// PREVIEW_FEATURES) — float16 path is unavailable.
return false;
}
catch (System.Text.Json.JsonException)
{
// Server returned a payload we can't parse as a float[] JSON array.
return false;
}
}

static DataTestUtility()
{
Config c = Config.Load();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,10 @@
<Compile Include="SQL\UdtTest\UdtTest2.cs" />
<Compile Include="SQL\UdtTest\UdtTestHelpers.cs" />
<Compile Include="SQL\Utf8SupportTest\Utf8SupportTest.cs" />
<Compile Include="SQL\VectorTest\Float16VectorTypeBackwardCompatibilityTests.cs" />
<Compile Include="SQL\VectorTest\NativeVectorFloat32Tests.cs" />
<Compile Include="SQL\VectorTest\VectorAPIValidationTest.cs" />
<Compile Include="SQL\VectorTest\VectorBackwardCompatTestBase.cs" />
<Compile Include="SQL\VectorTest\VectorTypeBackwardCompatibilityTests.cs" />
<Compile Include="SQL\WeakRefTest\WeakRefTest.cs" />
<Compile Include="SQL\WeakRefTestYukonSpecific\WeakRefTestYukonSpecific.cs" />
Expand Down
Comment thread
apoorvdeshmukh marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Collections.Generic;
using System.Text.Json;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;

namespace Microsoft.Data.SqlClient.ManualTesting.Tests.SQL.VectorTest
{
/// <summary>
/// Provides parameterized test data for backward compatibility tests that exchange
/// float16 vector data as varchar(max) JSON strings.
/// </summary>
public static class Float16VarcharVectorTestData
{
// Values chosen to be exactly representable in IEEE-754 binary16 (float16),
// so JSON round-trips through a vector(N, float16) column without precision loss.
public static readonly float[] TestData = { 1.0f, 2.0f, 3.0f };

/// <summary>
/// Generates test cases for all 4 SqlParameter construction patterns x 2 value types (non-null + null).
/// Each case yields: [int pattern, string jsonOrNull, float[] expectedData]
/// where jsonOrNull is null when testing DBNull insertion.
/// </summary>
public static IEnumerable<object[]> GetVarcharVectorInsertTestData()
{
string json = JsonSerializer.Serialize(TestData);

// Pattern 1-4 with non-null JSON value
yield return new object[] { 1, json, TestData };
yield return new object[] { 2, json, TestData };
yield return new object[] { 3, json, TestData };
yield return new object[] { 4, json, TestData };

// Pattern 1-4 with null value
yield return new object[] { 1, null, null };
yield return new object[] { 2, null, null };
yield return new object[] { 3, null, null };
yield return new object[] { 4, null, null };
}
}

public sealed class Float16VectorTypeBackwardCompatibilityTests : VectorBackwardCompatTestBase
{
public Float16VectorTypeBackwardCompatibilityTests(ITestOutputHelper output)
: base(output, columnDefinition: "vector(3, float16)", namePrefix: "VectorF16")
{
}

protected override float[] GetPrepareTestValues(int i) =>
new float[] { i + 1, i + 2, i + 3 };

#region Insert Tests

[ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsSqlVectorFloat16Supported))]
[MemberData(nameof(Float16VarcharVectorTestData.GetVarcharVectorInsertTestData), MemberType = typeof(Float16VarcharVectorTestData), DisableDiscoveryEnumeration = true)]
public void TestVectorDataInsertionAsVarchar(int pattern, string jsonValue, float[] expectedData)
=> InsertAndValidateAsVarchar(pattern, jsonValue, expectedData);

[ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsSqlVectorFloat16Supported))]
[MemberData(nameof(Float16VarcharVectorTestData.GetVarcharVectorInsertTestData), MemberType = typeof(Float16VarcharVectorTestData), DisableDiscoveryEnumeration = true)]
public async Task TestVectorDataInsertionAsVarcharAsync(int pattern, string jsonValue, float[] expectedData)
=> await InsertAndValidateAsVarcharAsync(pattern, jsonValue, expectedData);

#endregion

#region Stored Procedure Tests

[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsSqlVectorFloat16Supported))]
public void TestStoredProcParamsForVectorAsVarchar()
=> StoredProcRoundTrip(Float16VarcharVectorTestData.TestData);

[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsSqlVectorFloat16Supported))]
public async Task TestStoredProcParamsForVectorAsVarcharAsync()
=> await StoredProcRoundTripAsync(Float16VarcharVectorTestData.TestData);

#endregion

#region Bulk Copy Tests

[ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsSqlVectorFloat16Supported))]
[InlineData(1)]
[InlineData(2)]
public void TestSqlBulkCopyForVectorAsVarchar(int bulkCopySourceMode)
=> BulkCopyRoundTrip(bulkCopySourceMode, Float16VarcharVectorTestData.TestData);

[ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsSqlVectorFloat16Supported))]
[InlineData(1)]
[InlineData(2)]
public async Task TestSqlBulkCopyForVectorAsVarcharAsync(int bulkCopySourceMode)
=> await BulkCopyRoundTripAsync(bulkCopySourceMode, Float16VarcharVectorTestData.TestData);

#endregion

#region Prepared Statement Tests

[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsSqlVectorFloat16Supported))]
public void TestInsertVectorsAsVarcharWithPrepare()
=> PreparedInsertRoundTrip();

#endregion
}
}
Loading
Loading