1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
|
#ifndef NODE_SQLITE3_SRC_DATABASE_H
#define NODE_SQLITE3_SRC_DATABASE_H
#include <assert.h>
#include <string>
#include <queue>
#include <sqlite3.h>
#include <napi.h>
#include "async.h"
using namespace Napi;
namespace node_sqlite3 {
class Database;
class Database : public Napi::ObjectWrap<Database> {
public:
#if NAPI_VERSION < 6
static Napi::FunctionReference constructor;
#endif
static Napi::Object Init(Napi::Env env, Napi::Object exports);
static inline bool HasInstance(Napi::Value val) {
Napi::Env env = val.Env();
Napi::HandleScope scope(env);
if (!val.IsObject()) return false;
Napi::Object obj = val.As<Napi::Object>();
#if NAPI_VERSION < 6
return obj.InstanceOf(constructor.Value());
#else
Napi::FunctionReference* constructor =
env.GetInstanceData<Napi::FunctionReference>();
return obj.InstanceOf(constructor->Value());
#endif
}
struct Baton {
napi_async_work request = NULL;
Database* db;
Napi::FunctionReference callback;
int status;
std::string message;
Baton(Database* db_, Napi::Function cb_) :
db(db_), status(SQLITE_OK) {
db->Ref();
if (!cb_.IsUndefined() && cb_.IsFunction()) {
callback.Reset(cb_, 1);
}
}
virtual ~Baton() {
if (request) napi_delete_async_work(db->Env(), request);
db->Unref();
callback.Reset();
}
};
struct OpenBaton : Baton {
std::string filename;
int mode;
OpenBaton(Database* db_, Napi::Function cb_, const char* filename_, int mode_) :
Baton(db_, cb_), filename(filename_), mode(mode_) {}
};
struct ExecBaton : Baton {
std::string sql;
ExecBaton(Database* db_, Napi::Function cb_, const char* sql_) :
Baton(db_, cb_), sql(sql_) {}
};
struct LoadExtensionBaton : Baton {
std::string filename;
LoadExtensionBaton(Database* db_, Napi::Function cb_, const char* filename_) :
Baton(db_, cb_), filename(filename_) {}
};
struct LimitBaton : Baton {
int id;
int value;
LimitBaton(Database* db_, Napi::Function cb_, int id_, int value_) :
Baton(db_, cb_), id(id_), value(value_) {}
};
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<std::string, Database> AsyncTrace;
typedef Async<ProfileInfo, Database> AsyncProfile;
typedef Async<UpdateInfo, Database> AsyncUpdate;
friend class Statement;
friend class Backup;
void init() {
_handle = NULL;
open = false;
closing = false;
locked = false;
pending = 0;
serialize = false;
debug_trace = NULL;
debug_profile = NULL;
update_event = NULL;
}
Database(const Napi::CallbackInfo& info);
~Database() {
RemoveCallbacks();
sqlite3_close(_handle);
_handle = NULL;
open = false;
}
protected:
static void Work_BeginOpen(Baton* baton);
static void Work_Open(napi_env env, void* data);
static void Work_AfterOpen(napi_env env, napi_status status, void* data);
Napi::Value OpenGetter(const Napi::CallbackInfo& info);
void Schedule(Work_Callback callback, Baton* baton, bool exclusive = false);
void Process();
Napi::Value Exec(const Napi::CallbackInfo& info);
static void Work_BeginExec(Baton* baton);
static void Work_Exec(napi_env env, void* data);
static void Work_AfterExec(napi_env env, napi_status status, void* data);
Napi::Value Wait(const Napi::CallbackInfo& info);
static void Work_Wait(Baton* baton);
Napi::Value Close(const Napi::CallbackInfo& info);
static void Work_BeginClose(Baton* baton);
static void Work_Close(napi_env env, void* data);
static void Work_AfterClose(napi_env env, napi_status status, void* data);
Napi::Value LoadExtension(const Napi::CallbackInfo& info);
static void Work_BeginLoadExtension(Baton* baton);
static void Work_LoadExtension(napi_env env, void* data);
static void Work_AfterLoadExtension(napi_env env, napi_status status, void* data);
Napi::Value Serialize(const Napi::CallbackInfo& info);
Napi::Value Parallelize(const Napi::CallbackInfo& info);
Napi::Value Configure(const Napi::CallbackInfo& info);
Napi::Value Interrupt(const Napi::CallbackInfo& info);
static void SetBusyTimeout(Baton* baton);
static void SetLimit(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<Call*> queue;
AsyncTrace* debug_trace;
AsyncProfile* debug_profile;
AsyncUpdate* update_event;
};
}
#endif
|