Skip to content

Commit 0e999eb

Browse files
cjihrigaduh95
authored andcommitted
sqlite: add getter to detect transactions
This commit adds an isTransaction getter to the DatabaseSync class for determining if the database is currently within a transaction. Fixes: #57922 PR-URL: #57925 Reviewed-By: Edy Silva <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Michaël Zasso <[email protected]> Reviewed-By: Zeyu "Alex" Yang <[email protected]>
1 parent a4105db commit 0e999eb

File tree

4 files changed

+62
-0
lines changed

4 files changed

+62
-0
lines changed

doc/api/sqlite.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,15 @@ added: v22.15.0
200200

201201
* {boolean} Whether the database is currently open or not.
202202

203+
### `database.isTransaction`
204+
205+
<!-- YAML
206+
added: REPLACEME
207+
-->
208+
209+
* {boolean} Whether the database is currently within a transaction. This method
210+
is a wrapper around [`sqlite3_get_autocommit()`][].
211+
203212
### `database.open()`
204213

205214
<!-- YAML
@@ -628,6 +637,7 @@ resolution handler passed to [`database.applyChangeset()`][]. See also
628637
[`sqlite3_create_function_v2()`]: https://www.sqlite.org/c3ref/create_function.html
629638
[`sqlite3_exec()`]: https://www.sqlite.org/c3ref/exec.html
630639
[`sqlite3_expanded_sql()`]: https://www.sqlite.org/c3ref/expanded_sql.html
640+
[`sqlite3_get_autocommit()`]: https://sqlite.org/c3ref/get_autocommit.html
631641
[`sqlite3_last_insert_rowid()`]: https://www.sqlite.org/c3ref/last_insert_rowid.html
632642
[`sqlite3_load_extension()`]: https://www.sqlite.org/c3ref/load_extension.html
633643
[`sqlite3_prepare_v2()`]: https://www.sqlite.org/c3ref/prepare.html

src/node_sqlite.cc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,15 @@ void DatabaseSync::IsOpenGetter(const FunctionCallbackInfo<Value>& args) {
537537
args.GetReturnValue().Set(db->IsOpen());
538538
}
539539

540+
void DatabaseSync::IsTransactionGetter(
541+
const FunctionCallbackInfo<Value>& args) {
542+
DatabaseSync* db;
543+
ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
544+
Environment* env = Environment::GetCurrent(args);
545+
THROW_AND_RETURN_ON_BAD_STATE(env, !db->IsOpen(), "database is not open");
546+
args.GetReturnValue().Set(sqlite3_get_autocommit(db->connection_) == 0);
547+
}
548+
540549
void DatabaseSync::Close(const FunctionCallbackInfo<Value>& args) {
541550
DatabaseSync* db;
542551
ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
@@ -1876,6 +1885,10 @@ static void Initialize(Local<Object> target,
18761885
db_tmpl,
18771886
FIXED_ONE_BYTE_STRING(isolate, "isOpen"),
18781887
DatabaseSync::IsOpenGetter);
1888+
SetSideEffectFreeGetter(isolate,
1889+
db_tmpl,
1890+
FIXED_ONE_BYTE_STRING(isolate, "isTransaction"),
1891+
DatabaseSync::IsTransactionGetter);
18791892
SetConstructorFunction(context, target, "DatabaseSync", db_tmpl);
18801893
SetConstructorFunction(context,
18811894
target,

src/node_sqlite.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ class DatabaseSync : public BaseObject {
5555
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
5656
static void Open(const v8::FunctionCallbackInfo<v8::Value>& args);
5757
static void IsOpenGetter(const v8::FunctionCallbackInfo<v8::Value>& args);
58+
static void IsTransactionGetter(
59+
const v8::FunctionCallbackInfo<v8::Value>& args);
5860
static void Close(const v8::FunctionCallbackInfo<v8::Value>& args);
5961
static void Prepare(const v8::FunctionCallbackInfo<v8::Value>& args);
6062
static void Exec(const v8::FunctionCallbackInfo<v8::Value>& args);

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,3 +315,40 @@ suite('DatabaseSync.prototype.exec()', () => {
315315
});
316316
});
317317
});
318+
319+
suite('DatabaseSync.prototype.isTransaction', () => {
320+
test('correctly detects a committed transaction', (t) => {
321+
const db = new DatabaseSync(':memory:');
322+
323+
t.assert.strictEqual(db.isTransaction, false);
324+
db.exec('BEGIN');
325+
t.assert.strictEqual(db.isTransaction, true);
326+
db.exec('CREATE TABLE foo (id INTEGER PRIMARY KEY)');
327+
t.assert.strictEqual(db.isTransaction, true);
328+
db.exec('COMMIT');
329+
t.assert.strictEqual(db.isTransaction, false);
330+
});
331+
332+
test('correctly detects a rolled back transaction', (t) => {
333+
const db = new DatabaseSync(':memory:');
334+
335+
t.assert.strictEqual(db.isTransaction, false);
336+
db.exec('BEGIN');
337+
t.assert.strictEqual(db.isTransaction, true);
338+
db.exec('CREATE TABLE foo (id INTEGER PRIMARY KEY)');
339+
t.assert.strictEqual(db.isTransaction, true);
340+
db.exec('ROLLBACK');
341+
t.assert.strictEqual(db.isTransaction, false);
342+
});
343+
344+
test('throws if database is not open', (t) => {
345+
const db = new DatabaseSync(nextDb(), { open: false });
346+
347+
t.assert.throws(() => {
348+
return db.isTransaction;
349+
}, {
350+
code: 'ERR_INVALID_STATE',
351+
message: /database is not open/,
352+
});
353+
});
354+
});

0 commit comments

Comments
 (0)