From f95a43b2c0f1351fea5bc86719faa09632ab4765 Mon Sep 17 00:00:00 2001 From: Giovanni Campagna Date: Tue, 6 Mar 2018 22:36:24 -0800 Subject: [PATCH 1/2] Remove all mentions of native code This version of node-sqlite3 is going to assume the sqlite3 module is preloaded (part of process._linkedBinding) --- binding.gyp | 52 --- deps/common-sqlite.gypi | 56 --- deps/extract.py | 9 - deps/sqlite3.gyp | 105 ----- lib/sqlite3.js | 5 +- package.json | 14 +- src/async.h | 78 ---- src/database.cc | 689 ------------------------------ src/database.h | 192 --------- src/gcc-preinclude.h | 6 - src/macros.h | 154 ------- src/node_sqlite3.cc | 106 ----- src/statement.cc | 901 ---------------------------------------- src/statement.h | 248 ----------- src/threading.h | 48 --- 15 files changed, 2 insertions(+), 2661 deletions(-) delete mode 100644 binding.gyp delete mode 100644 deps/common-sqlite.gypi delete mode 100644 deps/extract.py delete mode 100755 deps/sqlite3.gyp delete mode 100644 src/async.h delete mode 100644 src/database.cc delete mode 100644 src/database.h delete mode 100644 src/gcc-preinclude.h delete mode 100644 src/macros.h delete mode 100644 src/node_sqlite3.cc delete mode 100644 src/statement.cc delete mode 100644 src/statement.h delete mode 100644 src/threading.h diff --git a/binding.gyp b/binding.gyp deleted file mode 100644 index 59c93d30a..000000000 --- a/binding.gyp +++ /dev/null @@ -1,52 +0,0 @@ -{ - "includes": [ "deps/common-sqlite.gypi" ], - "variables": { - "sqlite%":"internal", - "sqlite_libname%":"sqlite3" - }, - "targets": [ - { - "target_name": "<(module_name)", - "include_dirs": ["", "Dane Springmeyer ", @@ -36,11 +29,7 @@ "type": "git", "url": "git://github.com/mapbox/node-sqlite3.git" }, - "dependencies": { - "nan": "~2.10.0", - "node-pre-gyp": "^0.10.3", - "request": "^2.87.0" - }, + "dependencies": {}, "devDependencies": { "@mapbox/cloudfriend": "^1.9.0", "aws-sdk": "2.x", @@ -48,7 +37,6 @@ "mocha": "^5.2.0" }, "scripts": { - "install": "node-pre-gyp install --fallback-to-build", "pretest": "node test/support/createdb.js", "test": "mocha -R spec --timeout 480000" }, diff --git a/src/async.h b/src/async.h deleted file mode 100644 index 5232c127d..000000000 --- a/src/async.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef NODE_SQLITE3_SRC_ASYNC_H -#define NODE_SQLITE3_SRC_ASYNC_H - -#include "threading.h" -#include - -#if defined(NODE_SQLITE3_BOOST_THREADING) -#include -#endif - - -// Generic uv_async handler. -template class Async { - typedef void (*Callback)(Parent* parent, Item* item); - -protected: - uv_async_t watcher; - NODE_SQLITE3_MUTEX_t - std::vector data; - Callback callback; -public: - Parent* parent; - -public: - Async(Parent* parent_, Callback cb_) - : callback(cb_), parent(parent_) { - watcher.data = this; - NODE_SQLITE3_MUTEX_INIT - uv_async_init(uv_default_loop(), &watcher, reinterpret_cast(listener)); - } - - static void listener(uv_async_t* handle, int status) { - Async* async = static_cast(handle->data); - std::vector rows; - NODE_SQLITE3_MUTEX_LOCK(&async->mutex) - rows.swap(async->data); - NODE_SQLITE3_MUTEX_UNLOCK(&async->mutex) - for (unsigned int i = 0, size = rows.size(); i < size; i++) { - async->callback(async->parent, rows[i]); - } - } - - static void close(uv_handle_t* handle) { - assert(handle != NULL); - assert(handle->data != NULL); - Async* async = static_cast(handle->data); - delete async; - } - - 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) { - NODE_SQLITE3_MUTEX_LOCK(&mutex); - data.push_back(item); - NODE_SQLITE3_MUTEX_UNLOCK(&mutex) - } - - void send() { - uv_async_send(&watcher); - } - - void send(Item* item) { - add(item); - send(); - } - - ~Async() { - NODE_SQLITE3_MUTEX_DESTROY - } -}; - -#endif diff --git a/src/database.cc b/src/database.cc deleted file mode 100644 index 4dbd5c6ab..000000000 --- a/src/database.cc +++ /dev/null @@ -1,689 +0,0 @@ -#include - -#include "macros.h" -#include "database.h" -#include "statement.h" - -using namespace node_sqlite3; - -Nan::Persistent Database::constructor_template; - -NAN_MODULE_INIT(Database::Init) { - Nan::HandleScope scope; - - Local t = Nan::New(New); - - t->InstanceTemplate()->SetInternalFieldCount(1); - t->SetClassName(Nan::New("Database").ToLocalChecked()); - - Nan::SetPrototypeMethod(t, "close", Close); - Nan::SetPrototypeMethod(t, "exec", Exec); - Nan::SetPrototypeMethod(t, "wait", Wait); - Nan::SetPrototypeMethod(t, "loadExtension", LoadExtension); - Nan::SetPrototypeMethod(t, "serialize", Serialize); - Nan::SetPrototypeMethod(t, "parallelize", Parallelize); - Nan::SetPrototypeMethod(t, "configure", Configure); - Nan::SetPrototypeMethod(t, "interrupt", Interrupt); - - NODE_SET_GETTER(t, "open", OpenGetter); - - constructor_template.Reset(t); - - Nan::Set(target, Nan::New("Database").ToLocalChecked(), - Nan::GetFunction(t).ToLocalChecked()); -} - -void Database::Process() { - Nan::HandleScope scope; - - if (!open && locked && !queue.empty()) { - EXCEPTION(Nan::New("Database handle is closed").ToLocalChecked(), SQLITE_MISUSE, exception); - Local argv[] = { exception }; - bool called = false; - - // Call all callbacks with the error object. - while (!queue.empty()) { - Call* call = queue.front(); - Local cb = Nan::New(call->baton->callback); - if (!cb.IsEmpty() && cb->IsFunction()) { - TRY_CATCH_CALL(this->handle(), cb, 1, argv); - called = true; - } - queue.pop(); - // We don't call the actual callback, so we have to make sure that - // the baton gets destroyed. - delete call->baton; - delete call; - } - - // When we couldn't call a callback function, emit an error on the - // Database object. - if (!called) { - Local info[] = { Nan::New("error").ToLocalChecked(), exception }; - EMIT_EVENT(handle(), 2, info); - } - return; - } - - while (open && (!locked || pending == 0) && !queue.empty()) { - Call* call = queue.front(); - - if (call->exclusive && pending > 0) { - break; - } - - queue.pop(); - locked = call->exclusive; - call->callback(call->baton); - delete call; - - if (locked) break; - } -} - -void Database::Schedule(Work_Callback callback, Baton* baton, bool exclusive) { - Nan::HandleScope scope; - - if (!open && locked) { - EXCEPTION(Nan::New("Database is closed").ToLocalChecked(), SQLITE_MISUSE, exception); - Local cb = Nan::New(baton->callback); - if (!cb.IsEmpty() && cb->IsFunction()) { - Local argv[] = { exception }; - TRY_CATCH_CALL(handle(), cb, 1, argv); - } - else { - Local argv[] = { Nan::New("error").ToLocalChecked(), exception }; - EMIT_EVENT(handle(), 2, argv); - } - return; - } - - if (!open || ((locked || exclusive || serialize) && pending > 0)) { - queue.push(new Call(callback, baton, exclusive || serialize)); - } - else { - locked = exclusive; - callback(baton); - } -} - -NAN_METHOD(Database::New) { - if (!info.IsConstructCall()) { - return Nan::ThrowTypeError("Use the new operator to create new Database objects"); - } - - REQUIRE_ARGUMENT_STRING(0, filename); - int pos = 1; - - int mode; - if (info.Length() >= pos && info[pos]->IsInt32()) { - mode = Nan::To(info[pos++]).FromJust(); - } else { - mode = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX; - } - - Local callback; - if (info.Length() >= pos && info[pos]->IsFunction()) { - callback = Local::Cast(info[pos++]); - } - - Database* db = new Database(); - db->Wrap(info.This()); - - Nan::ForceSet(info.This(), Nan::New("filename").ToLocalChecked(), info[0].As(), ReadOnly); - Nan::ForceSet(info.This(), Nan::New("mode").ToLocalChecked(), Nan::New(mode), ReadOnly); - - // Start opening the database. - OpenBaton* baton = new OpenBaton(db, callback, *filename, mode); - Work_BeginOpen(baton); - - info.GetReturnValue().Set(info.This()); -} - -void Database::Work_BeginOpen(Baton* baton) { - int status = uv_queue_work(uv_default_loop(), - &baton->request, Work_Open, (uv_after_work_cb)Work_AfterOpen); - assert(status == 0); -} - -void Database::Work_Open(uv_work_t* req) { - OpenBaton* baton = static_cast(req->data); - Database* db = baton->db; - - baton->status = sqlite3_open_v2( - baton->filename.c_str(), - &db->_handle, - baton->mode, - NULL - ); - - if (baton->status != SQLITE_OK) { - baton->message = std::string(sqlite3_errmsg(db->_handle)); - sqlite3_close(db->_handle); - db->_handle = NULL; - } - else { - // Set default database handle values. - sqlite3_busy_timeout(db->_handle, 1000); - } -} - -void Database::Work_AfterOpen(uv_work_t* req) { - Nan::HandleScope scope; - - OpenBaton* baton = static_cast(req->data); - Database* db = baton->db; - - Local argv[1]; - if (baton->status != SQLITE_OK) { - EXCEPTION(Nan::New(baton->message.c_str()).ToLocalChecked(), baton->status, exception); - argv[0] = exception; - } - else { - db->open = true; - argv[0] = Nan::Null(); - } - - Local cb = Nan::New(baton->callback); - - if (!cb.IsEmpty() && cb->IsFunction()) { - TRY_CATCH_CALL(db->handle(), cb, 1, argv); - } - else if (!db->open) { - Local info[] = { Nan::New("error").ToLocalChecked(), argv[0] }; - EMIT_EVENT(db->handle(), 2, info); - } - - if (db->open) { - Local info[] = { Nan::New("open").ToLocalChecked() }; - EMIT_EVENT(db->handle(), 1, info); - db->Process(); - } - - delete baton; -} - -NAN_GETTER(Database::OpenGetter) { - Database* db = Nan::ObjectWrap::Unwrap(info.This()); - info.GetReturnValue().Set(db->open); -} - -NAN_METHOD(Database::Close) { - Database* db = Nan::ObjectWrap::Unwrap(info.This()); - OPTIONAL_ARGUMENT_FUNCTION(0, callback); - - Baton* baton = new Baton(db, callback); - db->Schedule(Work_BeginClose, baton, true); - - info.GetReturnValue().Set(info.This()); -} - -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(); - baton->db->closing = true; - - int status = uv_queue_work(uv_default_loop(), - &baton->request, Work_Close, (uv_after_work_cb)Work_AfterClose); - assert(status == 0); -} - -void Database::Work_Close(uv_work_t* req) { - Baton* baton = static_cast(req->data); - Database* db = baton->db; - - baton->status = sqlite3_close(db->_handle); - - if (baton->status != SQLITE_OK) { - baton->message = std::string(sqlite3_errmsg(db->_handle)); - } - else { - db->_handle = NULL; - } -} - -void Database::Work_AfterClose(uv_work_t* req) { - Nan::HandleScope scope; - - Baton* baton = static_cast(req->data); - Database* db = baton->db; - - db->closing = false; - - Local argv[1]; - if (baton->status != SQLITE_OK) { - EXCEPTION(Nan::New(baton->message.c_str()).ToLocalChecked(), baton->status, exception); - argv[0] = exception; - } - else { - db->open = false; - // Leave db->locked to indicate that this db object has reached - // the end of its life. - argv[0] = Nan::Null(); - } - - Local cb = Nan::New(baton->callback); - - // Fire callbacks. - if (!cb.IsEmpty() && cb->IsFunction()) { - TRY_CATCH_CALL(db->handle(), cb, 1, argv); - } - else if (db->open) { - Local info[] = { Nan::New("error").ToLocalChecked(), argv[0] }; - EMIT_EVENT(db->handle(), 2, info); - } - - if (!db->open) { - Local info[] = { Nan::New("close").ToLocalChecked(), argv[0] }; - EMIT_EVENT(db->handle(), 1, info); - db->Process(); - } - - delete baton; -} - -NAN_METHOD(Database::Serialize) { - Database* db = Nan::ObjectWrap::Unwrap(info.This()); - OPTIONAL_ARGUMENT_FUNCTION(0, callback); - - bool before = db->serialize; - db->serialize = true; - - if (!callback.IsEmpty() && callback->IsFunction()) { - TRY_CATCH_CALL(info.This(), callback, 0, NULL); - db->serialize = before; - } - - db->Process(); - - info.GetReturnValue().Set(info.This()); -} - -NAN_METHOD(Database::Parallelize) { - Database* db = Nan::ObjectWrap::Unwrap(info.This()); - OPTIONAL_ARGUMENT_FUNCTION(0, callback); - - bool before = db->serialize; - db->serialize = false; - - if (!callback.IsEmpty() && callback->IsFunction()) { - TRY_CATCH_CALL(info.This(), callback, 0, NULL); - db->serialize = before; - } - - db->Process(); - - info.GetReturnValue().Set(info.This()); -} - -NAN_METHOD(Database::Configure) { - Database* db = Nan::ObjectWrap::Unwrap(info.This()); - - REQUIRE_ARGUMENTS(2); - - if (Nan::Equals(info[0], Nan::New("trace").ToLocalChecked()).FromJust()) { - Local handle; - Baton* baton = new Baton(db, handle); - db->Schedule(RegisterTraceCallback, baton); - } - else if (Nan::Equals(info[0], Nan::New("profile").ToLocalChecked()).FromJust()) { - Local handle; - Baton* baton = new Baton(db, handle); - db->Schedule(RegisterProfileCallback, baton); - } - else if (Nan::Equals(info[0], Nan::New("busyTimeout").ToLocalChecked()).FromJust()) { - if (!info[1]->IsInt32()) { - return Nan::ThrowTypeError("Value must be an integer"); - } - Local handle; - Baton* baton = new Baton(db, handle); - baton->status = Nan::To(info[1]).FromJust(); - db->Schedule(SetBusyTimeout, baton); - } - else { - return Nan::ThrowError(Exception::Error(String::Concat( - Nan::To(info[0]).ToLocalChecked(), - Nan::New(" is not a valid configuration option").ToLocalChecked() - ))); - } - - db->Process(); - - info.GetReturnValue().Set(info.This()); -} - -NAN_METHOD(Database::Interrupt) { - Database* db = Nan::ObjectWrap::Unwrap(info.This()); - - if (!db->open) { - return Nan::ThrowError("Database is not open"); - } - - if (db->closing) { - return Nan::ThrowError("Database is closing"); - } - - sqlite3_interrupt(db->_handle); - info.GetReturnValue().Set(info.This()); -} - -void Database::SetBusyTimeout(Baton* baton) { - assert(baton->db->open); - assert(baton->db->_handle); - - // Abuse the status field for passing the timeout. - sqlite3_busy_timeout(baton->db->_handle, baton->status); - - delete baton; -} - -void Database::RegisterTraceCallback(Baton* baton) { - assert(baton->db->open); - assert(baton->db->_handle); - Database* db = baton->db; - - if (db->debug_trace == NULL) { - // Add it. - db->debug_trace = new AsyncTrace(db, TraceCallback); - sqlite3_trace(db->_handle, TraceCallback, db); - } - else { - // Remove it. - sqlite3_trace(db->_handle, NULL, NULL); - db->debug_trace->finish(); - db->debug_trace = NULL; - } - - delete baton; -} - -void Database::TraceCallback(void* db, const char* sql) { - // Note: This function is called in the thread pool. - // Note: Some queries, such as "EXPLAIN" queries, are not sent through this. - static_cast(db)->debug_trace->send(new std::string(sql)); -} - -void Database::TraceCallback(Database* db, std::string* sql) { - // Note: This function is called in the main V8 thread. - Nan::HandleScope scope; - - Local argv[] = { - Nan::New("trace").ToLocalChecked(), - Nan::New(sql->c_str()).ToLocalChecked() - }; - EMIT_EVENT(db->handle(), 2, argv); - delete sql; -} - -void Database::RegisterProfileCallback(Baton* baton) { - assert(baton->db->open); - assert(baton->db->_handle); - Database* db = baton->db; - - if (db->debug_profile == NULL) { - // Add it. - db->debug_profile = new AsyncProfile(db, ProfileCallback); - sqlite3_profile(db->_handle, ProfileCallback, db); - } - else { - // Remove it. - sqlite3_profile(db->_handle, NULL, NULL); - db->debug_profile->finish(); - db->debug_profile = NULL; - } - - delete baton; -} - -void Database::ProfileCallback(void* db, const char* sql, sqlite3_uint64 nsecs) { - // Note: This function is called in the thread pool. - // Note: Some queries, such as "EXPLAIN" queries, are not sent through this. - ProfileInfo* info = new ProfileInfo(); - info->sql = std::string(sql); - info->nsecs = nsecs; - static_cast(db)->debug_profile->send(info); -} - -void Database::ProfileCallback(Database *db, ProfileInfo* info) { - Nan::HandleScope scope; - - Local argv[] = { - Nan::New("profile").ToLocalChecked(), - Nan::New(info->sql.c_str()).ToLocalChecked(), - Nan::New((double)info->nsecs / 1000000.0) - }; - EMIT_EVENT(db->handle(), 3, argv); - delete info; -} - -void Database::RegisterUpdateCallback(Baton* baton) { - assert(baton->db->open); - assert(baton->db->_handle); - Database* db = baton->db; - - if (db->update_event == NULL) { - // Add it. - db->update_event = new AsyncUpdate(db, UpdateCallback); - sqlite3_update_hook(db->_handle, UpdateCallback, db); - } - else { - // Remove it. - sqlite3_update_hook(db->_handle, NULL, NULL); - db->update_event->finish(); - db->update_event = NULL; - } - - delete baton; -} - -void Database::UpdateCallback(void* db, int type, const char* database, - const char* table, sqlite3_int64 rowid) { - // Note: This function is called in the thread pool. - // Note: Some queries, such as "EXPLAIN" queries, are not sent through this. - UpdateInfo* info = new UpdateInfo(); - info->type = type; - info->database = std::string(database); - info->table = std::string(table); - info->rowid = rowid; - static_cast(db)->update_event->send(info); -} - -void Database::UpdateCallback(Database *db, UpdateInfo* info) { - Nan::HandleScope scope; - - Local argv[] = { - Nan::New(sqlite_authorizer_string(info->type)).ToLocalChecked(), - Nan::New(info->database.c_str()).ToLocalChecked(), - Nan::New(info->table.c_str()).ToLocalChecked(), - Nan::New(info->rowid), - }; - EMIT_EVENT(db->handle(), 4, argv); - delete info; -} - -NAN_METHOD(Database::Exec) { - Database* db = Nan::ObjectWrap::Unwrap(info.This()); - - REQUIRE_ARGUMENT_STRING(0, sql); - OPTIONAL_ARGUMENT_FUNCTION(1, callback); - - Baton* baton = new ExecBaton(db, callback, *sql); - db->Schedule(Work_BeginExec, baton, true); - - info.GetReturnValue().Set(info.This()); -} - -void Database::Work_BeginExec(Baton* baton) { - assert(baton->db->locked); - assert(baton->db->open); - assert(baton->db->_handle); - assert(baton->db->pending == 0); - int status = uv_queue_work(uv_default_loop(), - &baton->request, Work_Exec, (uv_after_work_cb)Work_AfterExec); - assert(status == 0); -} - -void Database::Work_Exec(uv_work_t* req) { - ExecBaton* baton = static_cast(req->data); - - char* message = NULL; - baton->status = sqlite3_exec( - baton->db->_handle, - baton->sql.c_str(), - NULL, - NULL, - &message - ); - - if (baton->status != SQLITE_OK && message != NULL) { - baton->message = std::string(message); - sqlite3_free(message); - } -} - -void Database::Work_AfterExec(uv_work_t* req) { - Nan::HandleScope scope; - - ExecBaton* baton = static_cast(req->data); - Database* db = baton->db; - - Local cb = Nan::New(baton->callback); - - if (baton->status != SQLITE_OK) { - EXCEPTION(Nan::New(baton->message.c_str()).ToLocalChecked(), baton->status, exception); - - if (!cb.IsEmpty() && cb->IsFunction()) { - Local argv[] = { exception }; - TRY_CATCH_CALL(db->handle(), cb, 1, argv); - } - else { - Local info[] = { Nan::New("error").ToLocalChecked(), exception }; - EMIT_EVENT(db->handle(), 2, info); - } - } - else if (!cb.IsEmpty() && cb->IsFunction()) { - Local argv[] = { Nan::Null() }; - TRY_CATCH_CALL(db->handle(), cb, 1, argv); - } - - db->Process(); - - delete baton; -} - -NAN_METHOD(Database::Wait) { - Database* db = Nan::ObjectWrap::Unwrap(info.This()); - - OPTIONAL_ARGUMENT_FUNCTION(0, callback); - - Baton* baton = new Baton(db, callback); - db->Schedule(Work_Wait, baton, true); - - info.GetReturnValue().Set(info.This()); -} - -void Database::Work_Wait(Baton* baton) { - Nan::HandleScope scope; - - assert(baton->db->locked); - assert(baton->db->open); - assert(baton->db->_handle); - assert(baton->db->pending == 0); - - Local cb = Nan::New(baton->callback); - if (!cb.IsEmpty() && cb->IsFunction()) { - Local argv[] = { Nan::Null() }; - TRY_CATCH_CALL(baton->db->handle(), cb, 1, argv); - } - - baton->db->Process(); - - delete baton; -} - -NAN_METHOD(Database::LoadExtension) { - Database* db = Nan::ObjectWrap::Unwrap(info.This()); - - REQUIRE_ARGUMENT_STRING(0, filename); - OPTIONAL_ARGUMENT_FUNCTION(1, callback); - - Baton* baton = new LoadExtensionBaton(db, callback, *filename); - db->Schedule(Work_BeginLoadExtension, baton, true); - - info.GetReturnValue().Set(info.This()); -} - -void Database::Work_BeginLoadExtension(Baton* baton) { - assert(baton->db->locked); - assert(baton->db->open); - assert(baton->db->_handle); - assert(baton->db->pending == 0); - int status = uv_queue_work(uv_default_loop(), - &baton->request, Work_LoadExtension, reinterpret_cast(Work_AfterLoadExtension)); - assert(status == 0); -} - -void Database::Work_LoadExtension(uv_work_t* req) { - LoadExtensionBaton* baton = static_cast(req->data); - - sqlite3_enable_load_extension(baton->db->_handle, 1); - - char* message = NULL; - baton->status = sqlite3_load_extension( - baton->db->_handle, - baton->filename.c_str(), - 0, - &message - ); - - sqlite3_enable_load_extension(baton->db->_handle, 0); - - if (baton->status != SQLITE_OK && message != NULL) { - baton->message = std::string(message); - sqlite3_free(message); - } -} - -void Database::Work_AfterLoadExtension(uv_work_t* req) { - Nan::HandleScope scope; - - LoadExtensionBaton* baton = static_cast(req->data); - Database* db = baton->db; - Local cb = Nan::New(baton->callback); - - if (baton->status != SQLITE_OK) { - EXCEPTION(Nan::New(baton->message.c_str()).ToLocalChecked(), baton->status, exception); - - if (!cb.IsEmpty() && cb->IsFunction()) { - Local argv[] = { exception }; - TRY_CATCH_CALL(db->handle(), cb, 1, argv); - } - else { - Local info[] = { Nan::New("error").ToLocalChecked(), exception }; - EMIT_EVENT(db->handle(), 2, info); - } - } - else if (!cb.IsEmpty() && cb->IsFunction()) { - Local argv[] = { Nan::Null() }; - TRY_CATCH_CALL(db->handle(), cb, 1, argv); - } - - db->Process(); - - delete baton; -} - -void Database::RemoveCallbacks() { - if (debug_trace) { - debug_trace->finish(); - debug_trace = NULL; - } - if (debug_profile) { - debug_profile->finish(); - debug_profile = NULL; - } -} diff --git a/src/database.h b/src/database.h deleted file mode 100644 index c5455abe3..000000000 --- a/src/database.h +++ /dev/null @@ -1,192 +0,0 @@ - -#ifndef NODE_SQLITE3_SRC_DATABASE_H -#define NODE_SQLITE3_SRC_DATABASE_H - - -#include -#include - -#include -#include - -#include "async.h" - -using namespace v8; - -namespace node_sqlite3 { - -class Database; - - -class Database : public Nan::ObjectWrap { -public: - static Nan::Persistent constructor_template; - static NAN_MODULE_INIT(Init); - - static inline bool HasInstance(Local val) { - Nan::HandleScope scope; - if (!val->IsObject()) return false; - Local obj = val.As(); - return Nan::New(constructor_template)->HasInstance(obj); - } - - struct Baton { - uv_work_t request; - Database* db; - Nan::Persistent callback; - int status; - std::string message; - - Baton(Database* db_, Local cb_) : - db(db_), status(SQLITE_OK) { - db->Ref(); - request.data = this; - callback.Reset(cb_); - } - virtual ~Baton() { - db->Unref(); - callback.Reset(); - } - }; - - struct OpenBaton : Baton { - std::string filename; - int mode; - OpenBaton(Database* db_, Local cb_, const char* filename_, int mode_) : - Baton(db_, cb_), filename(filename_), mode(mode_) {} - }; - - struct ExecBaton : Baton { - std::string sql; - ExecBaton(Database* db_, Local cb_, const char* sql_) : - Baton(db_, cb_), sql(sql_) {} - }; - - struct LoadExtensionBaton : Baton { - std::string filename; - LoadExtensionBaton(Database* db_, Local cb_, const char* filename_) : - Baton(db_, cb_), filename(filename_) {} - }; - - typedef void (*Work_Callback)(Baton* baton); - - struct Call { - Call(Work_Callback cb_, Baton* baton_, bool exclusive_ = false) : - callback(cb_), exclusive(exclusive_), baton(baton_) {}; - Work_Callback callback; - bool exclusive; - Baton* baton; - }; - - struct ProfileInfo { - std::string sql; - sqlite3_int64 nsecs; - }; - - struct UpdateInfo { - int type; - std::string database; - std::string table; - sqlite3_int64 rowid; - }; - - bool IsOpen() { return open; } - bool IsLocked() { return locked; } - - typedef Async AsyncTrace; - typedef Async AsyncProfile; - typedef Async AsyncUpdate; - - friend class Statement; - -protected: - Database() : Nan::ObjectWrap(), - _handle(NULL), - open(false), - closing(false), - locked(false), - pending(0), - serialize(false), - debug_trace(NULL), - debug_profile(NULL), - update_event(NULL) { - } - - ~Database() { - RemoveCallbacks(); - sqlite3_close(_handle); - _handle = NULL; - open = false; - } - - static NAN_METHOD(New); - static void Work_BeginOpen(Baton* baton); - static void Work_Open(uv_work_t* req); - static void Work_AfterOpen(uv_work_t* req); - - static NAN_GETTER(OpenGetter); - - void Schedule(Work_Callback callback, Baton* baton, bool exclusive = false); - void Process(); - - static NAN_METHOD(Exec); - static void Work_BeginExec(Baton* baton); - static void Work_Exec(uv_work_t* req); - static void Work_AfterExec(uv_work_t* req); - - static NAN_METHOD(Wait); - static void Work_Wait(Baton* baton); - - static NAN_METHOD(Close); - static void Work_BeginClose(Baton* baton); - static void Work_Close(uv_work_t* req); - static void Work_AfterClose(uv_work_t* req); - - static NAN_METHOD(LoadExtension); - static void Work_BeginLoadExtension(Baton* baton); - static void Work_LoadExtension(uv_work_t* req); - static void Work_AfterLoadExtension(uv_work_t* req); - - static NAN_METHOD(Serialize); - static NAN_METHOD(Parallelize); - - static NAN_METHOD(Configure); - - static NAN_METHOD(Interrupt); - - static void SetBusyTimeout(Baton* baton); - - static void RegisterTraceCallback(Baton* baton); - static void TraceCallback(void* db, const char* sql); - static void TraceCallback(Database* db, std::string* sql); - - static void RegisterProfileCallback(Baton* baton); - static void ProfileCallback(void* db, const char* sql, sqlite3_uint64 nsecs); - static void ProfileCallback(Database* db, ProfileInfo* info); - - static void RegisterUpdateCallback(Baton* baton); - static void UpdateCallback(void* db, int type, const char* database, const char* table, sqlite3_int64 rowid); - static void UpdateCallback(Database* db, UpdateInfo* info); - - void RemoveCallbacks(); - -protected: - sqlite3* _handle; - - bool open; - bool closing; - bool locked; - unsigned int pending; - - bool serialize; - - std::queue queue; - - AsyncTrace* debug_trace; - AsyncProfile* debug_profile; - AsyncUpdate* update_event; -}; - -} - -#endif diff --git a/src/gcc-preinclude.h b/src/gcc-preinclude.h deleted file mode 100644 index 9ea8c5765..000000000 --- a/src/gcc-preinclude.h +++ /dev/null @@ -1,6 +0,0 @@ - -// http://web.archive.org/web/20140401031018/http://rjpower9000.wordpress.com:80/2012/04/09/fun-with-shared-libraries-version-glibc_2-14-not-found/ - -#if defined(__linux__) && defined(__x86_64__) -__asm__(".symver memcpy,memcpy@GLIBC_2.2.5"); -#endif diff --git a/src/macros.h b/src/macros.h deleted file mode 100644 index 38399ee86..000000000 --- a/src/macros.h +++ /dev/null @@ -1,154 +0,0 @@ -#ifndef NODE_SQLITE3_SRC_MACROS_H -#define NODE_SQLITE3_SRC_MACROS_H - -const char* sqlite_code_string(int code); -const char* sqlite_authorizer_string(int type); - - -#define REQUIRE_ARGUMENTS(n) \ - if (info.Length() < (n)) { \ - return Nan::ThrowTypeError("Expected " #n "arguments"); \ - } - - -#define REQUIRE_ARGUMENT_EXTERNAL(i, var) \ - if (info.Length() <= (i) || !info[i]->IsExternal()) { \ - return Nan::ThrowTypeError("Argument " #i " invalid"); \ - } \ - Local var = Local::Cast(info[i]); - - -#define REQUIRE_ARGUMENT_FUNCTION(i, var) \ - if (info.Length() <= (i) || !info[i]->IsFunction()) { \ - return Nan::ThrowTypeError("Argument " #i " must be a function"); \ - } \ - Local var = Local::Cast(info[i]); - - -#define REQUIRE_ARGUMENT_STRING(i, var) \ - if (info.Length() <= (i) || !info[i]->IsString()) { \ - return Nan::ThrowTypeError("Argument " #i " must be a string"); \ - } \ - Nan::Utf8String var(info[i]); - - -#define OPTIONAL_ARGUMENT_FUNCTION(i, var) \ - Local var; \ - if (info.Length() > i && !info[i]->IsUndefined()) { \ - if (!info[i]->IsFunction()) { \ - return Nan::ThrowTypeError("Argument " #i " must be a function"); \ - } \ - var = Local::Cast(info[i]); \ - } - - -#define OPTIONAL_ARGUMENT_INTEGER(i, var, default) \ - int var; \ - if (info.Length() <= (i)) { \ - var = (default); \ - } \ - else if (info[i]->IsInt32()) { \ - var = Nan::To(info[i]).FromJust(); \ - } \ - else { \ - return Nan::ThrowTypeError("Argument " #i " must be an integer"); \ - } - - -#define DEFINE_CONSTANT_INTEGER(target, constant, name) \ - Nan::ForceSet(target, \ - Nan::New(#name).ToLocalChecked(), \ - Nan::New(constant), \ - static_cast(ReadOnly | DontDelete) \ - ); - -#define DEFINE_CONSTANT_STRING(target, constant, name) \ - Nan::ForceSet(target, \ - Nan::New(#name).ToLocalChecked(), \ - Nan::New(constant).ToLocalChecked(), \ - static_cast(ReadOnly | DontDelete) \ - ); - - -#define NODE_SET_GETTER(target, name, function) \ - Nan::SetAccessor((target)->InstanceTemplate(), \ - Nan::New(name).ToLocalChecked(), (function)); - -#define GET_STRING(source, name, property) \ - Nan::Utf8String name(Nan::Get(source, \ - Nan::New(prop).ToLocalChecked()).ToLocalChecked()); - -#define GET_INTEGER(source, name, prop) \ - int name = Nan::To(Nan::Get(source, \ - Nan::New(property).ToLocalChecked()).ToLocalChecked()).FromJust(); - -#define EXCEPTION(msg, errno, name) \ - Local name = Exception::Error( \ - String::Concat( \ - String::Concat( \ - Nan::New(sqlite_code_string(errno)).ToLocalChecked(), \ - Nan::New(": ").ToLocalChecked() \ - ), \ - (msg) \ - ) \ - ); \ - Local name ##_obj = name.As(); \ - Nan::Set(name ##_obj, Nan::New("errno").ToLocalChecked(), Nan::New(errno));\ - Nan::Set(name ##_obj, Nan::New("code").ToLocalChecked(), \ - Nan::New(sqlite_code_string(errno)).ToLocalChecked()); - - -#define EMIT_EVENT(obj, argc, argv) \ - TRY_CATCH_CALL((obj), \ - Nan::Get(obj, \ - Nan::New("emit").ToLocalChecked()).ToLocalChecked().As(),\ - argc, argv \ - ); - -#define TRY_CATCH_CALL(context, callback, argc, argv) \ - Nan::MakeCallback((context), (callback), (argc), (argv)) - -#define WORK_DEFINITION(name) \ - static NAN_METHOD(name); \ - 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); \ - assert(baton->stmt); \ - assert(!baton->stmt->locked); \ - assert(!baton->stmt->finalized); \ - assert(baton->stmt->prepared); \ - baton->stmt->locked = true; \ - baton->stmt->db->pending++; \ - int status = uv_queue_work(uv_default_loop(), \ - &baton->request, \ - Work_##type, reinterpret_cast(Work_After##type)); \ - assert(status == 0); - -#define STATEMENT_INIT(type) \ - type* baton = static_cast(req->data); \ - Statement* stmt = baton->stmt; - -#define STATEMENT_END() \ - assert(stmt->locked); \ - assert(stmt->db->pending); \ - stmt->locked = false; \ - stmt->db->pending--; \ - stmt->Process(); \ - stmt->db->Process(); \ - delete baton; - -#define DELETE_FIELD(field) \ - if (field != NULL) { \ - switch ((field)->type) { \ - case SQLITE_INTEGER: delete (Values::Integer*)(field); break; \ - case SQLITE_FLOAT: delete (Values::Float*)(field); break; \ - case SQLITE_TEXT: delete (Values::Text*)(field); break; \ - case SQLITE_BLOB: delete (Values::Blob*)(field); break; \ - case SQLITE_NULL: delete (Values::Null*)(field); break; \ - } \ - } - -#endif diff --git a/src/node_sqlite3.cc b/src/node_sqlite3.cc deleted file mode 100644 index 64326f784..000000000 --- a/src/node_sqlite3.cc +++ /dev/null @@ -1,106 +0,0 @@ -#include -#include -#include -#include -#include - -#include "macros.h" -#include "database.h" -#include "statement.h" - -using namespace node_sqlite3; - -namespace { - -NAN_MODULE_INIT(RegisterModule) { - Nan::HandleScope scope; - - Database::Init(target); - Statement::Init(target); - - DEFINE_CONSTANT_INTEGER(target, SQLITE_OPEN_READONLY, OPEN_READONLY); - DEFINE_CONSTANT_INTEGER(target, SQLITE_OPEN_READWRITE, OPEN_READWRITE); - DEFINE_CONSTANT_INTEGER(target, SQLITE_OPEN_CREATE, OPEN_CREATE); - DEFINE_CONSTANT_INTEGER(target, SQLITE_OPEN_FULLMUTEX, OPEN_FULLMUTEX); - DEFINE_CONSTANT_STRING(target, SQLITE_VERSION, VERSION); -#ifdef SQLITE_SOURCE_ID - DEFINE_CONSTANT_STRING(target, SQLITE_SOURCE_ID, SOURCE_ID); -#endif - DEFINE_CONSTANT_INTEGER(target, SQLITE_VERSION_NUMBER, VERSION_NUMBER); - - DEFINE_CONSTANT_INTEGER(target, SQLITE_OK, OK); - DEFINE_CONSTANT_INTEGER(target, SQLITE_ERROR, ERROR); - DEFINE_CONSTANT_INTEGER(target, SQLITE_INTERNAL, INTERNAL); - DEFINE_CONSTANT_INTEGER(target, SQLITE_PERM, PERM); - DEFINE_CONSTANT_INTEGER(target, SQLITE_ABORT, ABORT); - DEFINE_CONSTANT_INTEGER(target, SQLITE_BUSY, BUSY); - DEFINE_CONSTANT_INTEGER(target, SQLITE_LOCKED, LOCKED); - DEFINE_CONSTANT_INTEGER(target, SQLITE_NOMEM, NOMEM); - DEFINE_CONSTANT_INTEGER(target, SQLITE_READONLY, READONLY); - DEFINE_CONSTANT_INTEGER(target, SQLITE_INTERRUPT, INTERRUPT); - DEFINE_CONSTANT_INTEGER(target, SQLITE_IOERR, IOERR); - DEFINE_CONSTANT_INTEGER(target, SQLITE_CORRUPT, CORRUPT); - DEFINE_CONSTANT_INTEGER(target, SQLITE_NOTFOUND, NOTFOUND); - DEFINE_CONSTANT_INTEGER(target, SQLITE_FULL, FULL); - DEFINE_CONSTANT_INTEGER(target, SQLITE_CANTOPEN, CANTOPEN); - DEFINE_CONSTANT_INTEGER(target, SQLITE_PROTOCOL, PROTOCOL); - DEFINE_CONSTANT_INTEGER(target, SQLITE_EMPTY, EMPTY); - DEFINE_CONSTANT_INTEGER(target, SQLITE_SCHEMA, SCHEMA); - DEFINE_CONSTANT_INTEGER(target, SQLITE_TOOBIG, TOOBIG); - DEFINE_CONSTANT_INTEGER(target, SQLITE_CONSTRAINT, CONSTRAINT); - DEFINE_CONSTANT_INTEGER(target, SQLITE_MISMATCH, MISMATCH); - DEFINE_CONSTANT_INTEGER(target, SQLITE_MISUSE, MISUSE); - DEFINE_CONSTANT_INTEGER(target, SQLITE_NOLFS, NOLFS); - DEFINE_CONSTANT_INTEGER(target, SQLITE_AUTH, AUTH); - DEFINE_CONSTANT_INTEGER(target, SQLITE_FORMAT, FORMAT); - DEFINE_CONSTANT_INTEGER(target, SQLITE_RANGE, RANGE); - DEFINE_CONSTANT_INTEGER(target, SQLITE_NOTADB, NOTADB); -} - -} - -const char* sqlite_code_string(int code) { - switch (code) { - case SQLITE_OK: return "SQLITE_OK"; - case SQLITE_ERROR: return "SQLITE_ERROR"; - case SQLITE_INTERNAL: return "SQLITE_INTERNAL"; - case SQLITE_PERM: return "SQLITE_PERM"; - case SQLITE_ABORT: return "SQLITE_ABORT"; - case SQLITE_BUSY: return "SQLITE_BUSY"; - case SQLITE_LOCKED: return "SQLITE_LOCKED"; - case SQLITE_NOMEM: return "SQLITE_NOMEM"; - case SQLITE_READONLY: return "SQLITE_READONLY"; - case SQLITE_INTERRUPT: return "SQLITE_INTERRUPT"; - case SQLITE_IOERR: return "SQLITE_IOERR"; - case SQLITE_CORRUPT: return "SQLITE_CORRUPT"; - case SQLITE_NOTFOUND: return "SQLITE_NOTFOUND"; - case SQLITE_FULL: return "SQLITE_FULL"; - case SQLITE_CANTOPEN: return "SQLITE_CANTOPEN"; - case SQLITE_PROTOCOL: return "SQLITE_PROTOCOL"; - case SQLITE_EMPTY: return "SQLITE_EMPTY"; - case SQLITE_SCHEMA: return "SQLITE_SCHEMA"; - case SQLITE_TOOBIG: return "SQLITE_TOOBIG"; - case SQLITE_CONSTRAINT: return "SQLITE_CONSTRAINT"; - case SQLITE_MISMATCH: return "SQLITE_MISMATCH"; - case SQLITE_MISUSE: return "SQLITE_MISUSE"; - case SQLITE_NOLFS: return "SQLITE_NOLFS"; - case SQLITE_AUTH: return "SQLITE_AUTH"; - case SQLITE_FORMAT: return "SQLITE_FORMAT"; - case SQLITE_RANGE: return "SQLITE_RANGE"; - case SQLITE_NOTADB: return "SQLITE_NOTADB"; - case SQLITE_ROW: return "SQLITE_ROW"; - case SQLITE_DONE: return "SQLITE_DONE"; - default: return "UNKNOWN"; - } -} - -const char* sqlite_authorizer_string(int type) { - switch (type) { - case SQLITE_INSERT: return "insert"; - case SQLITE_UPDATE: return "update"; - case SQLITE_DELETE: return "delete"; - default: return ""; - } -} - -NODE_MODULE(node_sqlite3, RegisterModule) diff --git a/src/statement.cc b/src/statement.cc deleted file mode 100644 index 6efbe5766..000000000 --- a/src/statement.cc +++ /dev/null @@ -1,901 +0,0 @@ -#include -#include -#include -#include - -#include "macros.h" -#include "database.h" -#include "statement.h" - -using namespace node_sqlite3; - -Nan::Persistent Statement::constructor_template; - -NAN_MODULE_INIT(Statement::Init) { - Nan::HandleScope scope; - - Local t = Nan::New(New); - - t->InstanceTemplate()->SetInternalFieldCount(1); - t->SetClassName(Nan::New("Statement").ToLocalChecked()); - - Nan::SetPrototypeMethod(t, "bind", Bind); - Nan::SetPrototypeMethod(t, "get", Get); - Nan::SetPrototypeMethod(t, "run", Run); - Nan::SetPrototypeMethod(t, "all", All); - Nan::SetPrototypeMethod(t, "each", Each); - Nan::SetPrototypeMethod(t, "reset", Reset); - Nan::SetPrototypeMethod(t, "finalize", Finalize); - - constructor_template.Reset(t); - Nan::Set(target, Nan::New("Statement").ToLocalChecked(), - Nan::GetFunction(t).ToLocalChecked()); -} - -void Statement::Process() { - if (finalized && !queue.empty()) { - return CleanQueue(); - } - - while (prepared && !locked && !queue.empty()) { - Call* call = queue.front(); - queue.pop(); - - call->callback(call->baton); - delete call; - } -} - -void Statement::Schedule(Work_Callback callback, Baton* baton) { - if (finalized) { - queue.push(new Call(callback, baton)); - CleanQueue(); - } - else if (!prepared || locked) { - queue.push(new Call(callback, baton)); - } - else { - callback(baton); - } -} - -template void Statement::Error(T* baton) { - Nan::HandleScope scope; - - Statement* stmt = baton->stmt; - // Fail hard on logic errors. - assert(stmt->status != 0); - EXCEPTION(Nan::New(stmt->message.c_str()).ToLocalChecked(), stmt->status, exception); - - Local cb = Nan::New(baton->callback); - - if (!cb.IsEmpty() && cb->IsFunction()) { - Local argv[] = { exception }; - TRY_CATCH_CALL(stmt->handle(), cb, 1, argv); - } - else { - Local argv[] = { Nan::New("error").ToLocalChecked(), exception }; - EMIT_EVENT(stmt->handle(), 2, argv); - } -} - -// { Database db, String sql, Array params, Function callback } -NAN_METHOD(Statement::New) { - if (!info.IsConstructCall()) { - return Nan::ThrowTypeError("Use the new operator to create new Statement objects"); - } - - int length = info.Length(); - - if (length <= 0 || !Database::HasInstance(info[0])) { - return Nan::ThrowTypeError("Database object expected"); - } - else if (length <= 1 || !info[1]->IsString()) { - return Nan::ThrowTypeError("SQL query expected"); - } - else if (length > 2 && !info[2]->IsUndefined() && !info[2]->IsFunction()) { - return Nan::ThrowTypeError("Callback expected"); - } - - Database* db = Nan::ObjectWrap::Unwrap(info[0].As()); - Local sql = Local::Cast(info[1]); - - Nan::ForceSet(info.This(),Nan::New("sql").ToLocalChecked(), sql, ReadOnly); - - Statement* stmt = new Statement(db); - stmt->Wrap(info.This()); - - PrepareBaton* baton = new PrepareBaton(db, Local::Cast(info[2]), stmt); - baton->sql = std::string(*Nan::Utf8String(sql)); - db->Schedule(Work_BeginPrepare, baton); - - info.GetReturnValue().Set(info.This()); -} - -void Statement::Work_BeginPrepare(Database::Baton* baton) { - assert(baton->db->open); - baton->db->pending++; - int status = uv_queue_work(uv_default_loop(), - &baton->request, Work_Prepare, (uv_after_work_cb)Work_AfterPrepare); - assert(status == 0); -} - -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 - // error message. - sqlite3_mutex* mtx = sqlite3_db_mutex(baton->db->_handle); - sqlite3_mutex_enter(mtx); - - stmt->status = sqlite3_prepare_v2( - baton->db->_handle, - baton->sql.c_str(), - baton->sql.size(), - &stmt->_handle, - NULL - ); - - if (stmt->status != SQLITE_OK) { - stmt->message = std::string(sqlite3_errmsg(baton->db->_handle)); - stmt->_handle = NULL; - } - - sqlite3_mutex_leave(mtx); -} - -void Statement::Work_AfterPrepare(uv_work_t* req) { - Nan::HandleScope scope; - - STATEMENT_INIT(PrepareBaton); - - if (stmt->status != SQLITE_OK) { - Error(baton); - stmt->Finalize(); - } - else { - stmt->prepared = true; - Local cb = Nan::New(baton->callback); - if (!cb.IsEmpty() && cb->IsFunction()) { - Local argv[] = { Nan::Null() }; - TRY_CATCH_CALL(stmt->handle(), cb, 1, argv); - } - } - - STATEMENT_END(); -} - -template Values::Field* - Statement::BindParameter(const Local source, T pos) { - if (source->IsString() || source->IsRegExp()) { - Nan::Utf8String val(source); - return new Values::Text(pos, val.length(), *val); - } - else if (source->IsInt32()) { - return new Values::Integer(pos, Nan::To(source).FromJust()); - } - else if (source->IsNumber()) { - return new Values::Float(pos, Nan::To(source).FromJust()); - } - else if (source->IsBoolean()) { - return new Values::Integer(pos, Nan::To(source).FromJust() ? 1 : 0); - } - else if (source->IsNull()) { - return new Values::Null(pos); - } - else if (Buffer::HasInstance(source)) { - Local buffer = Nan::To(source).ToLocalChecked(); - return new Values::Blob(pos, Buffer::Length(buffer), Buffer::Data(buffer)); - } - else if (source->IsDate()) { - return new Values::Float(pos, Nan::To(source).FromJust()); - } - else { - return NULL; - } -} - -template T* Statement::Bind(Nan::NAN_METHOD_ARGS_TYPE info, int start, int last) { - Nan::HandleScope scope; - - if (last < 0) last = info.Length(); - Local callback; - if (last > start && info[last - 1]->IsFunction()) { - callback = Local::Cast(info[last - 1]); - last--; - } - - T* baton = new T(this, callback); - - if (start < last) { - if (info[start]->IsArray()) { - Local array = Local::Cast(info[start]); - int length = array->Length(); - // Note: bind parameters start with 1. - for (int i = 0, pos = 1; i < length; i++, pos++) { - baton->parameters.push_back(BindParameter(Nan::Get(array, i).ToLocalChecked(), pos)); - } - } - else if (!info[start]->IsObject() || info[start]->IsRegExp() || info[start]->IsDate() || Buffer::HasInstance(info[start])) { - // Parameters directly in array. - // Note: bind parameters start with 1. - for (int i = start, pos = 1; i < last; i++, pos++) { - baton->parameters.push_back(BindParameter(info[i], pos)); - } - } - else if (info[start]->IsObject()) { - Local object = Local::Cast(info[start]); - Local array = Nan::GetPropertyNames(object).ToLocalChecked(); - int length = array->Length(); - for (int i = 0; i < length; i++) { - Local name = Nan::Get(array, i).ToLocalChecked(); - - if (name->IsInt32()) { - baton->parameters.push_back( - BindParameter(Nan::Get(object, name).ToLocalChecked(), Nan::To(name).FromJust())); - } - else { - baton->parameters.push_back(BindParameter(Nan::Get(object, name).ToLocalChecked(), - *Nan::Utf8String(name))); - } - } - } - else { - return NULL; - } - } - - return baton; -} - -bool Statement::Bind(const Parameters & parameters) { - if (parameters.size() == 0) { - return true; - } - - sqlite3_reset(_handle); - sqlite3_clear_bindings(_handle); - - Parameters::const_iterator it = parameters.begin(); - Parameters::const_iterator end = parameters.end(); - - for (; it < end; ++it) { - Values::Field* field = *it; - - if (field != NULL) { - int pos; - if (field->index > 0) { - pos = field->index; - } - else { - pos = sqlite3_bind_parameter_index(_handle, field->name.c_str()); - } - - switch (field->type) { - case SQLITE_INTEGER: { - status = sqlite3_bind_int(_handle, pos, - ((Values::Integer*)field)->value); - } break; - case SQLITE_FLOAT: { - status = sqlite3_bind_double(_handle, pos, - ((Values::Float*)field)->value); - } break; - case SQLITE_TEXT: { - status = sqlite3_bind_text(_handle, pos, - ((Values::Text*)field)->value.c_str(), - ((Values::Text*)field)->value.size(), SQLITE_TRANSIENT); - } break; - case SQLITE_BLOB: { - status = sqlite3_bind_blob(_handle, pos, - ((Values::Blob*)field)->value, - ((Values::Blob*)field)->length, SQLITE_TRANSIENT); - } break; - case SQLITE_NULL: { - status = sqlite3_bind_null(_handle, pos); - } break; - } - - if (status != SQLITE_OK) { - message = std::string(sqlite3_errmsg(db->_handle)); - return false; - } - } - } - - return true; -} - -NAN_METHOD(Statement::Bind) { - Statement* stmt = Nan::ObjectWrap::Unwrap(info.This()); - - Baton* baton = stmt->Bind(info); - if (baton == NULL) { - return Nan::ThrowTypeError("Data type is not supported"); - } - else { - stmt->Schedule(Work_BeginBind, baton); - info.GetReturnValue().Set(info.This()); - } -} - -void Statement::Work_BeginBind(Baton* baton) { - STATEMENT_BEGIN(Bind); -} - -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); -} - -void Statement::Work_AfterBind(uv_work_t* req) { - Nan::HandleScope scope; - - STATEMENT_INIT(Baton); - - if (stmt->status != SQLITE_OK) { - Error(baton); - } - else { - // Fire callbacks. - Local cb = Nan::New(baton->callback); - if (!cb.IsEmpty() && cb->IsFunction()) { - Local argv[] = { Nan::Null() }; - TRY_CATCH_CALL(stmt->handle(), cb, 1, argv); - } - } - - STATEMENT_END(); -} - - - -NAN_METHOD(Statement::Get) { - Statement* stmt = Nan::ObjectWrap::Unwrap(info.This()); - - Baton* baton = stmt->Bind(info); - if (baton == NULL) { - return Nan::ThrowError("Data type is not supported"); - } - else { - stmt->Schedule(Work_BeginGet, baton); - info.GetReturnValue().Set(info.This()); - } -} - -void Statement::Work_BeginGet(Baton* baton) { - STATEMENT_BEGIN(Get); -} - -void Statement::Work_Get(uv_work_t* req) { - STATEMENT_INIT(RowBaton); - - if (stmt->status != SQLITE_DONE || baton->parameters.size()) { - sqlite3_mutex* mtx = sqlite3_db_mutex(stmt->db->_handle); - sqlite3_mutex_enter(mtx); - - if (stmt->Bind(baton->parameters)) { - stmt->status = sqlite3_step(stmt->_handle); - - if (!(stmt->status == SQLITE_ROW || stmt->status == SQLITE_DONE)) { - stmt->message = std::string(sqlite3_errmsg(stmt->db->_handle)); - } - } - - sqlite3_mutex_leave(mtx); - - if (stmt->status == SQLITE_ROW) { - // Acquire one result row before returning. - GetRow(&baton->row, stmt->_handle); - } - } -} - -void Statement::Work_AfterGet(uv_work_t* req) { - Nan::HandleScope scope; - - STATEMENT_INIT(RowBaton); - - if (stmt->status != SQLITE_ROW && stmt->status != SQLITE_DONE) { - Error(baton); - } - else { - // Fire callbacks. - Local cb = Nan::New(baton->callback); - if (!cb.IsEmpty() && cb->IsFunction()) { - if (stmt->status == SQLITE_ROW) { - // Create the result array from the data we acquired. - Local argv[] = { Nan::Null(), RowToJS(&baton->row) }; - TRY_CATCH_CALL(stmt->handle(), cb, 2, argv); - } - else { - Local argv[] = { Nan::Null() }; - TRY_CATCH_CALL(stmt->handle(), cb, 1, argv); - } - } - } - - STATEMENT_END(); -} - -NAN_METHOD(Statement::Run) { - Statement* stmt = Nan::ObjectWrap::Unwrap(info.This()); - - Baton* baton = stmt->Bind(info); - if (baton == NULL) { - return Nan::ThrowError("Data type is not supported"); - } - else { - stmt->Schedule(Work_BeginRun, baton); - info.GetReturnValue().Set(info.This()); - } -} - -void Statement::Work_BeginRun(Baton* baton) { - STATEMENT_BEGIN(Run); -} - -void Statement::Work_Run(uv_work_t* req) { - STATEMENT_INIT(RunBaton); - - sqlite3_mutex* mtx = sqlite3_db_mutex(stmt->db->_handle); - sqlite3_mutex_enter(mtx); - - // Make sure that we also reset when there are no parameters. - if (!baton->parameters.size()) { - sqlite3_reset(stmt->_handle); - } - - if (stmt->Bind(baton->parameters)) { - stmt->status = sqlite3_step(stmt->_handle); - - if (!(stmt->status == SQLITE_ROW || stmt->status == SQLITE_DONE)) { - stmt->message = std::string(sqlite3_errmsg(stmt->db->_handle)); - } - else { - baton->inserted_id = sqlite3_last_insert_rowid(stmt->db->_handle); - baton->changes = sqlite3_changes(stmt->db->_handle); - } - } - - sqlite3_mutex_leave(mtx); -} - -void Statement::Work_AfterRun(uv_work_t* req) { - Nan::HandleScope scope; - - STATEMENT_INIT(RunBaton); - - if (stmt->status != SQLITE_ROW && stmt->status != SQLITE_DONE) { - Error(baton); - } - else { - // Fire callbacks. - Local cb = Nan::New(baton->callback); - if (!cb.IsEmpty() && cb->IsFunction()) { - Nan::Set(stmt->handle(), Nan::New("lastID").ToLocalChecked(), Nan::New(baton->inserted_id)); - Nan::Set(stmt->handle(), Nan::New("changes").ToLocalChecked(), Nan::New(baton->changes)); - - Local argv[] = { Nan::Null() }; - TRY_CATCH_CALL(stmt->handle(), cb, 1, argv); - } - } - - STATEMENT_END(); -} - -NAN_METHOD(Statement::All) { - Statement* stmt = Nan::ObjectWrap::Unwrap(info.This()); - - Baton* baton = stmt->Bind(info); - if (baton == NULL) { - return Nan::ThrowError("Data type is not supported"); - } - else { - stmt->Schedule(Work_BeginAll, baton); - info.GetReturnValue().Set(info.This()); - } -} - -void Statement::Work_BeginAll(Baton* baton) { - STATEMENT_BEGIN(All); -} - -void Statement::Work_All(uv_work_t* req) { - STATEMENT_INIT(RowsBaton); - - sqlite3_mutex* mtx = sqlite3_db_mutex(stmt->db->_handle); - sqlite3_mutex_enter(mtx); - - // Make sure that we also reset when there are no parameters. - if (!baton->parameters.size()) { - sqlite3_reset(stmt->_handle); - } - - if (stmt->Bind(baton->parameters)) { - while ((stmt->status = sqlite3_step(stmt->_handle)) == SQLITE_ROW) { - Row* row = new Row(); - GetRow(row, stmt->_handle); - baton->rows.push_back(row); - } - - if (stmt->status != SQLITE_DONE) { - stmt->message = std::string(sqlite3_errmsg(stmt->db->_handle)); - } - } - - sqlite3_mutex_leave(mtx); -} - -void Statement::Work_AfterAll(uv_work_t* req) { - Nan::HandleScope scope; - - STATEMENT_INIT(RowsBaton); - - if (stmt->status != SQLITE_DONE) { - Error(baton); - } - else { - // Fire callbacks. - Local cb = Nan::New(baton->callback); - if (!cb.IsEmpty() && cb->IsFunction()) { - if (baton->rows.size()) { - // Create the result array from the data we acquired. - Local result(Nan::New(baton->rows.size())); - Rows::const_iterator it = baton->rows.begin(); - Rows::const_iterator end = baton->rows.end(); - for (int i = 0; it < end; ++it, i++) { - Nan::Set(result, i, RowToJS(*it)); - delete *it; - } - - Local argv[] = { Nan::Null(), result }; - TRY_CATCH_CALL(stmt->handle(), cb, 2, argv); - } - else { - // There were no result rows. - Local argv[] = { - Nan::Null(), - Nan::New(0) - }; - TRY_CATCH_CALL(stmt->handle(), cb, 2, argv); - } - } - } - - STATEMENT_END(); -} - -NAN_METHOD(Statement::Each) { - Statement* stmt = Nan::ObjectWrap::Unwrap(info.This()); - - int last = info.Length(); - - Local completed; - if (last >= 2 && info[last - 1]->IsFunction() && info[last - 2]->IsFunction()) { - completed = Local::Cast(info[--last]); - } - - EachBaton* baton = stmt->Bind(info, 0, last); - if (baton == NULL) { - return Nan::ThrowError("Data type is not supported"); - } - else { - baton->completed.Reset(completed); - stmt->Schedule(Work_BeginEach, baton); - info.GetReturnValue().Set(info.This()); - } -} - -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(baton); - each_baton->async = new Async(each_baton->stmt, reinterpret_cast(AsyncEach)); - each_baton->async->item_cb.Reset(each_baton->callback); - each_baton->async->completed_cb.Reset(each_baton->completed); - - STATEMENT_BEGIN(Each); -} - -void Statement::Work_Each(uv_work_t* req) { - STATEMENT_INIT(EachBaton); - - Async* async = baton->async; - - sqlite3_mutex* mtx = sqlite3_db_mutex(stmt->db->_handle); - - int retrieved = 0; - - // Make sure that we also reset when there are no parameters. - if (!baton->parameters.size()) { - sqlite3_reset(stmt->_handle); - } - - if (stmt->Bind(baton->parameters)) { - while (true) { - sqlite3_mutex_enter(mtx); - stmt->status = sqlite3_step(stmt->_handle); - if (stmt->status == SQLITE_ROW) { - sqlite3_mutex_leave(mtx); - Row* row = new Row(); - GetRow(row, stmt->_handle); - NODE_SQLITE3_MUTEX_LOCK(&async->mutex) - async->data.push_back(row); - retrieved++; - NODE_SQLITE3_MUTEX_UNLOCK(&async->mutex) - - uv_async_send(&async->watcher); - } - else { - if (stmt->status != SQLITE_DONE) { - stmt->message = std::string(sqlite3_errmsg(stmt->db->_handle)); - } - sqlite3_mutex_leave(mtx); - break; - } - } - } - - async->completed = true; - uv_async_send(&async->watcher); -} - -void Statement::CloseCallback(uv_handle_t* handle) { - assert(handle != NULL); - assert(handle->data != NULL); - Async* async = static_cast(handle->data); - delete async; -} - -void Statement::AsyncEach(uv_async_t* handle, int status) { - Nan::HandleScope scope; - - Async* async = static_cast(handle->data); - - while (true) { - // Get the contents out of the data cache for us to process in the JS callback. - Rows rows; - NODE_SQLITE3_MUTEX_LOCK(&async->mutex) - rows.swap(async->data); - NODE_SQLITE3_MUTEX_UNLOCK(&async->mutex) - - if (rows.empty()) { - break; - } - - Local cb = Nan::New(async->item_cb); - if (!cb.IsEmpty() && cb->IsFunction()) { - Local argv[2]; - argv[0] = Nan::Null(); - - Rows::const_iterator it = rows.begin(); - Rows::const_iterator end = rows.end(); - for (int i = 0; it < end; ++it, i++) { - argv[1] = RowToJS(*it); - async->retrieved++; - TRY_CATCH_CALL(async->stmt->handle(), cb, 2, argv); - delete *it; - } - } - } - - Local cb = Nan::New(async->completed_cb); - if (async->completed) { - if (!cb.IsEmpty() && - cb->IsFunction()) { - Local argv[] = { - Nan::Null(), - Nan::New(async->retrieved) - }; - TRY_CATCH_CALL(async->stmt->handle(), cb, 2, argv); - } - uv_close(reinterpret_cast(handle), CloseCallback); - } -} - -void Statement::Work_AfterEach(uv_work_t* req) { - Nan::HandleScope scope; - - STATEMENT_INIT(EachBaton); - - if (stmt->status != SQLITE_DONE) { - Error(baton); - } - - STATEMENT_END(); -} - -NAN_METHOD(Statement::Reset) { - Statement* stmt = Nan::ObjectWrap::Unwrap(info.This()); - - OPTIONAL_ARGUMENT_FUNCTION(0, callback); - - Baton* baton = new Baton(stmt, callback); - stmt->Schedule(Work_BeginReset, baton); - - info.GetReturnValue().Set(info.This()); -} - -void Statement::Work_BeginReset(Baton* baton) { - STATEMENT_BEGIN(Reset); -} - -void Statement::Work_Reset(uv_work_t* req) { - STATEMENT_INIT(Baton); - - sqlite3_reset(stmt->_handle); - stmt->status = SQLITE_OK; -} - -void Statement::Work_AfterReset(uv_work_t* req) { - Nan::HandleScope scope; - - STATEMENT_INIT(Baton); - - // Fire callbacks. - Local cb = Nan::New(baton->callback); - if (!cb.IsEmpty() && cb->IsFunction()) { - Local argv[] = { Nan::Null() }; - TRY_CATCH_CALL(stmt->handle(), cb, 1, argv); - } - - STATEMENT_END(); -} - -Local Statement::RowToJS(Row* row) { - Nan::EscapableHandleScope scope; - - Local result = Nan::New(); - - Row::const_iterator it = row->begin(); - Row::const_iterator end = row->end(); - for (int i = 0; it < end; ++it, i++) { - Values::Field* field = *it; - - Local value; - - switch (field->type) { - case SQLITE_INTEGER: { - value = Nan::New(((Values::Integer*)field)->value); - } break; - case SQLITE_FLOAT: { - value = Nan::New(((Values::Float*)field)->value); - } break; - case SQLITE_TEXT: { - value = Nan::New(((Values::Text*)field)->value.c_str(), ((Values::Text*)field)->value.size()).ToLocalChecked(); - } break; - case SQLITE_BLOB: { - value = Nan::CopyBuffer(((Values::Blob*)field)->value, ((Values::Blob*)field)->length).ToLocalChecked(); - } break; - case SQLITE_NULL: { - value = Nan::Null(); - } break; - } - - Nan::Set(result, Nan::New(field->name.c_str()).ToLocalChecked(), value); - - DELETE_FIELD(field); - } - - return scope.Escape(result); -} - -void Statement::GetRow(Row* row, sqlite3_stmt* stmt) { - int rows = sqlite3_column_count(stmt); - - for (int i = 0; i < rows; i++) { - int type = sqlite3_column_type(stmt, i); - const char* name = sqlite3_column_name(stmt, i); - switch (type) { - case SQLITE_INTEGER: { - row->push_back(new Values::Integer(name, sqlite3_column_int64(stmt, i))); - } break; - case SQLITE_FLOAT: { - row->push_back(new Values::Float(name, sqlite3_column_double(stmt, i))); - } break; - case SQLITE_TEXT: { - const char* text = (const char*)sqlite3_column_text(stmt, i); - int length = sqlite3_column_bytes(stmt, i); - row->push_back(new Values::Text(name, length, text)); - } break; - case SQLITE_BLOB: { - const void* blob = sqlite3_column_blob(stmt, i); - int length = sqlite3_column_bytes(stmt, i); - row->push_back(new Values::Blob(name, length, blob)); - } break; - case SQLITE_NULL: { - row->push_back(new Values::Null(name)); - } break; - default: - assert(false); - } - } -} - -NAN_METHOD(Statement::Finalize) { - Statement* stmt = Nan::ObjectWrap::Unwrap(info.This()); - OPTIONAL_ARGUMENT_FUNCTION(0, callback); - - Baton* baton = new Baton(stmt, callback); - stmt->Schedule(Finalize, baton); - - info.GetReturnValue().Set(stmt->db->handle()); -} - -void Statement::Finalize(Baton* baton) { - Nan::HandleScope scope; - - baton->stmt->Finalize(); - - // Fire callback in case there was one. - Local cb = Nan::New(baton->callback); - if (!cb.IsEmpty() && cb->IsFunction()) { - TRY_CATCH_CALL(baton->stmt->handle(), cb, 0, NULL); - } - - delete baton; -} - -void Statement::Finalize() { - assert(!finalized); - finalized = true; - CleanQueue(); - // Finalize returns the status code of the last operation. We already fired - // error events in case those failed. - sqlite3_finalize(_handle); - _handle = NULL; - db->Unref(); -} - -void Statement::CleanQueue() { - Nan::HandleScope scope; - - if (prepared && !queue.empty()) { - // This statement has already been prepared and is now finalized. - // Fire error for all remaining items in the queue. - EXCEPTION(Nan::New("Statement is already finalized").ToLocalChecked(), SQLITE_MISUSE, exception); - Local argv[] = { exception }; - bool called = false; - - // Clear out the queue so that this object can get GC'ed. - while (!queue.empty()) { - Call* call = queue.front(); - queue.pop(); - - Local cb = Nan::New(call->baton->callback); - - if (prepared && !cb.IsEmpty() && - cb->IsFunction()) { - TRY_CATCH_CALL(handle(), cb, 1, argv); - called = true; - } - - // We don't call the actual callback, so we have to make sure that - // the baton gets destroyed. - delete call->baton; - delete call; - } - - // When we couldn't call a callback function, emit an error on the - // Statement object. - if (!called) { - Local info[] = { Nan::New("error").ToLocalChecked(), exception }; - EMIT_EVENT(handle(), 2, info); - } - } - else while (!queue.empty()) { - // Just delete all items in the queue; we already fired an event when - // preparing the statement failed. - Call* call = queue.front(); - queue.pop(); - - // We don't call the actual callback, so we have to make sure that - // the baton gets destroyed. - delete call->baton; - delete call; - } -} diff --git a/src/statement.h b/src/statement.h deleted file mode 100644 index 90d295b70..000000000 --- a/src/statement.h +++ /dev/null @@ -1,248 +0,0 @@ -#ifndef NODE_SQLITE3_SRC_STATEMENT_H -#define NODE_SQLITE3_SRC_STATEMENT_H - - -#include "database.h" -#include "threading.h" - -#include -#include -#include -#include -#include - -#include -#include - -using namespace v8; -using namespace node; - -namespace node_sqlite3 { - -namespace Values { - struct Field { - inline Field(unsigned short _index, unsigned short _type = SQLITE_NULL) : - type(_type), index(_index) {} - inline Field(const char* _name, unsigned short _type = SQLITE_NULL) : - type(_type), index(0), name(_name) {} - - unsigned short type; - unsigned short index; - std::string name; - }; - - struct Integer : Field { - template inline Integer(T _name, int64_t val) : - Field(_name, SQLITE_INTEGER), value(val) {} - int64_t value; - }; - - struct Float : Field { - template inline Float(T _name, double val) : - Field(_name, SQLITE_FLOAT), value(val) {} - double value; - }; - - struct Text : Field { - template inline Text(T _name, size_t len, const char* val) : - Field(_name, SQLITE_TEXT), value(val, len) {} - std::string value; - }; - - struct Blob : Field { - template inline Blob(T _name, size_t len, const void* val) : - Field(_name, SQLITE_BLOB), length(len) { - value = (char*)malloc(len); - memcpy(value, val, len); - } - inline ~Blob() { - free(value); - } - int length; - char* value; - }; - - typedef Field Null; -} - -typedef std::vector Row; -typedef std::vector Rows; -typedef Row Parameters; - - - -class Statement : public Nan::ObjectWrap { -public: - static Nan::Persistent constructor_template; - - static NAN_MODULE_INIT(Init); - static NAN_METHOD(New); - - struct Baton { - uv_work_t request; - Statement* stmt; - Nan::Persistent callback; - Parameters parameters; - - Baton(Statement* stmt_, Local cb_) : stmt(stmt_) { - stmt->Ref(); - request.data = this; - callback.Reset(cb_); - } - virtual ~Baton() { - for (unsigned int i = 0; i < parameters.size(); i++) { - Values::Field* field = parameters[i]; - DELETE_FIELD(field); - } - stmt->Unref(); - callback.Reset(); - } - }; - - struct RowBaton : Baton { - RowBaton(Statement* stmt_, Local cb_) : - Baton(stmt_, cb_) {} - Row row; - }; - - struct RunBaton : Baton { - RunBaton(Statement* stmt_, Local cb_) : - Baton(stmt_, cb_), inserted_id(0), changes(0) {} - sqlite3_int64 inserted_id; - int changes; - }; - - struct RowsBaton : Baton { - RowsBaton(Statement* stmt_, Local cb_) : - Baton(stmt_, cb_) {} - Rows rows; - }; - - struct Async; - - struct EachBaton : Baton { - Nan::Persistent completed; - Async* async; // Isn't deleted when the baton is deleted. - - EachBaton(Statement* stmt_, Local cb_) : - Baton(stmt_, cb_) {} - virtual ~EachBaton() { - completed.Reset(); - } - }; - - struct PrepareBaton : Database::Baton { - Statement* stmt; - std::string sql; - PrepareBaton(Database* db_, Local cb_, Statement* stmt_) : - Baton(db_, cb_), stmt(stmt_) { - stmt->Ref(); - } - virtual ~PrepareBaton() { - stmt->Unref(); - if (!db->IsOpen() && db->IsLocked()) { - // The database handle was closed before the statement could be - // prepared. - stmt->Finalize(); - } - } - }; - - typedef void (*Work_Callback)(Baton* baton); - - struct Call { - Call(Work_Callback cb_, Baton* baton_) : callback(cb_), baton(baton_) {}; - Work_Callback callback; - Baton* baton; - }; - - struct Async { - uv_async_t watcher; - Statement* stmt; - Rows data; - NODE_SQLITE3_MUTEX_t; - bool completed; - int retrieved; - - // Store the callbacks here because we don't have - // access to the baton in the async callback. - Nan::Persistent item_cb; - Nan::Persistent completed_cb; - - Async(Statement* st, uv_async_cb async_cb) : - stmt(st), completed(false), retrieved(0) { - watcher.data = this; - NODE_SQLITE3_MUTEX_INIT - stmt->Ref(); - uv_async_init(uv_default_loop(), &watcher, async_cb); - } - - ~Async() { - stmt->Unref(); - item_cb.Reset(); - completed_cb.Reset(); - NODE_SQLITE3_MUTEX_DESTROY - } - }; - - Statement(Database* db_) : Nan::ObjectWrap(), - db(db_), - _handle(NULL), - status(SQLITE_OK), - prepared(false), - locked(true), - finalized(false) { - db->Ref(); - } - - ~Statement() { - if (!finalized) Finalize(); - } - - WORK_DEFINITION(Bind); - WORK_DEFINITION(Get); - WORK_DEFINITION(Run); - WORK_DEFINITION(All); - WORK_DEFINITION(Each); - WORK_DEFINITION(Reset); - - static NAN_METHOD(Finalize); - -protected: - static void Work_BeginPrepare(Database::Baton* baton); - static void Work_Prepare(uv_work_t* req); - static void Work_AfterPrepare(uv_work_t* req); - - static void AsyncEach(uv_async_t* handle, int status); - static void CloseCallback(uv_handle_t* handle); - - static void Finalize(Baton* baton); - void Finalize(); - - template inline Values::Field* BindParameter(const Local source, T pos); - template T* Bind(Nan::NAN_METHOD_ARGS_TYPE info, int start = 0, int end = -1); - bool Bind(const Parameters ¶meters); - - static void GetRow(Row* row, sqlite3_stmt* stmt); - static Local RowToJS(Row* row); - void Schedule(Work_Callback callback, Baton* baton); - void Process(); - void CleanQueue(); - template static void Error(T* baton); - -protected: - Database* db; - - sqlite3_stmt* _handle; - int status; - std::string message; - - bool prepared; - bool locked; - bool finalized; - std::queue queue; -}; - -} - -#endif diff --git a/src/threading.h b/src/threading.h deleted file mode 100644 index fe738a4c0..000000000 --- a/src/threading.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef NODE_SQLITE3_SRC_THREADING_H -#define NODE_SQLITE3_SRC_THREADING_H - - -#ifdef _WIN32 - -#include - - #define NODE_SQLITE3_MUTEX_t HANDLE mutex; - - #define NODE_SQLITE3_MUTEX_INIT mutex = CreateMutex(NULL, FALSE, NULL); - - #define NODE_SQLITE3_MUTEX_LOCK(m) WaitForSingleObject(*m, INFINITE); - - #define NODE_SQLITE3_MUTEX_UNLOCK(m) ReleaseMutex(*m); - - #define NODE_SQLITE3_MUTEX_DESTROY CloseHandle(mutex); - -#elif defined(NODE_SQLITE3_BOOST_THREADING) - -#include - - #define NODE_SQLITE3_MUTEX_t boost::mutex mutex; - - #define NODE_SQLITE3_MUTEX_INIT - - #define NODE_SQLITE3_MUTEX_LOCK(m) (*m).lock(); - - #define NODE_SQLITE3_MUTEX_UNLOCK(m) (*m).unlock(); - - #define NODE_SQLITE3_MUTEX_DESTROY mutex.unlock(); - -#else - - #define NODE_SQLITE3_MUTEX_t pthread_mutex_t mutex; - - #define NODE_SQLITE3_MUTEX_INIT pthread_mutex_init(&mutex,NULL); - - #define NODE_SQLITE3_MUTEX_LOCK(m) pthread_mutex_lock(m); - - #define NODE_SQLITE3_MUTEX_UNLOCK(m) pthread_mutex_unlock(m); - - #define NODE_SQLITE3_MUTEX_DESTROY pthread_mutex_destroy(&mutex); - -#endif - - -#endif // NODE_SQLITE3_SRC_THREADING_H From 85f47107b66c2c91596baa653f0d10e6b1114e41 Mon Sep 17 00:00:00 2001 From: Giovanni Campagna Date: Tue, 6 Mar 2018 22:39:47 -0800 Subject: [PATCH 2/2] Add version tag to mark this as the android version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b7d5d3b70..de2575b59 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sqlite3", "description": "Asynchronous, non-blocking SQLite3 bindings", - "version": "4.0.2", + "version": "4.0.2+android", "homepage": "http://github.com/mapbox/node-sqlite3", "author": { "name": "MapBox",