denisenkom / go-mssqldb

Microsoft SQL server driver written in go language
BSD 3-Clause "New" or "Revised" License
1.81k stars 493 forks source link

Precision Issue with SQL Server real Type in Golang Resulting in Unexpected Floating-Point Value #802

Open littlestar1998 opened 2 weeks ago

littlestar1998 commented 2 weeks ago

I have encountered a problem where my data field is of the real type and has a value of 1.232, leading to precision issues. The code is as follows:

Create SQL:

create table dbo.test
(
    id     int,
    v_real real
)
go

INSERT INTO master.dbo.test (id, v_real) VALUES (1, 1.232);

golang code

package main

import (
    "context"
    "database/sql"
    "fmt"
    _ "github.com/denisenkom/go-mssqldb"
    "log"
)

func main() {

    db, err := sql.Open("sqlserver", "sqlserver://sa:YourStrongPassw0rd@192.168.31.40:1433?database=master&connection+timeout=30")
    if err != nil {
        log.Fatal("Error creating connection pool: ", err.Error())
    }
    defer db.Close()

    err = db.PingContext(context.Background())
    if err != nil {
        log.Fatal("Error pinging database: ", err.Error())
    }
    fmt.Println("Connected to the database successfully")

    query := "SELECT id,v_real FROM dbo.test"
    rows, err := db.QueryContext(context.Background(), query)
    if err != nil {
        log.Fatal("Error querying database: ", err.Error())
    }
    defer rows.Close()

    // 获取列的信息
    columns, err := rows.Columns()
    if err != nil {
        log.Fatal("Error getting columns: ", err.Error())
    }

    values := make([]interface{}, len(columns))
    valuePtrs := make([]interface{}, len(columns))
    for i := range columns {
        valuePtrs[i] = &values[i]
    }

    // 读取行数据
    for rows.Next() {
        err := rows.Scan(valuePtrs...)
        if err != nil {
            log.Fatal("Error scanning row: ", err.Error())
        }

        for i, col := range columns {
            fmt.Printf("%s: %v\n", col, values[i])
        }
    }
}

The execution result is:

id: 1
v_real: 1.2319999933242798

The main issue arises from the type conversion in types.go at line 396. The math.Float32frombits function returns a 32-bit number, which is then forcibly converted to 64-bit.

Here is a Golang example:

var v float32 = 1.232
fmt.Println(fmt.Sprintln("%+v", float64(v)))

Problem reproduction:

If necessary, I can submit a PR to fix this.