From 33794c8ac7949602706f795a571fbfbff87f5bb3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 15 Nov 2025 12:21:21 +0000 Subject: [PATCH 1/5] Initial plan From 2d2c8f494fa8eb22cf49663be43f2206571914d7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 15 Nov 2025 12:32:25 +0000 Subject: [PATCH 2/5] Implement missing override methods for RETURNING operations Co-authored-by: renemadsen <76994+renemadsen@users.noreply.github.com> --- .../Internal/MySqlUpdateSqlGenerator.cs | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/src/EFCore.MySql/Update/Internal/MySqlUpdateSqlGenerator.cs b/src/EFCore.MySql/Update/Internal/MySqlUpdateSqlGenerator.cs index dfde995e5..6a36d4309 100644 --- a/src/EFCore.MySql/Update/Internal/MySqlUpdateSqlGenerator.cs +++ b/src/EFCore.MySql/Update/Internal/MySqlUpdateSqlGenerator.cs @@ -38,6 +38,45 @@ public override ResultSetMapping AppendInsertOperation( ? AppendInsertReturningOperation(commandStringBuilder, command, commandPosition, out requiresTransaction) : base.AppendInsertOperation(commandStringBuilder, command, commandPosition, out requiresTransaction); + /// + /// Appends SQL for inserting a row to the commands being built, via an INSERT containing a RETURNING clause + /// to retrieve any database-generated values. + /// + /// The builder to which the SQL should be appended. + /// The command that represents the insert operation. + /// The ordinal of this command in the batch. + /// Returns whether the SQL appended must be executed in a transaction to work correctly. + /// The for the command. + protected virtual ResultSetMapping AppendInsertReturningOperation( + StringBuilder commandStringBuilder, + IReadOnlyModificationCommand command, + int commandPosition, + out bool requiresTransaction) + { + var name = command.TableName; + var schema = command.Schema; + var operations = command.ColumnModifications; + + var writeOperations = operations.Where(o => o.IsWrite).ToList(); + var readOperations = operations.Where(o => o.IsRead).ToList(); + + AppendInsertCommandHeader(commandStringBuilder, name, schema, writeOperations); + AppendValuesHeader(commandStringBuilder, writeOperations); + AppendValues(commandStringBuilder, name, schema, writeOperations); + + // MySQL supports RETURNING clause starting from version 8.0.21 + if (_options.ServerVersion.Supports.Returning && readOperations.Count > 0) + { + AppendReturningClause(commandStringBuilder, readOperations); + } + + commandStringBuilder.AppendLine(SqlGenerationHelper.StatementTerminator); + + requiresTransaction = false; + + return readOperations.Count > 0 ? ResultSetMapping.LastInResultSet : ResultSetMapping.NoResults; + } + public virtual ResultSetMapping AppendBulkInsertOperation( StringBuilder commandStringBuilder, IReadOnlyList modificationCommands, @@ -137,6 +176,58 @@ protected override void AppendValues( } } + public override ResultSetMapping AppendUpdateOperation( + StringBuilder commandStringBuilder, + IReadOnlyModificationCommand command, + int commandPosition, + out bool requiresTransaction) + => _options.ServerVersion.Supports.Returning + ? AppendUpdateReturningOperation(commandStringBuilder, command, commandPosition, out requiresTransaction) + : base.AppendUpdateOperation(commandStringBuilder, command, commandPosition, out requiresTransaction); + + /// + /// Appends SQL for updating a row to the commands being built, via an UPDATE containing a RETURNING clause + /// to retrieve any database-generated values or for concurrency checking. + /// + /// The builder to which the SQL should be appended. + /// The command that represents the update operation. + /// The ordinal of this command in the batch. + /// Returns whether the SQL appended must be executed in a transaction to work correctly. + /// The for the command. + protected virtual ResultSetMapping AppendUpdateReturningOperation( + StringBuilder commandStringBuilder, + IReadOnlyModificationCommand command, + int commandPosition, + out bool requiresTransaction) + { + var name = command.TableName; + var schema = command.Schema; + var operations = command.ColumnModifications; + + var writeOperations = operations.Where(o => o.IsWrite).ToList(); + var conditionOperations = operations.Where(o => o.IsCondition).ToList(); + var readOperations = operations.Where(o => o.IsRead).ToList(); + + requiresTransaction = false; + + var anyReadOperations = readOperations.Count > 0; + + AppendUpdateCommandHeader(commandStringBuilder, name, schema, writeOperations); + AppendWhereClause(commandStringBuilder, conditionOperations); + + // MySQL supports RETURNING clause starting from version 8.0.21 + if (_options.ServerVersion.Supports.Returning) + { + AppendReturningClause(commandStringBuilder, readOperations, anyReadOperations ? null : "1"); + } + + commandStringBuilder.AppendLine(SqlGenerationHelper.StatementTerminator); + + return anyReadOperations + ? ResultSetMapping.LastInResultSet + : ResultSetMapping.LastInResultSet | ResultSetMapping.ResultSetWithRowsAffectedOnly; + } + public override ResultSetMapping AppendDeleteOperation(StringBuilder commandStringBuilder, IReadOnlyModificationCommand command, int commandPosition, @@ -145,6 +236,41 @@ public override ResultSetMapping AppendDeleteOperation(StringBuilder commandStri ? AppendDeleteReturningOperation(commandStringBuilder, command, commandPosition, out requiresTransaction) : base.AppendDeleteOperation(commandStringBuilder, command, commandPosition, out requiresTransaction); + /// + /// Appends SQL for deleting a row to the commands being built, via a DELETE containing a RETURNING clause + /// for concurrency checking. + /// + /// The builder to which the SQL should be appended. + /// The command that represents the delete operation. + /// The ordinal of this command in the batch. + /// Returns whether the SQL appended must be executed in a transaction to work correctly. + /// The for the command. + protected virtual ResultSetMapping AppendDeleteReturningOperation( + StringBuilder commandStringBuilder, + IReadOnlyModificationCommand command, + int commandPosition, + out bool requiresTransaction) + { + var name = command.TableName; + var schema = command.Schema; + var conditionOperations = command.ColumnModifications.Where(o => o.IsCondition).ToList(); + + requiresTransaction = false; + + AppendDeleteCommandHeader(commandStringBuilder, name, schema); + AppendWhereClause(commandStringBuilder, conditionOperations); + + // MySQL supports RETURNING clause starting from version 8.0.21 + if (_options.ServerVersion.Supports.Returning) + { + AppendReturningClause(commandStringBuilder, [], "1"); + } + + commandStringBuilder.AppendLine(SqlGenerationHelper.StatementTerminator); + + return ResultSetMapping.LastInResultSet | ResultSetMapping.ResultSetWithRowsAffectedOnly; + } + protected override ResultSetMapping AppendSelectAffectedCountCommand(StringBuilder commandStringBuilder, string name, string schema, int commandPosition) { commandStringBuilder From eada307423c7f81dc2ed89df421c112424abfc11 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 15 Nov 2025 13:06:22 +0000 Subject: [PATCH 3/5] Fix: Change RETURNING methods from virtual to override Co-authored-by: renemadsen <76994+renemadsen@users.noreply.github.com> --- src/EFCore.MySql/Update/Internal/MySqlUpdateSqlGenerator.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/EFCore.MySql/Update/Internal/MySqlUpdateSqlGenerator.cs b/src/EFCore.MySql/Update/Internal/MySqlUpdateSqlGenerator.cs index 6a36d4309..bcecff38f 100644 --- a/src/EFCore.MySql/Update/Internal/MySqlUpdateSqlGenerator.cs +++ b/src/EFCore.MySql/Update/Internal/MySqlUpdateSqlGenerator.cs @@ -47,7 +47,7 @@ public override ResultSetMapping AppendInsertOperation( /// The ordinal of this command in the batch. /// Returns whether the SQL appended must be executed in a transaction to work correctly. /// The for the command. - protected virtual ResultSetMapping AppendInsertReturningOperation( + protected override ResultSetMapping AppendInsertReturningOperation( StringBuilder commandStringBuilder, IReadOnlyModificationCommand command, int commandPosition, @@ -194,7 +194,7 @@ public override ResultSetMapping AppendUpdateOperation( /// The ordinal of this command in the batch. /// Returns whether the SQL appended must be executed in a transaction to work correctly. /// The for the command. - protected virtual ResultSetMapping AppendUpdateReturningOperation( + protected override ResultSetMapping AppendUpdateReturningOperation( StringBuilder commandStringBuilder, IReadOnlyModificationCommand command, int commandPosition, @@ -245,7 +245,7 @@ public override ResultSetMapping AppendDeleteOperation(StringBuilder commandStri /// The ordinal of this command in the batch. /// Returns whether the SQL appended must be executed in a transaction to work correctly. /// The for the command. - protected virtual ResultSetMapping AppendDeleteReturningOperation( + protected override ResultSetMapping AppendDeleteReturningOperation( StringBuilder commandStringBuilder, IReadOnlyModificationCommand command, int commandPosition, From 326f46a528e7814fb1871edfe03e490f9436c767 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 15 Nov 2025 14:22:52 +0000 Subject: [PATCH 4/5] Fix: Change RETURNING methods to public override Co-authored-by: renemadsen <76994+renemadsen@users.noreply.github.com> --- src/EFCore.MySql/Update/Internal/MySqlUpdateSqlGenerator.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/EFCore.MySql/Update/Internal/MySqlUpdateSqlGenerator.cs b/src/EFCore.MySql/Update/Internal/MySqlUpdateSqlGenerator.cs index bcecff38f..56c7a1441 100644 --- a/src/EFCore.MySql/Update/Internal/MySqlUpdateSqlGenerator.cs +++ b/src/EFCore.MySql/Update/Internal/MySqlUpdateSqlGenerator.cs @@ -47,7 +47,7 @@ public override ResultSetMapping AppendInsertOperation( /// The ordinal of this command in the batch. /// Returns whether the SQL appended must be executed in a transaction to work correctly. /// The for the command. - protected override ResultSetMapping AppendInsertReturningOperation( + public override ResultSetMapping AppendInsertReturningOperation( StringBuilder commandStringBuilder, IReadOnlyModificationCommand command, int commandPosition, @@ -194,7 +194,7 @@ public override ResultSetMapping AppendUpdateOperation( /// The ordinal of this command in the batch. /// Returns whether the SQL appended must be executed in a transaction to work correctly. /// The for the command. - protected override ResultSetMapping AppendUpdateReturningOperation( + public override ResultSetMapping AppendUpdateReturningOperation( StringBuilder commandStringBuilder, IReadOnlyModificationCommand command, int commandPosition, @@ -245,7 +245,7 @@ public override ResultSetMapping AppendDeleteOperation(StringBuilder commandStri /// The ordinal of this command in the batch. /// Returns whether the SQL appended must be executed in a transaction to work correctly. /// The for the command. - protected override ResultSetMapping AppendDeleteReturningOperation( + public override ResultSetMapping AppendDeleteReturningOperation( StringBuilder commandStringBuilder, IReadOnlyModificationCommand command, int commandPosition, From c94cf7749890bc8e9bd143b4437bc707de97e2b0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 15 Nov 2025 14:36:23 +0000 Subject: [PATCH 5/5] Fix: Use correct access modifiers for RETURNING methods Co-authored-by: renemadsen <76994+renemadsen@users.noreply.github.com> --- src/EFCore.MySql/Update/Internal/MySqlUpdateSqlGenerator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/EFCore.MySql/Update/Internal/MySqlUpdateSqlGenerator.cs b/src/EFCore.MySql/Update/Internal/MySqlUpdateSqlGenerator.cs index 56c7a1441..7f6f4cf3b 100644 --- a/src/EFCore.MySql/Update/Internal/MySqlUpdateSqlGenerator.cs +++ b/src/EFCore.MySql/Update/Internal/MySqlUpdateSqlGenerator.cs @@ -194,7 +194,7 @@ public override ResultSetMapping AppendUpdateOperation( /// The ordinal of this command in the batch. /// Returns whether the SQL appended must be executed in a transaction to work correctly. /// The for the command. - public override ResultSetMapping AppendUpdateReturningOperation( + protected override ResultSetMapping AppendUpdateReturningOperation( StringBuilder commandStringBuilder, IReadOnlyModificationCommand command, int commandPosition, @@ -245,7 +245,7 @@ public override ResultSetMapping AppendDeleteOperation(StringBuilder commandStri /// The ordinal of this command in the batch. /// Returns whether the SQL appended must be executed in a transaction to work correctly. /// The for the command. - public override ResultSetMapping AppendDeleteReturningOperation( + protected override ResultSetMapping AppendDeleteReturningOperation( StringBuilder commandStringBuilder, IReadOnlyModificationCommand command, int commandPosition,