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.
// TODO: async
var sys = require("sys");
var bindings = require("./sqlite3_bindings");
process.mixin(GLOBAL, bindings);
process.mixin(exports, bindings);
......@@ -31,23 +30,23 @@ exports.SQLITE_UPDATE = 23;
exports.openDatabaseSync = function (name, version, displayName,
estimatedSize, creationCallback) {
// 2nd-4th parameters are ignored
var db = new DatabaseSync(name);
if (creationCallback) creationCallback(db);
return db;
}
DatabaseSync.prototype.performQuery = function(sql, bindings,
callback, errback) {
var all = [];
// bindings param is optional
if (typeof bindings == 'function') {
errback = callback;
callback = bindings;
bindings = null;
DatabaseSync.prototype.query = function (sql, bindings, callback) {
// TODO: error callback
if (typeof(bindings) == "function") {
var tmp = bindings;
bindings = callback;
callback = tmp;
}
var all = [];
var stmt = this.prepare(sql);
while(stmt) {
if (bindings) {
......@@ -78,18 +77,6 @@ DatabaseSync.prototype.performQuery = function(sql, bindings,
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) {
var result = null;
} else {
......@@ -116,7 +103,10 @@ DatabaseSync.prototype.query = function (sql, bindings, callback) {
function SQLTransactionSync(db, txCallback, errCallback, successCallback) {
this.database = db;
this.rolledBack = false;
this.executeSql = function(sqlStatement, arguments, callback) {
if (this.rolledBack) return;
var result = db.query(sqlStatement, arguments);
if (callback) {
var tx = this;
......@@ -125,10 +115,21 @@ function SQLTransactionSync(db, txCallback, errCallback, successCallback) {
return result;
}
db.query("BEGIN TRANSACTION");
var that = this;
function unroll() {
that.rolledBack = true;
}
db.addListener("rollback", unroll);
this.executeSql("BEGIN TRANSACTION");
txCallback(this);
db.query("COMMIT");
if (successCallback) successCallback(this);
this.executeSql("COMMIT");
db.removeListener("rollback", unroll);
if (!this.rolledBack && successCallback)
successCallback(this);
}
......
......@@ -259,6 +259,8 @@ protected:
} else if (args[1]->IsString()) {
String::Utf8Value text(args[1]);
sqlite3_bind_text(*stmt, index, *text, text.length(),SQLITE_TRANSIENT);
} else if (args[1]->IsNull() || args[1]->IsUndefined()) {
sqlite3_bind_null(*stmt, index);
} else {
return ThrowException(Exception::TypeError(
String::New("Unable to bind value of this type")));
......
......@@ -50,7 +50,7 @@ db.query("INSERT INTO egg (a,y,e) VALUES (?,?,?)", ["one", "two", "three"]);
db.query("SELECT * FROM egg", function (rows) {
sys.puts(JSON.stringify(rows));
});
});
db.query("SELECT a FROM egg; SELECT y FROM egg", function (as, ys) {
sys.puts("As " + JSON.stringify(as));
......@@ -81,15 +81,14 @@ db.transaction(function(tx) {
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,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("UPDATE test SET y = 10;", [], function () {
sys.puts(this.rowsAffected + " rows affected");
process.assert(this.rowsAffected == 2);
});
});
db.transaction(function(tx) {
tx.executeSql("SELECT * FROM test WHERE x = ?", [1], function (tx,records) {
......@@ -107,10 +106,16 @@ try {
} 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);
sys.puts("rollbacks: " + rollbacks);
sys.puts("updates: " + updates);
asserteq(commits, 14);
asserteq(rollbacks, 1);
asserteq(updates, 19);
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