Skip to content

Commit 06fd951

Browse files
authored
Merge release/8.0-staging to release/8.0 (#37305)
Merge release/8.0-staging to release/8.0
2 parents 64eaa48 + 0f6eb92 commit 06fd951

File tree

8 files changed

+218
-18
lines changed

8 files changed

+218
-18
lines changed

azure-pipelines-public.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ stages:
176176
- job: macOS
177177
enablePublishTestResults: true
178178
pool:
179-
vmImage: macOS-13
179+
vmImage: macOS-15
180180
variables:
181181
# Rely on task Arcade injects, not auto-injected build step.
182182
- skipComponentGovernanceDetection: true
@@ -269,7 +269,7 @@ stages:
269269
value: $(_BuildConfig)
270270
- ${{ if eq(variables['System.TeamProject'], 'public') }}:
271271
- name: HelixTargetQueues
272-
value: Windows.10.Amd64.Open;OSX.13.Amd64.Open;OSX.13.ARM64.Open;[email protected]/dotnet-buildtools/prereqs:ubuntu-20.04-helix-sqlserver-amd64
272+
value: Windows.10.Amd64.Open;OSX.15.Amd64.Open;OSX.15.ARM64.Open;[email protected]/dotnet-buildtools/prereqs:ubuntu-20.04-helix-sqlserver-amd64
273273
- name: _HelixAccessToken
274274
value: '' # Needed for public queues
275275
- ${{ if ne(variables['System.TeamProject'], 'public') }}:

azure-pipelines.yml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ extends:
4747
parameters:
4848
featureFlags:
4949
autoBaseline: false
50+
usePrefastVersion3: true
5051
autoEnableRoslynWithNewRuleset: false
52+
binskimScanAllExtensions: true
5153
sdl:
5254
sourceAnalysisPool:
5355
name: NetCore1ESPool-Svc-Internal
@@ -57,6 +59,8 @@ extends:
5759
baselineFile: $(Build.SourcesDirectory)\.config\guardian\.gdnbaselines
5860
binskim:
5961
scanOutputDirectoryOnly: true
62+
analyzeTargetGlob: +:f|**/Microsoft.EntityFrameworkCore*.dll;+:f|**/Microsoft.Data.Sqlite*.dll;+:f|**/ef.exe;+:f|**/dotnet-ef.exe;-:f|**/shims/**/*.exe;
63+
preReleaseVersion: '4.3.1'
6064
customBuildTags:
6165
- ES365AIMigrationTooling
6266
stages:
@@ -131,7 +135,7 @@ extends:
131135
- job: macOS
132136
pool:
133137
name: Azure Pipelines
134-
image: macOS-13
138+
image: macOS-15
135139
os: macOS
136140
variables:
137141
# Rely on task Arcade injects, not auto-injected build step.
@@ -152,6 +156,9 @@ extends:
152156
COMPlus_EnableWriteXorExecute: 0
153157
displayName: Build
154158
templateContext:
159+
sdl:
160+
binskim:
161+
prereleaseVersion: ' '
155162
outputs:
156163
- output: pipelineArtifact
157164
displayName: Upload TestResults
@@ -190,6 +197,9 @@ extends:
190197
- script: eng/common/cibuild.sh --configuration $(_BuildConfig) --prepareMachine $(_InternalRuntimeDownloadArgs)
191198
displayName: Build
192199
templateContext:
200+
sdl:
201+
binskim:
202+
prereleaseVersion: ' '
193203
outputs:
194204
- output: pipelineArtifact
195205
displayName: Upload TestResults

src/EFCore/Query/Internal/ParameterExtractingExpressionVisitor.cs

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ public class ParameterExtractingExpressionVisitor : ExpressionVisitor
3434
private static readonly bool UseOldBehavior35100 =
3535
AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue35100", out var enabled35100) && enabled35100;
3636

37+
private static readonly bool UseOldBehavior37176 =
38+
AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue37176", out var enabled37176) && enabled37176;
39+
3740
/// <summary>
3841
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
3942
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
@@ -210,15 +213,32 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp
210213
switch (method.Name)
211214
{
212215
case nameof(MemoryExtensions.Contains)
213-
when methodCallExpression.Arguments is [var arg0, var arg1] &&
214-
TryUnwrapSpanImplicitCast(arg0, out var unwrappedArg0):
216+
when UseOldBehavior37176
217+
&& methodCallExpression.Arguments is [var arg0, var arg1]
218+
&& TryUnwrapSpanImplicitCast(arg0, out var unwrappedArg0):
215219
{
216220
return Visit(
217221
Expression.Call(
218222
EnumerableMethods.Contains.MakeGenericMethod(method.GetGenericArguments()[0]),
219223
unwrappedArg0, arg1));
220224
}
221225

226+
// In .NET 10, MemoryExtensions.Contains has an overload that accepts a third, optional comparer, in addition to the older
227+
// overload that accepts two parameters only.
228+
case nameof(MemoryExtensions.Contains)
229+
when !UseOldBehavior37176
230+
&& methodCallExpression.Arguments is [var spanArg, var valueArg, ..]
231+
&& (methodCallExpression.Arguments.Count is 2
232+
|| methodCallExpression.Arguments.Count is 3
233+
&& methodCallExpression.Arguments[2] is ConstantExpression { Value: null })
234+
&& TryUnwrapSpanImplicitCast(spanArg, out var unwrappedSpanArg):
235+
{
236+
return Visit(
237+
Expression.Call(
238+
EnumerableMethods.Contains.MakeGenericMethod(method.GetGenericArguments()[0]),
239+
unwrappedSpanArg, valueArg));
240+
}
241+
222242
case nameof(MemoryExtensions.SequenceEqual)
223243
when methodCallExpression.Arguments is [var arg0, var arg1]
224244
&& TryUnwrapSpanImplicitCast(arg0, out var unwrappedArg0)
@@ -231,20 +251,37 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp
231251

232252
static bool TryUnwrapSpanImplicitCast(Expression expression, [NotNullWhen(true)] out Expression? result)
233253
{
234-
if (expression is MethodCallExpression
254+
switch (expression)
255+
{
256+
// With newer versions of the SDK, the implicit cast is represented as a MethodCallExpression;
257+
// with older versions, it's a Convert node.
258+
case MethodCallExpression
235259
{
236260
Method: { Name: "op_Implicit", DeclaringType: { IsGenericType: true } implicitCastDeclaringType },
237261
Arguments: [var unwrapped]
262+
} when implicitCastDeclaringType.GetGenericTypeDefinition() is var genericTypeDefinition
263+
&& (genericTypeDefinition == typeof(Span<>) || genericTypeDefinition == typeof(ReadOnlySpan<>)):
264+
{
265+
result = unwrapped;
266+
return true;
238267
}
239-
&& implicitCastDeclaringType.GetGenericTypeDefinition() is var genericTypeDefinition
240-
&& (genericTypeDefinition == typeof(Span<>) || genericTypeDefinition == typeof(ReadOnlySpan<>)))
241-
{
242-
result = unwrapped;
243-
return true;
244-
}
245268

246-
result = null;
247-
return false;
269+
case UnaryExpression
270+
{
271+
NodeType: ExpressionType.Convert,
272+
Operand: var unwrapped,
273+
Type: { IsGenericType: true } convertType
274+
} when !UseOldBehavior37176 && convertType.GetGenericTypeDefinition() is var genericTypeDefinition
275+
&& (genericTypeDefinition == typeof(Span<>) || genericTypeDefinition == typeof(ReadOnlySpan<>)):
276+
{
277+
result = unwrapped;
278+
return true;
279+
}
280+
281+
default:
282+
result = null;
283+
return false;
284+
}
248285
}
249286
}
250287

src/Microsoft.Data.Sqlite.Core/SqliteBlob.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,12 @@ public virtual int Read(Span<byte> buffer)
206206
count = (int)(Length - position);
207207
}
208208

