Array translations: chained `Skip`/`Take` return an empty array, `int.MaxValue` bounds overflow, and `Intersect().Any()` ignores NULL elements
Maintainer antworten meist innerhalb von 1 Tag
Dieses Issue hat noch niemand übernommen.
- #4100 von @CaffeinatedCoder — ohne Merge geschlossen
Bewertung
- Schwierigkeit
- 4/5
- Geschätzter Aufwand
- 3-5 Tage
- Anfängerfreundlichkeit
- 30/100
Rechercherichtung
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.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
| 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
- Chained slices. PostgreSQL reads
a[:2][2:]as a two-dimensional slice of a one-dimensional array, which is empty.(a[:2])[2:]is{2}.TranslateTakemerges into an existing slice (NpgsqlQueryableMethodTranslatingExpressionVisitor.cs#L1094-L1108), butTranslateSkipwraps it (NpgsqlQueryableMethodTranslatingExpressionVisitor.cs#L1031-L1073), and the SQL generator doesn't parenthesize a slice inside a slice. - Overflow. The constant bounds are computed with unchecked
intarithmetic:Convert.ToInt32(constant.Value) + 1(NpgsqlQueryableMethodTranslatingExpressionVisitor.cs#L1544-L1547) andlowerBoundValue + takeCount - 1(NpgsqlQueryableMethodTranslatingExpressionVisitor.cs#L1106). Intersect().Any()becomes&&, which never matches NULL elements. The comment at NpgsqlQueryableMethodTranslatingExpressionVisitor.cs#L665-L668 says that's why it has to be guarded, but column arrays with nullable elements still take the&&path.
- Vorherrschende Sprache
- C#
- Sterne
- 1.8k
- Forks
- 268
- Ø Merge
- 2 Std. 35 Min.
- Gemergte PRs (30 T.)
- 136
Entwicklungsumgebung
Dieses Projekt bietet weder Dev-Container noch Dockerfile noch Beitragsleitfaden – die Einrichtung liegt bei Ihnen. Beginnen Sie mit der README; die allgemeinen Schritte stehen in unserem Leitfaden für den ersten Beitrag.
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus npgsql/efcore.pg
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
Maintainer antworten meist innerhalb von 1 Tag
-
NTS: the M ordinate is dropped from geometry SQL literals and from geometries stored in JSONEvtl. vergeben @Ahmed7991 hat das vor 5 Tagen übernommen. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 85/100
npgsql/efcore.pg#4093 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
`TimeSpan`/`Duration` component members: negative values are floored, and intervals computed in SQL are read field by fieldEvtl. vergeben @jeremy-morren hat das vor 11 Tagen übernommen. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 70/100
Maintainer antworten meist innerhalb von 1 Tag
-
Numeric storage parameters are formatted with the current culture, so migrations emit 0,01 instead of 0.01Evtl. vergeben @Sorbitol hat das vor 12 Tagen übernommen. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 30/100
Maintainer antworten meist innerhalb von 1 Tag
-
`Contains` on a JSON primitive collection compares JSON text, so `DateTime` and `TimeOnly` items never matchEvtl. vergeben @Mr444-dev hat das vor 7 Tagen übernommen. Offen
Schwierigkeit 4/5 3-5 Tage Anfängerfreundlichkeit 45/100
npgsql/efcore.pg#4099 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
Alle Issues in npgsql/efcore.pg
Ähnliche Issues
-
Issue-Bug Needs-Triage
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
Maintainer antworten meist innerhalb von 2 Tagen
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 66/100
JiaFeiMiao-K-Cat/DiscImageStudio#281 ·
Maintainer antworten meist innerhalb von 1 Tag
-
area/access-management Frontend onboarding candidate :handshake:
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 65/100
Altinn/altinn-auth#4941 ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
aws/aws-sdk-net#4586 ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
Kryptos-FR/MarkView.Avalonia#269 · 1 Reaktion ·
Maintainer antworten meist innerhalb von 1 Tag