Commit d2647714 by Konstantin Käfer

throw error messages when the queue gets stuck

parent 9a79d3df
...@@ -83,6 +83,21 @@ void Database::ProcessQueue(Database* db) { ...@@ -83,6 +83,21 @@ void Database::ProcessQueue(Database* db) {
if (!(call->Data() & db->status)) { if (!(call->Data() & db->status)) {
// The next task in the queue requires a different status than the // The next task in the queue requires a different status than the
// one we're currently in. Wait before invoking it. // one we're currently in. Wait before invoking it.
if (db->pending == 0) {
EXCEPTION("Invalid function call sequence", SQLITE_MISUSE, exception);
Local<Value> argv[] = { String::NewSymbol("error"), exception };
Local<Function> fn = Local<Function>::Cast(db->handle_->Get(String::NewSymbol("emit")));
TryCatch try_catch;
fn->Call(db->handle_, 2, argv);
if (try_catch.HasCaught()) {
FatalException(try_catch);
}
ev_unref(EV_DEFAULT_UC);
db->Unref();
db->queue.pop();
delete call;
}
break; break;
} }
...@@ -122,8 +137,8 @@ Handle<Value> Database::Open(const Arguments& args) { ...@@ -122,8 +137,8 @@ Handle<Value> Database::Open(const Arguments& args) {
} }
else { else {
db->status = IsOpening; db->status = IsOpening;
DatabaseBaton* baton = db->pending++;
new DatabaseBaton(db, Persistent<Function>::New(callback)); Baton* baton = new Baton(db, Persistent<Function>::New(callback));
eio_custom(EIO_Open, EIO_PRI_DEFAULT, EIO_AfterOpen, baton); eio_custom(EIO_Open, EIO_PRI_DEFAULT, EIO_AfterOpen, baton);
} }
...@@ -176,17 +191,19 @@ Handle<Value> Database::OpenSync(const Arguments& args) { ...@@ -176,17 +191,19 @@ Handle<Value> Database::OpenSync(const Arguments& args) {
} }
int Database::EIO_Open(eio_req *req) { int Database::EIO_Open(eio_req *req) {
DatabaseBaton* baton = static_cast<DatabaseBaton*>(req->data); Baton* baton = static_cast<Baton*>(req->data);
Open(baton->db); Open(baton->db);
return 0; return 0;
} }
int Database::EIO_AfterOpen(eio_req *req) { int Database::EIO_AfterOpen(eio_req *req) {
HandleScope scope; HandleScope scope;
DatabaseBaton* baton = static_cast<DatabaseBaton*>(req->data); Baton* baton = static_cast<Baton*>(req->data);
Database* db = baton->db; Database* db = baton->db;
ev_unref(EV_DEFAULT_UC); ev_unref(EV_DEFAULT_UC);
db->Unref(); db->Unref();
db->pending--;
Local<Value> argv[1]; Local<Value> argv[1];
if (db->error_status == SQLITE_OK) { if (db->error_status == SQLITE_OK) {
...@@ -226,8 +243,8 @@ Handle<Value> Database::Close(const Arguments& args) { ...@@ -226,8 +243,8 @@ Handle<Value> Database::Close(const Arguments& args) {
} }
else { else {
db->status = IsClosing; db->status = IsClosing;
DatabaseBaton* baton = db->pending++;
new DatabaseBaton(db, Persistent<Function>::New(callback)); Baton* baton = new Baton(db, Persistent<Function>::New(callback));
eio_custom(EIO_Close, EIO_PRI_DEFAULT, EIO_AfterClose, baton); eio_custom(EIO_Close, EIO_PRI_DEFAULT, EIO_AfterClose, baton);
} }
...@@ -276,18 +293,19 @@ Handle<Value> Database::CloseSync(const Arguments& args) { ...@@ -276,18 +293,19 @@ Handle<Value> Database::CloseSync(const Arguments& args) {
} }
int Database::EIO_Close(eio_req *req) { int Database::EIO_Close(eio_req *req) {
DatabaseBaton* baton = static_cast<DatabaseBaton*>(req->data); Baton* baton = static_cast<Baton*>(req->data);
Close(baton->db); Close(baton->db);
return 0; return 0;
} }
int Database::EIO_AfterClose(eio_req *req) { int Database::EIO_AfterClose(eio_req *req) {
HandleScope scope; HandleScope scope;
DatabaseBaton* baton = static_cast<DatabaseBaton*>(req->data); Baton* baton = static_cast<Baton*>(req->data);
Database* db = baton->db; Database* db = baton->db;
ev_unref(EV_DEFAULT_UC); ev_unref(EV_DEFAULT_UC);
db->Unref(); db->Unref();
db->pending--;
Local<Value> argv[1]; Local<Value> argv[1];
if (db->error_status != SQLITE_OK) { if (db->error_status != SQLITE_OK) {
......
...@@ -45,6 +45,12 @@ class Database : public EventEmitter { ...@@ -45,6 +45,12 @@ class Database : public EventEmitter {
typedef Deferred::Call<Status> Call; typedef Deferred::Call<Status> Call;
struct Baton {
Baton(Database* db_, Persistent<Function> callback_) :
db(db_), callback(callback_) {};
Database* db;
Persistent<Function> callback;
};
protected: protected:
Database() : EventEmitter(), Database() : EventEmitter(),
...@@ -103,13 +109,6 @@ class Database : public EventEmitter { ...@@ -103,13 +109,6 @@ class Database : public EventEmitter {
}; };
struct DatabaseBaton {
DatabaseBaton(Database* db_, Persistent<Function> callback_) :
db(db_), callback(callback_) {};
Database* db;
Persistent<Function> callback;
};
enum ExecMode { enum ExecMode {
EXEC_EMPTY = 0, EXEC_EMPTY = 0,
EXEC_LAST_INSERT_ID = 1, EXEC_LAST_INSERT_ID = 1,
......
...@@ -129,8 +129,6 @@ const char* sqlite_code_string(int code); ...@@ -129,8 +129,6 @@ const char* sqlite_code_string(int code);
name ##_obj->Set(NODE_PSYMBOL("code"), \ name ##_obj->Set(NODE_PSYMBOL("code"), \
String::NewSymbol(sqlite_code_string(errno))); String::NewSymbol(sqlite_code_string(errno)));
#define EXCEPTION_STR
#define EVENT_ONCE(event, callback) \ #define EVENT_ONCE(event, callback) \
Local<Value> argv[2] = { \ Local<Value> argv[2] = { \
String::NewSymbol(event), \ String::NewSymbol(event), \
......
...@@ -9,68 +9,68 @@ exports['constants'] = function() { ...@@ -9,68 +9,68 @@ exports['constants'] = function() {
assert.ok(sqlite3.OPEN_CREATE === 4); assert.ok(sqlite3.OPEN_CREATE === 4);
}; };
// exports['open and close non-existent database'] = function(beforeExit) { exports['open and close non-existent database'] = function(beforeExit) {
// var opened, closed; var opened, closed;
//
// helper.deleteFile('test/tmp/test_create.db'); helper.deleteFile('test/tmp/test_create.db');
// var db = new sqlite3.Database('test/tmp/test_create.db'); var db = new sqlite3.Database('test/tmp/test_create.db');
//
// db.open(function(err) { db.open(function(err) {
// if (err) throw err; if (err) throw err;
// assert.ok(!opened); assert.ok(!opened);
// assert.ok(!closed); assert.ok(!closed);
// opened = true; opened = true;
// }); });
// db.close(function(err) { db.close(function(err) {
// if (err) throw err; if (err) throw err;
// assert.ok(opened); assert.ok(opened);
// assert.ok(!closed); assert.ok(!closed);
// closed = true; closed = true;
// }); });
//
// beforeExit(function() { beforeExit(function() {
// assert.ok(opened, 'Database not opened'); assert.ok(opened, 'Database not opened');
// assert.ok(closed, 'Database not closed'); assert.ok(closed, 'Database not closed');
// assert.fileExists('test/tmp/test_create.db'); assert.fileExists('test/tmp/test_create.db');
// helper.deleteFile('test/tmp/test_create.db'); helper.deleteFile('test/tmp/test_create.db');
// }); });
// }; };
//
// exports['open inaccessible database'] = function(beforeExit) { exports['open inaccessible database'] = function(beforeExit) {
// var notOpened; var notOpened;
//
// var db = new sqlite3.Database('/usr/bin/test.db'); var db = new sqlite3.Database('/usr/bin/test.db');
// db.open(function(err) { db.open(function(err) {
// if (err && err.code === 'SQLITE_CANTOPEN') { if (err && err.code === 'SQLITE_CANTOPEN') {
// notOpened = true; notOpened = true;
// } }
// else if (err) throw err; else if (err) throw err;
// }); });
//
// beforeExit(function() { beforeExit(function() {
// assert.ok(notOpened, 'Database could be opened'); assert.ok(notOpened, 'Database could be opened');
// }); });
// }; };
//
//
// exports['open non-existent database without create'] = function(beforeExit) { exports['open non-existent database without create'] = function(beforeExit) {
// var notOpened; var notOpened;
//
// helper.deleteFile('tmp/test_readonly.db'); helper.deleteFile('tmp/test_readonly.db');
// var db = new sqlite3.Database('tmp/test_readonly.db', sqlite3.OPEN_READONLY); var db = new sqlite3.Database('tmp/test_readonly.db', sqlite3.OPEN_READONLY);
//
// db.open(function(err) { db.open(function(err) {
// if (err && err.code === 'SQLITE_CANTOPEN') { if (err && err.code === 'SQLITE_CANTOPEN') {
// notOpened = true; notOpened = true;
// } }
// else if (err) throw err; else if (err) throw err;
// }); });
//
// beforeExit(function() { beforeExit(function() {
// assert.ok(notOpened, 'Database could be opened'); assert.ok(notOpened, 'Database could be opened');
// assert.fileDoesNotExist('tmp/test_readonly.db'); assert.fileDoesNotExist('tmp/test_readonly.db');
// }); });
// }; };
exports['open and close memory database queuing'] = function(beforeExit) { exports['open and close memory database queuing'] = function(beforeExit) {
var opened = 0, closed = 0; var opened = 0, closed = 0;
...@@ -89,11 +89,8 @@ exports['open and close memory database queuing'] = function(beforeExit) { ...@@ -89,11 +89,8 @@ exports['open and close memory database queuing'] = function(beforeExit) {
} }
db.open(openedCallback); db.open(openedCallback);
db.open(openedCallback);
db.open(openedCallback);
db.open(openedCallback);
db.open(openedCallback);
db.close(closedCallback); db.close(closedCallback);
db.open(openedCallback);
db.close(closedCallback); db.close(closedCallback);
db.open(openedCallback); db.open(openedCallback);
db.close(closedCallback); db.close(closedCallback);
...@@ -102,8 +99,30 @@ exports['open and close memory database queuing'] = function(beforeExit) { ...@@ -102,8 +99,30 @@ exports['open and close memory database queuing'] = function(beforeExit) {
db.open(openedCallback); db.open(openedCallback);
beforeExit(function() { beforeExit(function() {
console.log(opened, closed);
assert.equal(opened, 5, 'Database not opened'); assert.equal(opened, 5, 'Database not opened');
assert.equal(closed, 4, 'Database not closed'); assert.equal(closed, 4, 'Database not closed');
}); });
}; };
exports['two opens in a row'] = function(beforeExit) {
var opened = 0, openErrors = 0;
var db = new sqlite3.Database(':memory:');
function openedCallback(err) {
if (err) throw err;
opened++;
}
db.on('error', function(err) {
openErrors++;
});
db.open(openedCallback);
db.open(openedCallback);
beforeExit(function() {
assert.equal(opened, 1, 'Database not opened');
assert.equal(openErrors, 1, 'Second open succeeded');
});
};
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