Skip to content

GetFieldType() does not Return SqlVector<float> #4104

@rhuijben

Description

@rhuijben

Describe the bug

SqlDataReader.GetFieldType() does not properly identify a VECTOR(3) field as vector, while .GetValue() and others
do the proper identification.

To reproduce

Based on original Vector usage sample this code triggers the issue with a set of assertions

class Vectors
{
    public int Id { get; set; }
    public SqlVector<float> VectorData { get; set; }
}

using var connection = new SqlConnection("...");
connection.Open();

var vectorDimensionCount = 3;

using (var command = connection.CreateCommand())
{
    command.CommandText = $@" IF OBJECT_ID('{nameof(Vectors)}', 'U') IS NOT NULL DROP TABLE {nameof(Vectors)};";
    command.ExecuteNonQuery();
}

using (var command = connection.CreateCommand())
{
    command.CommandText = $@"
        CREATE TABLE {nameof(Vectors)} (
            Id INT IDENTITY(1,1) PRIMARY KEY,
            VectorData VECTOR({vectorDimensionCount})
        );";
    command.ExecuteNonQuery();
}

// Raw insert, from Microsoft sample code
using (var command = connection.CreateCommand())
{
    command.CommandText = $@"INSERT INTO {nameof(Vectors)} (VectorData) VALUES (@VectorData)";
    var param = command.Parameters.Add("@VectorData", SqlDbTypeExtensions.Vector);

    // Insert non-null vector
    param.Value = new SqlVector<float>(new float[] { 3.14159f, 1.61803f, 1.41421f });
    command.ExecuteNonQuery();
}

using (var command = connection.CreateCommand())
{
    command.CommandText = $@"SELECT Id, VectorData FROM {nameof(Vectors)}";
    using var reader = command.ExecuteReader();

    Assert.AreEqual(typeof(int), reader.GetFieldType(0));
    // Assert.AreEqual(typeof(SqlVector<float>), reader.GetFieldType(1)); // This should be the check
    Assert.AreEqual(typeof(byte[]), reader.GetFieldType(1)); // This should return SqlVector<float>, but currently returns byte[] due to a bug in SqlClient

    while (reader.Read())
    {
        var value = reader.GetValue(1);

        Assert.IsInstanceOfType<SqlVector<float>>(value); // This succeeds, so the library is correctly identifying the type as SqlVector<float> and returning it as such, but the GetFieldType method is incorrectly reporting it as byte[] due to a bug in SqlClient

        var id = reader.GetFieldValue<int>(0);
        var dt = reader.GetFieldValue<SqlVector<float>>(1);

        Assert.ThrowsExactly<InvalidCastException>(() => reader.GetFieldValue<byte[]>(1));


        var dt2 = reader.GetSqlVector<float>(1);
    }
}

This sample passes with 7.0.0 on SqlServer 2025

Expected behavior

The GetFieldType call returns a type with which the value is not retrievable. It should return the right type, or at least a type with which the value is retrievable. (Returning typeof(object) is better than typeof(byte[]).

Given that the .GetValue(1) does the right thing, I think it should just return typeof(SqlVector<float>)

Further technical details

Tested with SqlServer 2025 (linux docker) on .Net 10 (=RepoDB test environment), but it looks like it is reproducable on many more configurations

Metadata

Metadata

Labels

Area\VectorUse this for issues that are targeted for the Vector feature in the driver.

Type

Projects

Status

In review

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions