78
78
src/node_sqlite.ccCopy file name to clipboard Expand all lines: src/node_sqlite.cc +19 Lines changed: 19 additions & 0 deletions Original file line number Diff line number Diff line change @@ -731,6 +731,8 @@ bool DatabaseSync::Open() {
731
731
CHECK_ERROR_OR_THROW (env ()->isolate (), this , r, SQLITE_OK, false );
732
732
CHECK_EQ (foreign_keys_enabled, open_config_.get_enable_foreign_keys ());
733
733
734
+ sqlite3_busy_timeout (connection_, open_config_.get_timeout ());
735
+
734
736
if (allow_load_extension_) {
735
737
if (env ()->permission ()->enabled ()) [[unlikely]] {
736
738
THROW_ERR_LOAD_SQLITE_EXTENSION (env (),
@@ -940,6 +942,23 @@ void DatabaseSync::New(const FunctionCallbackInfo& args) {
940
942
}
941
943
allow_load_extension = allow_extension_v.As ()->Value ();
942
944
}
945
+
946
+ Local timeout_v;
947
+ if (!options->Get (env->context (), env->timeout_string ())
948
+ .ToLocal (&timeout_v)) {
949
+ return ;
950
+ }
951
+
952
+ if (!timeout_v->IsUndefined ()) {
953
+ if (!timeout_v->IsInt32 ()) {
954
+ THROW_ERR_INVALID_ARG_TYPE (
955
+ env->isolate (),
956
+ " The \" options.timeout\" argument must be an integer." );
957
+ return ;
958
+ }
959
+
960
+ open_config.set_timeout (timeout_v.As ()->Value ());
961
+ }
943
962
}
944
963
945
964
new DatabaseSync (
Original file line number Diff line number Diff line change @@ -35,11 +35,16 @@ class DatabaseOpenConfiguration {
35
35
36
36
inline void set_enable_dqs (bool flag) { enable_dqs_ = flag; }
37
37
38
+ inline void set_timeout (int timeout) { timeout_ = timeout; }
39
+
40
+ inline int get_timeout () { return timeout_; }
41
+
38
42
private:
39
43
std::string location_;
40
44
bool read_only_ = false ;
41
45
bool enable_foreign_keys_ = true ;
42
46
bool enable_dqs_ = false ;
47
+ int timeout_ = 0 ;
43
48
};
44
49
45
50
class StatementSync ;
Original file line number Diff line number Diff line change @@ -77,6 +77,15 @@ suite('DatabaseSync() constructor', () => {
77
77
} ) ;
78
78
} ) ;
79
79
80
+ test ( 'throws if options.timeout is provided but is not an integer' , ( t ) => {
81
+ t . assert . throws ( ( ) => {
82
+ new DatabaseSync ( 'foo' , { timeout : .99 } ) ;
83
+ } , {
84
+ code : 'ERR_INVALID_ARG_TYPE' ,
85
+ message : / T h e " o p t i o n s \. t i m e o u t " a r g u m e n t m u s t b e a n i n t e g e r / ,
86
+ } ) ;
87
+ } ) ;
88
+
80
89
test ( 'is not read-only by default' , ( t ) => {
81
90
const dbPath = nextDb ( ) ;
82
91
const db = new DatabaseSync ( dbPath ) ;
Original file line number Diff line number Diff line change
1
+ 'use strict' ;
2
+ require ( '../common' ) ;
3
+ const tmpdir = require ( '../common/tmpdir' ) ;
4
+ const { join } = require ( 'node:path' ) ;
5
+ const { DatabaseSync } = require ( 'node:sqlite' ) ;
6
+ const { test } = require ( 'node:test' ) ;
7
+ const { once } = require ( 'node:events' ) ;
8
+ const { Worker } = require ( 'node:worker_threads' ) ;
9
+ let cnt = 0 ;
10
+
11
+ tmpdir . refresh ( ) ;
12
+
13
+ function nextDb ( ) {
14
+ return join ( tmpdir . path , `database-${ cnt ++ } .db` ) ;
15
+ }
16
+
17
+ test ( 'waits to acquire lock' , async ( t ) => {
18
+ const DB_PATH = nextDb ( ) ;
19
+ const conn = new DatabaseSync ( DB_PATH ) ;
20
+ t . after ( ( ) => {
21
+ try {
22
+ conn . close ( ) ;
23
+ } catch {
24
+ // Ignore.
25
+ }
26
+ } ) ;
27
+
28
+ conn . exec ( 'CREATE TABLE IF NOT EXISTS data (value TEXT)' ) ;
29
+ conn . exec ( 'BEGIN EXCLUSIVE;' ) ;
30
+ const worker = new Worker ( `
31
+ 'use strict';
32
+ const { DatabaseSync } = require('node:sqlite');
33
+ const { workerData } = require('node:worker_threads');
34
+ const conn = new DatabaseSync(workerData.database, { timeout: 30000 });
35
+ conn.exec('SELECT * FROM data');
36
+ conn.close();
37
+ ` , {
38
+ eval : true ,
39
+ workerData : {
40
+ database : DB_PATH ,
41
+ }
42
+ } ) ;
43
+ await once ( worker , 'online' ) ;
44
+ conn . exec ( 'COMMIT;' ) ;
45
+ await once ( worker , 'exit' ) ;
46
+ } ) ;
47
+
48
+ test ( 'throws if the lock cannot be acquired before timeout' , ( t ) => {
49
+ const DB_PATH = nextDb ( ) ;
50
+ const conn1 = new DatabaseSync ( DB_PATH ) ;
51
+ t . after ( ( ) => {
52
+ try {
53
+ conn1 . close ( ) ;
54
+ } catch {
55
+ // Ignore.
56
+ }
57
+ } ) ;
58
+ const conn2 = new DatabaseSync ( DB_PATH , { timeout : 1 } ) ;
59
+ t . after ( ( ) => {
60
+ try {
61
+ conn2 . close ( ) ;
62
+ } catch {
63
+ // Ignore.
64
+ }
65
+ } ) ;
66
+
67
+ conn1 . exec ( 'CREATE TABLE IF NOT EXISTS data (value TEXT)' ) ;
68
+ conn1 . exec ( 'PRAGMA locking_mode = EXCLUSIVE; BEGIN EXCLUSIVE;' ) ;
69
+ t . assert . throws ( ( ) => {
70
+ conn2 . exec ( 'SELECT * FROM data' ) ;
71
+ } , / d a t a b a s e i s l o c k e d / ) ;
72
+ } ) ;
You can’t perform that action at this time.
0 commit comments