Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
sqlite: add support for readBigInts option in db connection level
  • Loading branch information
miguelmarcondesf committed Jun 11, 2025
commit 6836df6a7e7523e2c3ebc60b0c1a758f7de150ca
18 changes: 17 additions & 1 deletion src/node_sqlite.cc
Original file line number Diff line number Diff line change
Expand Up @@ -950,6 +950,22 @@ void DatabaseSync::New(const FunctionCallbackInfo<Value>& args) {
allow_load_extension = allow_extension_v.As<Boolean>()->Value();
}

Local<String> read_bigints_string =
FIXED_ONE_BYTE_STRING(env->isolate(), "readBigInts");
Local<Value> read_bigints_v;
if (options->Get(env->context(), read_bigints_string)
.ToLocal(&read_bigints_v)) {
if (!read_bigints_v->IsUndefined()) {
if (!read_bigints_v->IsBoolean()) {
THROW_ERR_INVALID_ARG_TYPE(
env->isolate(),
"The \"options.readBigInts\" argument must be a boolean.");
Comment thread
miguelmarcondesf marked this conversation as resolved.
Outdated
return;
}
open_config.set_use_big_ints(read_bigints_v.As<Boolean>()->Value());
}
}

Local<Value> timeout_v;
if (!options->Get(env->context(), env->timeout_string())
.ToLocal(&timeout_v)) {
Expand Down Expand Up @@ -1772,10 +1788,10 @@ StatementSync::StatementSync(Environment* env,
: BaseObject(env, object), db_(std::move(db)) {
MakeWeak();
statement_ = stmt;
use_big_ints_ = db_->use_big_ints();
// In the future, some of these options could be set at the database
// connection level and inherited by statements to reduce boilerplate.
return_arrays_ = false;
use_big_ints_ = false;
allow_bare_named_params_ = true;
allow_unknown_named_params_ = false;
bare_named_params_ = std::nullopt;
Expand Down
6 changes: 6 additions & 0 deletions src/node_sqlite.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,17 @@ class DatabaseOpenConfiguration {

inline int get_timeout() { return timeout_; }

inline void set_use_big_ints(bool flag) { use_big_ints_ = flag; }

inline bool get_use_big_ints() const { return use_big_ints_; }

private:
std::string location_;
bool read_only_ = false;
bool enable_foreign_keys_ = true;
bool enable_dqs_ = false;
int timeout_ = 0;
bool use_big_ints_ = false;
};

class StatementSync;
Expand Down Expand Up @@ -82,6 +87,7 @@ class DatabaseSync : public BaseObject {
void FinalizeBackups();
void UntrackStatement(StatementSync* statement);
bool IsOpen();
bool use_big_ints() const { return open_config_.get_use_big_ints(); }
sqlite3* Connection();

// In some situations, such as when using custom functions, it is possible
Expand Down
55 changes: 55 additions & 0 deletions test/parallel/test-sqlite-database-sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,61 @@ suite('DatabaseSync() constructor', () => {
t.after(() => { db.close(); });
db.exec('SELECT "foo";');
});

test('throws if options.readBigInts is provided but is not a boolean', (t) => {
t.assert.throws(() => {
new DatabaseSync('foo', { readBigInts: 42 });
}, {
code: 'ERR_INVALID_ARG_TYPE',
message: /The "options\.readBigInts" argument must be a boolean/,
});
});

test('allows reading big integers', (t) => {
const dbPath = nextDb();
const db = new DatabaseSync(dbPath, { readBigInts: true });
t.after(() => { db.close(); });

const setup = db.exec(`
CREATE TABLE data(key INTEGER PRIMARY KEY, val INTEGER) STRICT;
INSERT INTO data (key, val) VALUES (1, 42);
`);
t.assert.strictEqual(setup, undefined);

const query = db.prepare('SELECT val FROM data');
t.assert.strictEqual(query.setReadBigInts(true), undefined);
Comment thread
miguelmarcondesf marked this conversation as resolved.
Outdated
t.assert.deepStrictEqual(query.get(), { __proto__: null, val: 42n });

const insert = db.prepare('INSERT INTO data (key) VALUES (?)');
t.assert.strictEqual(insert.setReadBigInts(true), undefined);
Comment thread
miguelmarcondesf marked this conversation as resolved.
Outdated
t.assert.deepStrictEqual(
insert.run(20),
{ changes: 1n, lastInsertRowid: 20n },
);
});

test('allows reading numbers', (t) => {
const dbPath = nextDb();
const db = new DatabaseSync(dbPath, { readBigInts: false });
t.after(() => { db.close(); });

const setup = db.exec(`
CREATE TABLE data(key INTEGER PRIMARY KEY, val INTEGER) STRICT;
INSERT INTO data (key, val) VALUES (1, 42);
`);
t.assert.strictEqual(setup, undefined);

const query = db.prepare('SELECT val FROM data');
t.assert.strictEqual(query.setReadBigInts(false), undefined);
t.assert.deepStrictEqual(query.get(), { __proto__: null, val: 42 });

const insert = db.prepare('INSERT INTO data (key) VALUES (?)');
t.assert.strictEqual(insert.setReadBigInts(false), undefined);
t.assert.deepStrictEqual(
insert.run(20),
{ changes: 1, lastInsertRowid: 20 },
);
});
});

suite('DatabaseSync.prototype.open()', () => {
Expand Down