Array translations: chained `Skip`/`Take` return an empty array, `int.MaxValue` bounds overflow, and `Intersect().Any()` ignores NULL elements

Ouverte
#4,098 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Les mainteneurs répondent en général sous 1 jour

Personne n'a encore pris cette issue.

  • #4100 par @CaffeinatedCoder — fermée sans fusion

Évaluation

Difficulté
4/5
Temps estimé
3-5 jours
Accessibilité débutants
30/100
Type d'issue
Bug
Clarté
Clairement spécifiée
Activité
À l'abandon
Stack technique
csharp, postgresql
Domaine
database

Piste de recherche

Start from src/EFCore.PG/Query/Internal/NpgsqlQueryableMethodTranslatingExpressionVisitor.cs, reading lines 1031-1073 (Skip), 1094-1108 (Take), 1544-1547 (bounds) and 665-668 (Intersect). Run the C# repro in the issue to see the three mismatches. Done means generated SQL uses parenthesized slices, checked bounds, and NULL-safe Intersect so database counts match .NET.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

Environment
PostgreSQL 18.6 (postgres:18), session TimeZone Etc/UTC
.NET 10 runtime 10.0.11, Npgsql.EntityFrameworkCore.PostgreSQL 10.0.3, EF Core 10.0.4
.NET 11 runtime 11.0.0-rc.2, Npgsql.EntityFrameworkCore.PostgreSQL 11.0.0-rc.2, EF Core 11.0.0-rc.2
Also Npgsql 10.0.3 on both lines, macOS arm64

Both lines print the same output. main at 150011d has the same code.

LINQ Row .NET PostgreSQL SQL
r.Ints.Take(2).Skip(1).Count() {1,2,3} 1 0 cardinality(r."Ints"[:2][2:])
r.Ints.Skip(int.MaxValue).Count() {1,2,3} 0 3 cardinality(r."Ints"[-2147483648:])
r.A.Intersect(r.B).Any() {1,NULL,3}, {NULL,5} true false r."A" && r."B"
Repro
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

await using var context = new TestContext();
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();

context.Rows.Add(new Row { Ints = [1, 2, 3], A = [1, null, 3], B = [null, 5] });
await context.SaveChangesAsync();
var row = await context.Rows.AsNoTracking().SingleAsync();

// 1. a[:2][2:] is a two-dimensional slice of a one-dimensional array in PostgreSQL
Console.WriteLine($"Ints.Take(2).Skip(1).Count(): .NET {row.Ints.Take(2).Skip(1).Count()}, database {await context.Rows.Select(r => r.Ints.Take(2).Skip(1).Count()).SingleAsync()}");

// 2. int.MaxValue + 1 overflows into the slice bound
Console.WriteLine($"Ints.Skip(int.MaxValue).Count(): .NET {row.Ints.Skip(int.MaxValue).Count()}, database {await context.Rows.Select(r => r.Ints.Skip(int.MaxValue).Count()).SingleAsync()}");

// 3. && never matches NULL elements; Intersect does
Console.WriteLine($"A.Intersect(B).Any() with a NULL in both: .NET {row.A.Intersect(row.B).Any()}, database {await context.Rows.Select(r => r.A.Intersect(r.B).Any()).SingleAsync()}");

public class TestContext : DbContext
{
    public DbSet<Row> Rows => Set<Row>();

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder
            .UseNpgsql(Environment.GetEnvironmentVariable("Test__Npgsql__DefaultConnection"))
            .LogTo(Console.WriteLine, LogLevel.Information)
            .EnableSensitiveDataLogging();
}

public class Row
{
    public int Id { get; set; }
    public int[] Ints { get; set; } = [];
    public int?[] A { get; set; } = [];
    public int?[] B { get; set; } = [];
}

Output, the same on both lines:

Ints.Take(2).Skip(1).Count(): .NET 1, database 0
Ints.Skip(int.MaxValue).Count(): .NET 0, database 3
A.Intersect(B).Any() with a NULL in both: .NET True, database False
Langage dominant
C#
Étoiles
1.8k
Forks
268
Merge moyen
2 h 35 min
PR mergées (30 j)
136

Préparer son environnement

Ce projet ne fournit ni conteneur de développement, ni Dockerfile, ni guide de contribution : l'installation est à votre charge. Commencez par son README, et consultez notre guide de la première contribution pour les étapes générales.

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de npgsql/efcore.pg

Toutes les issues de npgsql/efcore.pg

Issues similaires

Plus d'issues C#

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.