Skip to content

Conversation

Copy link

Copilot AI commented Dec 16, 2025

Fix DELETE with self-referencing subquery issue - COMPLETE ✅

Issue Summary

  • Error: Tests failed on MySQL 8.0.40 and MariaDB 10.5.27 with "You can't specify target table for update in FROM clause"
  • Root Cause: DELETE statements with self-referencing subqueries are not supported by MySQL and MariaDB < 11.0
  • Property: ServerVersionSupport.DeleteWithSelfReferencingSubquery tracks this capability

Changes Made

  • Fixed NonSharedModelBulkUpdatesMySqlTest.Delete_predicate_based_on_optional_navigation
  • Fixed NonSharedModelBulkUpdatesMySqlTest.Delete_entity_with_auto_include
  • Fixed NorthwindBulkUpdatesMySqlTest.Delete_with_cross_join
  • Fixed NorthwindBulkUpdatesMySqlTest.Delete_Where_OrderBy
  • Tests now catch MySqlException on unsupported versions (MySQL, MariaDB < 11.0)
  • Tests validate SQL on supported versions (MariaDB 11.0+)
  • Comprehensively searched all bulk update test files for similar patterns

Testing Results

MySQL 8.0.40: All tests pass (throw MySqlException as expected)
MariaDB 11.6.2: All tests pass (execute DELETE and validate SQL)

Key Finding

Tests with derived tables in subqueries (e.g., DELETE ... WHERE EXISTS (SELECT ... FROM (SELECT ... FROM table AS t0) AS t1)) do NOT have self-referencing issues because the derived table acts as a barrier. Only tests with direct table references in the subquery (e.g., DELETE ... WHERE EXISTS (SELECT ... FROM table AS t0 WHERE t0.id = t.id)) are affected.

Pattern for Future Tests

Tests with DELETE statements containing direct self-referencing subqueries should:

if (!AppConfig.ServerVersion.Supports.DeleteWithSelfReferencingSubquery)
{
    // Not supported by MySQL and older MariaDB versions
    await Assert.ThrowsAsync<MySqlException>(() => base.TestMethod(async));
    AssertSql(/* expected SQL */);
}
else
{
    await base.TestMethod(async);
    AssertSql(/* expected SQL */);
}
Original prompt

This section details on the original issue you should resolve

<issue_title>You can't specify target table 'p' for update in FROM clause</issue_title>
<issue_description>With respect to the difference in MySQL and Mariadb, this is broken for MySQL v8.0.40, MariaDB 10.5.27, but it works in MariaDB 11.6.2:

