diff --git a/src/node_sqlite.cc b/src/node_sqlite.cc index 1202d2c8cf2464..fbef4e3b0d71c8 100644 --- a/src/node_sqlite.cc +++ b/src/node_sqlite.cc @@ -370,12 +370,21 @@ bool StatementSync::BindValue(const Local& value, const int index) { Local StatementSync::ColumnToValue(const int column) { switch (sqlite3_column_type(statement_, column)) { - case SQLITE_INTEGER: + case SQLITE_INTEGER: { + sqlite3_int64 value = sqlite3_column_int64(statement_, column); if (use_big_ints_) { - return BigInt::New(env()->isolate(), - sqlite3_column_int64(statement_, column)); + return BigInt::New(env()->isolate(), value); + } else if (std::abs(value) <= kMaxSafeJsInteger) { + return Number::New(env()->isolate(), value); + } else { + THROW_ERR_OUT_OF_RANGE(env()->isolate(), + "The value of column %d is too large to be " + "represented as a JavaScript number: %" PRId64, + column, + value); + return Local(); } - // Fall through. + } case SQLITE_FLOAT: return Number::New(env()->isolate(), sqlite3_column_double(statement_, column)); diff --git a/test/parallel/test-sqlite.js b/test/parallel/test-sqlite.js index 99c8b7ee72a5c4..d07c3ac01b9a23 100644 --- a/test/parallel/test-sqlite.js +++ b/test/parallel/test-sqlite.js @@ -388,6 +388,22 @@ suite('StatementSync.prototype.setReadBigInts()', () => { message: /The "readBigInts" argument must be a boolean/, }); }); + + test('BigInt is required for reading large integers', (t) => { + const db = new DatabaseSync(nextDb()); + const bad = db.prepare(`SELECT ${Number.MAX_SAFE_INTEGER} + 1`); + t.assert.throws(() => { + bad.get(); + }, { + code: 'ERR_OUT_OF_RANGE', + message: /^The value of column 0 is too large.*: 9007199254740992$/, + }); + const good = db.prepare(`SELECT ${Number.MAX_SAFE_INTEGER} + 1`); + good.setReadBigInts(true); + t.assert.deepStrictEqual(good.get(), { + [`${Number.MAX_SAFE_INTEGER} + 1`]: 2n ** 53n, + }); + }); }); suite('StatementSync.prototype.setAllowBareNamedParameters()', () => {