209-
var rc = sqlite3_blob_read(_blob, buffer.Slice(0, count), (int)position);
210-
SqliteException.ThrowExceptionForRC(rc, _connection.Handle);
209+
// Newer sqlite3_blob_read returns error for 0-byte reads.
210+
if (count > 0)
211+
{
212+
var rc = sqlite3_blob_read(_blob, buffer.Slice(0, count), (int)position);
213+
SqliteException.ThrowExceptionForRC(rc, _connection.Handle);
214+
}
211215
_position += count;
212216
return count;
213217
}
@@ -280,8 +284,12 @@ public virtual void Write(ReadOnlySpan<byte> buffer)
280284
throw new NotSupportedException(Resources.ResizeNotSupported);
281285
}
282286

283-
var rc = sqlite3_blob_write(_blob, buffer.Slice(0, count), (int)position);
284-
SqliteException.ThrowExceptionForRC(rc, _connection.Handle);
287+
// Newer sqlite3_blob_write returns error for 0-byte writes.
288+
if (count > 0)
289+
{
290+
var rc = sqlite3_blob_write(_blob, buffer.Slice(0, count), (int)position);
291+
SqliteException.ThrowExceptionForRC(rc, _connection.Handle);
292+
}
285293
_position += count;
286294
}
287295

test/EFCore.Specification.Tests/Query/PrimitiveCollectionsQueryTestBase.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,34 @@ public virtual Task Column_collection_of_bools_Contains(bool async)
371371
async,
372372
ss => ss.Set<PrimitiveCollectionsEntity>().Where(c => c.Bools.Contains(true)));
373373

