Commit 07f206e8 by Konstantin Käfer

prepare/retrieve rows

parent fa981cc9
var sqlite3 = require('./lib/sqlite3'); var sqlite3 = require('./lib/sqlite3');
var db = new sqlite3.Database(':memory:'); var db = new sqlite3.Database(':memory:');
db.prepare("sdf", function() {});
db.prepare("CREATE TABLE foo (text bar)").run().finalize(function() { db.prepare("CREATE TABLE foo (text bar)").run().finalize(function() {
db.prepare("INSERT INTO foo VALUES('bar baz boo')").run().finalize(function() { db.prepare("INSERT INTO foo VALUES('bar baz boo')").run().finalize(function() {
db.prepare("SELECT * FROM foo").run(function(err, row) { db.prepare("SELECT * FROM foo").run(function(err, row) {
......
...@@ -69,15 +69,16 @@ void Statement::Schedule(EIO_Callback callback, Baton* baton) { ...@@ -69,15 +69,16 @@ void Statement::Schedule(EIO_Callback callback, Baton* baton) {
} }
template <class T> void Statement::Error(T* baton) { template <class T> void Statement::Error(T* baton) {
EXCEPTION(String::New(baton->message.c_str()), baton->status, exception); Statement* stmt = baton->stmt;
EXCEPTION(String::New(stmt->message.c_str()), stmt->status, exception);
if (!baton->callback.IsEmpty() && baton->callback->IsFunction()) { if (!baton->callback.IsEmpty() && baton->callback->IsFunction()) {
Local<Value> argv[] = { exception }; Local<Value> argv[] = { exception };
TRY_CATCH_CALL(baton->stmt->handle_, baton->callback, 1, argv); TRY_CATCH_CALL(stmt->handle_, baton->callback, 1, argv);
} }
else { else {
Local<Value> argv[] = { String::NewSymbol("error"), exception }; Local<Value> argv[] = { String::NewSymbol("error"), exception };
EMIT_EVENT(baton->stmt->handle_, 2, argv); EMIT_EVENT(stmt->handle_, 2, argv);
} }
} }
...@@ -139,7 +140,6 @@ Handle<Value> Statement::New(const Arguments& args) { ...@@ -139,7 +140,6 @@ Handle<Value> Statement::New(const Arguments& args) {
void Statement::EIO_BeginPrepare(Database::Baton* baton) { void Statement::EIO_BeginPrepare(Database::Baton* baton) {
assert(baton->db->open); assert(baton->db->open);
assert(!baton->db->locked); assert(!baton->db->locked);
fprintf(stderr, "Prepare started\n");
eio_custom(EIO_Prepare, EIO_PRI_DEFAULT, EIO_AfterPrepare, baton); eio_custom(EIO_Prepare, EIO_PRI_DEFAULT, EIO_AfterPrepare, baton);
} }
...@@ -153,7 +153,7 @@ int Statement::EIO_Prepare(eio_req *req) { ...@@ -153,7 +153,7 @@ int Statement::EIO_Prepare(eio_req *req) {
sqlite3_mutex* mtx = sqlite3_db_mutex(db->handle); sqlite3_mutex* mtx = sqlite3_db_mutex(db->handle);
sqlite3_mutex_enter(mtx); sqlite3_mutex_enter(mtx);
baton->status = sqlite3_prepare_v2( stmt->status = sqlite3_prepare_v2(
db->handle, db->handle,
baton->sql.c_str(), baton->sql.c_str(),
baton->sql.size(), baton->sql.size(),
...@@ -161,8 +161,8 @@ int Statement::EIO_Prepare(eio_req *req) { ...@@ -161,8 +161,8 @@ int Statement::EIO_Prepare(eio_req *req) {
NULL NULL
); );
if (baton->status != SQLITE_OK) { if (stmt->status != SQLITE_OK) {
baton->message = std::string(sqlite3_errmsg(db->handle)); stmt->message = std::string(sqlite3_errmsg(db->handle));
stmt->handle = NULL; stmt->handle = NULL;
} }
...@@ -178,7 +178,7 @@ int Statement::EIO_AfterPrepare(eio_req *req) { ...@@ -178,7 +178,7 @@ int Statement::EIO_AfterPrepare(eio_req *req) {
Statement* stmt = baton->stmt; Statement* stmt = baton->stmt;
if (baton->status != SQLITE_OK) { if (stmt->status != SQLITE_OK) {
Error(baton); Error(baton);
stmt->Finalize(); stmt->Finalize();
} }
...@@ -253,22 +253,24 @@ int Statement::EIO_Run(eio_req *req) { ...@@ -253,22 +253,24 @@ int Statement::EIO_Run(eio_req *req) {
Statement* stmt = baton->stmt; Statement* stmt = baton->stmt;
Database* db = stmt->db; Database* db = stmt->db;
// In case preparing fails, we use a mutex to make sure we get the associated if (stmt->status != SQLITE_DONE) {
// error message. // In case preparing fails, we use a mutex to make sure we get the associated
sqlite3_mutex* mtx = sqlite3_db_mutex(db->handle); // error message.
sqlite3_mutex_enter(mtx); sqlite3_mutex* mtx = sqlite3_db_mutex(db->handle);
sqlite3_mutex_enter(mtx);
baton->status = sqlite3_step(stmt->handle); stmt->status = sqlite3_step(stmt->handle);
if (!(baton->status == SQLITE_ROW || baton->status == SQLITE_DONE)) { if (!(stmt->status == SQLITE_ROW || stmt->status == SQLITE_DONE)) {
baton->message = std::string(sqlite3_errmsg(db->handle)); stmt->message = std::string(sqlite3_errmsg(db->handle));
} }
sqlite3_mutex_leave(mtx); sqlite3_mutex_leave(mtx);
if (baton->status == SQLITE_ROW) { if (stmt->status == SQLITE_ROW) {
// Acquire one result row before returning. // Acquire one result row before returning.
GetRow(&baton->row, stmt->handle); GetRow(&baton->row, stmt->handle);
}
} }
return 0; return 0;
...@@ -307,13 +309,13 @@ int Statement::EIO_AfterRun(eio_req *req) { ...@@ -307,13 +309,13 @@ int Statement::EIO_AfterRun(eio_req *req) {
RowBaton* baton = static_cast<RowBaton*>(req->data); RowBaton* baton = static_cast<RowBaton*>(req->data);
Statement* stmt = baton->stmt; Statement* stmt = baton->stmt;
if (baton->status != SQLITE_ROW && baton->status != SQLITE_DONE) { if (stmt->status != SQLITE_ROW && stmt->status != SQLITE_DONE) {
Error(baton); Error(baton);
} }
else { else {
// Fire callbacks. // Fire callbacks.
if (!baton->callback.IsEmpty() && baton->callback->IsFunction()) { if (!baton->callback.IsEmpty() && baton->callback->IsFunction()) {
if (baton->status == SQLITE_ROW) { if (stmt->status == SQLITE_ROW) {
// Create the result array from the data we acquired. // Create the result array from the data we acquired.
Local<Value> argv[] = { Local<Value>::New(Null()), RowToJS(&baton->row) }; Local<Value> argv[] = { Local<Value>::New(Null()), RowToJS(&baton->row) };
TRY_CATCH_CALL(stmt->handle_, baton->callback, 2, argv); TRY_CATCH_CALL(stmt->handle_, baton->callback, 2, argv);
...@@ -357,7 +359,6 @@ void Statement::Finalize(Baton* baton) { ...@@ -357,7 +359,6 @@ void Statement::Finalize(Baton* baton) {
void Statement::Finalize() { void Statement::Finalize() {
assert(!finalized); assert(!finalized);
finalized = true; finalized = true;
fprintf(stderr, "Statement destruct\n");
CleanQueue(); CleanQueue();
// Finalize returns the status code of the last operation. We already fired // Finalize returns the status code of the last operation. We already fired
// error events in case those failed. // error events in case those failed.
......
...@@ -82,8 +82,6 @@ public: ...@@ -82,8 +82,6 @@ public:
static struct Baton { static struct Baton {
Statement* stmt; Statement* stmt;
Persistent<Function> callback; Persistent<Function> callback;
int status;
std::string message;
Baton(Statement* stmt_, Handle<Function> cb_) : stmt(stmt_) { Baton(Statement* stmt_, Handle<Function> cb_) : stmt(stmt_) {
stmt->Ref(); stmt->Ref();
...@@ -126,6 +124,7 @@ public: ...@@ -126,6 +124,7 @@ public:
Statement(Database* db_) : EventEmitter(), Statement(Database* db_) : EventEmitter(),
db(db_), db(db_),
handle(NULL), handle(NULL),
status(SQLITE_OK),
prepared(false), prepared(false),
locked(false), locked(false),
finalized(false) { finalized(false) {
...@@ -162,6 +161,8 @@ protected: ...@@ -162,6 +161,8 @@ protected:
Database* db; Database* db;
sqlite3_stmt* handle; sqlite3_stmt* handle;
int status;
std::string message;
bool prepared; bool prepared;
bool locked; bool locked;
......
...@@ -17,10 +17,7 @@ exports['Blob overflow test'] = function(beforeExit) { ...@@ -17,10 +17,7 @@ exports['Blob overflow test'] = function(beforeExit) {
Step( Step(
function() { function() {
var next = this; var next = this;
db.prepare('CREATE TABLE elmos (image BLOB);', function(err, statement) { db.prepare('CREATE TABLE elmos (image BLOB);').run(next);
assert.ok(!err);
statement.step(next);
});
}, },
function() { function() {
var group = this.group(); var group = this.group();
......
...@@ -5,7 +5,7 @@ exports.deleteFile = function(name) { ...@@ -5,7 +5,7 @@ exports.deleteFile = function(name) {
try { try {
fs.unlinkSync(name); fs.unlinkSync(name);
} catch(err) { } catch(err) {
if (err.errno !== process.ENOENT) { if (err.errno !== process.ENOENT && err.code !== 'ENOENT') {
throw err; throw err;
} }
} }
...@@ -15,7 +15,7 @@ assert.fileDoesNotExist = function(name) { ...@@ -15,7 +15,7 @@ assert.fileDoesNotExist = function(name) {
try { try {
fs.statSync(name); fs.statSync(name);
} catch(err) { } catch(err) {
if (err.errno !== process.ENOENT) { if (err.errno !== process.ENOENT && err.code !== 'ENOENT') {
throw err; throw err;
} }
} }
......
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