Commit cd623f4c by Artem Kustikov

Implemented last inserted ID/affected rows count loading

parent ecaa5831
...@@ -18,6 +18,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ...@@ -18,6 +18,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
var sys = require("sys"); var sys = require("sys");
var sqlite = require("./sqlite3_bindings"); var sqlite = require("./sqlite3_bindings");
// load numeric constants from sqlite3_bindings
for (prop in sqlite) {
var obj = sqlite[prop];
if ((obj === +obj) || (toString.call(obj) === '[object Number]') ) {
exports[prop] = sqlite[prop];
}
}
var Database = exports.Database = function () { var Database = exports.Database = function () {
var self = this; var self = this;
...@@ -59,7 +67,6 @@ function _queryDone(db, statement) { ...@@ -59,7 +67,6 @@ function _queryDone(db, statement) {
} }
statement.finalize(function () { statement.finalize(function () {
db.currentQuery = undefined;
// if there are any queries queued, let them know it's safe to go // if there are any queries queued, let them know it's safe to go
db.emit("ready"); db.emit("ready");
}); });
...@@ -67,15 +74,16 @@ function _queryDone(db, statement) { ...@@ -67,15 +74,16 @@ function _queryDone(db, statement) {
function _doStep(db, statement, rowCallback) { function _doStep(db, statement, rowCallback) {
statement.step(function (error, row) { statement.step(function (error, row) {
if (error) throw error; if (error)
return rowCallback (error);
if (!row) { if (!row) {
// rows.rowsAffected = this.changes();
// rows.insertId = this.lastInsertRowid();
rowCallback(); rowCallback();
_queryDone(db, statement); _queryDone(db, statement);
return; return;
} }
rowCallback(row); rowCallback(undefined, row);
_doStep(db, statement, rowCallback); _doStep(db, statement, rowCallback);
}); });
} }
...@@ -94,21 +102,36 @@ function _onPrepare(db, statement, bindings, rowCallback) { ...@@ -94,21 +102,36 @@ function _onPrepare(db, statement, bindings, rowCallback) {
} }
} }
Database.prototype.query = function(sql, bindings, rowCallback) { Database.prototype.query = function(sql, bindings, rowCallback, prepareMode) {
var self = this; var self = this;
if (typeof(bindings) == "function") { if (typeof(bindings) == "function") {
prepareMode = rowCallback || sqlite.EXEC_EMPTY;
rowCallback = bindings; rowCallback = bindings;
bindings = []; bindings = [];
} }
if (typeof(prepareMode) == "undefined")
prepareMode = sqlite.EXEC_EMPTY;
this.prepare(sql, function(error, statement) { this.prepare(sql, function(error, statement) {
if (error) throw error; if (error)
return rowCallback (error);
if (statement) { if (statement) {
_onPrepare(self, statement, bindings, rowCallback) _onPrepare(self, statement, bindings, rowCallback);
} else { } else {
rowCallback(); rowCallback();
self.currentQuery = undefined;
} }
}); }, prepareMode);
} }
Database.prototype.insert = function(sql, insertCallback) {
var self = this;
this.prepare(sql, function(error, info) {
if (error)
return insertCallback (error);
insertCallback (undefined, (info ? info.last_inserted_id : 0));
}, sqlite.EXEC_LAST_INSERT_ID);
}
...@@ -73,6 +73,13 @@ static Persistent<String> callback_sym; ...@@ -73,6 +73,13 @@ static Persistent<String> callback_sym;
String::New("Argument " #I " must be an integer"))); \ String::New("Argument " #I " must be an integer"))); \
} }
enum ExecMode
{
EXEC_EMPTY = 0,
EXEC_LAST_INSERT_ID = 1,
EXEC_AFFECTED_ROWS = 2
};
class Sqlite3Db : public EventEmitter { class Sqlite3Db : public EventEmitter {
public: public:
static Persistent<FunctionTemplate> constructor_template; static Persistent<FunctionTemplate> constructor_template;
...@@ -95,6 +102,11 @@ public: ...@@ -95,6 +102,11 @@ public:
target->Set(v8::String::NewSymbol("Database"), target->Set(v8::String::NewSymbol("Database"),
constructor_template->GetFunction()); constructor_template->GetFunction());
// insert/update execution result mask
NODE_DEFINE_CONSTANT (target, EXEC_EMPTY);
NODE_DEFINE_CONSTANT (target, EXEC_LAST_INSERT_ID);
NODE_DEFINE_CONSTANT (target, EXEC_AFFECTED_ROWS);
Statement::Init(target); Statement::Init(target);
} }
...@@ -298,7 +310,7 @@ protected: ...@@ -298,7 +310,7 @@ protected:
Sqlite3Db* dbo = ObjectWrap::Unwrap<Sqlite3Db>(args.This()); Sqlite3Db* dbo = ObjectWrap::Unwrap<Sqlite3Db>(args.This());
Local<Number> result = Integer::New(sqlite3_last_insert_rowid(dbo->db_)); Local<Number> result = Integer::New(sqlite3_last_insert_rowid(dbo->db_));
return scope.Close(result); return scope.Close(result);
} };
// Hooks // Hooks
...@@ -329,6 +341,9 @@ protected: ...@@ -329,6 +341,9 @@ protected:
Persistent<Function> cb; Persistent<Function> cb;
Sqlite3Db *dbo; Sqlite3Db *dbo;
sqlite3_stmt* stmt; sqlite3_stmt* stmt;
int mode;
sqlite3_int64 lastInsertId;
int affectedRows;
const char* tail; const char* tail;
char sql[1]; char sql[1];
}; };
...@@ -346,10 +361,30 @@ protected: ...@@ -346,10 +361,30 @@ protected:
argv[0] = Exception::Error( argv[0] = Exception::Error(
String::New(sqlite3_errmsg(prep_req->dbo->db_))); String::New(sqlite3_errmsg(prep_req->dbo->db_)));
argc = 1; argc = 1;
}
else { } else {
if (req->int1 == SQLITE_DONE) { if (req->int1 == SQLITE_DONE) {
argc = 0;
if (prep_req->mode != EXEC_EMPTY) {
argv[0] = Local<Value>::New(Undefined()); // no error
Local<Object> info = Object::New();
if (prep_req->mode & EXEC_LAST_INSERT_ID) {
info->Set(String::NewSymbol("last_inserted_id"),
Integer::NewFromUnsigned (prep_req->lastInsertId));
}
if (prep_req->mode & EXEC_AFFECTED_ROWS) {
info->Set(String::NewSymbol("affected_rows"),
Integer::New (prep_req->affectedRows));
}
argv[1] = info;
argc = 2;
} else {
argc = 0;
}
} else { } else {
argv[0] = External::New(prep_req->stmt); argv[0] = External::New(prep_req->stmt);
argv[1] = Integer::New(req->int1); argv[1] = Integer::New(req->int1);
...@@ -410,6 +445,15 @@ protected: ...@@ -410,6 +445,15 @@ protected:
} }
} }
prep_req->lastInsertId = 0;
prep_req->affectedRows = 0;
// load custom properties
if (prep_req->mode & EXEC_LAST_INSERT_ID)
prep_req->lastInsertId = sqlite3_last_insert_rowid(db);
if (prep_req->mode & EXEC_AFFECTED_ROWS)
prep_req->affectedRows = sqlite3_changes(db);
return 0; return 0;
} }
...@@ -417,6 +461,7 @@ protected: ...@@ -417,6 +461,7 @@ protected:
HandleScope scope; HandleScope scope;
REQ_STR_ARG(0, sql); REQ_STR_ARG(0, sql);
REQ_FUN_ARG(1, cb); REQ_FUN_ARG(1, cb);
OPT_INT_ARG(2, mode, EXEC_EMPTY);
Sqlite3Db* dbo = ObjectWrap::Unwrap<Sqlite3Db>(args.This()); Sqlite3Db* dbo = ObjectWrap::Unwrap<Sqlite3Db>(args.This());
...@@ -432,6 +477,7 @@ protected: ...@@ -432,6 +477,7 @@ protected:
strcpy(prep_req->sql, *sql); strcpy(prep_req->sql, *sql);
prep_req->cb = Persistent<Function>::New(cb); prep_req->cb = Persistent<Function>::New(cb);
prep_req->dbo = dbo; prep_req->dbo = dbo;
prep_req->mode = mode;
eio_custom(EIO_Prepare, EIO_PRI_DEFAULT, EIO_AfterPrepare, prep_req); eio_custom(EIO_Prepare, EIO_PRI_DEFAULT, EIO_AfterPrepare, prep_req);
......
var sqlite = require('../sqlite3_bindings'); var sqlite = require('../sqlite3_bindings');
var sys = require('sys'); var sys = require('sys');
var assert = require('assert');
var puts = sys.puts; var puts = sys.puts;
var inspect = sys.inspect; var inspect = sys.inspect;
...@@ -34,7 +35,7 @@ function getRows() { ...@@ -34,7 +35,7 @@ function getRows() {
} }
function createTable(db, callback) { function createTable(db, callback) {
db.prepare("CREATE TABLE t1 (alpha INTEGER)", function (error, statement) { db.prepare("CREATE TABLE t1 (id INTEGER PRIMARY KEY, alpha INTEGER)", function (error, statement) {
if (error) throw error; if (error) throw error;
callback(); callback();
}); });
...@@ -42,10 +43,12 @@ function createTable(db, callback) { ...@@ -42,10 +43,12 @@ function createTable(db, callback) {
var count = 0; var count = 0;
function onPrepare(error, statement) { function onInsert(error, info) {
var d; var d;
if (error) throw error; if (error) throw error;
assert.ok (info && info.last_inserted_id > 0, 'Last inserted ID loading failed');
if (++rows == total) { if (++rows == total) {
d = ((new Date)-t0)/1000; d = ((new Date)-t0)/1000;
puts("**** " + d + "s to insert " + rows + " rows (" + (rows/d) + "/s)"); puts("**** " + d + "s to insert " + rows + " rows (" + (rows/d) + "/s)");
...@@ -57,7 +60,9 @@ db.open(':memory:', function () { ...@@ -57,7 +60,9 @@ db.open(':memory:', function () {
createTable(db, function () { createTable(db, function () {
t0 = new Date(); t0 = new Date();
for (var i = 0; i < total; i++) { for (var i = 0; i < total; i++) {
db.prepare("INSERT INTO t1 VALUES (1)", onPrepare); db.prepare("INSERT INTO t1 (alpha) VALUES (1)",
onInsert,
sqlite.EXEC_LAST_INSERT_ID);
} }
}); });
}); });
var sqlite = require('./sqlite3_bindings'); var sqlite = require('../sqlite3_bindings');
var sys = require('sys'); var sys = require('sys');
var puts = sys.puts; var puts = sys.puts;
......
...@@ -10,14 +10,14 @@ var db = new sqlite.Database(); ...@@ -10,14 +10,14 @@ var db = new sqlite.Database();
function readTest(db, callback) { function readTest(db, callback) {
var t0 = new Date; var t0 = new Date;
var rows = 0; var rows = 0;
db.query("SELECT * FROM t1", function(row) { db.query("SELECT * FROM t1", function(error, row) {
if (!row) { if (!row) {
var d = ((new Date)-t0)/1000; var d = ((new Date)-t0)/1000;
puts("**** " + rows + " rows in " + d + "s (" + (rows/d) + "/s)"); puts("**** " + rows + " rows in " + d + "s (" + (rows/d) + "/s)");
if (callback) callback(db); if (callback) callback(db);
}
else { } else {
// puts("got a row" + inspect(arguments)); // puts("got a row" + inspect(arguments));
rows++; rows++;
} }
...@@ -25,15 +25,15 @@ function readTest(db, callback) { ...@@ -25,15 +25,15 @@ function readTest(db, callback) {
} }
function writeTest(db, i, callback) { function writeTest(db, i, callback) {
db.query("INSERT INTO t1 VALUES (1)", function (row) { db.insert("INSERT INTO t1 VALUES (1)", function (error, id) {
if (!i--) { if (!i--) {
// end of results // end of results
var dt = ((new Date)-t0)/1000; var dt = ((new Date)-t0)/1000;
puts("**** " + count + " insertions in " + dt + "s (" + (count/dt) + "/s)"); puts("**** " + count + " insertions in " + dt + "s (" + (count/dt) + "/s)");
if (callback) callback(db); if (callback) callback(db);
}
else { } else {
writeTest(db, i--, callback); writeTest(db, i--, callback);
} }
}); });
......
var fs = require("fs"), var fs = require("fs"),
sys = require("sys"), sys = require("sys"),
sqlite = require("./sqlite"); sqlite = require("../sqlite");
var puts = sys.puts; var puts = sys.puts;
var inspect = sys.inspect; var inspect = sys.inspect;
var sqlite = require("./sqlite");
var db = new sqlite.Database(); var db = new sqlite.Database();
function readTest(db, callback) { function readTest(db, callback) {
var t0 = new Date; var t0 = new Date;
var rows = 0; var rows = 0;
db.query("SELECT * FROM t1", function(row) { db.query("SELECT * FROM t1", function(error, row) {
if (!row) { if (!row) {
var d = ((new Date)-t0)/1000; var d = ((new Date)-t0)/1000;
puts("**** " + rows + " rows in " + d + "s (" + (rows/d) + "/s)"); puts("**** " + rows + " rows in " + d + "s (" + (rows/d) + "/s)");
...@@ -27,7 +26,7 @@ function readTest(db, callback) { ...@@ -27,7 +26,7 @@ function readTest(db, callback) {
} }
function writeTest(db, i, callback) { function writeTest(db, i, callback) {
db.query("INSERT INTO t1 VALUES (1, 'hello', 3.141)", function (row) { db.insert("INSERT INTO t1 VALUES (1, 'hello', 3.141)", function (error, id) {
if (!i--) { if (!i--) {
// end of results // end of results
var dt = ((new Date)-t0)/1000; var dt = ((new Date)-t0)/1000;
......
var fs = require("fs"); var fs = require("fs");
var sys = require("sys"); var sys = require("sys");
var assert = require("assert");
var puts = sys.puts var sqlite = require("../sqlite3_bindings");
var inspect = sys.inspect
var sqlite = require("./sqlite3_bindings"); var puts = sys.puts;
var inspect = sys.inspect;
var db = new sqlite.Database(); var db = new sqlite.Database();
throws(function () { assert.throws(function () {
db.open(); db.open();
}); });
throws(function () { assert.throws(function () {
db.open("my.db"); db.open("my.db");
}); });
throws(function () { assert.throws(function () {
db.open("foo.db"); db.open("foo.db");
}); });
...@@ -74,9 +75,11 @@ function test_simple() { ...@@ -74,9 +75,11 @@ function test_simple() {
db.open("mydatabase.db", function () { db.open("mydatabase.db", function () {
db.prepare("SELECT bar, baz FROM foo WHERE baz > 5", function (error, statement) { db.prepare("SELECT bar, baz FROM foo WHERE baz > 5", function (error, statement) {
puts('prepare callback'); puts('prepare callback');
if (error) throw (error);
puts(inspect(arguments)); puts(inspect(arguments));
statement.step(function () { statement.step(function (error) {
puts('query callback'); puts('query callback');
puts(inspect(arguments)); puts(inspect(arguments));
statement.step(function () { statement.step(function () {
......
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