374+
// C# 14 first-class spans caused MemoryExtensions.Contains to get resolved instead of Enumerable.Contains.
375+
// The following tests that the various overloads are all supported.
376+
[ConditionalTheory]
377+
[MemberData(nameof(IsAsyncData))]
378+
public virtual Task Contains_on_Enumerable(bool async)
379+
=> AssertQuery(
380+
async,
381+
ss => ss.Set<PrimitiveCollectionsEntity>().Where(c => Enumerable.Contains(new[] { 10, 999 }, c.Int)));
382+
383+
// C# 14 first-class spans caused MemoryExtensions.Contains to get resolved instead of Enumerable.Contains.
384+
// The following tests that the various overloads are all supported.
385+
[ConditionalTheory]
386+
[MemberData(nameof(IsAsyncData))]
387+
public virtual Task Contains_on_MemoryExtensions(bool async)
388+
=> AssertQuery(
389+
async,
390+
ss => ss.Set<PrimitiveCollectionsEntity>().Where(c => MemoryExtensions.Contains(new[] { 10, 999 }, c.Int)));
391+
392+
// Note that we don't test EF 8/9 with .NET 10; this test is here for completeness/documentation purposes.
393+
#if NET10_0_OR_GREATER
394+
[ConditionalTheory]
395+
[MemberData(nameof(IsAsyncData))]
396+
public virtual Task Contains_with_MemoryExtensions_with_null_comparer(bool async)
397+
=> AssertQuery(
398+
async,
399+
ss => ss.Set<PrimitiveCollectionsEntity>().Where(c => MemoryExtensions.Contains(new[] { 10, 999 }, c.Int, comparer: null)));
400+
#endif
401+
374402
[ConditionalTheory]
375403
[MemberData(nameof(IsAsyncData))]
376404
public virtual Task Column_collection_Count_method(bool async)

test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQueryOldSqlServerTest.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,45 @@ await context.Database.SqlQuery<string>($"SELECT [Bools] AS [Value] FROM [Primit
462462
.SingleAsync());
463463
}
464464

