← 返回日报
精读 预计 1 分钟

The same SQLite query returns different results in Bun and Node

摘要

作者发现同一条 SQLite 查询在 Node.js 中返回浮点数而在 Bun 中返回整数。原因在于 Node.js 将所有数字参数绑定为 double,而 Bun 会识别整数并使用 sqlite3_bind_int。文章探讨了两种环境对 JavaScript 数值类型的不同理解:Node 侧重于 JS 规范中数值均为 double 的特性,而 Bun 侧重于保持 SQL 行为的一致性。

荐读理由

在跨 Node 和 Bun 环境开发或迁移项目时,需警惕 SQLite 参数绑定导致的计算逻辑不一致:Node 将所有数字绑定为 double(使 3/2=1.5),而 Bun 会按需绑定为 int(使 3/2=1),这直接影响你对数据库查询结果一致性的判断。

原文

Bun and NodeJS return different results for the same SQLite query

Until the other day, I didn't even think this was possible. The same language, the same database, and the same query returning different results.

Take this SQL:

select 3 / 2;

The result turns out to be 1 because SQLite and most other databases treat this as integer arithmetic. Both bun and node return the result as 1 also:

Here is the node version:

import { DatabaseSync } from 'node:sqlite';

const db = new DatabaseSync(':memory:');
const statement = db.prepare('select 3 / 2 as result');
const result = statement.get();

console.log(result); // { result: 1 }

Now, let's pass the 2 in as a parameter instead using node:

import { DatabaseSync } from 'node:sqlite';

const db = new DatabaseSync(':memory:');
const statement = db.prepare('select 3 / ? as result');
const result = statement.get(2);

console.log(result); // { result: 1.5 }

The result has changed to 1.5.

Let's try it with bun:

import { Database } from 'bun:sqlite';

const db = new Database(':memory:');
const statement = db.prepare('select 3 / ? as result');
const result = statement.get(2);

console.log(result); // { result: 1 }

The same query, the same database, and the same language, but different results.

Why is this the case? It turns out that node chooses to bind all number parameters using sqlite3_bind_double regardless of whether they are mathemetical integers or not. Bun, on the other hand, decides to use sqlite3_bind_int or the 64-bit version of this if the value is actually an integer.

Who is right? One argument from the node camp is that

JavaScript doesn't have an integer type so all numbers should be bound to statements as doubles

Everyone knows this right? All the smart people do at least. JavaScript doesn't have an integer type! It is true, but does JavaScript have the concept of integers? This is a different question. The answer is yes.

const shift = 5 << 1;

What is 5? It is very specifically an integer in this context, so the debate cannot end there. When you ask somebody what the 2 is in this code, what will they say?

const result = statement.get(2);

"It is a number". "What kind of number?", you ask. "An integer".

It still seems entirely up for debate as to what the correct approach is. The fact that taking a number out of the statement and turning it into a parameter results in a different outcome is maybe the best case for binding integers as integers.

Hacker News · 1 赞 · 0 评 讨论 → 阅读原文 →

这条对你有帮助吗?