Commit dc076bfe by Dane Springmeyer

Merge pull request #631 from briangreenery/sqlite3-interrupt

Add support for sqlite3_interrupt (with fixed test)
parents 9a038b50 434d0daa
...@@ -23,6 +23,7 @@ NAN_MODULE_INIT(Database::Init) { ...@@ -23,6 +23,7 @@ NAN_MODULE_INIT(Database::Init) {
Nan::SetPrototypeMethod(t, "serialize", Serialize); Nan::SetPrototypeMethod(t, "serialize", Serialize);
Nan::SetPrototypeMethod(t, "parallelize", Parallelize); Nan::SetPrototypeMethod(t, "parallelize", Parallelize);
Nan::SetPrototypeMethod(t, "configure", Configure); Nan::SetPrototypeMethod(t, "configure", Configure);
Nan::SetPrototypeMethod(t, "interrupt", Interrupt);
NODE_SET_GETTER(t, "open", OpenGetter); NODE_SET_GETTER(t, "open", OpenGetter);
...@@ -224,6 +225,8 @@ void Database::Work_BeginClose(Baton* baton) { ...@@ -224,6 +225,8 @@ void Database::Work_BeginClose(Baton* baton) {
assert(baton->db->pending == 0); assert(baton->db->pending == 0);
baton->db->RemoveCallbacks(); baton->db->RemoveCallbacks();
baton->db->closing = true;
int status = uv_queue_work(uv_default_loop(), int status = uv_queue_work(uv_default_loop(),
&baton->request, Work_Close, (uv_after_work_cb)Work_AfterClose); &baton->request, Work_Close, (uv_after_work_cb)Work_AfterClose);
assert(status == 0); assert(status == 0);
...@@ -249,6 +252,8 @@ void Database::Work_AfterClose(uv_work_t* req) { ...@@ -249,6 +252,8 @@ void Database::Work_AfterClose(uv_work_t* req) {
Baton* baton = static_cast<Baton*>(req->data); Baton* baton = static_cast<Baton*>(req->data);
Database* db = baton->db; Database* db = baton->db;
db->closing = false;
Local<Value> argv[1]; Local<Value> argv[1];
if (baton->status != SQLITE_OK) { if (baton->status != SQLITE_OK) {
EXCEPTION(Nan::New(baton->message.c_str()).ToLocalChecked(), baton->status, exception); EXCEPTION(Nan::New(baton->message.c_str()).ToLocalChecked(), baton->status, exception);
...@@ -351,6 +356,21 @@ NAN_METHOD(Database::Configure) { ...@@ -351,6 +356,21 @@ NAN_METHOD(Database::Configure) {
info.GetReturnValue().Set(info.This()); info.GetReturnValue().Set(info.This());
} }
NAN_METHOD(Database::Interrupt) {
Database* db = Nan::ObjectWrap::Unwrap<Database>(info.This());
if (!db->open) {
return Nan::ThrowError("Database is not open");
}
if (db->closing) {
return Nan::ThrowError("Database is closing");
}
sqlite3_interrupt(db->_handle);
info.GetReturnValue().Set(info.This());
}
void Database::SetBusyTimeout(Baton* baton) { void Database::SetBusyTimeout(Baton* baton) {
assert(baton->db->open); assert(baton->db->open);
assert(baton->db->_handle); assert(baton->db->_handle);
......
...@@ -103,6 +103,7 @@ protected: ...@@ -103,6 +103,7 @@ protected:
Database() : Nan::ObjectWrap(), Database() : Nan::ObjectWrap(),
_handle(NULL), _handle(NULL),
open(false), open(false),
closing(false),
locked(false), locked(false),
pending(0), pending(0),
serialize(false), serialize(false),
...@@ -151,6 +152,8 @@ protected: ...@@ -151,6 +152,8 @@ protected:
static NAN_METHOD(Configure); static NAN_METHOD(Configure);
static NAN_METHOD(Interrupt);
static void SetBusyTimeout(Baton* baton); static void SetBusyTimeout(Baton* baton);
static void RegisterTraceCallback(Baton* baton); static void RegisterTraceCallback(Baton* baton);
...@@ -171,6 +174,7 @@ protected: ...@@ -171,6 +174,7 @@ protected:
sqlite3* _handle; sqlite3* _handle;
bool open; bool open;
bool closing;
bool locked; bool locked;
unsigned int pending; unsigned int pending;
......
var sqlite3 = require('..');
var assert = require('assert');
describe('interrupt', function() {
it('should interrupt queries', function(done) {
var interrupted = false;
var saved = null;
var db = new sqlite3.Database(':memory:', function() {
db.serialize();
var setup = 'create table t (n int);';
for (var i = 0; i < 8; i += 1) {
setup += 'insert into t values (' + i + ');';
}
db.exec(setup);
var query = 'select last.n ' +
'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';
db.each(query, function(err) {
if (err) {
saved = err;
} else if (!interrupted) {
interrupted = true;
db.interrupt();
}
});
db.close(function() {
if (saved) {
assert.equal(saved.message, 'SQLITE_INTERRUPT: interrupted');
assert.equal(saved.errno, sqlite3.INTERRUPT);
assert.equal(saved.code, 'SQLITE_INTERRUPT');
done();
} else {
done(new Error('Completed query without error, but expected error'));
}
});
});
});
it('should throw if interrupt is called before open', function(done) {
var db = new sqlite3.Database(':memory:');
assert.throws(function() {
db.interrupt();
}, (/Database is not open/));
db.close();
done();
});
it('should throw if interrupt is called after close', function(done) {
var db = new sqlite3.Database(':memory:');
db.close(function() {
assert.throws(function() {
db.interrupt();
}, (/Database is not open/));
done();
});
});
it('should throw if interrupt is called during close', function(done) {
var db = new sqlite3.Database(':memory:', function() {
db.close();
assert.throws(function() {
db.interrupt();
}, (/Database is closing/));
done();
});
});
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment