Dapper icon indicating copy to clipboard operation
Dapper copied to clipboard

Unsigned type mapping overflow

Open Suprcode opened this issue 7 years ago • 7 comments

When querying to a strongly type object which uses an unsigned short (ushort) you get an arithmetic overflow if the SQL value is greater than short.MaxValue (32767).

The SQL data type is an INT (best used for ushort values)

The mapping looks to be ignoring the fact its converting to an unsigned value which should allow twice the size (65535)

Errors "Arithmetic operation resulted in an overflow." Error parsing column 21 (XX=65535 - Int32)

Suprcode avatar Dec 05 '18 23:12 Suprcode

Just hit this now with uint to bigint too

mika76 avatar Jan 16 '19 11:01 mika76

I fixed this by adding a custom handler for each of the unsigned types - though i think this should really be built in

public class UShortHandler : SqlMapper.TypeHandler<ushort>
    {
        private UShortHandler() {  }
        
        public static readonly SqlMapper.ITypeHandler Default = new UShortHandler();

        public override ushort Parse(object value)
        {
            return Convert.ToUInt16(value);
        }

        public override void SetValue(IDbDataParameter parameter, ushort value)
        {
            parameter.DbType = DbType.UInt16;
            parameter.Value = value;
        }
    }

Suprcode avatar Jan 17 '19 18:01 Suprcode

Oooh that's clever, thanks 😄 👍

mika76 avatar Jan 18 '19 10:01 mika76

Tagging this as 2.0 - I agree adding these handlers in the box in the next release seems correct on the surface. Going on the list.

NickCraver avatar Jan 27 '19 13:01 NickCraver

I encountered the same when trying to map (dap?) a BIGINT to a uint storage object property. Dapper version: 2.0.78

ChristoWolf avatar Oct 13 '21 13:10 ChristoWolf

I think I found the root of the issue. I encountered the same problem with mapping from SmallInt to byte. It is failing only with values more than 127.

I suspect method SqlMapper.FlexibleConvertBoxedFromHeadOfStack uses wrong OpCodes mapping because in my case with byte the method uses OpCodes.Conv_Ovf_I1_Un so it is trying to convert SQL value to type with max value = 127 when byte have max value = 255 and as result we have OverflowException for values bigger that 127. I think for conversion from SmallInt to byte the method should use OpCodes.Conv_Ovf_U1 or OpCodes.Conv_Ovf_U1_Un. I see a similar problem with other unsigned types: UInt16, UInt32 and UInt64.

Dapper version: 2.0.4 Stack trace:

System.Data.DataException: Error parsing column 2 (PaymentMethodID=130 - Int16)
 ---> System.OverflowException: Arithmetic operation resulted in an overflow.
 at Deserialize0b626ef8-7dcd-4ff8-bb3d-3a4e1e08cf86(IDataReader )
 --- End of inner exception stack trace ---
 at Dapper.SqlMapper.ThrowDataException(Exception ex, Int32 index, IDataReader reader, Object value) in C:\projects\dapper\Dapper\SqlMapper.cs:line 3633
 at Deserialize0b626ef8-7dcd-4ff8-bb3d-3a4e1e08cf86(IDataReader )
 at Dapper.SqlMapper.QueryAsync[T](IDbConnection cnn, Type effectiveType, CommandDefinition command)
 at DevcodePaymentProcessor.DataAccessLayer.RequestSettingRepository.GetRequestSettingPaymentMethodsAsync(Nullable`1 requestSettingId)
 at DevcodePaymentProcessor.BusinessLogic.Commands.ReadPaymentProcessingSettingsCommand.ReadPaymentProcessingSettingsAsync()
 at DevcodePaymentProcessor.Handlers.GetPaymentProcessingSettingsHandler.GetPaymentProcessingSettingsAsync()
 at Grpc.Shared.Server.UnaryServerMethodInvoker`3.ResolvedInterceptorInvoker(TRequest resolvedRequest, ServerCallContext resolvedContext)
 at Grpc.Shared.Server.UnaryServerMethodInvoker`3.ResolvedInterceptorInvoker(TRequest resolvedRequest, ServerCallContext resolvedContext)
 at DevcodePaymentProcessor.Logging.DevcodeLoggingInterceptor.UnaryServerHandler[TRequest,TResponse](TRequest request, ServerCallContext context, UnaryServerMethod`2 continuation)

Mapping type:

public class ProcessorRequestSettingPaymentMethod
{
    public int RowID { get; set; }
    public int ProcessorRequestSettingID { get; set; }
    public byte PaymentMethodID { get; set; }
}

rukpet avatar Jul 01 '22 19:07 rukpet

@mgravell, sorry for tagging, but I see this issue is stuck. There is a solution (PR #1795) for the issue. Please check PR.

rukpet avatar Nov 01 '23 11:11 rukpet