465+
public override async Task Contains_on_Enumerable(bool async)
466+
{
467+
await base.Contains_on_Enumerable(async);
468+
469+
AssertSql(
470+
"""
471+
SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings]
472+
FROM [PrimitiveCollectionsEntity] AS [p]
473+
WHERE [p].[Int] IN (10, 999)
474+
""");
475+
}
476+
477+
478+
public override async Task Contains_on_MemoryExtensions(bool async)
479+
{
480+
await base.Contains_on_MemoryExtensions(async);
481+
482+
AssertSql(
483+
"""
484+
SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings]
485+
FROM [PrimitiveCollectionsEntity] AS [p]
486+
WHERE [p].[Int] IN (10, 999)
487+
""");
488+
}
489+
490+
#if NET10_0_OR_GREATER
491+
public override async Task Contains_with_MemoryExtensions_with_null_comparer(bool async)
492+
{
493+
await base.Contains_with_MemoryExtensions_with_null_comparer(async);
494+
495+
AssertSql(
496+
"""
497+
SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings]
498+
FROM [PrimitiveCollectionsEntity] AS [p]
499+
WHERE [p].[Int] IN (10, 999)
500+
""");
501+
}
502+
#endif
503+
465504
public override Task Column_collection_Count_method(bool async)
466505
=> AssertCompatibilityLevelTooLow(() => base.Column_collection_Count_method(async));
467506

test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerTest.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,45 @@ await context.Database.SqlQuery<string>($"SELECT [Bools] AS [Value] FROM [Primit
635635
.SingleAsync());
636636
}
637637

638+
public override async Task Contains_on_Enumerable(bool async)
639+
{
640+
await base.Contains_on_Enumerable(async);
641+
642+
AssertSql(
643+
"""
644+
SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings]
645+
FROM [PrimitiveCollectionsEntity] AS [p]
646+
WHERE [p].[Int] IN (10, 999)
647+
""");
648+
}
649+
650+
651+
public override async Task Contains_on_MemoryExtensions(bool async)
652+
{
653+
await base.Contains_on_MemoryExtensions(async);
654+
655+
AssertSql(
656+
"""
657+
SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings]
658+
FROM [PrimitiveCollectionsEntity] AS [p]
659+
WHERE [p].[Int] IN (10, 999)
660+
""");
661+
}
662+
663+
#if NET10_0_OR_GREATER
664+
public override async Task Contains_with_MemoryExtensions_with_null_comparer(bool async)
665+
{
666+
await base.Contains_with_MemoryExtensions_with_null_comparer(async);
667+
668+
AssertSql(
669+
"""
670+
SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[String], [p].[Strings]
671+
FROM [PrimitiveCollectionsEntity] AS [p]
672+
WHERE [p].[Int] IN (10, 999)
673+
""");
674+
}
675+
#endif
676+
638677
public override async Task Column_collection_Count_method(bool async)
639678
{
640679
await base.Column_collection_Count_method(async);

test/EFCore.Sqlite.FunctionalTests/Query/PrimitiveCollectionsQuerySqliteTest.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,45 @@ FROM json_each("p"."Bools") AS "b"
625625
""");
626626
}
627627

628+
public override async Task Contains_on_Enumerable(bool async)
629+
{
630+
await base.Contains_on_Enumerable(async);
631+
632+
AssertSql(
633+
"""
634+
SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."String", "p"."Strings"
635+
FROM "PrimitiveCollectionsEntity" AS "p"
636+
WHERE "p"."Int" IN (10, 999)
637+
""");
638+
}
639+
640+
641+
public override async Task Contains_on_MemoryExtensions(bool async)
642+
{
643+
await base.Contains_on_MemoryExtensions(async);
644+
645+
AssertSql(
646+
"""
647+
SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."String", "p"."Strings"
648+
FROM "PrimitiveCollectionsEntity" AS "p"
649+
WHERE "p"."Int" IN (10, 999)
650+
""");
651+
}
652+
653+
#if NET10_0_OR_GREATER
654+
public override async Task Contains_with_MemoryExtensions_with_null_comparer(bool async)
655+
{
656+
await base.Contains_with_MemoryExtensions_with_null_comparer(async);
657+
658+
AssertSql(
659+
"""
660+
SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."String", "p"."Strings"
661+
FROM "PrimitiveCollectionsEntity" AS "p"
662+
WHERE "p"."Int" IN (10, 999)
663+
""");
664+
}
665+
#endif
666+
628667
public override async Task Column_collection_Count_method(bool async)
629668
{
630669
await base.Column_collection_Count_method(async);

0 commit comments

Comments
 (0)