Commit 3992c84e by Eric Fredricksen Committed by Eric Fredricksen

Allow bind of nulls. Clean up some.

parent ae95e3c7
#!/usr/local/bin/node
/*
//!! To be processed by docbyex.py (or run by Node)
<head>
<title>node-sqlite</title>
<style>
pre, code { color: #060; font-size: 11pt; }
pre { margin-left: 2ex; padding: 1ex; background: #eee; }
p { font-size: 12pt; }
body { margin: 2em; background-color: #fff; color: black }
</style>
</head>
<body>
<h1>node-sqlite</h1>
<a href=http://sqlite.org/>SQLite</a> bindings for
<a //href=http://nodejs.org/>Node</a>.
The semantics conform somewhat to those of the <a
href=http://dev.w3.org/html5/webdatabase/#sql>HTML5 Web SQL API</a>,
plus some extensions. Also, only the synchronous API is implemented;
the asynchronous API is a big TODO item.
<h2>Documentation by Example</h2>
*/
// Import the library and open a database. (Only syncronous database
// access is implemented at this time.)
var sqlite = require("./sqlite");
var db = sqlite.openDatabaseSync("example.db");
// Perform an SQL query on the database:
db.query("CREATE TABLE foo (a,b,c)");
// This is a more convenient form than the HTML5 syntax for the same
// thing, but which is also supported:
db.transaction(function(tx) {
tx.executeSql("CREATE TABLE bar (x,y,z)");
});
// This allows the same or similar code to work on the client and
// server end (modulo browser support of HTML5 Web SQL).
// Transactions generate either a "commit" or "rollback" event.
var rollbacks = 0;
db.addListener("rollback", function () {
++rollbacks;
});
// Both forms take an optional second parameter which is values to
// bind to fields in the query, as an array:
db.query("INSERT INTO foo (a,b,c) VALUES (?,?,?)", ['apple','banana',22]);
// or as a map:
db.query("INSERT INTO bar (x,y,z) VALUES ($x,$y,$zebra)",
{$x: 10, $y:20, $zebra:"stripes"});
// Also optional is a callback function which is called with an object
// representing the results of the query:
db.query("SELECT x FROM bar", function (records) {
process.assert(records.length == 1);
process.assert(records[0].x == 10);
// The HTML5 semantics for the record set also work:
process.assert(records.rows.length == 1);
process.assert(records.rows.item(0).x == 10);
});
// INSERT, UPDATE & DELETE queries set `rowsAffected` on their result
// set object:
db.query("UPDATE foo SET a = ? WHERE a = ?", ['orange', 'apple'], function(r) {
process.assert(r.rowsAffected == 1);
});
// They also emit an `"update"` event.
// INSERT queries set `insertId`:
var insert = db.query("INSERT INTO foo VALUES (1,2,3)");
process.assert(insert.insertId == 2);
// Note here that the result set passed to the callback is also
// returned by `query`.
// Multiple-statement queries are supported; each statement's result set is retuned to the callback as a separate parameter:
var q = db.query("UPDATE bar SET z=20; SELECT SUM(z) FROM bar;",
function (update, select) {
process.assert(update.rowsAffected == 1);
process.assert(select[0]['SUM(z)'] == 20);
});
// An array of all result sets is available as the `.all` property on
// each result set:
process.assert(q.all[1].length == 1);
// HTML5 semantics are supported.
db.transaction(function(tx) {
tx.executeSql("SELECT * FROM foo WHERE c = ?", [3], function(tx,res) {
process.assert(res.rows.item(0).c == 3);
});
});
// The `query` and `transaction` APIs wrap lower level APIs that more
// thinly wrap the underlying C api:
var stmt = db.prepare("INSERT INTO foo VALUES (?,?,?)");
stmt.bind(1, "curly");
stmt.bind(2, "moe");
stmt.bind(3, "larry");
stmt.step(); // Insert Curly, Moe & Larry
stmt.reset();
stmt.step(); // Insert another row with same stooges
stmt.reset();
stmt.clearBindings();
stmt.bind(2, "lonely");
stmt.step(); // Insert (null, "lonely", null)
stmt.finalize();
// Close it!
db.close();
// !!**
// Might as well clean up the mess we made.
var posix = require("posix");
posix.unlink('example.db');
var sys = require("sys");
sys.puts("OK");
...@@ -16,7 +16,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ...@@ -16,7 +16,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// TODO: async // TODO: async
var sys = require("sys");
var bindings = require("./sqlite3_bindings"); var bindings = require("./sqlite3_bindings");
process.mixin(GLOBAL, bindings); process.mixin(GLOBAL, bindings);
process.mixin(exports, bindings); process.mixin(exports, bindings);
...@@ -31,23 +30,23 @@ exports.SQLITE_UPDATE = 23; ...@@ -31,23 +30,23 @@ exports.SQLITE_UPDATE = 23;
exports.openDatabaseSync = function (name, version, displayName, exports.openDatabaseSync = function (name, version, displayName,
estimatedSize, creationCallback) { estimatedSize, creationCallback) {
// 2nd-4th parameters are ignored
var db = new DatabaseSync(name); var db = new DatabaseSync(name);
if (creationCallback) creationCallback(db); if (creationCallback) creationCallback(db);
return db; return db;
} }
DatabaseSync.prototype.performQuery = function(sql, bindings, DatabaseSync.prototype.query = function (sql, bindings, callback) {
callback, errback) { // TODO: error callback
var all = []; if (typeof(bindings) == "function") {
var tmp = bindings;
// bindings param is optional bindings = callback;
if (typeof bindings == 'function') { callback = tmp;
errback = callback;
callback = bindings;
bindings = null;
} }
var all = [];
var stmt = this.prepare(sql); var stmt = this.prepare(sql);
while(stmt) { while(stmt) {
if (bindings) { if (bindings) {
...@@ -77,19 +76,7 @@ DatabaseSync.prototype.performQuery = function(sql, bindings, ...@@ -77,19 +76,7 @@ DatabaseSync.prototype.performQuery = function(sql, bindings,
stmt.finalize(); stmt.finalize();
stmt = this.prepare(stmt.tail); stmt = this.prepare(stmt.tail);
} }
return all;
}
DatabaseSync.prototype.query = function (sql, bindings, callback) {
// TODO: error callback
if (typeof(bindings) == "function") {
var tmp = bindings;
bindings = callback;
callback = tmp;
}
var all = this.performQuery(sql, bindings);
if (all.length == 0) { if (all.length == 0) {
var result = null; var result = null;
} else { } else {
...@@ -116,7 +103,10 @@ DatabaseSync.prototype.query = function (sql, bindings, callback) { ...@@ -116,7 +103,10 @@ DatabaseSync.prototype.query = function (sql, bindings, callback) {
function SQLTransactionSync(db, txCallback, errCallback, successCallback) { function SQLTransactionSync(db, txCallback, errCallback, successCallback) {
this.database = db; this.database = db;
this.rolledBack = false;
this.executeSql = function(sqlStatement, arguments, callback) { this.executeSql = function(sqlStatement, arguments, callback) {
if (this.rolledBack) return;
var result = db.query(sqlStatement, arguments); var result = db.query(sqlStatement, arguments);
if (callback) { if (callback) {
var tx = this; var tx = this;
...@@ -125,10 +115,21 @@ function SQLTransactionSync(db, txCallback, errCallback, successCallback) { ...@@ -125,10 +115,21 @@ function SQLTransactionSync(db, txCallback, errCallback, successCallback) {
return result; return result;
} }
db.query("BEGIN TRANSACTION"); var that = this;
function unroll() {
that.rolledBack = true;
}
db.addListener("rollback", unroll);
this.executeSql("BEGIN TRANSACTION");
txCallback(this); txCallback(this);
db.query("COMMIT"); this.executeSql("COMMIT");
if (successCallback) successCallback(this);
db.removeListener("rollback", unroll);
if (!this.rolledBack && successCallback)
successCallback(this);
} }
......
...@@ -259,6 +259,8 @@ protected: ...@@ -259,6 +259,8 @@ protected:
} else if (args[1]->IsString()) { } else if (args[1]->IsString()) {
String::Utf8Value text(args[1]); String::Utf8Value text(args[1]);
sqlite3_bind_text(*stmt, index, *text, text.length(),SQLITE_TRANSIENT); sqlite3_bind_text(*stmt, index, *text, text.length(),SQLITE_TRANSIENT);
} else if (args[1]->IsNull() || args[1]->IsUndefined()) {
sqlite3_bind_null(*stmt, index);
} else { } else {
return ThrowException(Exception::TypeError( return ThrowException(Exception::TypeError(
String::New("Unable to bind value of this type"))); String::New("Unable to bind value of this type")));
......
...@@ -49,8 +49,8 @@ db.query("INSERT INTO egg (a,y,e) VALUES (?,?,?)", [1.01, 10e20, -0.0]); ...@@ -49,8 +49,8 @@ db.query("INSERT INTO egg (a,y,e) VALUES (?,?,?)", [1.01, 10e20, -0.0]);
db.query("INSERT INTO egg (a,y,e) VALUES (?,?,?)", ["one", "two", "three"]); db.query("INSERT INTO egg (a,y,e) VALUES (?,?,?)", ["one", "two", "three"]);
db.query("SELECT * FROM egg", function (rows) { db.query("SELECT * FROM egg", function (rows) {
sys.puts(JSON.stringify(rows)); sys.puts(JSON.stringify(rows));
}); });
db.query("SELECT a FROM egg; SELECT y FROM egg", function (as, ys) { db.query("SELECT a FROM egg; SELECT y FROM egg", function (as, ys) {
sys.puts("As " + JSON.stringify(as)); sys.puts("As " + JSON.stringify(as));
...@@ -80,16 +80,15 @@ db.transaction(function(tx) { ...@@ -80,16 +80,15 @@ db.transaction(function(tx) {
db.query("CREATE TABLE test (x,y,z)", function () { db.query("CREATE TABLE test (x,y,z)", function () {
db.query("INSERT INTO test (x,y) VALUES (?,?)", [5,10]); db.query("INSERT INTO test (x,y) VALUES (?,?)", [5,10]);
db.query("INSERT INTO test (x,y,z) VALUES ($x, $y, $z)", {$x:1, $y:2, $z:3}); db.query("INSERT INTO test (x,y,z) VALUES ($x,$y,$z)", {$x:1, $y:2, $z:3});
}); });
db.query("SELECT * FROM test WHERE rowid < ?;", [1]); db.query("SELECT * FROM test WHERE rowid < ?;", [1]);
db.query("UPDATE test SET y = 10;", [], function () { db.query("UPDATE test SET y = 10;", [], function () {
sys.puts(this.rowsAffected + " rows affected"); process.assert(this.rowsAffected == 2);
process.assert(this.rowsAffected == 2); });
});
db.transaction(function(tx) { db.transaction(function(tx) {
tx.executeSql("SELECT * FROM test WHERE x = ?", [1], function (tx,records) { tx.executeSql("SELECT * FROM test WHERE x = ?", [1], function (tx,records) {
...@@ -107,10 +106,16 @@ try { ...@@ -107,10 +106,16 @@ try {
} catch (e) { } catch (e) {
} }
db.transaction(function(tx){
for (var i = 0; i < 3; ++i)
tx.executeSql("INSERT INTO test VALUES (6,6,6)");
tx.executeSql("ROLLBACK");
});
sys.puts("commits: " + commits); asserteq(commits, 14);
sys.puts("rollbacks: " + rollbacks); asserteq(rollbacks, 1);
sys.puts("updates: " + updates); asserteq(updates, 19);
db.close(); db.close();
......
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