Skip to content

Conversation

Copy link

Copilot AI commented Dec 16, 2025

MySQL 8.4.3 fails with syntax errors when attempting to use RETURNING clause in INSERT/UPDATE/DELETE statements. The code incorrectly assumed MySQL 8.0.21+ supported this PostgreSQL feature.

Changes

  • MySqlServerVersion.cs: Set Returning property to always return false (was >= 8.0.21)
  • MySqlUpdateSqlGenerator.cs: Updated comments to clarify RETURNING support status

Technical Details

MySQL: Does not support RETURNING in any version (tested 8.0.39, 8.4.3)

MariaDB: Partial support exists (INSERT/DELETE work since 10.0/10.5, UPDATE does not work). Disabled because EF Core's UpdateAndSelectSqlGenerator requires consistent support across all DML operations.

Both databases now use the fallback mechanism:

INSERT INTO `Drinks` (`Name`) VALUES (@p0);
SELECT `Id` FROM `Drinks`
WHERE ROW_COUNT() = 1 AND `Id` = LAST_INSERT_ID();

Impact

  • Fixes SQL syntax errors on MySQL 8.4.3+
  • No breaking changes - fallback mechanism already in use pre-8.0.21
  • MariaDB behavior unchanged (RETURNING was already disabled)
Original prompt

This section details on the original issue you should resolve

<issue_title>You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'RETURNING Id;</issue_title>
<issue_description>MySQL 8.4.3 failing with this error, ensure that any changes to fix this keeps working for MariaDB 11.6.2

Failed Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query.TPHInheritanceQueryMySqlTest.Can_filter_all_animals(async: False) [1 ms]
  Error Message:
   Microsoft.EntityFrameworkCore.DbUpdateException : An error occurred while saving the entity changes. See the inner exception for details.
---- MySqlConnector.MySqlException : You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'RETURNING `Id`;
INSERT INTO `Drinks` (`LiltCO2`, `Discriminator`, `SortIndex`, `' at line 3
  Stack Trace:
     at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChangesAsync(IList`1 entries, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
   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.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
   at Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities.MySqlTestStore.InitializeAsync(Func`1 createContext, Func`2 seed, Func`2 clean) in /home/runner/work/Pomelo.EntityFrameworkCore.MySql/Pomelo.EntityFrameworkCore.MySql/test/EFCore.MySql.FunctionalTests/TestUtilities/MySqlTestStore.cs:line 152
   at Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities.MySqlTestStore.InitializeAsync(Func`1 createContext, Func`2 seed, Func`2 clean) in /home/runner/work/Pomelo.EntityFrameworkCore.MySql/Pomelo.EntityFrameworkCore.MySql/test/EFCore.MySql.FunctionalTests/TestUtilities/MySqlTestStore.cs:line 154
   at Microsoft.EntityFrameworkCore.TestUtilities.TestStore.<>c__DisplayClass13_0.<<InitializeAsync>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.EntityFrameworkCore.TestUtilities.TestStoreIndex.CreateSharedAsync(String name, Func`1 initializeDatabase)
   at Microsoft.EntityFrameworkCore.TestUtilities.TestStore.InitializeAsync(IServiceProvider serviceProvider, Func`1 createContext, Func`2 seed, Func`2 clean)
   at Microsoft.EntityFrameworkCore.TestUtilities.RelationalTestStore.InitializeAsync(IServiceProvider serviceProvider, Func`1 createContext, Func`2 seed, Func`2 clean)
   at Microsoft.EntityFrameworkCore.SharedStoreFixtureBase`1.InitializeAsync()
----- Inner 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(...

</details>



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

- Fixes microting/Pomelo.EntityFrameworkCore.MySql#210

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

💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

Copilot AI changed the title [WIP] Fix SQL syntax error for MySQL compatibility Disable RETURNING clause for MySQL and MariaDB to fix SQL syntax errors Dec 16, 2025
Copilot AI requested a review from renemadsen December 16, 2025 04:58
@renemadsen
Copy link
Member

@copilot Now that this is working, search documentation for MySQL versions 9.x and MariaDB versions 11.x and 12.x

Copy link
Author

Copilot AI commented Dec 16, 2025

@copilot Now that this is working, search documentation for MySQL versions 9.x and MariaDB versions 11.x and 12.x

Research completed on MySQL 9.x and MariaDB 11.x/12.x RETURNING support:

MySQL 9.x (9.0, 9.1, 9.2):

  • ❌ No RETURNING support for INSERT/UPDATE/DELETE
  • Same as MySQL 8.x - MySQL has never implemented RETURNING

MariaDB 11.x (11.0-11.6):

  • ✅ INSERT ... RETURNING: Supported (since 10.5.0)
  • ✅ DELETE ... RETURNING: Supported (since 10.0)
  • ❌ UPDATE ... RETURNING: NOT supported (confirmed by testing 11.6.2)

MariaDB 12.0:

  • ✅ INSERT ... RETURNING: Supported
  • ✅ DELETE ... RETURNING: Supported
  • ❌ UPDATE ... RETURNING: Still NOT supported

Conclusion:
Our fix remains correct for all versions. The Returning property must stay false because:

  1. MySQL never supports RETURNING (including 9.x)
  2. MariaDB lacks UPDATE...RETURNING support (11.x and 12.x)
  3. EF Core's UpdateAndSelectSqlGenerator requires consistent support across all DML operations

The fallback mechanism (LAST_INSERT_ID() + SELECT) works correctly for all versions.

@renemadsen
Copy link
Member

@copilot 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.NorthwindBulkUpdatesMySqlTest.Delete_with_LeftJoin(async: False) [161 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_LeftJoin(Boolean async) in /home/runner/work/Pomelo.EntityFrameworkCore.MySql/Pomelo.EntityFrameworkCore.MySql/test/EFCore.MySql.FunctionalTests/BulkUpdates/NorthwindBulkUpdatesMySqlTest.cs:line 557
--- End of stack trace from previous location ---

Copy link
Author

Copilot AI commented Dec 16, 2025

@copilot 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.FunctionalTe...

This is a separate issue unrelated to the RETURNING clause fix. The error "You can't specify target table 'o' for update in FROM clause" is a known MySQL limitation when using DELETE with self-referencing subqueries.

This is a MySQL/MariaDB version difference in how they handle DELETE statements with JOINs:

  • MySQL 8.0.40 and MariaDB 10.5.27: Enforce the restriction (fails)
  • MariaDB 11.6.2: Allows it (works)

The RETURNING clause changes I made don't affect this behavior - they only change how generated values are retrieved after INSERT/UPDATE/DELETE operations. This appears to be a pre-existing compatibility issue with the bulk delete query generation that's exposed by the version differences.

This would require a separate investigation into how Delete_with_LeftJoin generates its SQL and whether it needs version-specific handling.

@renemadsen renemadsen marked this pull request as ready for review December 16, 2025 05:16
@renemadsen renemadsen merged commit 3a12ab0 into master Dec 16, 2025
19 of 39 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