node-postgres icon indicating copy to clipboard operation
node-postgres copied to clipboard

Precision loss on numbers close to MAX_SAFE_INTEGER on Postgres < 12

Open SevInf opened this issue 2 years ago • 0 comments

To reproduce:

const assert = require("assert");
const { Client } = require("pg");
const pg = new Client("postgres://prisma:prisma@localhost:5432/tests");

async function main() {
  await pg.connect();

  try {
    const result = await pg.query({
      text: "SELECT $1::FLOAT8",
      values: [Number.MAX_SAFE_INTEGER],
    });
    assert.strictEqual(result.rows[0].float8, Number.MAX_SAFE_INTEGER);
  } finally {
    await pg.end();
  }
}

main();

If used with Postgres < 12, this fails with:

AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
+ actual - expected

+ 9007199254740990
- 9007199254740991

Postgres 12+ is fine.

This value can be correctly stored in both JS and Postgress without precision loss. I believe the problem is default extra_float_digits settings: pre-12, postgres rounded floats to 15 digits when outputting them as text, starting from 12 they switched default to outputting as many digits as necessary to preserve the precision. Setting extra_float_digits to 1 fixes the problem.

There was a similar issue, #730 that is marked as fixed. Might just not be the case for extremely large numbers.

SevInf avatar Nov 06 '23 14:11 SevInf