ralmsdeveloper / EntityFrameworkCore.FirebirdSQL

FirebirdSQL database provider for Entity Framework Core.
Other
44 stars 26 forks source link

Exception on update if the updated column also appears in WHERE clause #24

Closed thomaspope closed 6 years ago

thomaspope commented 6 years ago

The issue

DbUpdateException thrown under certain circumstances (duplicate parameter specification)

Steps to reproduce

I stumbled upon the exception while struggling to use ASP.NET Boilerplate (ABP) with Firebird. I attach a sample solution: AbpFb.zip To reproduce the error, setup the solution as described in README.txt, then try to log in via the Angular frontend (login: admin, password: 123qwe).

As far as I can tell, it happens when the ColumnModifications in FbUpdateSqlGenerator.AppendBulkUpdateOperation() contains an operation which has both IsWrite and IsCondition set to true, so it's added twice to the block parameters' list (p2 in this case, as the third and the last):

EXECUTE BLOCK ( 
p0  INTEGER=@p0,p1  VARCHAR(64)=@p1,p2  VARCHAR(4000)=@p2,p3  TIMESTAMP=@p3,p4  BIGINT=@p4,p5  BIGINT=@p5,p6  TIMESTAMP=@p6,p7  VARCHAR(256)=@p7,p8  VARCHAR(328)=@p8,p9  BOOLEAN=@p9,p10  BOOLEAN=@p10,p11  BOOLEAN=@p11,p12  BOOLEAN=@p12,p13  BOOLEAN=@p13,p14  BOOLEAN=@p14,p15  TIMESTAMP=@p15,p16  TIMESTAMP=@p16,p17  BIGINT=@p17,p18  TIMESTAMP=@p18,p19  VARCHAR(32)=@p19,p20  VARCHAR(256)=@p20,p21  VARCHAR(32)=@p21,p22  VARCHAR(128)=@p22,p23  VARCHAR(328)=@p23,p24  VARCHAR(4000)=@p24,p25  VARCHAR(4000)=@p25,p26  VARCHAR(32)=@p26,p27  INTEGER=@p27,p28  VARCHAR(32)=@p28,p29  BIGINT=@p29,p2  VARCHAR(4000)=@p2) 
RETURNS (AffectedRows BIGINT) AS BEGIN
AffectedRows=0;

UPDATE "AbpUsers" SET "AccessFailedCount" = :p0, "AuthenticationSource" = :p1, "ConcurrencyStamp" = :p2, "CreationTime" = :p3, "CreatorUserId" = :p4, "DeleterUserId" = :p5, "DeletionTime" = :p6, "EmailAddress" = :p7, "EmailConfirmationCode" = :p8, "IsActive" = :p9, "IsDeleted" = :p10, "IsEmailConfirmed" = :p11, "IsLockoutEnabled" = :p12, "IsPhoneNumberConfirmed" = :p13, "IsTwoFactorEnabled" = :p14, "LastLoginTime" = :p15, "LastModificationTime" = :p16, "LastModifierUserId" = :p17, "LockoutEndDateUtc" = :p18, "Name" = :p19, "NormalizedEmailAddress" = :p20, "NormalizedUserName" = :p21, "Password" = :p22, "PasswordResetCode" = :p23, "PhoneNumber" = :p24, "SecurityStamp" = :p25, "Surname" = :p26, "TenantId" = :p27, "UserName" = :p28 WHERE "Id" = :p29 AND "ConcurrencyStamp" = :p2;
   AffectedRows=AffectedRows+1;
SUSPEND;
END;

Parameters:
Name:@p29   Type:BigInt Used Value:1
Name:@p0    Type:Integer    Used Value:0
Name:@p1    Type:VarChar    Used Value:<null>
Name:@p2    Type:VarChar    Used Value:27f6b6c2-1ed0-4e36-bd3f-37983b7a58e8
Name:@p30   Type:VarChar    Used Value:234197cb-9b10-4597-8319-b985877c65ea
Name:@p3    Type:TimeStamp  Used Value:1/25/2018 12:19:00 PM
Name:@p4    Type:BigInt Used Value:<null>
Name:@p5    Type:BigInt Used Value:<null>
Name:@p6    Type:TimeStamp  Used Value:<null>
Name:@p7    Type:VarChar    Used Value:admin@aspnetboilerplate.com
Name:@p8    Type:VarChar    Used Value:<null>
Name:@p9    Type:Boolean    Used Value:True
Name:@p10   Type:Boolean    Used Value:False
Name:@p11   Type:Boolean    Used Value:True
Name:@p12   Type:Boolean    Used Value:True
Name:@p13   Type:Boolean    Used Value:False
Name:@p14   Type:Boolean    Used Value:False
Name:@p15   Type:TimeStamp  Used Value:1/25/2018 7:42:48 PM
Name:@p16   Type:TimeStamp  Used Value:1/25/2018 7:42:48 PM
Name:@p17   Type:BigInt Used Value:<null>
Name:@p18   Type:TimeStamp  Used Value:<null>
Name:@p19   Type:VarChar    Used Value:admin
Name:@p20   Type:VarChar    Used Value:ADMIN@ASPNETBOILERPLATE.COM
Name:@p21   Type:VarChar    Used Value:ADMIN
Name:@p22   Type:VarChar    Used Value:AQAAAAEAACcQAAAAEPzIJ+zmzu15jHbjz1U/s9KC/2xe2lHDsWLJAKIsqoVo7C/xyuNDsBVJD9fcPRxtYA==
Name:@p23   Type:VarChar    Used Value:<null>
Name:@p24   Type:VarChar    Used Value:<null>
Name:@p25   Type:VarChar    Used Value:477db6f3-7322-298c-969c-39e43f37ace7
Name:@p26   Type:VarChar    Used Value:admin
Name:@p27   Type:Integer    Used Value:<null>
Name:@p28   Type:VarChar    Used Value:admin

Notice the "ConcurrencyStamp" indeed appears both in SET and WHERE sections of the update. Interestingly, the logged parameters' list contains a @p30 parameter which is not actually used in the update. It is the same type as @p2 and I stumbled upon a case where it also had the same value.

Error details

Exception message:
Dynamic SQL Error
SQL error code = -637
duplicate specification of P2 - not supported

Stack trace:
at FirebirdSql.Data.FirebirdClient.FbCommand.ExecuteReader(CommandBehavior behavior) in C:\Users\Jiri\Documents\devel\NETProvider\working\Provider\src\FirebirdSql.Data.FirebirdClient\FirebirdClient\FbCommand.cs:line 517
   at System.Data.Common.DbCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.<ExecuteAsync>d__17.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.<ExecuteAsync>d__32.MoveNext()

Further technical details

Firebird version: 3.0.2 EntityFrameworkCore.FirebirdSql version: dev branch snapshot from 2018-01-25

Other details about my project setup: I added a byte-smallint mapping to FbTypeMapper as a workaround for unsupported TINYINT in Firebird; it allowed me to regenerate the migration and successfully update database (ABP enums have byte as an underlying type); I hope it's irrelevant to the exception.