Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CreateAggregate state is shared, breaking multiple use of an aggregate function in the same query #26070

Closed
wzchua opened this issue Sep 16, 2021 · 7 comments · Fixed by #31531
Assignees
Labels
area-adonet-sqlite closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported priority-bug Issues which requires API breaks and have bigger impact hence should be fixed earlier in the release punted-for-7.0 Originally planned for the EF Core 7.0 (EF7) release, but moved out due to resource constraints. Servicing-approved type-bug
Milestone

Comments

@wzchua
Copy link

wzchua commented Sep 16, 2021

using SqliteConnection connection = new SqliteConnection(new SqliteConnectionStringBuilder
{
    DataSource = "A",
    Mode = SqliteOpenMode.Memory
}.ToString());
connection.Open();

using (var command = connection.CreateCommand())
{
    command.CommandText = "CREATE TABLE [test](a, b, c);";
    command.ExecuteNonQuery();

    command.CommandText = "INSERT INTO [test](a, b, c) VALUES(1, 2, 3)";
    command.ExecuteNonQuery();
    command.ExecuteNonQuery();
}
connection.CreateAggregate(
    "testCount",
    new AggClass(),
    (AggClass agg, int number) =>
    {
        agg.Counter++;
        return agg;
    },
    agg => agg.Counter);
using (var command = connection.CreateCommand())
{
    command.CommandText = "SELECT testCount(a), testCount(b), count(a), count(b) FROM [test];";
    using var reader = command.ExecuteReader();
    reader.Read();
    Console.WriteLine((reader.GetInt32(0), reader.GetInt32(1), reader.GetInt32(2), reader.GetInt32(3))); // (4, 4, 2, 2)
}

Microsoft.Data.Sqlite version: 5.0.10
Target framework: (e.g. .NET 5.0) .NET 5.0
Operating system: Windows 10 / MacOS 11.5.2

@ajcvickers
Copy link
Contributor

/cc @bricelam

@bricelam
Copy link
Contributor

bricelam commented Sep 24, 2021

Hmm yes, I agree we're handling the seed parameter (and accumulate argument) incorrectly. We're currently passing it as user data, but as you've found, this is shared across all invocations of the function within a query. Instead, we need to pass it as part of the aggregate context.

We should consider adding a separate way to specify (and access) the user data when we fix this.

@bricelam bricelam self-assigned this Sep 24, 2021
@bricelam
Copy link
Contributor

Invocations in subsequent queries are probably also broken by this.

@bricelam
Copy link
Contributor

It should work correctly if you change AggClass to a struct.

@wzchua
Copy link
Author

wzchua commented Sep 25, 2021

It doesn't work with struct.

as a workaround I'm using something like this

var handle = connection.Handle;
var map = new Dictionary<sqlite3_context, AggClass>();
raw.sqlite3_create_function(handle, "testCount2", 1, map,
    static (ctx, data, values) =>
    {
        var map = (Dictionary<sqlite3_context, AggClass>)data;
        if (!map.TryGetValue(ctx, out AggClass? i))
        {
            i = new AggClass();
            map.Add(ctx, i);
        }

        i.Counter++;
    },
     static(ctx, data) =>
    {
        var map = (Dictionary<sqlite3_context, AggClass>)data;
        if (!map.Remove(ctx, out AggClass? i))
        {
            raw.sqlite3_result_int(ctx, 0);
            return;
        }
        
        raw.sqlite3_result_int(ctx, i.Counter);
    });

@ajcvickers ajcvickers added this to the Backlog milestone Oct 5, 2021
@bricelam bricelam added the priority-bug Issues which requires API breaks and have bigger impact hence should be fixed earlier in the release label Nov 5, 2021
@ajcvickers ajcvickers modified the milestones: Backlog, 7.0.0 Nov 10, 2021
@ajcvickers ajcvickers added punted-for-7.0 Originally planned for the EF Core 7.0 (EF7) release, but moved out due to resource constraints. and removed propose-punt labels Jul 7, 2022
@ajcvickers ajcvickers modified the milestones: 7.0.0, Backlog Jul 7, 2022
@pimbrouwers
Copy link

How can I help here? To me, this is an absolutely critical update. I'm not sure I understand the value of CreateAggregate if it can't be called across multiple columns in the same query easily.

@bricelam
Copy link
Contributor

bricelam commented Apr 4, 2023

@pimbrouwers #26070 (comment) gives a sketch of the solution if you're interested in giving it a go.

@bricelam bricelam modified the milestones: Backlog, 7.0.0 Aug 1, 2023
@bricelam bricelam modified the milestones: Backlog, 8.0.0 Aug 22, 2023
bricelam added a commit to bricelam/efcore that referenced this issue Aug 22, 2023
@bricelam bricelam added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Aug 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-adonet-sqlite closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported priority-bug Issues which requires API breaks and have bigger impact hence should be fixed earlier in the release punted-for-7.0 Originally planned for the EF Core 7.0 (EF7) release, but moved out due to resource constraints. Servicing-approved type-bug
Projects
None yet
4 participants