Commit 482517de by Konstantin Käfer

add .reset()

parent 457146dd
...@@ -143,5 +143,20 @@ const char* sqlite_code_string(int code); ...@@ -143,5 +143,20 @@ const char* sqlite_code_string(int code);
FatalException(try_catch); \ FatalException(try_catch); \
} } } }
#define EIO_DEFINITION(name) \
static Handle<Value> name(const Arguments& args); \
static void EIO_Begin##name(Baton* baton); \
static int EIO_##name(eio_req *req); \
static int EIO_After##name(eio_req *req);
#define STATEMENT_INIT(type) \
type* baton = static_cast<type*>(req->data); \
Statement* stmt = baton->stmt;
#define STATEMENT_END() \
stmt->locked = false; \
stmt->Process(); \
delete baton;
#endif #endif
...@@ -36,6 +36,7 @@ void Statement::Init(v8::Handle<Object> target) { ...@@ -36,6 +36,7 @@ void Statement::Init(v8::Handle<Object> target) {
NODE_SET_PROTOTYPE_METHOD(constructor_template, "bind", Bind); NODE_SET_PROTOTYPE_METHOD(constructor_template, "bind", Bind);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "get", Get); NODE_SET_PROTOTYPE_METHOD(constructor_template, "get", Get);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "reset", Reset);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "finalize", Finalize); NODE_SET_PROTOTYPE_METHOD(constructor_template, "finalize", Finalize);
target->Set(v8::String::NewSymbol("Statement"), target->Set(v8::String::NewSymbol("Statement"),
...@@ -128,17 +129,15 @@ void Statement::EIO_BeginPrepare(Database::Baton* baton) { ...@@ -128,17 +129,15 @@ void Statement::EIO_BeginPrepare(Database::Baton* baton) {
} }
int Statement::EIO_Prepare(eio_req *req) { int Statement::EIO_Prepare(eio_req *req) {
PrepareBaton* baton = static_cast<PrepareBaton*>(req->data); STATEMENT_INIT(PrepareBaton);
Database* db = baton->db;
Statement* stmt = baton->stmt;
// In case preparing fails, we use a mutex to make sure we get the associated // In case preparing fails, we use a mutex to make sure we get the associated
// error message. // error message.
sqlite3_mutex* mtx = sqlite3_db_mutex(db->handle); sqlite3_mutex* mtx = sqlite3_db_mutex(baton->db->handle);
sqlite3_mutex_enter(mtx); sqlite3_mutex_enter(mtx);
stmt->status = sqlite3_prepare_v2( stmt->status = sqlite3_prepare_v2(
db->handle, baton->db->handle,
baton->sql.c_str(), baton->sql.c_str(),
baton->sql.size(), baton->sql.size(),
&stmt->handle, &stmt->handle,
...@@ -146,7 +145,7 @@ int Statement::EIO_Prepare(eio_req *req) { ...@@ -146,7 +145,7 @@ int Statement::EIO_Prepare(eio_req *req) {
); );
if (stmt->status != SQLITE_OK) { if (stmt->status != SQLITE_OK) {
stmt->message = std::string(sqlite3_errmsg(db->handle)); stmt->message = std::string(sqlite3_errmsg(baton->db->handle));
stmt->handle = NULL; stmt->handle = NULL;
} }
...@@ -157,10 +156,7 @@ int Statement::EIO_Prepare(eio_req *req) { ...@@ -157,10 +156,7 @@ int Statement::EIO_Prepare(eio_req *req) {
int Statement::EIO_AfterPrepare(eio_req *req) { int Statement::EIO_AfterPrepare(eio_req *req) {
HandleScope scope; HandleScope scope;
PrepareBaton* baton = static_cast<PrepareBaton*>(req->data); STATEMENT_INIT(PrepareBaton);
Database* db = baton->db;
Statement* stmt = baton->stmt;
if (stmt->status != SQLITE_OK) { if (stmt->status != SQLITE_OK) {
Error(baton); Error(baton);
...@@ -172,12 +168,10 @@ int Statement::EIO_AfterPrepare(eio_req *req) { ...@@ -172,12 +168,10 @@ int Statement::EIO_AfterPrepare(eio_req *req) {
Local<Value> argv[] = { Local<Value>::New(Null()) }; Local<Value> argv[] = { Local<Value>::New(Null()) };
TRY_CATCH_CALL(stmt->handle_, baton->callback, 1, argv); TRY_CATCH_CALL(stmt->handle_, baton->callback, 1, argv);
} }
stmt->Process();
} }
db->Process(); STATEMENT_END();
baton->db->Process();
delete baton;
return 0; return 0;
} }
...@@ -230,11 +224,9 @@ void Statement::EIO_BeginBind(Baton* baton) { ...@@ -230,11 +224,9 @@ void Statement::EIO_BeginBind(Baton* baton) {
} }
int Statement::EIO_Bind(eio_req *req) { int Statement::EIO_Bind(eio_req *req) {
BindBaton* baton = static_cast<BindBaton*>(req->data); STATEMENT_INIT(BindBaton);
Statement* stmt = baton->stmt;
Database* db = stmt->db;
sqlite3_mutex* mtx = sqlite3_db_mutex(db->handle); sqlite3_mutex* mtx = sqlite3_db_mutex(stmt->db->handle);
sqlite3_mutex_enter(mtx); sqlite3_mutex_enter(mtx);
Result::Row::iterator it = baton->values.begin(); Result::Row::iterator it = baton->values.begin();
...@@ -264,7 +256,7 @@ int Statement::EIO_Bind(eio_req *req) { ...@@ -264,7 +256,7 @@ int Statement::EIO_Bind(eio_req *req) {
} }
if (stmt->status != SQLITE_OK) { if (stmt->status != SQLITE_OK) {
stmt->message = std::string(sqlite3_errmsg(db->handle)); stmt->message = std::string(sqlite3_errmsg(stmt->db->handle));
break; break;
} }
} }
...@@ -276,8 +268,7 @@ int Statement::EIO_Bind(eio_req *req) { ...@@ -276,8 +268,7 @@ int Statement::EIO_Bind(eio_req *req) {
int Statement::EIO_AfterBind(eio_req *req) { int Statement::EIO_AfterBind(eio_req *req) {
HandleScope scope; HandleScope scope;
BindBaton* baton = static_cast<BindBaton*>(req->data); STATEMENT_INIT(BindBaton);
Statement* stmt = baton->stmt;
if (stmt->status != SQLITE_OK) { if (stmt->status != SQLITE_OK) {
Error(baton); Error(baton);
...@@ -290,10 +281,7 @@ int Statement::EIO_AfterBind(eio_req *req) { ...@@ -290,10 +281,7 @@ int Statement::EIO_AfterBind(eio_req *req) {
} }
} }
stmt->locked = false; STATEMENT_END();
stmt->Process();
delete baton;
return 0; return 0;
} }
...@@ -320,20 +308,18 @@ void Statement::EIO_BeginGet(Baton* baton) { ...@@ -320,20 +308,18 @@ void Statement::EIO_BeginGet(Baton* baton) {
} }
int Statement::EIO_Get(eio_req *req) { int Statement::EIO_Get(eio_req *req) {
RowBaton* baton = static_cast<RowBaton*>(req->data); STATEMENT_INIT(RowBaton);
Statement* stmt = baton->stmt;
Database* db = stmt->db;
if (stmt->status != SQLITE_DONE) { if (stmt->status != SQLITE_DONE) {
// In case preparing fails, we use a mutex to make sure we get the associated // In case preparing fails, we use a mutex to make sure we get the associated
// error message. // error message.
sqlite3_mutex* mtx = sqlite3_db_mutex(db->handle); sqlite3_mutex* mtx = sqlite3_db_mutex(stmt->db->handle);
sqlite3_mutex_enter(mtx); sqlite3_mutex_enter(mtx);
stmt->status = sqlite3_step(stmt->handle); stmt->status = sqlite3_step(stmt->handle);
if (!(stmt->status == SQLITE_ROW || stmt->status == SQLITE_DONE)) { if (!(stmt->status == SQLITE_ROW || stmt->status == SQLITE_DONE)) {
stmt->message = std::string(sqlite3_errmsg(db->handle)); stmt->message = std::string(sqlite3_errmsg(stmt->db->handle));
} }
sqlite3_mutex_leave(mtx); sqlite3_mutex_leave(mtx);
...@@ -349,8 +335,7 @@ int Statement::EIO_Get(eio_req *req) { ...@@ -349,8 +335,7 @@ int Statement::EIO_Get(eio_req *req) {
int Statement::EIO_AfterGet(eio_req *req) { int Statement::EIO_AfterGet(eio_req *req) {
HandleScope scope; HandleScope scope;
RowBaton* baton = static_cast<RowBaton*>(req->data); STATEMENT_INIT(RowBaton);
Statement* stmt = baton->stmt;
if (stmt->status != SQLITE_ROW && stmt->status != SQLITE_DONE) { if (stmt->status != SQLITE_ROW && stmt->status != SQLITE_DONE) {
Error(baton); Error(baton);
...@@ -370,10 +355,50 @@ int Statement::EIO_AfterGet(eio_req *req) { ...@@ -370,10 +355,50 @@ int Statement::EIO_AfterGet(eio_req *req) {
} }
} }
stmt->locked = false; STATEMENT_END();
stmt->Process(); return 0;
}
delete baton; Handle<Value> Statement::Reset(const Arguments& args) {
HandleScope scope;
Statement* stmt = ObjectWrap::Unwrap<Statement>(args.This());
OPTIONAL_ARGUMENT_FUNCTION(0, callback);
Baton* baton = new Baton(stmt, callback);
stmt->Schedule(EIO_BeginReset, baton);
return args.This();
}
void Statement::EIO_BeginReset(Baton* baton) {
assert(!baton->stmt->locked);
assert(!baton->stmt->finalized);
assert(baton->stmt->prepared);
baton->stmt->locked = true;
eio_custom(EIO_Reset, EIO_PRI_DEFAULT, EIO_AfterReset, baton);
}
int Statement::EIO_Reset(eio_req *req) {
STATEMENT_INIT(Baton);
sqlite3_reset(stmt->handle);
stmt->status = SQLITE_OK;
return 0;
}
int Statement::EIO_AfterReset(eio_req *req) {
HandleScope scope;
STATEMENT_INIT(Baton);
// Fire callbacks.
if (!baton->callback.IsEmpty() && baton->callback->IsFunction()) {
Local<Value> argv[] = { Local<Value>::New(Null()) };
TRY_CATCH_CALL(stmt->handle_, baton->callback, 1, argv);
}
STATEMENT_END();
return 0; return 0;
} }
......
...@@ -143,23 +143,17 @@ public: ...@@ -143,23 +143,17 @@ public:
} }
protected: protected:
static Handle<Value> Bind(const Arguments& args); static void EIO_BeginPrepare(Database::Baton* baton);
static void EIO_BeginBind(Baton* baton); static int EIO_Prepare(eio_req *req);
static int EIO_Bind(eio_req *req); static int EIO_AfterPrepare(eio_req *req);
static int EIO_AfterBind(eio_req *req);
static Handle<Value> Get(const Arguments& args); EIO_DEFINITION(Bind);
static void EIO_BeginGet(Baton* baton); EIO_DEFINITION(Get);
static int EIO_Get(eio_req *req); EIO_DEFINITION(Reset);
static int EIO_AfterGet(eio_req *req);
static void GetRow(Result::Row* row, sqlite3_stmt* stmt); static void GetRow(Result::Row* row, sqlite3_stmt* stmt);
static Local<Array> RowToJS(Result::Row* row); static Local<Array> RowToJS(Result::Row* row);
static void EIO_BeginPrepare(Database::Baton* baton);
static int EIO_Prepare(eio_req *req);
static int EIO_AfterPrepare(eio_req *req);
void Schedule(EIO_Callback callback, Baton* baton); void Schedule(EIO_Callback callback, Baton* baton);
void Process(); void Process();
void CleanQueue(); void CleanQueue();
......
...@@ -4,7 +4,7 @@ var Step = require('step'); ...@@ -4,7 +4,7 @@ var Step = require('step');
exports['test simple prepared statement with invalid SQL'] = function(beforeExit) { exports['test simple prepared statement with invalid SQL'] = function(beforeExit) {
var error = false; var error = false;
var db = new sqlite3.Database(':memory:') var db = new sqlite3.Database(':memory:');
db.prepare('CRATE TALE foo text bar)', function(err, statement) { db.prepare('CRATE TALE foo text bar)', function(err, statement) {
if (err && err.errno == sqlite3.ERROR && if (err && err.errno == sqlite3.ERROR &&
err.message === 'SQLITE_ERROR: near "CRATE": syntax error') { err.message === 'SQLITE_ERROR: near "CRATE": syntax error') {
...@@ -42,7 +42,7 @@ exports['test inserting and retrieving rows'] = function(beforeExit) { ...@@ -42,7 +42,7 @@ exports['test inserting and retrieving rows'] = function(beforeExit) {
var retrieved = 0; var retrieved = 0;
// We insert and retrieve that many rows. // We insert and retrieve that many rows.
var count = 5000; var count = 1000;
Step( Step(
function() { function() {
...@@ -92,5 +92,37 @@ exports['test inserting and retrieving rows'] = function(beforeExit) { ...@@ -92,5 +92,37 @@ exports['test inserting and retrieving rows'] = function(beforeExit) {
beforeExit(function() { beforeExit(function() {
assert.equal(count, inserted, "Didn't insert all rows"); assert.equal(count, inserted, "Didn't insert all rows");
assert.equal(count, retrieved, "Didn't retrieve all rows"); assert.equal(count, retrieved, "Didn't retrieve all rows");
}) });
};
exports['test retrieving reset() function'] = function(beforeExit) {
var db = new sqlite3.Database('test/support/prepare.db', sqlite3.OPEN_READONLY);
var retrieved = 0;
Step(
function() {
var stmt = db.prepare("SELECT txt, num, flt, blb FROM foo ORDER BY num");
var group = this.group();
for (var i = 0; i < 10; i++) {
stmt.reset();
stmt.get(group());
}
},
function(err, rows) {
if (err) throw err;
for (var i = 0; i < rows.length; i++) {
assert.equal(rows[i][0], 'String 0');
assert.equal(rows[i][1], 0);
assert.equal(rows[i][2], 0.0);
assert.equal(rows[i][3], null);
retrieved++;
}
}
);
beforeExit(function() {
assert.equal(10, retrieved, "Didn't retrieve all rows");
});
}; };
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