注册

【Node.js 驱动】dmdb 1.0.52452 查询 BIGINT 列静默丢失精度(超出 JS 安全整数范围无任何报错)

刺 2026/10/21 349 1

为提高效率,提问时请提供以下信息,问题描述清晰可优先响应。
【DM版本】:DM8(问题位于 Node.js 驱动 dmdb 端,与 DM 服务器版本无关,任意版本均可复现)
【操作系统】:Windows / Linux 均可复现(Node.js ≥ 18
【CPU】:【CPU】:无关联(x64 / ARM 均可复现)
【问题描述】:
一、现象
BIGINT 列的值超出 JS 安全整数范围(Number.MAX_SAFE_INTEGER = 2^53-1 ≈ 9.007e15)时,驱动不抛错、静默返回丢精度后的 number。业务系统普遍使用雪花 ID(19 位,约 1e18 量级)作主键,会导致查出来的 ID 本身就是错的,且极难察觉——拿错误 ID 回查会得出"记录不存在"的错误结论。
二、复现步骤
SQL:
CREATE TABLE T(ID BIGINT);
INSERT INTO T VALUES(2071964095068016641);
COMMIT;
Node.js(dmdb@1.0.52452,npm 最新版):
const dmdb = require('dmdb');
const conn = await dmdb.getConnection({ connectString: 'dm://localhost:5236', user: 'SYSDBA', password: '
**' });
const r = await conn.execute('SELECT ID FROM T');
console.log(r.rows[0][0]); // 输出 2071964095068016600(实际值 ...641,差 41)
console.log(typeof r.rows[0][0]); // number,无任何警告
三、根因定位(驱动源码)

  1. src/utils/bufferUtil.js:BufferUtil.i(di)已用 BigInt 精确读出 8 字节 Int64;
  2. src/convert/db2j.js:DB2J.toNumber 的 BIGINT 分支执行 Number(BufferUtil.i(t, 0)),将精确的 BigInt 主动转为 double,精度在此丢失;
  3. 对比 DB2J.toString 的 BIGINT 分支为 BufferUtil.i(d, 0).toString(),精确无损——即配置 dmdb.fetchAsString = [dmdb.NUMBER] 后结果正确,说明精确的数据通路已存在,仅默认路径有损。
    四、建议(任一即可)
  4. 参考 node-postgres:int8 默认以字符串返回(业界对此问题的成熟做法);
  5. 参考 mysql2 的 supportBigNumbers / bigNumberStrings:增加选项,BIGINT 超出安全整数范围时返回字符串;
  6. 至少在《DM Node.js 编程指南》补充显著警告:BIGINT / DECIMAL 超出 2^53-1 会静默丢精度,需配置 dmdb.fetchAsString = [dmdb.NUMBER] 规避。
    五、现行规避方式
    dmdb.fetchAsString = [dmdb.NUMBER] 可让数值列以字符串精确返回(已实测验证),但会改变所有数值列的返回类型,希望官方提供更精准的方案或文档说明。
回答 0
暂无回答
扫一扫
联系客服