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
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
|
#ifndef NODE_SQLITE3_SRC_STATEMENT_H
#define NODE_SQLITE3_SRC_STATEMENT_H
#include <cstdlib>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <sqlite3.h>
#include <napi.h>
#include <uv.h>
#include "database.h"
#include "threading.h"
using namespace Napi;
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;
virtual ~Field() = default;
};
struct Integer : Field {
template <class T> inline Integer(T _name, int64_t val) :
Field(_name, SQLITE_INTEGER), value(val) {}
int64_t value;
virtual ~Integer() override = default;
};
struct Float : Field {
template <class T> inline Float(T _name, double val) :
Field(_name, SQLITE_FLOAT), value(val) {}
double value;
virtual ~Float() override = default;
};
struct Text : Field {
template <class T> inline Text(T _name, size_t len, const char* val) :
Field(_name, SQLITE_TEXT), value(val, len) {}
std::string value;
virtual ~Text() override = default;
};
struct Blob : Field {
template <class T> inline Blob(T _name, size_t len, const void* val) :
Field(_name, SQLITE_BLOB), length(len) {
value = new char[len];
assert(value != nullptr);
memcpy(value, val, len);
}
inline virtual ~Blob() override {
delete[] value;
}
int length;
char* value;
};
typedef Field Null;
}
typedef std::vector<std::unique_ptr<Values::Field> > Row;
typedef std::vector<std::unique_ptr<Row> > Rows;
typedef Row Parameters;
class Statement : public Napi::ObjectWrap<Statement> {
public:
static Napi::Object Init(Napi::Env env, Napi::Object exports);
static Napi::Value New(const Napi::CallbackInfo& info);
struct Baton {
napi_async_work request = NULL;
Statement* stmt;
Napi::FunctionReference callback;
Parameters parameters;
Baton(Statement* stmt_, Napi::Function cb_) : stmt(stmt_) {
stmt->Ref();
callback.Reset(cb_, 1);
}
virtual ~Baton() {
parameters.clear();
if (request) napi_delete_async_work(stmt->Env(), request);
stmt->Unref();
callback.Reset();
}
};
struct RowBaton : Baton {
RowBaton(Statement* stmt_, Napi::Function cb_) :
Baton(stmt_, cb_) {}
Row row;
virtual ~RowBaton() override = default;
};
struct RunBaton : Baton {
RunBaton(Statement* stmt_, Napi::Function cb_) :
Baton(stmt_, cb_), inserted_id(0), changes(0) {}
sqlite3_int64 inserted_id;
int changes;
virtual ~RunBaton() override = default;
};
struct RowsBaton : Baton {
RowsBaton(Statement* stmt_, Napi::Function cb_) :
Baton(stmt_, cb_) {}
Rows rows;
virtual ~RowsBaton() override = default;
};
struct Async;
struct EachBaton : Baton {
Napi::FunctionReference completed;
Async* async; // Isn't deleted when the baton is deleted.
EachBaton(Statement* stmt_, Napi::Function cb_) :
Baton(stmt_, cb_) {}
virtual ~EachBaton() override {
completed.Reset();
}
};
struct PrepareBaton : Database::Baton {
Statement* stmt;
std::string sql;
PrepareBaton(Database* db_, Napi::Function cb_, Statement* stmt_) :
Baton(db_, cb_), stmt(stmt_) {
stmt->Ref();
}
virtual ~PrepareBaton() override {
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.
Napi::FunctionReference item_cb;
Napi::FunctionReference 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_loop_t *loop;
napi_get_uv_event_loop(stmt->Env(), &loop);
uv_async_init(loop, &watcher, async_cb);
}
~Async() {
stmt->Unref();
item_cb.Reset();
completed_cb.Reset();
NODE_SQLITE3_MUTEX_DESTROY
}
};
Statement(const Napi::CallbackInfo& info);
~Statement() {
if (!finalized) Finalize_();
}
WORK_DEFINITION(Bind)
WORK_DEFINITION(Get)
WORK_DEFINITION(Run)
WORK_DEFINITION(All)
WORK_DEFINITION(Each)
WORK_DEFINITION(Reset)
Napi::Value Finalize_(const Napi::CallbackInfo& info);
protected:
static void Work_BeginPrepare(Database::Baton* baton);
static void Work_Prepare(napi_env env, void* data);
static void Work_AfterPrepare(napi_env env, napi_status status, void* data);
static void AsyncEach(uv_async_t* handle);
static void CloseCallback(uv_handle_t* handle);
static void Finalize_(Baton* baton);
void Finalize_();
template <class T> inline std::unique_ptr<Values::Field> BindParameter(const Napi::Value source, T pos);
template <class T> T* Bind(const Napi::CallbackInfo& info, int start = 0, int end = -1);
bool Bind(const Parameters ¶meters);
static void GetRow(Row* row, sqlite3_stmt* stmt);
static Napi::Value RowToJS(Napi::Env env, Row* row);
void Schedule(Work_Callback callback, Baton* baton);
void Process();
void CleanQueue();
template <class T> static void Error(T* baton);
protected:
Database* db;
sqlite3_stmt* _handle = NULL;
int status = SQLITE_OK;
bool prepared = false;
bool locked = true;
bool finalized = false;
std::queue<Call*> queue;
std::string message;
};
}
#endif
|