better-sqlite3-multiple-ciphers 12.1.1 → 12.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,120 @@
1
+ Backup::Backup(
2
+ Database* db,
3
+ sqlite3* dest_handle,
4
+ sqlite3_backup* backup_handle,
5
+ sqlite3_uint64 id,
6
+ bool unlink
7
+ ) :
8
+ node::ObjectWrap(),
9
+ db(db),
10
+ dest_handle(dest_handle),
11
+ backup_handle(backup_handle),
12
+ id(id),
13
+ alive(true),
14
+ unlink(unlink) {
15
+ assert(db != NULL);
16
+ assert(dest_handle != NULL);
17
+ assert(backup_handle != NULL);
18
+ db->AddBackup(this);
19
+ }
20
+
21
+ Backup::~Backup() {
22
+ if (alive) db->RemoveBackup(this);
23
+ CloseHandles();
24
+ }
25
+
26
+ // Whenever this is used, db->RemoveBackup must be invoked beforehand.
27
+ void Backup::CloseHandles() {
28
+ if (alive) {
29
+ alive = false;
30
+ std::string filename(sqlite3_db_filename(dest_handle, "main"));
31
+ sqlite3_backup_finish(backup_handle);
32
+ int status = sqlite3_close(dest_handle);
33
+ assert(status == SQLITE_OK); ((void)status);
34
+ if (unlink) remove(filename.c_str());
35
+ }
36
+ }
37
+
38
+ INIT(Backup::Init) {
39
+ v8::Local<v8::FunctionTemplate> t = NewConstructorTemplate(isolate, data, JS_new, "Backup");
40
+ SetPrototypeMethod(isolate, data, t, "transfer", JS_transfer);
41
+ SetPrototypeMethod(isolate, data, t, "close", JS_close);
42
+ return t->GetFunction(OnlyContext).ToLocalChecked();
43
+ }
44
+
45
+ NODE_METHOD(Backup::JS_new) {
46
+ UseAddon;
47
+ if (!addon->privileged_info) return ThrowTypeError("Disabled constructor");
48
+ assert(info.IsConstructCall());
49
+ Database* db = Unwrap<Database>(addon->privileged_info->This());
50
+ REQUIRE_DATABASE_OPEN(db->GetState());
51
+ REQUIRE_DATABASE_NOT_BUSY(db->GetState());
52
+
53
+ v8::Local<v8::Object> database = (*addon->privileged_info)[0].As<v8::Object>();
54
+ v8::Local<v8::String> attachedName = (*addon->privileged_info)[1].As<v8::String>();
55
+ v8::Local<v8::String> destFile = (*addon->privileged_info)[2].As<v8::String>();
56
+ bool unlink = (*addon->privileged_info)[3].As<v8::Boolean>()->Value();
57
+
58
+ UseIsolate;
59
+ sqlite3* dest_handle;
60
+ v8::String::Utf8Value dest_file(isolate, destFile);
61
+ v8::String::Utf8Value attached_name(isolate, attachedName);
62
+ int mask = (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
63
+
64
+ if (sqlite3_open_v2(*dest_file, &dest_handle, mask, NULL) != SQLITE_OK) {
65
+ Database::ThrowSqliteError(addon, dest_handle);
66
+ int status = sqlite3_close(dest_handle);
67
+ assert(status == SQLITE_OK); ((void)status);
68
+ return;
69
+ }
70
+
71
+ sqlite3_extended_result_codes(dest_handle, 1);
72
+ sqlite3_limit(dest_handle, SQLITE_LIMIT_LENGTH, INT_MAX);
73
+ sqlite3_backup* backup_handle = sqlite3_backup_init(dest_handle, "main", db->GetHandle(), *attached_name);
74
+ if (backup_handle == NULL) {
75
+ Database::ThrowSqliteError(addon, dest_handle);
76
+ int status = sqlite3_close(dest_handle);
77
+ assert(status == SQLITE_OK); ((void)status);
78
+ return;
79
+ }
80
+
81
+ Backup* backup = new Backup(db, dest_handle, backup_handle, addon->NextId(), unlink);
82
+ backup->Wrap(info.This());
83
+ SetFrozen(isolate, OnlyContext, info.This(), addon->cs.database, database);
84
+
85
+ info.GetReturnValue().Set(info.This());
86
+ }
87
+
88
+ NODE_METHOD(Backup::JS_transfer) {
89
+ Backup* backup = Unwrap<Backup>(info.This());
90
+ REQUIRE_ARGUMENT_INT32(first, int pages);
91
+ REQUIRE_DATABASE_OPEN(backup->db->GetState());
92
+ assert(backup->db->GetState()->busy == false);
93
+ assert(backup->alive == true);
94
+
95
+ sqlite3_backup* backup_handle = backup->backup_handle;
96
+ int status = sqlite3_backup_step(backup_handle, pages) & 0xff;
97
+
98
+ Addon* addon = backup->db->GetAddon();
99
+ if (status == SQLITE_OK || status == SQLITE_DONE || status == SQLITE_BUSY) {
100
+ int total_pages = sqlite3_backup_pagecount(backup_handle);
101
+ int remaining_pages = sqlite3_backup_remaining(backup_handle);
102
+ UseIsolate;
103
+ UseContext;
104
+ v8::Local<v8::Object> result = v8::Object::New(isolate);
105
+ result->Set(ctx, addon->cs.totalPages.Get(isolate), v8::Int32::New(isolate, total_pages)).FromJust();
106
+ result->Set(ctx, addon->cs.remainingPages.Get(isolate), v8::Int32::New(isolate, remaining_pages)).FromJust();
107
+ info.GetReturnValue().Set(result);
108
+ if (status == SQLITE_DONE) backup->unlink = false;
109
+ } else {
110
+ Database::ThrowSqliteError(addon, sqlite3_errstr(status), status);
111
+ }
112
+ }
113
+
114
+ NODE_METHOD(Backup::JS_close) {
115
+ Backup* backup = Unwrap<Backup>(info.This());
116
+ assert(backup->db->GetState()->busy == false);
117
+ if (backup->alive) backup->db->RemoveBackup(backup);
118
+ backup->CloseHandles();
119
+ info.GetReturnValue().Set(info.This());
120
+ }
@@ -0,0 +1,36 @@
1
+ class Backup : public node::ObjectWrap {
2
+ public:
3
+
4
+ ~Backup();
5
+
6
+ // Whenever this is used, db->RemoveBackup must be invoked beforehand.
7
+ void CloseHandles();
8
+
9
+ // Used to support ordered containers.
10
+ static inline bool Compare(Backup const * const a, Backup const * const b) {
11
+ return a->id < b->id;
12
+ }
13
+
14
+ static INIT(Init);
15
+
16
+ private:
17
+
18
+ explicit Backup(
19
+ Database* db,
20
+ sqlite3* dest_handle,
21
+ sqlite3_backup* backup_handle,
22
+ sqlite3_uint64 id,
23
+ bool unlink
24
+ );
25
+
26
+ static NODE_METHOD(JS_new);
27
+ static NODE_METHOD(JS_transfer);
28
+ static NODE_METHOD(JS_close);
29
+
30
+ Database* const db;
31
+ sqlite3* const dest_handle;
32
+ sqlite3_backup* const backup_handle;
33
+ const sqlite3_uint64 id;
34
+ bool alive;
35
+ bool unlink;
36
+ };
@@ -0,0 +1,457 @@
1
+ const int Database::MAX_BUFFER_SIZE = (
2
+ node::Buffer::kMaxLength > INT_MAX
3
+ ? INT_MAX
4
+ : static_cast<int>(node::Buffer::kMaxLength)
5
+ );
6
+
7
+ const int Database::MAX_STRING_SIZE = (
8
+ v8::String::kMaxLength > INT_MAX
9
+ ? INT_MAX
10
+ : static_cast<int>(v8::String::kMaxLength)
11
+ );
12
+
13
+ Database::Database(
14
+ v8::Isolate* isolate,
15
+ Addon* addon,
16
+ sqlite3* db_handle,
17
+ v8::Local<v8::Value> logger
18
+ ) :
19
+ node::ObjectWrap(),
20
+ db_handle(db_handle),
21
+ open(true),
22
+ busy(false),
23
+ safe_ints(false),
24
+ unsafe_mode(false),
25
+ was_js_error(false),
26
+ has_logger(logger->IsFunction()),
27
+ iterators(0),
28
+ addon(addon),
29
+ logger(isolate, logger),
30
+ stmts(),
31
+ backups() {
32
+ assert(db_handle != NULL);
33
+ addon->dbs.insert(this);
34
+ }
35
+
36
+ Database::~Database() {
37
+ if (open) addon->dbs.erase(this);
38
+ CloseHandles();
39
+ }
40
+
41
+ // Whenever this is used, addon->dbs.erase() must be invoked beforehand.
42
+ void Database::CloseHandles() {
43
+ if (open) {
44
+ open = false;
45
+ for (Statement* stmt : stmts) stmt->CloseHandles();
46
+ for (Backup* backup : backups) backup->CloseHandles();
47
+ stmts.clear();
48
+ backups.clear();
49
+ int status = sqlite3_close(db_handle);
50
+ assert(status == SQLITE_OK); ((void)status);
51
+ }
52
+ }
53
+
54
+ void Database::ThrowDatabaseError() {
55
+ if (was_js_error) was_js_error = false;
56
+ else ThrowSqliteError(addon, db_handle);
57
+ }
58
+
59
+ void Database::ThrowSqliteError(Addon* addon, sqlite3* db_handle) {
60
+ assert(db_handle != NULL);
61
+ ThrowSqliteError(addon, sqlite3_errmsg(db_handle), sqlite3_extended_errcode(db_handle));
62
+ }
63
+
64
+ void Database::ThrowSqliteError(Addon* addon, const char* message, int code) {
65
+ assert(message != NULL);
66
+ assert((code & 0xff) != SQLITE_OK);
67
+ assert((code & 0xff) != SQLITE_ROW);
68
+ assert((code & 0xff) != SQLITE_DONE);
69
+ EasyIsolate;
70
+ v8::Local<v8::Value> args[2] = {
71
+ StringFromUtf8(isolate, message, -1),
72
+ addon->cs.Code(isolate, code)
73
+ };
74
+ isolate->ThrowException(addon->SqliteError.Get(isolate)
75
+ ->NewInstance(OnlyContext, 2, args)
76
+ .ToLocalChecked());
77
+ }
78
+
79
+ // Allows Statements to log their executed SQL.
80
+ bool Database::Log(v8::Isolate* isolate, sqlite3_stmt* handle) {
81
+ assert(was_js_error == false);
82
+ if (!has_logger) return false;
83
+ char* expanded = sqlite3_expanded_sql(handle);
84
+ v8::Local<v8::Value> arg = StringFromUtf8(isolate, expanded ? expanded : sqlite3_sql(handle), -1);
85
+ was_js_error = logger.Get(isolate).As<v8::Function>()
86
+ ->Call(OnlyContext, v8::Undefined(isolate), 1, &arg)
87
+ .IsEmpty();
88
+ if (expanded) sqlite3_free(expanded);
89
+ return was_js_error;
90
+ }
91
+
92
+ bool Database::Deserialize(
93
+ v8::Local<v8::Object> buffer,
94
+ Addon* addon,
95
+ sqlite3* db_handle,
96
+ bool readonly
97
+ ) {
98
+ size_t length = node::Buffer::Length(buffer);
99
+ unsigned char* data = (unsigned char*)sqlite3_malloc64(length);
100
+ unsigned int flags = SQLITE_DESERIALIZE_FREEONCLOSE | SQLITE_DESERIALIZE_RESIZEABLE;
101
+
102
+ if (readonly) {
103
+ flags |= SQLITE_DESERIALIZE_READONLY;
104
+ }
105
+ if (length) {
106
+ if (!data) {
107
+ ThrowError("Out of memory");
108
+ return false;
109
+ }
110
+ memcpy(data, node::Buffer::Data(buffer), length);
111
+ }
112
+
113
+ int status = sqlite3_deserialize(db_handle, "main", data, length, length, flags);
114
+ if (status != SQLITE_OK) {
115
+ ThrowSqliteError(addon, status == SQLITE_ERROR ? "unable to deserialize database" : sqlite3_errstr(status), status);
116
+ return false;
117
+ }
118
+
119
+ return true;
120
+ }
121
+
122
+ void Database::FreeSerialization(char* data, void* _) {
123
+ sqlite3_free(data);
124
+ }
125
+
126
+ INIT(Database::Init) {
127
+ v8::Local<v8::FunctionTemplate> t = NewConstructorTemplate(isolate, data, JS_new, "Database");
128
+ SetPrototypeMethod(isolate, data, t, "prepare", JS_prepare);
129
+ SetPrototypeMethod(isolate, data, t, "key", JS_key);
130
+ SetPrototypeMethod(isolate, data, t, "rekey", JS_rekey);
131
+ SetPrototypeMethod(isolate, data, t, "exec", JS_exec);
132
+ SetPrototypeMethod(isolate, data, t, "backup", JS_backup);
133
+ SetPrototypeMethod(isolate, data, t, "serialize", JS_serialize);
134
+ SetPrototypeMethod(isolate, data, t, "function", JS_function);
135
+ SetPrototypeMethod(isolate, data, t, "aggregate", JS_aggregate);
136
+ SetPrototypeMethod(isolate, data, t, "table", JS_table);
137
+ SetPrototypeMethod(isolate, data, t, "loadExtension", JS_loadExtension);
138
+ SetPrototypeMethod(isolate, data, t, "close", JS_close);
139
+ SetPrototypeMethod(isolate, data, t, "defaultSafeIntegers", JS_defaultSafeIntegers);
140
+ SetPrototypeMethod(isolate, data, t, "unsafeMode", JS_unsafeMode);
141
+ SetPrototypeGetter(isolate, data, t, "open", JS_open);
142
+ SetPrototypeGetter(isolate, data, t, "inTransaction", JS_inTransaction);
143
+ return t->GetFunction(OnlyContext).ToLocalChecked();
144
+ }
145
+
146
+ NODE_METHOD(Database::JS_new) {
147
+ assert(info.IsConstructCall());
148
+ REQUIRE_ARGUMENT_STRING(first, v8::Local<v8::String> filename);
149
+ REQUIRE_ARGUMENT_STRING(second, v8::Local<v8::String> filenameGiven);
150
+ REQUIRE_ARGUMENT_BOOLEAN(third, bool in_memory);
151
+ REQUIRE_ARGUMENT_BOOLEAN(fourth, bool readonly);
152
+ REQUIRE_ARGUMENT_BOOLEAN(fifth, bool must_exist);
153
+ REQUIRE_ARGUMENT_INT32(sixth, int timeout);
154
+ REQUIRE_ARGUMENT_ANY(seventh, v8::Local<v8::Value> logger);
155
+ REQUIRE_ARGUMENT_ANY(eighth, v8::Local<v8::Value> buffer);
156
+
157
+ UseAddon;
158
+ UseIsolate;
159
+ sqlite3* db_handle;
160
+ v8::String::Utf8Value utf8(isolate, filename);
161
+ int mask = readonly ? SQLITE_OPEN_READONLY
162
+ : must_exist ? SQLITE_OPEN_READWRITE
163
+ : (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
164
+
165
+ if (sqlite3_open_v2(*utf8, &db_handle, mask, NULL) != SQLITE_OK) {
166
+ ThrowSqliteError(addon, db_handle);
167
+ int status = sqlite3_close(db_handle);
168
+ assert(status == SQLITE_OK); ((void)status);
169
+ return;
170
+ }
171
+
172
+ assert(sqlite3_db_mutex(db_handle) == NULL);
173
+ sqlite3_extended_result_codes(db_handle, 1);
174
+ sqlite3_busy_timeout(db_handle, timeout);
175
+ sqlite3_limit(db_handle, SQLITE_LIMIT_LENGTH, MAX_BUFFER_SIZE < MAX_STRING_SIZE ? MAX_BUFFER_SIZE : MAX_STRING_SIZE);
176
+ sqlite3_limit(db_handle, SQLITE_LIMIT_SQL_LENGTH, MAX_STRING_SIZE);
177
+ int status = sqlite3_db_config(db_handle, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1, NULL);
178
+ assert(status == SQLITE_OK); ((void)status);
179
+ status = sqlite3_db_config(db_handle, SQLITE_DBCONFIG_DEFENSIVE, 1, NULL);
180
+ assert(status == SQLITE_OK); ((void)status);
181
+
182
+ if (node::Buffer::HasInstance(buffer) && !Deserialize(buffer.As<v8::Object>(), addon, db_handle, readonly)) {
183
+ int status = sqlite3_close(db_handle);
184
+ assert(status == SQLITE_OK); ((void)status);
185
+ return;
186
+ }
187
+
188
+ UseContext;
189
+ Database* db = new Database(isolate, addon, db_handle, logger);
190
+ db->Wrap(info.This());
191
+ SetFrozen(isolate, ctx, info.This(), addon->cs.memory, v8::Boolean::New(isolate, in_memory));
192
+ SetFrozen(isolate, ctx, info.This(), addon->cs.readonly, v8::Boolean::New(isolate, readonly));
193
+ SetFrozen(isolate, ctx, info.This(), addon->cs.name, filenameGiven);
194
+
195
+ info.GetReturnValue().Set(info.This());
196
+ }
197
+
198
+ NODE_METHOD(Database::JS_prepare) {
199
+ REQUIRE_ARGUMENT_STRING(first, v8::Local<v8::String> source);
200
+ REQUIRE_ARGUMENT_OBJECT(second, v8::Local<v8::Object> database);
201
+ REQUIRE_ARGUMENT_BOOLEAN(third, bool pragmaMode);
202
+ (void)source;
203
+ (void)database;
204
+ (void)pragmaMode;
205
+ UseAddon;
206
+ UseIsolate;
207
+ v8::Local<v8::Function> c = addon->Statement.Get(isolate);
208
+ addon->privileged_info = &info;
209
+ v8::MaybeLocal<v8::Object> maybeStatement = c->NewInstance(OnlyContext, 0, NULL);
210
+ addon->privileged_info = NULL;
211
+ if (!maybeStatement.IsEmpty()) info.GetReturnValue().Set(maybeStatement.ToLocalChecked());
212
+ }
213
+
214
+ NODE_METHOD(Database::JS_key) {
215
+ Database* db = Unwrap<Database>(info.This());
216
+ REQUIRE_ARGUMENT_OBJECT(first, v8::Local<v8::Object> key);
217
+ REQUIRE_ARGUMENT_INT32(second, unsigned int len);
218
+ (void)key;
219
+ (void)len;
220
+ char* buffer = (char*) node::Buffer::Data(key);
221
+ REQUIRE_DATABASE_OPEN(db);
222
+ REQUIRE_DATABASE_NOT_BUSY(db);
223
+ sqlite3* const db_handle = db->db_handle;
224
+ int status = sqlite3_key(db_handle, buffer, len);
225
+ if (status != SQLITE_OK) {
226
+ db->ThrowSqliteError(db->addon, sqlite3_errstr(status), status);
227
+ }
228
+ else {
229
+ info.GetReturnValue().Set(status);
230
+ }
231
+ }
232
+
233
+ NODE_METHOD(Database::JS_rekey) {
234
+ Database* db = Unwrap<Database>(info.This());
235
+ REQUIRE_ARGUMENT_OBJECT(first, v8::Local<v8::Object> key);
236
+ REQUIRE_ARGUMENT_INT32(second, unsigned int len);
237
+ (void)key;
238
+ (void)len;
239
+ char* buffer = (char*) node::Buffer::Data(key);
240
+ REQUIRE_DATABASE_OPEN(db);
241
+ REQUIRE_DATABASE_NOT_BUSY(db);
242
+ sqlite3* const db_handle = db->db_handle;
243
+ int status = sqlite3_rekey(db_handle, buffer, len);
244
+ if (status != SQLITE_OK) {
245
+ db->ThrowSqliteError(db->addon, sqlite3_errstr(status), status);
246
+ }
247
+ else {
248
+ info.GetReturnValue().Set(status);
249
+ }
250
+ }
251
+
252
+ NODE_METHOD(Database::JS_exec) {
253
+ Database* db = Unwrap<Database>(info.This());
254
+ REQUIRE_ARGUMENT_STRING(first, v8::Local<v8::String> source);
255
+ REQUIRE_DATABASE_OPEN(db);
256
+ REQUIRE_DATABASE_NOT_BUSY(db);
257
+ REQUIRE_DATABASE_NO_ITERATORS_UNLESS_UNSAFE(db);
258
+ db->busy = true;
259
+
260
+ UseIsolate;
261
+ v8::String::Utf8Value utf8(isolate, source);
262
+ const char* sql = *utf8;
263
+ const char* tail;
264
+
265
+ int status;
266
+ const bool has_logger = db->has_logger;
267
+ sqlite3* const db_handle = db->db_handle;
268
+ sqlite3_stmt* handle;
269
+
270
+ for (;;) {
271
+ while (IS_SKIPPED(*sql)) ++sql;
272
+ status = sqlite3_prepare_v2(db_handle, sql, -1, &handle, &tail);
273
+ sql = tail;
274
+ if (!handle) break;
275
+ if (has_logger && db->Log(isolate, handle)) {
276
+ sqlite3_finalize(handle);
277
+ status = -1;
278
+ break;
279
+ }
280
+ do status = sqlite3_step(handle);
281
+ while (status == SQLITE_ROW);
282
+ status = sqlite3_finalize(handle);
283
+ if (status != SQLITE_OK) break;
284
+ }
285
+
286
+ db->busy = false;
287
+ if (status != SQLITE_OK) {
288
+ db->ThrowDatabaseError();
289
+ }
290
+ }
291
+
292
+ NODE_METHOD(Database::JS_backup) {
293
+ REQUIRE_ARGUMENT_OBJECT(first, v8::Local<v8::Object> database);
294
+ REQUIRE_ARGUMENT_STRING(second, v8::Local<v8::String> attachedName);
295
+ REQUIRE_ARGUMENT_STRING(third, v8::Local<v8::String> destFile);
296
+ REQUIRE_ARGUMENT_BOOLEAN(fourth, bool unlink);
297
+ (void)database;
298
+ (void)attachedName;
299
+ (void)destFile;
300
+ (void)unlink;
301
+ UseAddon;
302
+ UseIsolate;
303
+ v8::Local<v8::Function> c = addon->Backup.Get(isolate);
304
+ addon->privileged_info = &info;
305
+ v8::MaybeLocal<v8::Object> maybeBackup = c->NewInstance(OnlyContext, 0, NULL);
306
+ addon->privileged_info = NULL;
307
+ if (!maybeBackup.IsEmpty()) info.GetReturnValue().Set(maybeBackup.ToLocalChecked());
308
+ }
309
+
310
+ NODE_METHOD(Database::JS_serialize) {
311
+ Database* db = Unwrap<Database>(info.This());
312
+ REQUIRE_ARGUMENT_STRING(first, v8::Local<v8::String> attachedName);
313
+ REQUIRE_DATABASE_OPEN(db);
314
+ REQUIRE_DATABASE_NOT_BUSY(db);
315
+ REQUIRE_DATABASE_NO_ITERATORS(db);
316
+
317
+ UseIsolate;
318
+ v8::String::Utf8Value attached_name(isolate, attachedName);
319
+ sqlite3_int64 length = -1;
320
+ unsigned char* data = sqlite3_serialize(db->db_handle, *attached_name, &length, 0);
321
+
322
+ if (!data && length) {
323
+ ThrowError("Out of memory");
324
+ return;
325
+ }
326
+
327
+ info.GetReturnValue().Set(
328
+ SAFE_NEW_BUFFER(isolate, reinterpret_cast<char*>(data), length, FreeSerialization, NULL).ToLocalChecked()
329
+ );
330
+ }
331
+
332
+ NODE_METHOD(Database::JS_function) {
333
+ Database* db = Unwrap<Database>(info.This());
334
+ REQUIRE_ARGUMENT_FUNCTION(first, v8::Local<v8::Function> fn);
335
+ REQUIRE_ARGUMENT_STRING(second, v8::Local<v8::String> nameString);
336
+ REQUIRE_ARGUMENT_INT32(third, int argc);
337
+ REQUIRE_ARGUMENT_INT32(fourth, int safe_ints);
338
+ REQUIRE_ARGUMENT_BOOLEAN(fifth, bool deterministic);
339
+ REQUIRE_ARGUMENT_BOOLEAN(sixth, bool direct_only);
340
+ REQUIRE_DATABASE_OPEN(db);
341
+ REQUIRE_DATABASE_NOT_BUSY(db);
342
+ REQUIRE_DATABASE_NO_ITERATORS(db);
343
+
344
+ UseIsolate;
345
+ v8::String::Utf8Value name(isolate, nameString);
346
+ int mask = SQLITE_UTF8;
347
+ if (deterministic) mask |= SQLITE_DETERMINISTIC;
348
+ if (direct_only) mask |= SQLITE_DIRECTONLY;
349
+ safe_ints = safe_ints < 2 ? safe_ints : static_cast<int>(db->safe_ints);
350
+
351
+ if (sqlite3_create_function_v2(db->db_handle, *name, argc, mask, new CustomFunction(isolate, db, *name, fn, safe_ints), CustomFunction::xFunc, NULL, NULL, CustomFunction::xDestroy) != SQLITE_OK) {
352
+ db->ThrowDatabaseError();
353
+ }
354
+ }
355
+
356
+ NODE_METHOD(Database::JS_aggregate) {
357
+ Database* db = Unwrap<Database>(info.This());
358
+ REQUIRE_ARGUMENT_ANY(first, v8::Local<v8::Value> start);
359
+ REQUIRE_ARGUMENT_FUNCTION(second, v8::Local<v8::Function> step);
360
+ REQUIRE_ARGUMENT_ANY(third, v8::Local<v8::Value> inverse);
361
+ REQUIRE_ARGUMENT_ANY(fourth, v8::Local<v8::Value> result);
362
+ REQUIRE_ARGUMENT_STRING(fifth, v8::Local<v8::String> nameString);
363
+ REQUIRE_ARGUMENT_INT32(sixth, int argc);
364
+ REQUIRE_ARGUMENT_INT32(seventh, int safe_ints);
365
+ REQUIRE_ARGUMENT_BOOLEAN(eighth, bool deterministic);
366
+ REQUIRE_ARGUMENT_BOOLEAN(ninth, bool direct_only);
367
+ REQUIRE_DATABASE_OPEN(db);
368
+ REQUIRE_DATABASE_NOT_BUSY(db);
369
+ REQUIRE_DATABASE_NO_ITERATORS(db);
370
+
371
+ UseIsolate;
372
+ v8::String::Utf8Value name(isolate, nameString);
373
+ auto xInverse = inverse->IsFunction() ? CustomAggregate::xInverse : NULL;
374
+ auto xValue = xInverse ? CustomAggregate::xValue : NULL;
375
+ int mask = SQLITE_UTF8;
376
+ if (deterministic) mask |= SQLITE_DETERMINISTIC;
377
+ if (direct_only) mask |= SQLITE_DIRECTONLY;
378
+ safe_ints = safe_ints < 2 ? safe_ints : static_cast<int>(db->safe_ints);
379
+
380
+ if (sqlite3_create_window_function(db->db_handle, *name, argc, mask, new CustomAggregate(isolate, db, *name, start, step, inverse, result, safe_ints), CustomAggregate::xStep, CustomAggregate::xFinal, xValue, xInverse, CustomAggregate::xDestroy) != SQLITE_OK) {
381
+ db->ThrowDatabaseError();
382
+ }
383
+ }
384
+
385
+ NODE_METHOD(Database::JS_table) {
386
+ Database* db = Unwrap<Database>(info.This());
387
+ REQUIRE_ARGUMENT_FUNCTION(first, v8::Local<v8::Function> factory);
388
+ REQUIRE_ARGUMENT_STRING(second, v8::Local<v8::String> nameString);
389
+ REQUIRE_ARGUMENT_BOOLEAN(third, bool eponymous);
390
+ REQUIRE_DATABASE_OPEN(db);
391
+ REQUIRE_DATABASE_NOT_BUSY(db);
392
+ REQUIRE_DATABASE_NO_ITERATORS(db);
393
+
394
+ UseIsolate;
395
+ v8::String::Utf8Value name(isolate, nameString);
396
+ sqlite3_module* module = eponymous ? &CustomTable::EPONYMOUS_MODULE : &CustomTable::MODULE;
397
+
398
+ db->busy = true;
399
+ if (sqlite3_create_module_v2(db->db_handle, *name, module, new CustomTable(isolate, db, *name, factory), CustomTable::Destructor) != SQLITE_OK) {
400
+ db->ThrowDatabaseError();
401
+ }
402
+ db->busy = false;
403
+ }
404
+
405
+ NODE_METHOD(Database::JS_loadExtension) {
406
+ Database* db = Unwrap<Database>(info.This());
407
+ v8::Local<v8::String> entryPoint;
408
+ REQUIRE_ARGUMENT_STRING(first, v8::Local<v8::String> filename);
409
+ if (info.Length() > 1) { REQUIRE_ARGUMENT_STRING(second, entryPoint); }
410
+ REQUIRE_DATABASE_OPEN(db);
411
+ REQUIRE_DATABASE_NOT_BUSY(db);
412
+ REQUIRE_DATABASE_NO_ITERATORS(db);
413
+ UseIsolate;
414
+ char* error;
415
+ int status = sqlite3_load_extension(
416
+ db->db_handle,
417
+ *v8::String::Utf8Value(isolate, filename),
418
+ entryPoint.IsEmpty() ? NULL : *v8::String::Utf8Value(isolate, entryPoint),
419
+ &error
420
+ );
421
+ if (status != SQLITE_OK) {
422
+ ThrowSqliteError(db->addon, error, status);
423
+ }
424
+ sqlite3_free(error);
425
+ }
426
+
427
+ NODE_METHOD(Database::JS_close) {
428
+ Database* db = Unwrap<Database>(info.This());
429
+ if (db->open) {
430
+ REQUIRE_DATABASE_NOT_BUSY(db);
431
+ REQUIRE_DATABASE_NO_ITERATORS(db);
432
+ db->addon->dbs.erase(db);
433
+ db->CloseHandles();
434
+ }
435
+ }
436
+
437
+ NODE_METHOD(Database::JS_defaultSafeIntegers) {
438
+ Database* db = Unwrap<Database>(info.This());
439
+ if (info.Length() == 0) db->safe_ints = true;
440
+ else { REQUIRE_ARGUMENT_BOOLEAN(first, db->safe_ints); }
441
+ }
442
+
443
+ NODE_METHOD(Database::JS_unsafeMode) {
444
+ Database* db = Unwrap<Database>(info.This());
445
+ if (info.Length() == 0) db->unsafe_mode = true;
446
+ else { REQUIRE_ARGUMENT_BOOLEAN(first, db->unsafe_mode); }
447
+ sqlite3_db_config(db->db_handle, SQLITE_DBCONFIG_DEFENSIVE, static_cast<int>(!db->unsafe_mode), NULL);
448
+ }
449
+
450
+ NODE_GETTER(Database::JS_open) {
451
+ info.GetReturnValue().Set(Unwrap<Database>(info.This())->open);
452
+ }
453
+
454
+ NODE_GETTER(Database::JS_inTransaction) {
455
+ Database* db = Unwrap<Database>(info.This());
456
+ info.GetReturnValue().Set(db->open && !static_cast<bool>(sqlite3_get_autocommit(db->db_handle)));
457
+ }