UNPKG

6.78 kBtext/x-cView Raw
1#ifndef NODE_SQLITE3_SRC_STATEMENT_H
2#define NODE_SQLITE3_SRC_STATEMENT_H
3
4#include <cstdlib>
5#include <cstring>
6#include <string>
7#include <queue>
8#include <vector>
9#include <sqlite3.h>
10#include <napi.h>
11#include <uv.h>
12
13#include "database.h"
14#include "threading.h"
15
16using namespace Napi;
17
18namespace node_sqlite3 {
19
20namespace Values {
21 struct Field {
22 inline Field(unsigned short _index, unsigned short _type = SQLITE_NULL) :
23 type(_type), index(_index) {}
24 inline Field(const char* _name, unsigned short _type = SQLITE_NULL) :
25 type(_type), index(0), name(_name) {}
26
27 unsigned short type;
28 unsigned short index;
29 std::string name;
30
31 virtual ~Field() = default;
32 };
33
34 struct Integer : Field {
35 template <class T> inline Integer(T _name, int64_t val) :
36 Field(_name, SQLITE_INTEGER), value(val) {}
37 int64_t value;
38 virtual ~Integer() override = default;
39 };
40
41 struct Float : Field {
42 template <class T> inline Float(T _name, double val) :
43 Field(_name, SQLITE_FLOAT), value(val) {}
44 double value;
45 virtual ~Float() override = default;
46 };
47
48 struct Text : Field {
49 template <class T> inline Text(T _name, size_t len, const char* val) :
50 Field(_name, SQLITE_TEXT), value(val, len) {}
51 std::string value;
52 virtual ~Text() override = default;
53 };
54
55 struct Blob : Field {
56 template <class T> inline Blob(T _name, size_t len, const void* val) :
57 Field(_name, SQLITE_BLOB), length(len) {
58 value = new char[len];
59 assert(value != nullptr);
60 memcpy(value, val, len);
61 }
62 inline virtual ~Blob() override {
63 delete[] value;
64 }
65 int length;
66 char* value;
67 };
68
69 typedef Field Null;
70}
71
72typedef std::vector<std::unique_ptr<Values::Field> > Row;
73typedef std::vector<std::unique_ptr<Row> > Rows;
74typedef Row Parameters;
75
76
77
78class Statement : public Napi::ObjectWrap<Statement> {
79public:
80 static Napi::Object Init(Napi::Env env, Napi::Object exports);
81 static Napi::Value New(const Napi::CallbackInfo& info);
82
83 struct Baton {
84 napi_async_work request = NULL;
85 Statement* stmt;
86 Napi::FunctionReference callback;
87 Parameters parameters;
88
89 Baton(Statement* stmt_, Napi::Function cb_) : stmt(stmt_) {
90 stmt->Ref();
91 callback.Reset(cb_, 1);
92 }
93 virtual ~Baton() {
94 parameters.clear();
95 if (request) napi_delete_async_work(stmt->Env(), request);
96 stmt->Unref();
97 callback.Reset();
98 }
99 };
100
101 struct RowBaton : Baton {
102 RowBaton(Statement* stmt_, Napi::Function cb_) :
103 Baton(stmt_, cb_) {}
104 Row row;
105 virtual ~RowBaton() override = default;
106 };
107
108 struct RunBaton : Baton {
109 RunBaton(Statement* stmt_, Napi::Function cb_) :
110 Baton(stmt_, cb_), inserted_id(0), changes(0) {}
111 sqlite3_int64 inserted_id;
112 int changes;
113 virtual ~RunBaton() override = default;
114 };
115
116 struct RowsBaton : Baton {
117 RowsBaton(Statement* stmt_, Napi::Function cb_) :
118 Baton(stmt_, cb_) {}
119 Rows rows;
120 virtual ~RowsBaton() override = default;
121 };
122
123 struct Async;
124
125 struct EachBaton : Baton {
126 Napi::FunctionReference completed;
127 Async* async; // Isn't deleted when the baton is deleted.
128
129 EachBaton(Statement* stmt_, Napi::Function cb_) :
130 Baton(stmt_, cb_) {}
131 virtual ~EachBaton() override {
132 completed.Reset();
133 }
134 };
135
136 struct PrepareBaton : Database::Baton {
137 Statement* stmt;
138 std::string sql;
139 PrepareBaton(Database* db_, Napi::Function cb_, Statement* stmt_) :
140 Baton(db_, cb_), stmt(stmt_) {
141 stmt->Ref();
142 }
143 virtual ~PrepareBaton() override {
144 stmt->Unref();
145 if (!db->IsOpen() && db->IsLocked()) {
146 // The database handle was closed before the statement could be
147 // prepared.
148 stmt->Finalize_();
149 }
150 }
151 };
152
153 typedef void (*Work_Callback)(Baton* baton);
154
155 struct Call {
156 Call(Work_Callback cb_, Baton* baton_) : callback(cb_), baton(baton_) {};
157 Work_Callback callback;
158 Baton* baton;
159 };
160
161 struct Async {
162 uv_async_t watcher;
163 Statement* stmt;
164 Rows data;
165 NODE_SQLITE3_MUTEX_t;
166 bool completed;
167 int retrieved;
168
169 // Store the callbacks here because we don't have
170 // access to the baton in the async callback.
171 Napi::FunctionReference item_cb;
172 Napi::FunctionReference completed_cb;
173
174 Async(Statement* st, uv_async_cb async_cb) :
175 stmt(st), completed(false), retrieved(0) {
176 watcher.data = this;
177 NODE_SQLITE3_MUTEX_INIT
178 stmt->Ref();
179 uv_loop_t *loop;
180 napi_get_uv_event_loop(stmt->Env(), &loop);
181 uv_async_init(loop, &watcher, async_cb);
182 }
183
184 ~Async() {
185 stmt->Unref();
186 item_cb.Reset();
187 completed_cb.Reset();
188 NODE_SQLITE3_MUTEX_DESTROY
189 }
190 };
191
192 Statement(const Napi::CallbackInfo& info);
193
194 ~Statement() {
195 if (!finalized) Finalize_();
196 }
197
198 WORK_DEFINITION(Bind)
199 WORK_DEFINITION(Get)
200 WORK_DEFINITION(Run)
201 WORK_DEFINITION(All)
202 WORK_DEFINITION(Each)
203 WORK_DEFINITION(Reset)
204
205 Napi::Value Finalize_(const Napi::CallbackInfo& info);
206
207protected:
208 static void Work_BeginPrepare(Database::Baton* baton);
209 static void Work_Prepare(napi_env env, void* data);
210 static void Work_AfterPrepare(napi_env env, napi_status status, void* data);
211
212 static void AsyncEach(uv_async_t* handle);
213 static void CloseCallback(uv_handle_t* handle);
214
215 static void Finalize_(Baton* baton);
216 void Finalize_();
217
218 template <class T> inline std::unique_ptr<Values::Field> BindParameter(const Napi::Value source, T pos);
219 template <class T> T* Bind(const Napi::CallbackInfo& info, int start = 0, int end = -1);
220 bool Bind(const Parameters &parameters);
221
222 static void GetRow(Row* row, sqlite3_stmt* stmt);
223 static Napi::Value RowToJS(Napi::Env env, Row* row);
224 void Schedule(Work_Callback callback, Baton* baton);
225 void Process();
226 void CleanQueue();
227 template <class T> static void Error(T* baton);
228
229protected:
230 Database* db;
231
232 sqlite3_stmt* _handle = NULL;
233 int status = SQLITE_OK;
234 bool prepared = false;
235 bool locked = true;
236 bool finalized = false;
237
238 std::queue<Call*> queue;
239 std::string message;
240};
241
242}
243
244#endif