go-sql-driver / mysql

Go MySQL Driver is a MySQL driver for Go's (golang) database/sql package
https://pkg.go.dev/github.com/go-sql-driver/mysql
Mozilla Public License 2.0
14.45k stars 2.3k forks source link

Float32 support broken #1617

Closed luisgarciaalanis closed 1 month ago

luisgarciaalanis commented 1 month ago

Issue description

Storing a float32 value stores it incorrectly.

0.16 is stored as 0.1599999964237213

Diving into the code I found this seems to happen when the reflect Package Float() returns a float64 out of the original float32 value.

Since the reflect package does not support float32, this conversion might need to be done manually.

Here is the line where this happens: https://github.com/go-sql-driver/mysql/blob/master/statement.go#L177

Example code


DB.Exec("update some_table set some_value=0.16;") // <----- this store 0.16 as expected.

DB.Exec("update some_table set some_value=?;", float32(0.16)) <---- this stores 0.1599999964237213 

// Also you can inspect how the value changes on a debugger:
    var a = float32(0.16)
    var b = reflect.ValueOf(a)
    var c = b.Float()   // <--- here is where it goes bad.

Error log

If you have an error log, please paste it here.

Configuration

Driver version (or git SHA): v1.8.1

Go version: run go version in your console go1.22.5

Server version: E.g. MySQL 5.6, MariaDB 10.0.20 docker.io/library/mariadb:11.3.2

Server OS: E.g. Debian 8.1 (Jessie), Windows 10 alpine:3.19.1

shogo82148 commented 1 month ago

This is a limitation of floating-point numbers, not a driver bug. Since float32 cannot precisely represent 0.16, float32(0.16) is rounded to the nearest value, which is 0.1599999964237213134765625. This loss of information occurs during the conversion to float32, so the driver cannot restore it.

reference:

luisgarciaalanis commented 1 month ago

This is a limitation of floating-point numbers, not a driver bug. Since float32 cannot precisely represent 0.16, float32(0.16) is rounded to the nearest value, which is 0.1599999964237213134765625. This loss of information occurs during the conversion to float32, so the driver cannot restore it.

reference:

Thanks