Skip to content

Commit ced65d4

Browse files
authored
Merge pull request #213 from microting/copilot/fix-target-table-update-error
Handle MySQL/MariaDB DELETE with self-referencing subquery limitation
2 parents 3a12ab0 + 3765e63 commit ced65d4

File tree

5 files changed

+51
-7
lines changed

5 files changed

+51
-7
lines changed

src/EFCore.MySql/Infrastructure/MariaDbServerVersion.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ internal MariaDbServerVersionSupport([NotNull] ServerVersion serverVersion)
9999
public override bool WhereSubqueryReferencesOuterQuery => false;
100100
public override bool FieldReferenceInTableValueConstructor => false;
101101
public override bool CollationCharacterSetApplicabilityWithFullCollationNameColumn => ServerVersion.Version >= new Version(10, 10, 1);
102+
public override bool DeleteWithSelfReferencingSubquery => ServerVersion.Version >= new Version(11, 0, 0); // MariaDB 11+ supports DELETE with self-referencing subqueries
102103

103104
public override bool JsonTableImplementationStable => false;
104105
public override bool JsonTableImplementationWithoutMariaDbBugs => false;

src/EFCore.MySql/Infrastructure/MySqlServerVersion.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ internal MySqlServerVersionSupport([NotNull] ServerVersion serverVersion)
101101
public override bool WhereSubqueryReferencesOuterQuery => false;
102102
public override bool FieldReferenceInTableValueConstructor => true;
103103
public override bool CollationCharacterSetApplicabilityWithFullCollationNameColumn => false;
104+
public override bool DeleteWithSelfReferencingSubquery => false; // MySQL does not support DELETE with self-referencing subqueries (Error 1093)
104105

105106
public override bool JsonTableImplementationStable => false;
106107
public override bool JsonTableImplementationWithoutMySqlBugs => false; // Other non-fatal bugs regarding JSON_TABLE.

src/EFCore.MySql/Infrastructure/ServerVersionSupport.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ public virtual bool PropertyOrVersion(string propertyNameOrServerVersion)
9797
public virtual bool WhereSubqueryReferencesOuterQuery => false;
9898
public virtual bool FieldReferenceInTableValueConstructor => false;
9999
public virtual bool CollationCharacterSetApplicabilityWithFullCollationNameColumn => false;
100+
public virtual bool DeleteWithSelfReferencingSubquery => false;
100101

101102
public virtual bool JsonTableImplementationStable => JsonTable;
102103
public virtual bool JsonTableImplementationWithoutMySqlBugs => JsonTable;

test/EFCore.MySql.FunctionalTests/BulkUpdates/NorthwindBulkUpdatesMySqlTest.cs

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -554,9 +554,39 @@ LIMIT @p0 OFFSET @p
554554

555555
public override async Task Delete_with_LeftJoin(bool async)
556556
{
557-
await base.Delete_with_LeftJoin(async);
557+
if (!AppConfig.ServerVersion.Supports.DeleteWithSelfReferencingSubquery)
558+
{
559+
// Not supported by MySQL and older MariaDB versions:
560+
// Error Code: 1093. You can't specify target table 'o' for update in FROM clause
561+
await Assert.ThrowsAsync<MySqlException>(
562+
() => base.Delete_with_LeftJoin(async));
558563

559-
AssertSql(
564+
AssertSql(
565+
"""
566+
@p0='100'
567+
@p='0'
568+
569+
DELETE `o`
570+
FROM `Order Details` AS `o`
571+
WHERE EXISTS (
572+
SELECT 1
573+
FROM `Order Details` AS `o0`
574+
LEFT JOIN (
575+
SELECT `o2`.`OrderID`
576+
FROM `Orders` AS `o2`
577+
WHERE `o2`.`OrderID` < 10300
578+
ORDER BY `o2`.`OrderID`
579+
LIMIT @p0 OFFSET @p
580+
) AS `o1` ON `o0`.`OrderID` = `o1`.`OrderID`
581+
WHERE (`o0`.`OrderID` < 10276) AND ((`o0`.`OrderID` = `o`.`OrderID`) AND (`o0`.`ProductID` = `o`.`ProductID`)))
582+
""");
583+
}
584+
else
585+
{
586+
// Works as expected in MariaDB 11+.
587+
await base.Delete_with_LeftJoin(async);
588+
589+
AssertSql(
560590
"""
561591
@p0='100'
562592
@p='0'
@@ -575,6 +605,7 @@ LIMIT @p0 OFFSET @p
575605
) AS `o1` ON `o0`.`OrderID` = `o1`.`OrderID`
576606
WHERE (`o0`.`OrderID` < 10276) AND ((`o0`.`OrderID` = `o`.`OrderID`) AND (`o0`.`ProductID` = `o`.`ProductID`)))
577607
""");
608+
}
578609
}
579610

580611
public override async Task Delete_with_cross_join(bool async)
@@ -989,7 +1020,7 @@ await Assert.ThrowsAsync<MySqlException>(
9891020
}
9901021
else
9911022
{
992-
// Works as expected in MariaDB.
1023+
// Works as expected in MariaDB (all versions).
9931024
await base.Update_Where_GroupBy_First_set_constant_3(async);
9941025

9951026
AssertExecuteUpdateSql(
@@ -1555,7 +1586,18 @@ public override async Task Update_with_two_inner_joins(bool async)
15551586

15561587
public override async Task Delete_with_LeftJoin_via_flattened_GroupJoin(bool async)
15571588
{
1558-
await base.Delete_with_LeftJoin_via_flattened_GroupJoin(async);
1589+
if (!AppConfig.ServerVersion.Supports.DeleteWithSelfReferencingSubquery)
1590+
{
1591+
// Not supported by MySQL and older MariaDB versions:
1592+
// Error Code: 1093. You can't specify target table 'o' for update in FROM clause
1593+
await Assert.ThrowsAsync<MySqlException>(
1594+
() => base.Delete_with_LeftJoin_via_flattened_GroupJoin(async));
1595+
}
1596+
else
1597+
{
1598+
// Works as expected in MariaDB 11+.
1599+
await base.Delete_with_LeftJoin_via_flattened_GroupJoin(async);
1600+
}
15591601

15601602
// Note: SQL validation skipped - actual SQL needs to be captured from test run
15611603
}

test/EFCore.MySql.FunctionalTests/BulkUpdates/TPHFiltersInheritanceBulkUpdatesMySqlTest.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,7 @@ public override async Task Delete_GroupBy_Where_Select_First_2(bool async)
9494

9595
public override async Task Delete_GroupBy_Where_Select_First_3(bool async)
9696
{
97-
if (AppConfig.ServerVersion.Type == ServerType.MariaDb &&
98-
AppConfig.ServerVersion.Version >= new Version(11, 1))
97+
if (AppConfig.ServerVersion.Supports.DeleteWithSelfReferencingSubquery)
9998
{
10099
await base.Delete_GroupBy_Where_Select_First_3(async);
101100

@@ -118,7 +117,7 @@ HAVING COUNT(*) < 3
118117
}
119118
else
120119
{
121-
// Not supported by MySQL:
120+
// Not supported by MySQL and older MariaDB versions:
122121
// Error Code: 1093. You can't specify target table 'c' for update in FROM clause
123122
await Assert.ThrowsAsync<MySqlException>(
124123
() => base.Delete_GroupBy_Where_Select_First_3(async));

0 commit comments

Comments
 (0)