Failed Pomelo.EntityFrameworkCore.MySql.FunctionalTests.BulkUpdates.NonSharedModelBulkUpdatesMySqlTest.Delete_predicate_based_on_optional_navigation(async: False) [3 s]
  Error Message:
   MySqlConnector.MySqlException : You can't specify target table 'p' for update in FROM clause
  Stack Trace:
     at MySqlConnector.Core.ServerSession.ReceiveReplyAsync(IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/Core/ServerSession.cs:line 1125
   at MySqlConnector.Core.ResultSet.ReadResultSetHeaderAsync(IOBehavior ioBehavior) in /_/src/MySqlConnector/Core/ResultSet.cs:line 37
   at MySqlConnector.MySqlDataReader.ActivateResultSet(CancellationToken cancellationToken) in /_/src/MySqlConnector/MySqlDataReader.cs:line 133
   at MySqlConnector.MySqlDataReader.InitAsync(CommandListPosition commandListPosition, ICommandPayloadCreator payloadCreator, IDictionary`2 cachedProcedures, IMySqlCommand command, CommandBehavior behavior, Activity activity, IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/MySqlDataReader.cs:line 489
   at MySqlConnector.Core.CommandExecutor.ExecuteReaderAsync(CommandListPosition commandListPosition, ICommandPayloadCreator payloadCreator, CommandBehavior behavior, Activity activity, IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/Core/CommandExecutor.cs:line 58
   at MySqlConnector.MySqlCommand.ExecuteNonQueryAsync(IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/MySqlCommand.cs:line 304
   at MySqlConnector.MySqlCommand.ExecuteNonQuery() in /_/src/MySqlConnector/MySqlCommand.cs:line 108
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQuery(RelationalCommandParameterObject parameterObject)
   at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.<>c.<NonQueryResult>b__30_0(DbContext _, ValueTuple`3 state)
   at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
   at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.NonQueryResult(RelationalQueryContext relationalQueryContext, RelationalCommandResolver relationalCommandResolver, Type contextType, CommandSource commandSource, Boolean threadSafetyChecksEnabled)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteCore[TResult](Expression query, Boolean async, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteDelete[TSource](IQueryable`1 source)
   at Microsoft.EntityFrameworkCore.BulkUpdates.NonSharedModelBulkUpdatesTestBase.<>c__DisplayClass28_0`2.<<AssertDelete>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.EntityFrameworkCore.TestUtilities.TestHelpers.<>c__DisplayClass41_0`1.<<ExecuteWithStrategyInTransactionAsync>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.EntityFrameworkCore.ExecutionStrategyExtensions.<>c__7`1.<<ExecuteAsync>b__7_0>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.<>c__DisplayClass30_0`2.<<ExecuteAsync>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func`4 operation, Func`4 verifySucceeded, TState state, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func`4 operation, Func`4 verifySucceeded, TState state, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.TestUtilities.TestHelpers.ExecuteWithStrategyInTransactionAsync[TContext](Func`1 createContext, Action`2 useTransaction, Func`2 testOperation, Func`2 nestedTestOperation1, Func`2 nestedTestOperation2, Func`2 nestedTestOperation3)
   at Microsoft.EntityFrameworkCore.BulkUpdates.NonSharedModelBulkUpdatesTestBase.Delete_predicate_based_on_optional_navigation(Boolean async)
   at Pomelo.EntityFrameworkCore.MySql.FunctionalTests.BulkUpdates.NonSharedModelBulkUpdatesMySqlTest.Delete_predicate_based...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes microting/Pomelo.EntityFrameworkCore.MySql#214

<!-- START COPILOT CODING AGENT TIPS -->
---

✨ Let Copilot coding agent [set things up for you](https://github.com/microting/Pomelo.EntityFrameworkCore.MySql/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot) — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI changed the title [WIP] Fix target table update issue for MySQL 8.0.40 Fix DELETE with self-referencing subquery tests for MySQL/MariaDB < 11.0 Dec 16, 2025
Copilot AI requested a review from renemadsen December 16, 2025 06:35
@renemadsen
Copy link
Member

@copilot Same kind of error here:

Failed Pomelo.EntityFrameworkCore.MySql.FunctionalTests.BulkUpdates.NorthwindBulkUpdatesMySqlTest.Delete_with_cross_join(async: False) [272 ms]
Error Message:
MySqlConnector.MySqlException : You can't specify target table 'o' for update in FROM clause
Stack Trace:
at MySqlConnector.Core.ServerSession.ReceiveReplyAsync(IOBehavior ioBehavior, CancellationToken cancellationToken) in //src/MySqlConnector/Core/ServerSession.cs:line 1125
at MySqlConnector.Core.ResultSet.ReadResultSetHeaderAsync(IOBehavior ioBehavior) in /
/src/MySqlConnector/Core/ResultSet.cs:line 37
at MySqlConnector.MySqlDataReader.ActivateResultSet(CancellationToken cancellationToken) in /_/src/MySqlConnector/MySqlDataReader.cs:line 133
at MySqlConnector.MySqlDataReader.InitAsync(CommandListPosition commandListPosition, ICommandPayloadCreator payloadCreator, IDictionary2 cachedProcedures, IMySqlCommand command, CommandBehavior behavior, Activity activity, IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/MySqlDataReader.cs:line 489 at MySqlConnector.Core.CommandExecutor.ExecuteReaderAsync(CommandListPosition commandListPosition, ICommandPayloadCreator payloadCreator, CommandBehavior behavior, Activity activity, IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/Core/CommandExecutor.cs:line 58 at MySqlConnector.MySqlCommand.ExecuteNonQueryAsync(IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/MySqlCommand.cs:line 304 at MySqlConnector.MySqlCommand.ExecuteNonQuery() in /_/src/MySqlConnector/MySqlCommand.cs:line 108 at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQuery(RelationalCommandParameterObject parameterObject) at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.<>c.<NonQueryResult>b__30_0(DbContext _, ValueTuple3 state)
at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.Execute[TState,TResult](TState state, Func3 operation, Func3 verifySucceeded)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.NonQueryResult(RelationalQueryContext relationalQueryContext, RelationalCommandResolver relationalCommandResolver, Type contextType, CommandSource commandSource, Boolean threadSafetyChecksEnabled)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteCore[TResult](Expression query, Boolean async, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteDelete[TSource](IQueryable1 source) at Microsoft.EntityFrameworkCore.TestUtilities.BulkUpdatesAsserter.<>c__DisplayClass6_01.<b__0>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.EntityFrameworkCore.TestUtilities.TestHelpers.<>c__DisplayClass41_01.<<ExecuteWithStrategyInTransactionAsync>b__0>d.MoveNext() --- End of stack trace from previous location --- at Microsoft.EntityFrameworkCore.ExecutionStrategyExtensions.<>c__71.<b__7_0>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.<>c__DisplayClass30_02.<<ExecuteAsync>b__0>d.MoveNext() --- End of stack trace from previous location --- at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func4 operation, Func4 verifySucceeded, TState state, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func4 operation, Func4 verifySucceeded, TState state, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func4 operation, Func4 verifySucceeded, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.TestUtilities.TestHelpers.ExecuteWithStrategyInTransactionAsync[TContext](Func1 createContext, Action2 useTransaction, Func2 testOperation, Func2 nestedTestOperation1, Func2 nestedTestOperation2, Func`2 nestedTestOperation3)
at Pomelo.EntityFrameworkCore.MySql.FunctionalTests.BulkUpdates.NorthwindBulkUpdatesMySqlTest.Delete_with_cross_join(Boolean async) in /home/runner/work/Pomelo.EntityFrameworkCore.MySql/Pomelo.EntityFrameworkCore.MySql/test/EFCore.MySql.FunctionalTests/BulkUpdates/NorthwindBulkUpdatesMySqlTest.cs:line 613
--- End of stack trace from previous location ---

Copy link
Author

Copilot AI commented Dec 16, 2025

@copilot Same kind of error here:

Failed Pomelo.EntityFrameworkCore.MySql.FunctionalTests.BulkUpdates.NorthwindBulkUpdatesMySqlTest.Delete_with_cross_join(async: False) [272 ms]...

Fixed in commit 43049cb. The Delete_with_cross_join test now uses the same conditional pattern to handle the self-referencing subquery limitation on MySQL and MariaDB < 11.0.

@renemadsen
Copy link
Member

@copilot Search for other places that matches the same patteren and would require the same kind of theck for MySQL version and MariaDB versions.

Copy link
Author

Copilot AI commented Dec 16, 2025

@copilot Search for other places that matches the same patteren and would require the same kind of theck for MySQL version and MariaDB versions.

Searched comprehensively across all bulk update test files. Found and fixed:

Already Fixed:

  • Delete_predicate_based_on_optional_navigation (NonSharedModelBulkUpdatesMySqlTest) - commit 4d9b353
  • Delete_entity_with_auto_include (NonSharedModelBulkUpdatesMySqlTest) - commit 4d9b353
  • Delete_with_cross_join (NorthwindBulkUpdatesMySqlTest) - commit 43049cb
  • Delete_Where_OrderBy (NorthwindBulkUpdatesMySqlTest) - commit b340298

Note: Tests with derived tables in subqueries (e.g., DELETE ... WHERE EXISTS (SELECT ... FROM (SELECT ... FROM table AS t0) AS t1)) do NOT have self-referencing issues because the derived table acts as a barrier. Only tests with direct table references in the subquery (e.g., DELETE ... WHERE EXISTS (SELECT ... FROM table AS t0 WHERE t0.id = t.id)) are affected.

All affected tests now use the DeleteWithSelfReferencingSubquery property to conditionally handle MySQL/MariaDB < 11.0.

@renemadsen renemadsen marked this pull request as ready for review December 16, 2025 07:55
@renemadsen renemadsen merged commit 1acb0eb into master Dec 16, 2025
25 of 55 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants