summaryrefslogtreecommitdiff
diff options
authorDavid Paleino <dapal@debian.org>2012-03-22 00:16:39 +0100
committergit-ubuntu importer <ubuntu-devel-discuss@lists.ubuntu.com>2012-03-22 09:27:31 +0000
commit8dea0f0101d887dd54e3220c3926bd28cf0ad56c (patch)
treee40221aa1134ed5abc3eef3cc4b3bcb5382318ae
parentcdf45e3af6ca05e668c847d69e5f67506579ba00 (diff)
parente26536e0362ec3973a5cd10813e8d054484362bc (diff)
Imported using git-ubuntu import.
-rw-r--r--.gitignore3
-rw-r--r--README.md6
-rw-r--r--debian/changelog19
-rw-r--r--debian/control6
-rw-r--r--debian/copyright5
-rw-r--r--debian/patches/00-use_systemwide_sqlite3.patch20
-rw-r--r--debian/patches/series1
-rwxr-xr-xdebian/rules5
-rw-r--r--debian/watch4
-rw-r--r--lib/sqlite3.js19
-rw-r--r--package.json15
-rw-r--r--src/async.h45
-rw-r--r--src/database.cc128
-rw-r--r--src/database.h60
-rw-r--r--src/macros.h12
-rw-r--r--src/sqlite3.cc14
-rw-r--r--src/statement.cc138
-rw-r--r--src/statement.h71
-rw-r--r--test/database_fail.test.js10
-rw-r--r--test/scheduling.test.js16
-rw-r--r--wscript100
21 files changed, 355 insertions, 342 deletions
diff --git a/.gitignore b/.gitignore
index 3324487..c0c4a11 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
.DS_Store
+.lock-wscript
build/
TODO
wiki
lib/sqlite3_bindings.node
-deps/sqlite-autoconf-3070701 \ No newline at end of file
+deps/sqlite-autoconf-3070800 \ No newline at end of file
diff --git a/README.md b/README.md
index 62e098c..88e4e0c 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# NAME
-node-sqlite3 - Asynchronous, non-blocking [SQLite3](http://sqlite.org/) bindings for [node.js](https://github.com/joyent/node) 0.2.\* and 0.4.\*.
+node-sqlite3 - Asynchronous, non-blocking [SQLite3](http://sqlite.org/) bindings for [node.js](https://github.com/joyent/node) 0.2-0.4 (versions 2.0.x) and **0.6.x** (versions 2.1.x).
@@ -75,14 +75,14 @@ You can also use [`npm`](https://github.com/isaacs/npm) to download and install
# CONTRIBUTORS
* [Konstantin Käfer](https://github.com/kkaefer)
+* [Dane Springmeyer](https://github.com/springmeyer)
+* [Will White](https://github.com/willwhite)
* [Orlando Vazquez](https://github.com/orlandov)
* [Artem Kustikov](https://github.com/artiz)
* [Eric Fredricksen](https://github.com/grumdrig)
* [John Wright](https://github.com/mrjjwright)
* [Ryan Dahl](https://github.com/ry)
-* [Will White](https://github.com/willwhite)
* [Tom MacWright](https://github.com/tmcw)
-* [Dane Springmeyer](https://github.com/springmeyer)
* [Carter Thaxton](https://github.com/carter-thaxton)
* [Audrius Kažukauskas](https://github.com/audriusk)
* [Johannes Schauer](https://github.com/pyneo)
diff --git a/debian/changelog b/debian/changelog
index fc8e682..b15435e 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,22 @@
+node-sqlite3 (2.1.1+ds1-1) unstable; urgency=low
+
+ * New upstream version
+ - supports NodeJS 0.6 (Closes: #664912)
+ * Bump Standards-Version to 3.9.3, no changes needed
+ * Updated debian/copyright
+ * Bump dependencies on node to >= 0.6
+
+ -- David Paleino <dapal@debian.org> Thu, 22 Mar 2012 00:16:39 +0100
+
+node-sqlite3 (2.0.18+ds1-1) unstable; urgency=low
+
+ * New upstream version
+ * Add debian/watch
+ * Fix debian/rules to get correct upstream version number
+ * Fix buildsystem again to link against system-wide sqlite3
+
+ -- David Paleino <dapal@debian.org> Sat, 31 Dec 2011 12:36:55 +0100
+
node-sqlite3 (2.0.17+ds1-2) unstable; urgency=low
* Compliance to Debian Javascript Policy
diff --git a/debian/control b/debian/control
index 08ad197..9a2badd 100644
--- a/debian/control
+++ b/debian/control
@@ -6,9 +6,9 @@ Uploaders: David Paleino <dapal@debian.org>
Build-Depends:
debhelper (>= 8~)
, dh-buildinfo
- , nodejs-dev
+ , nodejs-dev (>= 0.6)
, libsqlite3-dev
-Standards-Version: 3.9.2
+Standards-Version: 3.9.3
Homepage: http://github.com/developmentseed/node-sqlite3
Vcs-Git: git://git.debian.org/collab-maint/node-sqlite3.git
Vcs-Browser: http://git.debian.org/?p=collab-maint/node-sqlite3.git;a=summary
@@ -18,7 +18,7 @@ Architecture: any
Depends:
${shlibs:Depends}
, ${misc:Depends}
- , nodejs
+ , nodejs (>= 0.6)
Description: asynchronous, non-blocking SQLite3 bindings for NodeJS
node-sqlite3 provides asynchronous, non-blocking SQLite3 bindings for NodeJS.
Its features are:
diff --git a/debian/copyright b/debian/copyright
index 24a0f44..88fb81f 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -1,12 +1,11 @@
-Format: http://dep.debian.net/deps/dep5
-Upstream-Name: node-sqlite3
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0
Files: *
Copyright: © 2011, Konstantin Käfer <kkaefer@gmail.com>
License: BSD-3
Files: debian/*
-Copyright: © 2011, David Paleino <dapal@debian.org>
+Copyright: © 2011-2012, David Paleino <dapal@debian.org>
License: GPL-2.0+
License: BSD-3
diff --git a/debian/patches/00-use_systemwide_sqlite3.patch b/debian/patches/00-use_systemwide_sqlite3.patch
deleted file mode 100644
index 066f881..0000000
--- a/debian/patches/00-use_systemwide_sqlite3.patch
+++ /dev/null
@@ -1,20 +0,0 @@
-From: David Paleino <dapal@debian.org>
-Subject: fix default value for using sqlite3 system lib
-Origin: vendor
-Forwarded: https://github.com/developmentseed/node-sqlite3/pull/42
-
----
- wscript | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- node-sqlite3.orig/wscript
-+++ node-sqlite3/wscript
-@@ -25,7 +25,7 @@ def set_options(opt):
-
- opt.add_option( '--internal-sqlite'
- , action='store_true'
-- , default=True
-+ , default=False
- , help='Build dynamically against external install of libsqlite3 (default False - build uses internal copy)'
- , dest='internal_sqlite'
- )
diff --git a/debian/patches/series b/debian/patches/series
deleted file mode 100644
index 070bafa..0000000
--- a/debian/patches/series
+++ /dev/null
@@ -1 +0,0 @@
-00-use_systemwide_sqlite3.patch
diff --git a/debian/rules b/debian/rules
index 6a5185f..615a34f 100755
--- a/debian/rules
+++ b/debian/rules
@@ -4,7 +4,9 @@
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
-UPVER := $(shell dpkg-parsechangelog | grep ^Version | cut -d- -f1 | cut -d+ -f1)
+ifndef UPVER
+UPVER := $(shell dpkg-parsechangelog | grep ^Version | cut -d\ -f2 | cut -d- -f1 | cut -d+ -f1)
+endif
%:
dh $@
@@ -12,6 +14,7 @@ UPVER := $(shell dpkg-parsechangelog | grep ^Version | cut -d- -f1 | cut -d+ -f1
override_dh_auto_configure:
./configure \
--prefix=/usr \
+ --with-sqlite3=/usr \
--destdir=$(CURDIR)/debian/node-sqlite3
override_dh_auto_test:
diff --git a/debian/watch b/debian/watch
new file mode 100644
index 0000000..f34b9c3
--- /dev/null
+++ b/debian/watch
@@ -0,0 +1,4 @@
+version=3
+opts=dversionmangle=s/\+ds\d// \
+https://alioth.debian.org/~dapal/npmjs.php?id=sqlite3 \
+http://registry.npmjs.org/sqlite3/-/sqlite3-(\d+.*)\.tgz
diff --git a/lib/sqlite3.js b/lib/sqlite3.js
index f8f2b1d..8db674a 100644
--- a/lib/sqlite3.js
+++ b/lib/sqlite3.js
@@ -1,10 +1,8 @@
-var sqlite3 = module.exports = exports = require('./sqlite3_bindings');
+var sqlite3 = module.exports = exports = require('./sqlite3_bindings.node');
var path = require('path');
+var util = require('util');
var EventEmitter = require('events').EventEmitter;
-var Database = sqlite3.Database;
-var Statement = sqlite3.Statement;
-
function errorCallback(args) {
if (typeof args[args.length - 1] === 'function') {
var callback = args[args.length - 1];
@@ -12,6 +10,11 @@ function errorCallback(args) {
}
}
+function inherits(target, source) {
+ for (var k in source.prototype)
+ target.prototype[k] = source.prototype[k];
+}
+
sqlite3.cached = {
Database: function(file, a, b) {
if (file === '' || file === ':memory:') {
@@ -42,6 +45,13 @@ sqlite3.cached = {
objects: {}
};
+
+var Database = sqlite3.Database;
+var Statement = sqlite3.Statement;
+
+inherits(Database, EventEmitter);
+inherits(Statement, EventEmitter);
+
// Database#prepare(sql, [bind1, bind2, ...], [callback])
Database.prototype.prepare = function(sql) {
var params = Array.prototype.slice.call(arguments, 1);
@@ -148,7 +158,6 @@ Database.prototype.removeAllListeners = function(type) {
return val;
};
-
// Save the stack trace over EIO callbacks.
sqlite3.verbose = function() {
if (!isVerbose) {
diff --git a/package.json b/package.json
index 4eb3eb2..d476e91 100644
--- a/package.json
+++ b/package.json
@@ -1,18 +1,23 @@
{
"name": "sqlite3",
"description": "Asynchronous, non-blocking SQLite3 bindings",
- "version": "2.0.17",
+ "version": "2.1.1",
"homepage": "http://github.com/developmentseed/node-sqlite3",
- "author": "Konstantin Käfer <kkaefer@gmail.com>",
+ "author": {
+ "name": "Development Seed",
+ "url": "http://developmentseed.org/",
+ "email": "info@developmentseed.org"
+ },
"contributors": [
+ "Konstantin Käfer <mail@kkaefer.com>",
+ "Dane Springmeyer <dane@developmentseed.org>",
+ "Will White <will@developmentseed.org>",
"Orlando Vazquez <ovazquez@gmail.com>",
"Artem Kustikov <kustikoff@gmail.com>",
"Eric Fredricksen <efredricksen@gmail.com>",
"John Wright <mrjjwright@gmail.com>",
"Ryan Dahl <ry@tinyclouds.org>",
- "Will White <will@developmentseed.org>",
"Tom MacWright <tom@developmentseed.org>",
- "Dane Springmeyer <dane@developmentseed.org>",
"Carter Thaxton <carter.thaxton@gmail.com>",
"Audrius Kažukauskas <audrius@neutrino.lt>",
"Johannes Schauer <josch@pyneo.org>"
@@ -25,7 +30,7 @@
"step": "0.0.4"
},
"engines": {
- "node": ">=0.2.4 <0.5"
+ "node": "~0.6.0"
},
"licenses": [{ "type": "BSD" }],
"main": "./lib/sqlite3"
diff --git a/src/async.h b/src/async.h
index 77f7e0e..b910ae6 100644
--- a/src/async.h
+++ b/src/async.h
@@ -2,12 +2,12 @@
#define NODE_SQLITE3_SRC_ASYNC_H
-// Generic ev_async handler.
+// Generic uv_async handler.
template <class Item, class Parent> class Async {
typedef void (*Callback)(Parent* parent, Item* item);
protected:
- ev_async watcher;
+ uv_async_t watcher;
pthread_mutex_t mutex;
std::vector<Item*> data;
Callback callback;
@@ -15,47 +15,60 @@ public:
Parent* parent;
public:
- inline Async(Parent* parent_, Callback cb_)
+ Async(Parent* parent_, Callback cb_)
: callback(cb_), parent(parent_) {
watcher.data = this;
- ev_async_init(&watcher, listener);
- ev_async_start(EV_DEFAULT_UC_ &watcher);
pthread_mutex_init(&mutex, NULL);
+ uv_async_init(uv_default_loop(), &watcher, listener);
}
- static void listener(EV_P_ ev_async *w, int revents) {
- Async* async = static_cast<Async*>(w->data);
+ static void listener(uv_async_t* handle, int status) {
+ Async* async = static_cast<Async*>(handle->data);
std::vector<Item*> rows;
pthread_mutex_lock(&async->mutex);
rows.swap(async->data);
pthread_mutex_unlock(&async->mutex);
for (unsigned int i = 0, size = rows.size(); i < size; i++) {
- ev_unref(EV_DEFAULT_UC);
+ uv_unref(uv_default_loop());
async->callback(async->parent, rows[i]);
}
}
- inline void add(Item* item) {
+ static void close(uv_handle_t* handle) {
+ assert(handle != NULL);
+ assert(handle->data != NULL);
+ Async* async = static_cast<Async*>(handle->data);
+ delete async;
+ handle->data = NULL;
+ }
+
+ void finish() {
+ // Need to call the listener again to ensure all items have been
+ // processed. Is this a bug in uv_async? Feels like uv_close
+ // should handle that.
+ listener(&watcher, 0);
+ uv_close((uv_handle_t*)&watcher, close);
+ }
+
+ void add(Item* item) {
// Make sure node runs long enough to deliver the messages.
- ev_ref(EV_DEFAULT_UC);
+ uv_ref(uv_default_loop());
pthread_mutex_lock(&mutex);
data.push_back(item);
pthread_mutex_unlock(&mutex);
}
- inline void send() {
- ev_async_send(EV_DEFAULT_ &watcher);
+ void send() {
+ uv_async_send(&watcher);
}
- inline void send(Item* item) {
+ void send(Item* item) {
add(item);
send();
}
- inline ~Async() {
- ev_invoke(EV_DEFAULT_UC_ &watcher, ev_async_pending(&watcher));
+ ~Async() {
pthread_mutex_destroy(&mutex);
- ev_async_stop(EV_DEFAULT_UC_ &watcher);
}
};
diff --git a/src/database.cc b/src/database.cc
index c8e945a..70e092a 100644
--- a/src/database.cc
+++ b/src/database.cc
@@ -1,7 +1,6 @@
#include <string.h>
#include <v8.h>
#include <node.h>
-#include <node_events.h>
#include "macros.h"
#include "database.h"
@@ -17,7 +16,6 @@ void Database::Init(Handle<Object> target) {
Local<FunctionTemplate> t = FunctionTemplate::New(New);
constructor_template = Persistent<FunctionTemplate>::New(t);
- constructor_template->Inherit(EventEmitter::constructor_template);
constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
constructor_template->SetClassName(String::NewSymbol("Database"));
@@ -79,7 +77,7 @@ void Database::Process() {
}
}
-void Database::Schedule(EIO_Callback callback, Baton* baton, bool exclusive) {
+void Database::Schedule(Work_Callback callback, Baton* baton, bool exclusive) {
if (!open && locked) {
EXCEPTION(String::New("Database is closed"), SQLITE_MISUSE, exception);
if (!baton->callback.IsEmpty() && baton->callback->IsFunction()) {
@@ -105,7 +103,7 @@ void Database::Schedule(EIO_Callback callback, Baton* baton, bool exclusive) {
Handle<Value> Database::New(const Arguments& args) {
HandleScope scope;
- if (!Database::HasInstance(args.This())) {
+ if (!args.IsConstructCall()) {
return ThrowException(Exception::TypeError(
String::New("Use the new operator to create new Database objects"))
);
@@ -132,16 +130,18 @@ Handle<Value> Database::New(const Arguments& args) {
// Start opening the database.
OpenBaton* baton = new OpenBaton(db, callback, *filename, SQLITE_OPEN_FULLMUTEX | mode);
- EIO_BeginOpen(baton);
+ Work_BeginOpen(baton);
return args.This();
}
-void Database::EIO_BeginOpen(Baton* baton) {
- eio_custom(EIO_Open, EIO_PRI_DEFAULT, EIO_AfterOpen, baton);
+void Database::Work_BeginOpen(Baton* baton) {
+ int status = uv_queue_work(uv_default_loop(),
+ &baton->request, Work_Open, Work_AfterOpen);
+ assert(status == 0);
}
-int Database::EIO_Open(eio_req *req) {
+void Database::Work_Open(uv_work_t* req) {
OpenBaton* baton = static_cast<OpenBaton*>(req->data);
Database* db = baton->db;
@@ -161,11 +161,9 @@ int Database::EIO_Open(eio_req *req) {
// Set default database handle values.
sqlite3_busy_timeout(db->handle, 1000);
}
-
- return 0;
}
-int Database::EIO_AfterOpen(eio_req *req) {
+void Database::Work_AfterOpen(uv_work_t* req) {
HandleScope scope;
OpenBaton* baton = static_cast<OpenBaton*>(req->data);
Database* db = baton->db;
@@ -195,7 +193,6 @@ int Database::EIO_AfterOpen(eio_req *req) {
}
delete baton;
- return 0;
}
Handle<Value> Database::OpenGetter(Local<String> str, const AccessorInfo& accessor) {
@@ -210,22 +207,24 @@ Handle<Value> Database::Close(const Arguments& args) {
OPTIONAL_ARGUMENT_FUNCTION(0, callback);
Baton* baton = new Baton(db, callback);
- db->Schedule(EIO_BeginClose, baton, true);
+ db->Schedule(Work_BeginClose, baton, true);
return args.This();
}
-void Database::EIO_BeginClose(Baton* baton) {
+void Database::Work_BeginClose(Baton* baton) {
assert(baton->db->locked);
assert(baton->db->open);
assert(baton->db->handle);
assert(baton->db->pending == 0);
baton->db->RemoveCallbacks();
- eio_custom(EIO_Close, EIO_PRI_DEFAULT, EIO_AfterClose, baton);
+ int status = uv_queue_work(uv_default_loop(),
+ &baton->request, Work_Close, Work_AfterClose);
+ assert(status == 0);
}
-int Database::EIO_Close(eio_req *req) {
+void Database::Work_Close(uv_work_t* req) {
Baton* baton = static_cast<Baton*>(req->data);
Database* db = baton->db;
@@ -237,10 +236,9 @@ int Database::EIO_Close(eio_req *req) {
else {
db->handle = NULL;
}
- return 0;
}
-int Database::EIO_AfterClose(eio_req *req) {
+void Database::Work_AfterClose(uv_work_t* req) {
HandleScope scope;
Baton* baton = static_cast<Baton*>(req->data);
Database* db = baton->db;
@@ -273,7 +271,6 @@ int Database::EIO_AfterClose(eio_req *req) {
}
delete baton;
- return 0;
}
Handle<Value> Database::Serialize(const Arguments& args) {
@@ -374,7 +371,7 @@ void Database::RegisterTraceCallback(Baton* baton) {
else {
// Remove it.
sqlite3_trace(db->handle, NULL, NULL);
- delete db->debug_trace;
+ db->debug_trace->finish();
db->debug_trace = NULL;
}
@@ -411,7 +408,7 @@ void Database::RegisterProfileCallback(Baton* baton) {
else {
// Remove it.
sqlite3_profile(db->handle, NULL, NULL);
- delete db->debug_profile;
+ db->debug_profile->finish();
db->debug_profile = NULL;
}
@@ -451,7 +448,7 @@ void Database::RegisterUpdateCallback(Baton* baton) {
else {
// Remove it.
sqlite3_update_hook(db->handle, NULL, NULL);
- delete db->update_event;
+ db->update_event->finish();
db->update_event = NULL;
}
@@ -491,20 +488,22 @@ Handle<Value> Database::Exec(const Arguments& args) {
OPTIONAL_ARGUMENT_FUNCTION(1, callback);
Baton* baton = new ExecBaton(db, callback, *sql);
- db->Schedule(EIO_BeginExec, baton, true);
+ db->Schedule(Work_BeginExec, baton, true);
return args.This();
}
-void Database::EIO_BeginExec(Baton* baton) {
+void Database::Work_BeginExec(Baton* baton) {
assert(baton->db->locked);
assert(baton->db->open);
assert(baton->db->handle);
assert(baton->db->pending == 0);
- eio_custom(EIO_Exec, EIO_PRI_DEFAULT, EIO_AfterExec, baton);
+ int status = uv_queue_work(uv_default_loop(),
+ &baton->request, Work_Exec, Work_AfterExec);
+ assert(status == 0);
}
-int Database::EIO_Exec(eio_req *req) {
+void Database::Work_Exec(uv_work_t* req) {
ExecBaton* baton = static_cast<ExecBaton*>(req->data);
char* message = NULL;
@@ -520,11 +519,9 @@ int Database::EIO_Exec(eio_req *req) {
baton->message = std::string(message);
sqlite3_free(message);
}
-
- return 0;
}
-int Database::EIO_AfterExec(eio_req *req) {
+void Database::Work_AfterExec(uv_work_t* req) {
HandleScope scope;
ExecBaton* baton = static_cast<ExecBaton*>(req->data);
Database* db = baton->db;
@@ -550,7 +547,6 @@ int Database::EIO_AfterExec(eio_req *req) {
db->Process();
delete baton;
- return 0;
}
Handle<Value> Database::LoadExtension(const Arguments& args) {
@@ -561,20 +557,22 @@ Handle<Value> Database::LoadExtension(const Arguments& args) {
OPTIONAL_ARGUMENT_FUNCTION(1, callback);
Baton* baton = new LoadExtensionBaton(db, callback, *filename);
- db->Schedule(EIO_BeginLoadExtension, baton, true);
+ db->Schedule(Work_BeginLoadExtension, baton, true);
return args.This();
}
-void Database::EIO_BeginLoadExtension(Baton* baton) {
+void Database::Work_BeginLoadExtension(Baton* baton) {
assert(baton->db->locked);
assert(baton->db->open);
assert(baton->db->handle);
assert(baton->db->pending == 0);
- eio_custom(EIO_LoadExtension, EIO_PRI_DEFAULT, EIO_AfterLoadExtension, baton);
+ int status = uv_queue_work(uv_default_loop(),
+ &baton->request, Work_LoadExtension, Work_AfterLoadExtension);
+ assert(status == 0);
}
-int Database::EIO_LoadExtension(eio_req *req) {
+void Database::Work_LoadExtension(uv_work_t* req) {
LoadExtensionBaton* baton = static_cast<LoadExtensionBaton*>(req->data);
sqlite3_enable_load_extension(baton->db->handle, 1);
@@ -593,11 +591,9 @@ int Database::EIO_LoadExtension(eio_req *req) {
baton->message = std::string(message);
sqlite3_free(message);
}
-
- return 0;
}
-int Database::EIO_AfterLoadExtension(eio_req *req) {
+void Database::Work_AfterLoadExtension(uv_work_t* req) {
HandleScope scope;
LoadExtensionBaton* baton = static_cast<LoadExtensionBaton*>(req->data);
Database* db = baton->db;
@@ -622,69 +618,15 @@ int Database::EIO_AfterLoadExtension(eio_req *req) {
db->Process();
delete baton;
- return 0;
}
void Database::RemoveCallbacks() {
if (debug_trace) {
- delete debug_trace;
+ debug_trace->finish();
debug_trace = NULL;
}
if (debug_profile) {
- delete debug_profile;
+ debug_profile->finish();
debug_profile = NULL;
}
}
-
-/**
- * Override this so that we can properly close the database when this object
- * gets garbage collected.
- */
-void Database::Wrap(Handle<Object> handle) {
- assert(handle_.IsEmpty());
- assert(handle->InternalFieldCount() > 0);
- handle_ = Persistent<Object>::New(handle);
- handle_->SetPointerInInternalField(0, this);
- handle_.MakeWeak(this, Destruct);
-}
-
-inline void Database::MakeWeak (void) {
- handle_.MakeWeak(this, Destruct);
-}
-
-void Database::Unref() {
- assert(!handle_.IsEmpty());
- assert(!handle_.IsWeak());
- assert(refs_ > 0);
- if (--refs_ == 0) { MakeWeak(); }
-}
-
-void Database::Destruct(Persistent<Value> value, void *data) {
- Database* db = static_cast<Database*>(data);
-
- db->RemoveCallbacks();
-
- if (db->handle) {
- eio_custom(EIO_Destruct, EIO_PRI_DEFAULT, EIO_AfterDestruct, db);
- ev_ref(EV_DEFAULT_UC);
- }
- else {
- delete db;
- }
-}
-
-int Database::EIO_Destruct(eio_req *req) {
- Database* db = static_cast<Database*>(req->data);
-
- sqlite3_close(db->handle);
- db->handle = NULL;
-
- return 0;
-}
-
-int Database::EIO_AfterDestruct(eio_req *req) {
- Database* db = static_cast<Database*>(req->data);
- ev_unref(EV_DEFAULT_UC);
- delete db;
- return 0;
-}
diff --git a/src/database.h b/src/database.h
index 6af8738..0018950 100644
--- a/src/database.h
+++ b/src/database.h
@@ -3,7 +3,6 @@
#include <v8.h>
#include <node.h>
-#include <node_events.h>
#include <string>
#include <queue>
@@ -19,7 +18,7 @@ namespace node_sqlite3 {
class Database;
-class Database : public EventEmitter {
+class Database : public ObjectWrap {
public:
static Persistent<FunctionTemplate> constructor_template;
static void Init(Handle<Object> target);
@@ -31,6 +30,7 @@ public:
}
struct Baton {
+ uv_work_t request;
Database* db;
Persistent<Function> callback;
int status;
@@ -39,12 +39,13 @@ public:
Baton(Database* db_, Handle<Function> cb_) :
db(db_), status(SQLITE_OK) {
db->Ref();
- ev_ref(EV_DEFAULT_UC);
+ uv_ref(uv_default_loop());
+ request.data = this;
callback = Persistent<Function>::New(cb_);
}
virtual ~Baton() {
db->Unref();
- ev_unref(EV_DEFAULT_UC);
+ uv_unref(uv_default_loop());
callback.Dispose();
}
};
@@ -68,12 +69,12 @@ public:
Baton(db_, cb_), filename(filename_) {}
};
- typedef void (*EIO_Callback)(Baton* baton);
+ typedef void (*Work_Callback)(Baton* baton);
struct Call {
- Call(EIO_Callback cb_, Baton* baton_, bool exclusive_ = false) :
+ Call(Work_Callback cb_, Baton* baton_, bool exclusive_ = false) :
callback(cb_), exclusive(exclusive_), baton(baton_) {};
- EIO_Callback callback;
+ Work_Callback callback;
bool exclusive;
Baton* baton;
};
@@ -89,7 +90,7 @@ public:
std::string table;
sqlite3_int64 rowid;
};
-
+
bool IsOpen() { return open; }
bool IsLocked() { return locked; }
@@ -100,7 +101,7 @@ public:
friend class Statement;
protected:
- Database() : EventEmitter(),
+ Database() : ObjectWrap(),
handle(NULL),
open(false),
locked(false),
@@ -112,37 +113,36 @@ protected:
}
~Database() {
- assert(handle == NULL);
- if (debug_trace) {
- delete debug_trace;
- debug_trace = NULL;
- }
+ RemoveCallbacks();
+ sqlite3_close(handle);
+ handle = NULL;
+ open = false;
}
static Handle<Value> New(const Arguments& args);
- static void EIO_BeginOpen(Baton* baton);
- static int EIO_Open(eio_req *req);
- static int EIO_AfterOpen(eio_req *req);
+ static void Work_BeginOpen(Baton* baton);
+ static void Work_Open(uv_work_t* req);
+ static void Work_AfterOpen(uv_work_t* req);
static Handle<Value> OpenGetter(Local<String> str, const AccessorInfo& accessor);
- void Schedule(EIO_Callback callback, Baton* baton, bool exclusive = false);
+ void Schedule(Work_Callback callback, Baton* baton, bool exclusive = false);
void Process();
static Handle<Value> Exec(const Arguments& args);
- static void EIO_BeginExec(Baton* baton);
- static int EIO_Exec(eio_req *req);
- static int EIO_AfterExec(eio_req *req);
+ static void Work_BeginExec(Baton* baton);
+ static void Work_Exec(uv_work_t* req);
+ static void Work_AfterExec(uv_work_t* req);
static Handle<Value> Close(const Arguments& args);
- static void EIO_BeginClose(Baton* baton);
- static int EIO_Close(eio_req *req);
- static int EIO_AfterClose(eio_req *req);
+ static void Work_BeginClose(Baton* baton);
+ static void Work_Close(uv_work_t* req);
+ static void Work_AfterClose(uv_work_t* req);
static Handle<Value> LoadExtension(const Arguments& args);
- static void EIO_BeginLoadExtension(Baton* baton);
- static int EIO_LoadExtension(eio_req *req);
- static int EIO_AfterLoadExtension(eio_req *req);
+ static void Work_BeginLoadExtension(Baton* baton);
+ static void Work_LoadExtension(uv_work_t* req);
+ static void Work_AfterLoadExtension(uv_work_t* req);
static Handle<Value> Serialize(const Arguments& args);
static Handle<Value> Parallelize(const Arguments& args);
@@ -164,12 +164,6 @@ protected:
static void UpdateCallback(Database* db, UpdateInfo* info);
void RemoveCallbacks();
- void Wrap (Handle<Object> handle);
- inline void MakeWeak();
- virtual void Unref();
- static void Destruct (Persistent<Value> value, void *data);
- static int EIO_Destruct(eio_req *req);
- static int EIO_AfterDestruct(eio_req *req);
protected:
sqlite3* handle;
diff --git a/src/macros.h b/src/macros.h
index f5c0333..d5c91fd 100644
--- a/src/macros.h
+++ b/src/macros.h
@@ -121,11 +121,11 @@ const char* sqlite_authorizer_string(int type);
FatalException(try_catch); \
} }
-#define EIO_DEFINITION(name) \
+#define WORK_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);
+ static void Work_Begin##name(Baton* baton); \
+ static void Work_##name(uv_work_t* req); \
+ static void Work_After##name(uv_work_t* req);
#define STATEMENT_BEGIN(type) \
assert(baton); \
@@ -135,7 +135,9 @@ const char* sqlite_authorizer_string(int type);
assert(baton->stmt->prepared); \
baton->stmt->locked = true; \
baton->stmt->db->pending++; \
- eio_custom(EIO_##type, EIO_PRI_DEFAULT, EIO_After##type, baton);
+ int status = uv_queue_work(uv_default_loop(), \
+ &baton->request, Work_##type, Work_After##type); \
+ assert(status == 0);
#define STATEMENT_INIT(type) \
type* baton = static_cast<type*>(req->data); \
diff --git a/src/sqlite3.cc b/src/sqlite3.cc
index abb2519..b73d08c 100644
--- a/src/sqlite3.cc
+++ b/src/sqlite3.cc
@@ -1,7 +1,11 @@
#include <v8.h>
#include <node.h>
-#include <node_events.h>
+#include <node_buffer.h>
+#include <stdint.h>
+#include <sstream>
+#include <cstring>
+#include <string>
#include <sqlite3.h>
#include "macros.h"
@@ -10,7 +14,9 @@
using namespace node_sqlite3;
-extern "C" void init (v8::Handle<Object> target) {
+namespace {
+
+void RegisterModule(v8::Handle<Object> target) {
Database::Init(target);
Statement::Init(target);
@@ -52,6 +58,8 @@ extern "C" void init (v8::Handle<Object> target) {
DEFINE_CONSTANT_INTEGER(target, SQLITE_NOTADB, NOTADB);
}
+}
+
const char* sqlite_code_string(int code) {
switch (code) {
case SQLITE_OK: return "SQLITE_OK";
@@ -95,3 +103,5 @@ const char* sqlite_authorizer_string(int type) {
default: return "";
}
}
+
+NODE_MODULE(sqlite3_bindings, RegisterModule);
diff --git a/src/statement.cc b/src/statement.cc
index 418aa54..07b6182 100644
--- a/src/statement.cc
+++ b/src/statement.cc
@@ -1,9 +1,7 @@
#include <string.h>
#include <v8.h>
#include <node.h>
-#include <node_events.h>
#include <node_buffer.h>
-#include <node_version.h>
#include "macros.h"
#include "database.h"
@@ -19,7 +17,6 @@ void Statement::Init(Handle<Object> target) {
Local<FunctionTemplate> t = FunctionTemplate::New(New);
constructor_template = Persistent<FunctionTemplate>::New(t);
- constructor_template->Inherit(EventEmitter::constructor_template);
constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
constructor_template->SetClassName(String::NewSymbol("Statement"));
@@ -49,7 +46,7 @@ void Statement::Process() {
}
}
-void Statement::Schedule(EIO_Callback callback, Baton* baton) {
+void Statement::Schedule(Work_Callback callback, Baton* baton) {
if (finalized) {
queue.push(new Call(callback, baton));
CleanQueue();
@@ -82,6 +79,12 @@ template <class T> void Statement::Error(T* baton) {
Handle<Value> Statement::New(const Arguments& args) {
HandleScope scope;
+ if (!args.IsConstructCall()) {
+ return ThrowException(Exception::TypeError(
+ String::New("Use the new operator to create new Statement objects"))
+ );
+ }
+
int length = args.Length();
if (length <= 0 || !Database::HasInstance(args[0])) {
@@ -107,18 +110,20 @@ Handle<Value> Statement::New(const Arguments& args) {
PrepareBaton* baton = new PrepareBaton(db, Local<Function>::Cast(args[2]), stmt);
baton->sql = std::string(*String::Utf8Value(sql));
- db->Schedule(EIO_BeginPrepare, baton);
+ db->Schedule(Work_BeginPrepare, baton);
return args.This();
}
-void Statement::EIO_BeginPrepare(Database::Baton* baton) {
+void Statement::Work_BeginPrepare(Database::Baton* baton) {
assert(baton->db->open);
baton->db->pending++;
- eio_custom(EIO_Prepare, EIO_PRI_DEFAULT, EIO_AfterPrepare, baton);
+ int status = uv_queue_work(uv_default_loop(),
+ &baton->request, Work_Prepare, Work_AfterPrepare);
+ assert(status == 0);
}
-int Statement::EIO_Prepare(eio_req *req) {
+void Statement::Work_Prepare(uv_work_t* req) {
STATEMENT_INIT(PrepareBaton);
// In case preparing fails, we use a mutex to make sure we get the associated
@@ -140,11 +145,9 @@ int Statement::EIO_Prepare(eio_req *req) {
}
sqlite3_mutex_leave(mtx);
-
- return 0;
}
-int Statement::EIO_AfterPrepare(eio_req *req) {
+void Statement::Work_AfterPrepare(uv_work_t* req) {
HandleScope scope;
STATEMENT_INIT(PrepareBaton);
@@ -161,7 +164,6 @@ int Statement::EIO_AfterPrepare(eio_req *req) {
}
STATEMENT_END();
- return 0;
}
template <class T> Values::Field*
@@ -183,13 +185,8 @@ template <class T> Values::Field*
return new Values::Null(pos);
}
else if (Buffer::HasInstance(source)) {
-#if NODE_VERSION_AT_LEAST(0,3,0)
Local<Object> buffer = source->ToObject();
return new Values::Blob(pos, Buffer::Length(buffer), Buffer::Data(buffer));
-#else
- Buffer* buffer = ObjectWrap::Unwrap<Buffer>(source->ToObject());
- return new Values::Blob(pos, buffer->length(), buffer->data());
-#endif
}
else if (source->IsDate()) {
return new Values::Float(pos, source->NumberValue());
@@ -319,27 +316,25 @@ Handle<Value> Statement::Bind(const Arguments& args) {
return ThrowException(Exception::Error(String::New("Data type is not supported")));
}
else {
- stmt->Schedule(EIO_BeginBind, baton);
+ stmt->Schedule(Work_BeginBind, baton);
return args.This();
}
}
-void Statement::EIO_BeginBind(Baton* baton) {
+void Statement::Work_BeginBind(Baton* baton) {
STATEMENT_BEGIN(Bind);
}
-int Statement::EIO_Bind(eio_req *req) {
+void Statement::Work_Bind(uv_work_t* req) {
STATEMENT_INIT(Baton);
sqlite3_mutex* mtx = sqlite3_db_mutex(stmt->db->handle);
sqlite3_mutex_enter(mtx);
stmt->Bind(baton->parameters);
sqlite3_mutex_leave(mtx);
-
- return 0;
}
-int Statement::EIO_AfterBind(eio_req *req) {
+void Statement::Work_AfterBind(uv_work_t* req) {
HandleScope scope;
STATEMENT_INIT(Baton);
@@ -355,7 +350,6 @@ int Statement::EIO_AfterBind(eio_req *req) {
}
STATEMENT_END();
- return 0;
}
@@ -369,16 +363,16 @@ Handle<Value> Statement::Get(const Arguments& args) {
return ThrowException(Exception::Error(String::New("Data type is not supported")));
}
else {
- stmt->Schedule(EIO_BeginGet, baton);
+ stmt->Schedule(Work_BeginGet, baton);
return args.This();
}
}
-void Statement::EIO_BeginGet(Baton* baton) {
+void Statement::Work_BeginGet(Baton* baton) {
STATEMENT_BEGIN(Get);
}
-int Statement::EIO_Get(eio_req *req) {
+void Statement::Work_Get(uv_work_t* req) {
STATEMENT_INIT(RowBaton);
if (stmt->status != SQLITE_DONE || baton->parameters.size()) {
@@ -400,11 +394,9 @@ int Statement::EIO_Get(eio_req *req) {
GetRow(&baton->row, stmt->handle);
}
}
-
- return 0;
}
-int Statement::EIO_AfterGet(eio_req *req) {
+void Statement::Work_AfterGet(uv_work_t* req) {
HandleScope scope;
STATEMENT_INIT(RowBaton);
@@ -427,7 +419,6 @@ int Statement::EIO_AfterGet(eio_req *req) {
}
STATEMENT_END();
- return 0;
}
Handle<Value> Statement::Run(const Arguments& args) {
@@ -439,16 +430,16 @@ Handle<Value> Statement::Run(const Arguments& args) {
return ThrowException(Exception::Error(String::New("Data type is not supported")));
}
else {
- stmt->Schedule(EIO_BeginRun, baton);
+ stmt->Schedule(Work_BeginRun, baton);
return args.This();
}
}
-void Statement::EIO_BeginRun(Baton* baton) {
+void Statement::Work_BeginRun(Baton* baton) {
STATEMENT_BEGIN(Run);
}
-int Statement::EIO_Run(eio_req *req) {
+void Statement::Work_Run(uv_work_t* req) {
STATEMENT_INIT(RunBaton);
sqlite3_mutex* mtx = sqlite3_db_mutex(stmt->db->handle);
@@ -472,11 +463,9 @@ int Statement::EIO_Run(eio_req *req) {
}
sqlite3_mutex_leave(mtx);
-
- return 0;
}
-int Statement::EIO_AfterRun(eio_req *req) {
+void Statement::Work_AfterRun(uv_work_t* req) {
HandleScope scope;
STATEMENT_INIT(RunBaton);
@@ -495,7 +484,6 @@ int Statement::EIO_AfterRun(eio_req *req) {
}
STATEMENT_END();
- return 0;
}
Handle<Value> Statement::All(const Arguments& args) {
@@ -507,16 +495,16 @@ Handle<Value> Statement::All(const Arguments& args) {
return ThrowException(Exception::Error(String::New("Data type is not supported")));
}
else {
- stmt->Schedule(EIO_BeginAll, baton);
+ stmt->Schedule(Work_BeginAll, baton);
return args.This();
}
}
-void Statement::EIO_BeginAll(Baton* baton) {
+void Statement::Work_BeginAll(Baton* baton) {
STATEMENT_BEGIN(All);
}
-int Statement::EIO_All(eio_req *req) {
+void Statement::Work_All(uv_work_t* req) {
STATEMENT_INIT(RowsBaton);
sqlite3_mutex* mtx = sqlite3_db_mutex(stmt->db->handle);
@@ -540,11 +528,9 @@ int Statement::EIO_All(eio_req *req) {
}
sqlite3_mutex_leave(mtx);
-
- return 0;
}
-int Statement::EIO_AfterAll(eio_req *req) {
+void Statement::Work_AfterAll(uv_work_t* req) {
HandleScope scope;
STATEMENT_INIT(RowsBaton);
@@ -579,7 +565,6 @@ int Statement::EIO_AfterAll(eio_req *req) {
}
STATEMENT_END();
- return 0;
}
Handle<Value> Statement::Each(const Arguments& args) {
@@ -599,19 +584,26 @@ Handle<Value> Statement::Each(const Arguments& args) {
}
else {
baton->completed = Persistent<Function>::New(completed);
- stmt->Schedule(EIO_BeginEach, baton);
+ stmt->Schedule(Work_BeginEach, baton);
return args.This();
}
}
-void Statement::EIO_BeginEach(Baton* baton) {
+void Statement::Work_BeginEach(Baton* baton) {
+ // Only create the Async object when we're actually going into
+ // the event loop. This prevents dangling events.
+ EachBaton* each_baton = static_cast<EachBaton*>(baton);
+ each_baton->async = new Async(each_baton->stmt, AsyncEach);
+ each_baton->async->item_cb = Persistent<Function>::New(each_baton->callback);
+ each_baton->async->completed_cb = Persistent<Function>::New(each_baton->completed);
+
STATEMENT_BEGIN(Each);
}
-int Statement::EIO_Each(eio_req *req) {
+void Statement::Work_Each(uv_work_t* req) {
STATEMENT_INIT(EachBaton);
- Async* async = new Async(stmt, baton->callback, baton->completed, AsyncEach);
+ Async* async = baton->async;
sqlite3_mutex* mtx = sqlite3_db_mutex(stmt->db->handle);
@@ -636,7 +628,7 @@ int Statement::EIO_Each(eio_req *req) {
retrieved++;
pthread_mutex_unlock(&async->mutex);
- ev_async_send(EV_DEFAULT_ &async->watcher);
+ uv_async_send(&async->watcher);
}
else {
if (stmt->status != SQLITE_DONE) {
@@ -649,14 +641,20 @@ int Statement::EIO_Each(eio_req *req) {
}
async->completed = true;
- ev_async_send(EV_DEFAULT_ &async->watcher);
+ uv_async_send(&async->watcher);
+}
- return 0;
+void Statement::CloseCallback(uv_handle_t* handle) {
+ assert(handle != NULL);
+ assert(handle->data != NULL);
+ Async* async = static_cast<Async*>(handle->data);
+ delete async;
+ handle->data = NULL;
}
-void Statement::AsyncEach(EV_P_ ev_async *w, int revents) {
+void Statement::AsyncEach(uv_async_t* handle, int status) {
HandleScope scope;
- Async* async = static_cast<Async*>(w->data);
+ Async* async = static_cast<Async*>(handle->data);
while (true) {
// Get the contents out of the data cache for us to process in the JS callback.
@@ -669,7 +667,7 @@ void Statement::AsyncEach(EV_P_ ev_async *w, int revents) {
break;
}
- if (!async->callback.IsEmpty() && async->callback->IsFunction()) {
+ if (!async->item_cb.IsEmpty() && async->item_cb->IsFunction()) {
Local<Value> argv[2];
argv[0] = Local<Value>::New(Null());
@@ -678,27 +676,26 @@ void Statement::AsyncEach(EV_P_ ev_async *w, int revents) {
for (int i = 0; it < end; it++, i++) {
argv[1] = RowToJS(*it);
async->retrieved++;
- TRY_CATCH_CALL(async->stmt->handle_, async->callback, 2, argv);
+ TRY_CATCH_CALL(async->stmt->handle_, async->item_cb, 2, argv);
delete *it;
}
}
}
if (async->completed) {
- if (!async->completed_callback.IsEmpty() &&
- async->completed_callback->IsFunction()) {
+ if (!async->completed_cb.IsEmpty() &&
+ async->completed_cb->IsFunction()) {
Local<Value> argv[] = {
Local<Value>::New(Null()),
Integer::New(async->retrieved)
};
- TRY_CATCH_CALL(async->stmt->handle_, async->completed_callback, 2, argv);
+ TRY_CATCH_CALL(async->stmt->handle_, async->completed_cb, 2, argv);
}
- delete async;
- w->data = NULL;
+ uv_close((uv_handle_t*)handle, CloseCallback);
}
}
-int Statement::EIO_AfterEach(eio_req *req) {
+void Statement::Work_AfterEach(uv_work_t* req) {
HandleScope scope;
STATEMENT_INIT(EachBaton);
@@ -707,7 +704,6 @@ int Statement::EIO_AfterEach(eio_req *req) {
}
STATEMENT_END();
- return 0;
}
Handle<Value> Statement::Reset(const Arguments& args) {
@@ -717,25 +713,23 @@ Handle<Value> Statement::Reset(const Arguments& args) {
OPTIONAL_ARGUMENT_FUNCTION(0, callback);
Baton* baton = new Baton(stmt, callback);
- stmt->Schedule(EIO_BeginReset, baton);
+ stmt->Schedule(Work_BeginReset, baton);
return args.This();
}
-void Statement::EIO_BeginReset(Baton* baton) {
+void Statement::Work_BeginReset(Baton* baton) {
STATEMENT_BEGIN(Reset);
}
-int Statement::EIO_Reset(eio_req *req) {
+void Statement::Work_Reset(uv_work_t* req) {
STATEMENT_INIT(Baton);
sqlite3_reset(stmt->handle);
stmt->status = SQLITE_OK;
-
- return 0;
}
-int Statement::EIO_AfterReset(eio_req *req) {
+void Statement::Work_AfterReset(uv_work_t* req) {
HandleScope scope;
STATEMENT_INIT(Baton);
@@ -746,7 +740,6 @@ int Statement::EIO_AfterReset(eio_req *req) {
}
STATEMENT_END();
- return 0;
}
Local<Object> Statement::RowToJS(Row* row) {
@@ -770,12 +763,7 @@ Local<Object> Statement::RowToJS(Row* row) {
value = Local<Value>(String::New(((Values::Text*)field)->value.c_str(), ((Values::Text*)field)->value.size()));
} break;
case SQLITE_BLOB: {
-#if NODE_VERSION_AT_LEAST(0,3,0)
Buffer *buffer = Buffer::New(((Values::Blob*)field)->value, ((Values::Blob*)field)->length);
-#else
- Buffer *buffer = Buffer::New(((Values::Blob*)field)->length);
- memcpy(buffer->data(), ((Values::Blob*)field)->value, buffer->length());
-#endif
value = Local<Value>::New(buffer->handle_);
} break;
case SQLITE_NULL: {
diff --git a/src/statement.h b/src/statement.h
index 73e58f9..3f76307 100644
--- a/src/statement.h
+++ b/src/statement.h
@@ -3,7 +3,6 @@
#include <v8.h>
#include <node.h>
-#include <node_events.h>
#include "database.h"
@@ -72,7 +71,7 @@ typedef Row Parameters;
-class Statement : public EventEmitter {
+class Statement : public ObjectWrap {
public:
static Persistent<FunctionTemplate> constructor_template;
@@ -80,22 +79,24 @@ public:
static Handle<Value> New(const Arguments& args);
struct Baton {
+ uv_work_t request;
Statement* stmt;
Persistent<Function> callback;
Parameters parameters;
Baton(Statement* stmt_, Handle<Function> cb_) : stmt(stmt_) {
stmt->Ref();
- ev_ref(EV_DEFAULT_UC);
+ uv_ref(uv_default_loop());
+ request.data = this;
callback = Persistent<Function>::New(cb_);
}
- ~Baton() {
+ virtual ~Baton() {
for (unsigned int i = 0; i < parameters.size(); i++) {
Values::Field* field = parameters[i];
DELETE_FIELD(field);
}
stmt->Unref();
- ev_unref(EV_DEFAULT_UC);
+ uv_unref(uv_default_loop());
callback.Dispose();
}
};
@@ -119,10 +120,13 @@ public:
Rows rows;
};
+ struct Async;
+
struct EachBaton : Baton {
EachBaton(Statement* stmt_, Handle<Function> cb_) :
Baton(stmt_, cb_) {}
Persistent<Function> completed;
+ Async* async; // Isn't deleted when the baton is deleted.
};
struct PrepareBaton : Database::Baton {
@@ -142,48 +146,44 @@ public:
}
};
- typedef void (*EIO_Callback)(Baton* baton);
+ typedef void (*Work_Callback)(Baton* baton);
struct Call {
- Call(EIO_Callback cb_, Baton* baton_) : callback(cb_), baton(baton_) {};
- EIO_Callback callback;
+ Call(Work_Callback cb_, Baton* baton_) : callback(cb_), baton(baton_) {};
+ Work_Callback callback;
Baton* baton;
};
- typedef void (*Async_Callback)(EV_P_ ev_async *w, int revents);
-
struct Async {
- ev_async watcher;
+ uv_async_t watcher;
Statement* stmt;
Rows data;
pthread_mutex_t mutex;
- Persistent<Function> callback;
bool completed;
int retrieved;
- Persistent<Function> completed_callback;
- Async(Statement* st, Handle<Function> cb, Handle<Function>completed_cb,
- Async_Callback async_cb) :
+ // Store the callbacks here because we don't have
+ // access to the baton in the async callback.
+ Persistent<Function> item_cb;
+ Persistent<Function> completed_cb;
+
+ Async(Statement* st, uv_async_cb async_cb) :
stmt(st), completed(false), retrieved(0) {
watcher.data = this;
- ev_async_init(&watcher, async_cb);
- ev_async_start(EV_DEFAULT_UC_ &watcher);
- callback = Persistent<Function>::New(cb);
- completed_callback = Persistent<Function>::New(completed_cb);
- stmt->Ref();
pthread_mutex_init(&mutex, NULL);
+ stmt->Ref();
+ uv_async_init(uv_default_loop(), &watcher, async_cb);
}
~Async() {
- callback.Dispose();
- completed_callback.Dispose();
stmt->Unref();
+ item_cb.Dispose();
+ completed_cb.Dispose();
pthread_mutex_destroy(&mutex);
- ev_async_stop(EV_DEFAULT_UC_ &watcher);
}
};
- Statement(Database* db_) : EventEmitter(),
+ Statement(Database* db_) : ObjectWrap(),
db(db_),
handle(NULL),
status(SQLITE_OK),
@@ -198,18 +198,19 @@ public:
}
protected:
- static void EIO_BeginPrepare(Database::Baton* baton);
- static int EIO_Prepare(eio_req *req);
- static int EIO_AfterPrepare(eio_req *req);
+ static void Work_BeginPrepare(Database::Baton* baton);
+ static void Work_Prepare(uv_work_t* req);
+ static void Work_AfterPrepare(uv_work_t* req);
- EIO_DEFINITION(Bind);
- EIO_DEFINITION(Get);
- EIO_DEFINITION(Run);
- EIO_DEFINITION(All);
- EIO_DEFINITION(Each);
- EIO_DEFINITION(Reset);
+ WORK_DEFINITION(Bind);
+ WORK_DEFINITION(Get);
+ WORK_DEFINITION(Run);
+ WORK_DEFINITION(All);
+ WORK_DEFINITION(Each);
+ WORK_DEFINITION(Reset);
- static void AsyncEach(EV_P_ ev_async *w, int revents);
+ static void AsyncEach(uv_async_t* handle, int status);
+ static void CloseCallback(uv_handle_t* handle);
static Handle<Value> Finalize(const Arguments& args);
static void Finalize(Baton* baton);
@@ -221,7 +222,7 @@ protected:
static void GetRow(Row* row, sqlite3_stmt* stmt);
static Local<Object> RowToJS(Row* row);
- void Schedule(EIO_Callback callback, Baton* baton);
+ void Schedule(Work_Callback callback, Baton* baton);
void Process();
void CleanQueue();
template <class T> static void Error(T* baton);
diff --git a/test/database_fail.test.js b/test/database_fail.test.js
index d420a56..817772b 100644
--- a/test/database_fail.test.js
+++ b/test/database_fail.test.js
@@ -1,6 +1,16 @@
var sqlite3 = require('sqlite3');
var assert = require('assert');
+exports['test Database() without new'] = function(beforeExit) {
+ assert.throws(function() {
+ sqlite3.Database(':memory:');
+ }, (/Use the new operator to create new Database objects/));
+
+ assert.throws(function() {
+ sqlite3.Statement();
+ }, (/Use the new operator to create new Statement objects/));
+};
+
exports['test Database#get prepare fail'] = function(beforeExit) {
var db = new sqlite3.Database(':memory:');
diff --git a/test/scheduling.test.js b/test/scheduling.test.js
index f30ee4f..d28d2be 100644
--- a/test/scheduling.test.js
+++ b/test/scheduling.test.js
@@ -43,14 +43,16 @@ exports['test scheduling a query with callback after the database was closed'] =
exports['test running a query after the database was closed'] = function(beforeExit) {
var error = false;
var db = new sqlite3.Database(':memory:');
- db.on('error', function(err) {
- error = true;
- assert.equal(err.message, "SQLITE_BUSY: unable to close due to unfinalised statements");
- });
- var stmt = db.prepare("CREATE TABLE foo (id int)");
- db.close();
- stmt.run();
+ var stmt = db.prepare("SELECT * FROM sqlite_master", function(err) {
+ if (err) throw err;
+ db.close(function(err) {
+ assert.ok(err);
+ error = true;
+ assert.equal(err.message, "SQLITE_BUSY: unable to close due to unfinalised statements");
+ stmt.run();
+ });
+ });
beforeExit(function() {
assert.ok(error);
diff --git a/wscript b/wscript
index a5bf9cd..7114252 100644
--- a/wscript
+++ b/wscript
@@ -12,58 +12,87 @@ import Utils
TARGET = 'sqlite3_bindings'
TARGET_FILE = '%s.node' % TARGET
-built = 'build/default/%s' % TARGET_FILE
+built = 'build/Release/%s' % TARGET_FILE
dest = 'lib/%s' % TARGET_FILE
-BUNDLED_SQLITE3_VERSION = '3070701'
+BUNDLED_SQLITE3_VERSION = '3070800'
BUNDLED_SQLITE3 = 'sqlite-autoconf-%s' % BUNDLED_SQLITE3_VERSION
BUNDLED_SQLITE3_TAR = 'sqlite-autoconf-%s.tar.gz' % BUNDLED_SQLITE3_VERSION
SQLITE3_TARGET = 'deps/%s' % BUNDLED_SQLITE3
+sqlite3_test_program = '''
+#include "stdio.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <sqlite3.h>
+#ifdef __cplusplus
+}
+#endif
+
+int
+main() {
+ return 0;
+}
+'''
+
+
def set_options(opt):
opt.tool_options("compiler_cxx")
-
- opt.add_option( '--internal-sqlite'
- , action='store_true'
- , default=False
- , help='Build dynamically against external install of libsqlite3 (default False - build uses internal copy)'
- , dest='internal_sqlite'
+ opt.add_option( '--with-sqlite3'
+ , action='store'
+ , default=None
+ , help='Directory prefix containing sqlite "lib" and "include" files (default is to compile against internal copy of sqlite v%s' % BUNDLED_SQLITE3_VERSION
+ , dest='sqlite3_dir'
)
+def _conf_exit(conf,msg):
+ conf.fatal('\n\n' + msg + '\n...check the build/config.log for details')
+
+def _build_paths(conf,prefix):
+ if not os.path.exists(prefix):
+ _conf_exit(conf,'configure path of %s not found' % prefix)
+ norm_path = os.path.normpath(os.path.realpath(prefix))
+ if norm_path.endswith('lib') or norm_path.endswith('include'):
+ norm_path = os.path.dirname(norm_path)
+ return os.path.join('%s' % norm_path,'lib'),os.path.join('%s' % norm_path,'include')
+
def configure(conf):
conf.check_tool("compiler_cxx")
conf.check_tool("node_addon")
-
-
- if not Options.options.internal_sqlite:
- try:
- conf.check_cfg(package="sqlite3", args='--libs --cflags',
- uselib_store="SQLITE3", mandatory=True)
- except ConfigurationError:
- conf.check(lib="sqlite3", libpath=['/usr/local/lib', '/opt/local/lib'],
- uselib_store="SQLITE3", mandatory=True)
+ o = Options.options
- Utils.pprint('YELLOW','Note: pass --internal-sqlite to compile and link against bundled sqlite (version %s)' % BUNDLED_SQLITE3_VERSION)
-
+ if not o.sqlite3_dir:
+ configure_internal_sqlite3(conf)
else:
- configure_interal_sqlite3(conf)
+ lib, include = _build_paths(conf,o.sqlite3_dir)
+
+ if conf.check_cxx(lib='sqlite3',
+ fragment=sqlite3_test_program,
+ uselib_store='SQLITE3',
+ libpath=lib,
+ msg='Checking for libsqlite3 at %s' % lib,
+ includes=include):
+ Utils.pprint('GREEN', 'Sweet, found viable sqlite3 dependency at: %s ' % o.sqlite3_dir)
+ else:
+ _conf_exit(conf,'sqlite3 libs/headers not found at %s' % o.sqlite3_dir)
linkflags = []
if os.environ.has_key('LINKFLAGS'):
linkflags.extend(os.environ['LINKFLAGS'].split(' '))
-
- if Options.options.internal_sqlite and Options.platform == 'darwin':
+
+ if not o.sqlite3_dir and Options.platform == 'darwin':
linkflags.append('-Wl,-search_paths_first')
-
+
conf.env.append_value("LINKFLAGS", linkflags)
-def configure_interal_sqlite3(conf):
- Utils.pprint('GREEN','Using internal sqlite3!')
-
+def configure_internal_sqlite3(conf):
+ Utils.pprint('GREEN','Note: will build against internal copy of sqlite3 v%s\n(pass --with-sqlite3=/usr/local to build against an external version)' % BUNDLED_SQLITE3_VERSION)
+
os.chdir('deps')
if not os.path.exists(BUNDLED_SQLITE3):
- os.system('tar xvf %s' % BUNDLED_SQLITE3_TAR)
+ os.system('tar xf %s' % BUNDLED_SQLITE3_TAR)
os.chdir(BUNDLED_SQLITE3)
cxxflags = ''
if os.environ.has_key('CFLAGS'):
@@ -73,14 +102,17 @@ def configure_interal_sqlite3(conf):
cxxflags += os.environ['CXXFLAGS']
# LINKFLAGS appear to be picked up automatically...
if not os.path.exists('config.status'):
- os.system("CFLAGS='%s -DSQLITE_ENABLE_RTREE=1 -fPIC -O3 -DNDEBUG' ./configure --disable-dependency-tracking --enable-static --disable-shared" % cxxflags)
+ cmd = "CFLAGS='%s -DSQLITE_ENABLE_RTREE=1 -fPIC -O3 -DNDEBUG' ./configure --enable-static --disable-shared" % cxxflags
+ if Options.platform == 'darwin':
+ cmd += ' --disable-dependency-tracking'
+ os.system(cmd)
os.chdir('../../')
-
+
conf.env.append_value("CPPPATH_SQLITE3", ['../deps/%s' % BUNDLED_SQLITE3])
conf.env.append_value("LINKFLAGS", ['-L../deps/%s/.libs' % BUNDLED_SQLITE3, '-lsqlite3'])
-
-def build_internal_sqlite3():
- if not Options.commands['clean'] and Options.options.internal_sqlite:
+
+def build_internal_sqlite3(bld):
+ if not Options.commands['clean'] and '../deps' in bld.env['CPPPATH_SQLITE3'][0]:
if not os.path.exists(SQLITE3_TARGET):
Utils.pprint('RED','Please re-run ./configure or node-waf configure')
sys.exit()
@@ -94,10 +126,10 @@ def clean_internal_sqlite3():
def build(bld):
obj = bld.new_task_gen("cxx", "shlib", "node_addon")
- build_internal_sqlite3()
+ build_internal_sqlite3(bld)
obj.cxxflags = ["-g", "-D_FILE_OFFSET_BITS=64", "-D_LARGEFILE_SOURCE",
"-DSQLITE_ENABLE_RTREE=1", "-pthread", "-Wall"]
- # uncomment the next line to remove '-undefined dynamic_lookup'
+ # uncomment the next line to remove '-undefined dynamic_lookup'
# in order to review linker errors (v8, libev/eio references can be ignored)
#obj.env['LINKFLAGS_MACBUNDLE'] = ['-bundle']
obj.target = TARGET