sqlite: excess bound parameters produce an opaque "column index out of range" error
还没有人认领这个 Issue。
- 主要语言
- JavaScript
- 星标
- 122k
- 派生
- 37.4k
- 平均合并
- 4 天 3 小时
- 30 天内合并 PR
- 272
描述
Version
v24.15.0 (also present on main)
Platform
Darwin 25.6.0 arm64 (platform-independent — pure BindParams logic)
Subsystem
sqlite
What steps will reproduce the bug?
const { DatabaseSync } = require('node:sqlite');
const db = new DatabaseSync(':memory:');
db.exec('CREATE TABLE t(a)');
const ins = db.prepare('INSERT INTO t VALUES (?)');
ins.run(1, 2); // ERR_SQLITE_ERROR, errcode 25, "column index out of range"
db.prepare('SELECT 1').get(5); // same
Any excess anonymous argument reproduces it, regardless of type — 2, 'x', and null all give the identical message.
How often does it reproduce? Is there a required condition?
Always, whenever the number of anonymous arguments exceeds the statement's sqlite3_bind_parameter_count().
What is the expected behavior? Why is that the expected behavior?
An error naming the actual problem — that more parameters were supplied than the statement accepts, ideally with both counts. Something like:
TypeError [ERR_INVALID_ARG_COUNT]: Statement accepts 1 parameter, but 2 were provided.
Two reasons this matters:
-
The message describes the wrong thing. "Column index out of range" is SQLite's wording for a binding index, but to a JS caller "column" reads as a table column, pointing them at their schema rather than their call site. Nothing in the message indicates an argument-count mismatch.
-
It's inconsistent with how the adjacent failure is reported. A wrong-type argument gets a precise Node-authored error:
ERR_INVALID_ARG_TYPE: Provided value cannot be bound to SQLite parameter 2.A wrong-count argument falls through to a raw SQLite error code. Both are caller mistakes in the same call, caught in the same function.
What do you see instead?
ERR_SQLITE_ERROR with errcode: 25 and message column index out of range.
Additional information
The anonymous-binding loop in StatementSync::BindParams (src/node_sqlite.cc) iterates args from anon_start to args.Length() without comparing that span against sqlite3_bind_parameter_count(), so the overflow surfaces from sqlite3_bind_* instead. param_count is already fetched a few lines above, inside the bare-named-params block. A pre-loop guard would cover every excess-argument case at once.
Worth deciding up front whether this should throw at all, or ignore extra arguments the way ordinary JS functions do. Throwing seems better for a database API, and it's the current behavior, so a guard would preserve semantics while fixing only the message. Note this would be a breaking change for anyone matching on ERR_SQLITE_ERROR/errcode 25, so it likely wants semver-major treatment.
Surfaced while reviewing #62008, which changes undefined handling in the same function; the two are independent.
贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
调研方向
从 src/node_sqlite.cc 中的 StatementSync::BindParams 开始,阅读现有的 param_count 处理逻辑和匿名 binding 循环。使用提供的 SQL 片段重现该问题;完成的标准是:多余的匿名参数报告明确的参数数量错误,而不是 SQLite errcode 25,同时不改变现有的 binding 行为。
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- javascript, node.js, sqlite
- 领域
- databases
- Issue 类型
- 缺陷
- 难度
- 3/5
- 预计耗时
- 1-2 天
- 活跃度
- 冷清
- 描述清晰度
- 描述清楚
- 新手友好度
- 68/100