Skip to content

Commit 2fc910b

Browse files
committed
sqlite: improve error for excess bound parameters
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
1 parent ee5a070 commit 2fc910b

3 files changed

Lines changed: 36 additions & 6 deletions

File tree

doc/api/sqlite.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,6 +1034,9 @@ Binding a key that does not name a parameter of the statement throws an
10341034
`ERR_INVALID_STATE` error unless unknown named parameters are ignored. See
10351035
[`statement.setAllowUnknownNamedParameters()`][].
10361036

1037+
Passing more anonymous parameters than the statement has also throws an
1038+
`ERR_INVALID_STATE` error.
1039+
10371040
See [Type conversion between JavaScript and SQLite][] for the values that can be
10381041
bound. Binding any other value throws an `ERR_INVALID_ARG_TYPE` error.
10391042

src/node_sqlite.cc

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2777,13 +2777,25 @@ bool StatementSync::BindParams(const FunctionCallbackInfo<Value>& args) {
27772777
anon_start++;
27782778
}
27792779

2780+
int param_count = sqlite3_bind_parameter_count(statement_);
2781+
27802782
for (int i = anon_start; i < args.Length(); ++i) {
2781-
while (1) {
2783+
while (anon_idx <= param_count) {
27822784
const char* param = sqlite3_bind_parameter_name(statement_, anon_idx);
27832785
if (param == nullptr || param[0] == '?') break;
27842786
anon_idx++;
27852787
}
27862788

2789+
if (anon_idx > param_count) {
2790+
THROW_ERR_INVALID_STATE(
2791+
env(),
2792+
"Too many parameter values were provided. The statement accepts "
2793+
"%d, but received %d",
2794+
i - anon_start,
2795+
args.Length() - anon_start);
2796+
return false;
2797+
}
2798+
27872799
if (!BindValue(args[i], anon_idx)) {
27882800
return false;
27892801
}

test/parallel/test-sqlite-statement-sync.js

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ suite('StatementSync.prototype.run()', () => {
337337
t.assert.deepStrictEqual(stmt.run(), { changes: 1, lastInsertRowid: 1 });
338338
});
339339

340-
test('SQLite throws when trying to bind too many parameters', (t) => {
340+
test('throws when trying to bind too many parameters', (t) => {
341341
const db = new DatabaseSync(':memory:');
342342
t.after(() => { db.close(); });
343343
const setup = db.exec(
@@ -348,10 +348,25 @@ suite('StatementSync.prototype.run()', () => {
348348
t.assert.throws(() => {
349349
stmt.run(1, 2, 3);
350350
}, {
351-
code: 'ERR_SQLITE_ERROR',
352-
message: 'column index out of range',
353-
errcode: 25,
354-
errstr: 'column index out of range',
351+
code: 'ERR_INVALID_STATE',
352+
message: 'Too many parameter values were provided. ' +
353+
'The statement accepts 2, but received 3',
354+
});
355+
356+
t.assert.throws(() => {
357+
db.prepare('SELECT 1').get(5);
358+
}, {
359+
code: 'ERR_INVALID_STATE',
360+
message: 'Too many parameter values were provided. ' +
361+
'The statement accepts 0, but received 1',
362+
});
363+
364+
t.assert.throws(() => {
365+
db.prepare('SELECT $a AS a, ? AS b').get({ $a: 1 }, 2, 3);
366+
}, {
367+
code: 'ERR_INVALID_STATE',
368+
message: 'Too many parameter values were provided. ' +
369+
'The statement accepts 1, but received 2',
355370
});
356371
});
357372

0 commit comments

Comments
 (0)