Skip to content

Commit dc076bf

Browse files
author
Dane Springmeyer
committed
Merge pull request #631 from briangreenery/sqlite3-interrupt
Add support for sqlite3_interrupt (with fixed test)
2 parents 9a038b5 + 434d0da commit dc076bf

File tree

3 files changed

+99
-0
lines changed

3 files changed

+99
-0
lines changed

src/database.cc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ NAN_MODULE_INIT(Database::Init) {
2323
Nan::SetPrototypeMethod(t, "serialize", Serialize);
2424
Nan::SetPrototypeMethod(t, "parallelize", Parallelize);
2525
Nan::SetPrototypeMethod(t, "configure", Configure);
26+
Nan::SetPrototypeMethod(t, "interrupt", Interrupt);
2627

2728
NODE_SET_GETTER(t, "open", OpenGetter);
2829

@@ -224,6 +225,8 @@ void Database::Work_BeginClose(Baton* baton) {
224225
assert(baton->db->pending == 0);
225226

226227
baton->db->RemoveCallbacks();
228+
baton->db->closing = true;
229+
227230
int status = uv_queue_work(uv_default_loop(),
228231
&baton->request, Work_Close, (uv_after_work_cb)Work_AfterClose);
229232
assert(status == 0);
@@ -249,6 +252,8 @@ void Database::Work_AfterClose(uv_work_t* req) {
249252
Baton* baton = static_cast<Baton*>(req->data);
250253
Database* db = baton->db;
251254

255+
db->closing = false;
256+
252257
Local<Value> argv[1];
253258
if (baton->status != SQLITE_OK) {
254259
EXCEPTION(Nan::New(baton->message.c_str()).ToLocalChecked(), baton->status, exception);
@@ -351,6 +356,21 @@ NAN_METHOD(Database::Configure) {
351356
info.GetReturnValue().Set(info.This());
352357
}
353358

359+
NAN_METHOD(Database::Interrupt) {
360+
Database* db = Nan::ObjectWrap::Unwrap<Database>(info.This());
361+
362+
if (!db->open) {
363+
return Nan::ThrowError("Database is not open");
364+
}
365+
366+
if (db->closing) {
367+
return Nan::ThrowError("Database is closing");
368+
}
369+
370+
sqlite3_interrupt(db->_handle);
371+
info.GetReturnValue().Set(info.This());
372+
}
373+
354374
void Database::SetBusyTimeout(Baton* baton) {
355375
assert(baton->db->open);
356376
assert(baton->db->_handle);

src/database.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ class Database : public Nan::ObjectWrap {
103103
Database() : Nan::ObjectWrap(),
104104
_handle(NULL),
105105
open(false),
106+
closing(false),
106107
locked(false),
107108
pending(0),
108109
serialize(false),
@@ -151,6 +152,8 @@ class Database : public Nan::ObjectWrap {
151152

152153
static NAN_METHOD(Configure);
153154

155+
static NAN_METHOD(Interrupt);
156+
154157
static void SetBusyTimeout(Baton* baton);
155158

156159
static void RegisterTraceCallback(Baton* baton);
@@ -171,6 +174,7 @@ class Database : public Nan::ObjectWrap {
171174
sqlite3* _handle;
172175

173176
bool open;
177+
bool closing;
174178
bool locked;
175179
unsigned int pending;
176180

test/interrupt.test.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
var sqlite3 = require('..');
2+
var assert = require('assert');
3+
4+
describe('interrupt', function() {
5+
it('should interrupt queries', function(done) {
6+
var interrupted = false;
7+
var saved = null;
8+
9+
var db = new sqlite3.Database(':memory:', function() {
10+
db.serialize();
11+
12+
var setup = 'create table t (n int);';
13+
for (var i = 0; i < 8; i += 1) {
14+
setup += 'insert into t values (' + i + ');';
15+
}
16+
db.exec(setup);
17+
18+
var query = 'select last.n ' +
19+
'from t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t,t as last';
20+
21+
db.each(query, function(err) {
22+
if (err) {
23+
saved = err;
24+
} else if (!interrupted) {
25+
interrupted = true;
26+
db.interrupt();
27+
}
28+
});
29+
30+
db.close(function() {
31+
if (saved) {
32+
assert.equal(saved.message, 'SQLITE_INTERRUPT: interrupted');
33+
assert.equal(saved.errno, sqlite3.INTERRUPT);
34+
assert.equal(saved.code, 'SQLITE_INTERRUPT');
35+
done();
36+
} else {
37+
done(new Error('Completed query without error, but expected error'));
38+
}
39+
});
40+
});
41+
});
42+
43+
it('should throw if interrupt is called before open', function(done) {
44+
var db = new sqlite3.Database(':memory:');
45+
46+
assert.throws(function() {
47+
db.interrupt();
48+
}, (/Database is not open/));
49+
50+
db.close();
51+
done();
52+
});
53+
54+
it('should throw if interrupt is called after close', function(done) {
55+
var db = new sqlite3.Database(':memory:');
56+
57+
db.close(function() {
58+
assert.throws(function() {
59+
db.interrupt();
60+
}, (/Database is not open/));
61+
62+
done();
63+
});
64+
});
65+
66+
it('should throw if interrupt is called during close', function(done) {
67+
var db = new sqlite3.Database(':memory:', function() {
68+
db.close();
69+
assert.throws(function() {
70+
db.interrupt();
71+
}, (/Database is closing/));
72+
done();
73+
});
74+
});
75+
});

0 commit comments

Comments
 (0)