Skip to content

[BUG]: MSSQL real() column returns imprecise float64 values -- missing mapFromDriverValue #5527

@valerii-kuzivanov

Description

@valerii-kuzivanov

Report hasn't been filed before.

  • I have verified that the bug I'm about to report hasn't been filed before.

What version of drizzle-orm are you using?

1.0.0-beta.18-7eb39f0

What version of drizzle-kit are you using?

1.0.0-beta.18-7eb39f0

Other packages

No response

Describe the Bug

Issue

The MSSQL real() column type returns imprecise float64 representations of float32 values. A value stored as 0.01 in a SQL Server real column is returned to JavaScript as 0.009999999776482582.

SQL Server's real type is IEEE 754 single-precision (float32, ~7 significant digits). The mssql Node.js driver (tedious) reads the 4-byte float32 from the wire and widens it to a JavaScript number (float64). This widening exposes the float32 representation error -- 0.01 cannot be represented exactly in 32 bits, so the float64 value becomes 0.009999999776482582.

The MsSqlReal class in drizzle-orm/mssql-core/columns/real.js has no mapFromDriverValue override, so the raw widened value is passed through as-is:

var MsSqlReal = class extends MsSqlColumnWithIdentity {
    static [entityKind] = "MsSqlReal";
    getSQLType() {
        return "real";
    }
    // no mapFromDriverValue -- raw float64 value is used
};

By contrast, MsSqlFloat (which maps to float(53) / float64) does not have this problem because the driver value is already native float64 precision.

Expected behavior:

real() columns should return values rounded to 7 significant digits (the actual precision of float32), so 0.01 in the database comes back as 0.01 in JavaScript, not 0.009999999776482582.

Suggested fix:

Add a mapFromDriverValue to MsSqlReal that rounds to float32 precision:

class MsSqlReal extends MsSqlColumnWithIdentity {
    static [entityKind] = "MsSqlReal";
    getSQLType() {
        return "real";
    }
    mapFromDriverValue(value: number): number {
        return parseFloat(value.toPrecision(7));
    }
}

Alternatively, Math.fround(value) could be used, but parseFloat(value.toPrecision(7)) produces cleaner decimal output.

Reproduction

import { drizzle } from 'drizzle-orm/node-mssql';
import { mssqlTable, real, int } from 'drizzle-orm/mssql-core';
const testTable = mssqlTable('test', {
    id: int().primaryKey(),
    tolerance: real(),
});
// Assume a row with tolerance = 0.01 exists in SQL Server
const rows = await db.select().from(testTable);
console.log(rows[0].tolerance);
// Actual:   0.009999999776482582
// Expected: 0.01

Current workaround

Replace real with a customType that includes fromDriver rounding:

import { customType } from 'drizzle-orm/mssql-core';

const real = customType<{ data: number; driverData: number }>({
    dataType() { return 'real'; },
    fromDriver(value: number): number {
        return parseFloat(value.toPrecision(7));
    },
});

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions