better-sqlite3-multiple-ciphers 7.4.7-beta.1 → 7.5.0-beta.0

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.
Files changed (81) hide show
  1. package/README.md +1 -1
  2. package/deps/download.sh +111 -108
  3. package/deps/setup.ps1 +9 -11
  4. package/deps/sqlite3/sqlite3.c +272560 -0
  5. package/deps/sqlite3/sqlite3.h +12770 -0
  6. package/deps/sqlite3/sqlite3ext.h +675 -0
  7. package/deps/sqlite3.gyp +13 -7
  8. package/deps/symlink.js +7 -4
  9. package/lib/database.js +17 -6
  10. package/lib/sqlite-error.js +1 -2
  11. package/package.json +10 -4
  12. package/src/better_sqlite3.cpp +46 -35
  13. package/src/better_sqlite3.hpp +40 -38
  14. package/.gitattributes +0 -1
  15. package/.github/workflows/prebuild.yml +0 -49
  16. package/.github/workflows/test.yml +0 -59
  17. package/benchmark/benchmark.js +0 -31
  18. package/benchmark/drivers.js +0 -21
  19. package/benchmark/index.js +0 -83
  20. package/benchmark/seed.js +0 -47
  21. package/benchmark/trials.js +0 -65
  22. package/benchmark/types/insert.js +0 -16
  23. package/benchmark/types/select-all.js +0 -14
  24. package/benchmark/types/select-iterate.js +0 -23
  25. package/benchmark/types/select.js +0 -14
  26. package/benchmark/types/transaction.js +0 -40
  27. package/deps/extract.js +0 -16
  28. package/deps/sqlite3.tar.gz +0 -0
  29. package/docs/api.md +0 -645
  30. package/docs/benchmark.md +0 -38
  31. package/docs/compilation.md +0 -76
  32. package/docs/integer.md +0 -79
  33. package/docs/performance.md +0 -39
  34. package/docs/threads.md +0 -97
  35. package/docs/tips.md +0 -35
  36. package/docs/troubleshooting.md +0 -23
  37. package/docs/unsafe.md +0 -16
  38. package/src/better_sqlite3.lzz +0 -88
  39. package/src/objects/backup.lzz +0 -138
  40. package/src/objects/database.lzz +0 -468
  41. package/src/objects/statement-iterator.lzz +0 -138
  42. package/src/objects/statement.lzz +0 -323
  43. package/src/util/bind-map.lzz +0 -73
  44. package/src/util/binder.lzz +0 -190
  45. package/src/util/constants.lzz +0 -151
  46. package/src/util/custom-aggregate.lzz +0 -121
  47. package/src/util/custom-function.lzz +0 -59
  48. package/src/util/custom-table.lzz +0 -397
  49. package/src/util/data-converter.lzz +0 -17
  50. package/src/util/data.lzz +0 -145
  51. package/src/util/macros.lzz +0 -159
  52. package/src/util/query-macros.lzz +0 -71
  53. package/test/00.setup.js +0 -25
  54. package/test/01.sqlite-error.js +0 -27
  55. package/test/10.database.open.js +0 -159
  56. package/test/11.database.close.js +0 -68
  57. package/test/12.database.pragma.js +0 -65
  58. package/test/13.database.prepare.js +0 -60
  59. package/test/14.database.exec.js +0 -46
  60. package/test/20.statement.run.js +0 -170
  61. package/test/21.statement.get.js +0 -109
  62. package/test/22.statement.all.js +0 -129
  63. package/test/23.statement.iterate.js +0 -223
  64. package/test/24.statement.bind.js +0 -107
  65. package/test/25.statement.columns.js +0 -46
  66. package/test/30.database.transaction.js +0 -157
  67. package/test/31.database.checkpoint.js +0 -62
  68. package/test/32.database.function.js +0 -211
  69. package/test/33.database.aggregate.js +0 -603
  70. package/test/34.database.table.js +0 -671
  71. package/test/35.database.load-extension.js +0 -75
  72. package/test/36.database.backup.js +0 -240
  73. package/test/37.database.serialize.js +0 -81
  74. package/test/40.bigints.js +0 -145
  75. package/test/41.at-exit.js +0 -52
  76. package/test/42.integrity.js +0 -531
  77. package/test/43.verbose.js +0 -100
  78. package/test/44.worker-threads.js +0 -66
  79. package/test/45.unsafe-mode.js +0 -52
  80. package/test/46.encryption.js +0 -69
  81. package/test/50.misc.js +0 -44
@@ -1,323 +0,0 @@
1
- class Statement : public node::ObjectWrap { friend class StatementIterator;
2
- public:
3
-
4
- INIT(Init) {
5
- v8::Local<v8::FunctionTemplate> t = NewConstructorTemplate(isolate, data, JS_new, "Statement");
6
- SetPrototypeMethod(isolate, data, t, "run", JS_run);
7
- SetPrototypeMethod(isolate, data, t, "get", JS_get);
8
- SetPrototypeMethod(isolate, data, t, "all", JS_all);
9
- SetPrototypeMethod(isolate, data, t, "iterate", JS_iterate);
10
- SetPrototypeMethod(isolate, data, t, "bind", JS_bind);
11
- SetPrototypeMethod(isolate, data, t, "pluck", JS_pluck);
12
- SetPrototypeMethod(isolate, data, t, "expand", JS_expand);
13
- SetPrototypeMethod(isolate, data, t, "raw", JS_raw);
14
- SetPrototypeMethod(isolate, data, t, "safeIntegers", JS_safeIntegers);
15
- SetPrototypeMethod(isolate, data, t, "columns", JS_columns);
16
- return t->GetFunction(OnlyContext).ToLocalChecked();
17
- }
18
-
19
- // Used to support ordered containers.
20
- static inline bool Compare(Statement const * const a, Statement const * const b) {
21
- return a->extras->id < b->extras->id;
22
- }
23
-
24
- // Returns the Statement's bind map (creates it upon first execution).
25
- BindMap* GetBindMap(v8::Isolate* isolate) {
26
- if (has_bind_map) return &extras->bind_map;
27
- BindMap* bind_map = &extras->bind_map;
28
- int param_count = sqlite3_bind_parameter_count(handle);
29
- for (int i = 1; i <= param_count; ++i) {
30
- const char* name = sqlite3_bind_parameter_name(handle, i);
31
- if (name != NULL) bind_map->Add(isolate, name + 1, i);
32
- }
33
- has_bind_map = true;
34
- return bind_map;
35
- }
36
-
37
- // Whenever this is used, db->RemoveStatement must be invoked beforehand.
38
- void CloseHandles() {
39
- if (alive) {
40
- alive = false;
41
- sqlite3_finalize(handle);
42
- }
43
- }
44
-
45
- ~Statement() {
46
- if (alive) db->RemoveStatement(this);
47
- CloseHandles();
48
- delete extras;
49
- }
50
-
51
- private:
52
-
53
- // A class for holding values that are less often used.
54
- class Extras { friend class Statement;
55
- explicit Extras(sqlite3_uint64 id) : bind_map(0), id(id) {}
56
- BindMap bind_map;
57
- const sqlite3_uint64 id;
58
- };
59
-
60
- explicit Statement(
61
- Database* db,
62
- sqlite3_stmt* handle,
63
- sqlite3_uint64 id,
64
- bool returns_data
65
- ) :
66
- node::ObjectWrap(),
67
- db(db),
68
- handle(handle),
69
- extras(new Extras(id)),
70
- alive(true),
71
- locked(false),
72
- bound(false),
73
- has_bind_map(false),
74
- safe_ints(db->GetState()->safe_ints),
75
- mode(Data::FLAT),
76
- returns_data(returns_data) {
77
- assert(db != NULL);
78
- assert(handle != NULL);
79
- assert(db->GetState()->open);
80
- assert(!db->GetState()->busy);
81
- db->AddStatement(this);
82
- }
83
-
84
- NODE_METHOD(JS_new) {
85
- UseAddon;
86
- if (!addon->privileged_info) {
87
- return ThrowTypeError("Statements can only be constructed by the db.prepare() method");
88
- }
89
- assert(info.IsConstructCall());
90
- Database* db = Unwrap<Database>(addon->privileged_info->This());
91
- REQUIRE_DATABASE_OPEN(db->GetState());
92
- REQUIRE_DATABASE_NOT_BUSY(db->GetState());
93
-
94
- v8::Local<v8::String> source = (*addon->privileged_info)[0].As<v8::String>();
95
- v8::Local<v8::Object> database = (*addon->privileged_info)[1].As<v8::Object>();
96
- bool pragmaMode = (*addon->privileged_info)[2].As<v8::Boolean>()->Value();
97
- int flags = SQLITE_PREPARE_PERSISTENT;
98
-
99
- if (pragmaMode) {
100
- REQUIRE_DATABASE_NO_ITERATORS_UNLESS_UNSAFE(db->GetState());
101
- flags = 0;
102
- }
103
-
104
- UseIsolate;
105
- v8::String::Utf8Value utf8(isolate, source);
106
- sqlite3_stmt* handle;
107
- const char* tail;
108
-
109
- if (sqlite3_prepare_v3(db->GetHandle(), *utf8, utf8.length() + 1, flags, &handle, &tail) != SQLITE_OK) {
110
- return db->ThrowDatabaseError();
111
- }
112
- if (handle == NULL) {
113
- return ThrowRangeError("The supplied SQL string contains no statements");
114
- }
115
- for (char c; (c = *tail); ++tail) {
116
- if (IS_SKIPPED(c)) continue;
117
- if (c == '/' && tail[1] == '*') {
118
- tail += 2;
119
- for (char c; (c = *tail); ++tail) {
120
- if (c == '*' && tail[1] == '/') {
121
- tail += 1;
122
- break;
123
- }
124
- }
125
- } else if (c == '-' && tail[1] == '-') {
126
- tail += 2;
127
- for (char c; (c = *tail); ++tail) {
128
- if (c == '\n') break;
129
- }
130
- } else {
131
- sqlite3_finalize(handle);
132
- return ThrowRangeError("The supplied SQL string contains more than one statement");
133
- }
134
- }
135
-
136
- UseContext;
137
- bool returns_data = sqlite3_column_count(handle) >= 1 || pragmaMode;
138
- Statement* stmt = new Statement(db, handle, addon->NextId(), returns_data);
139
- stmt->Wrap(info.This());
140
- SetFrozen(isolate, ctx, info.This(), addon->cs.reader, v8::Boolean::New(isolate, returns_data));
141
- SetFrozen(isolate, ctx, info.This(), addon->cs.readonly, v8::Boolean::New(isolate, sqlite3_stmt_readonly(handle) != 0));
142
- SetFrozen(isolate, ctx, info.This(), addon->cs.source, source);
143
- SetFrozen(isolate, ctx, info.This(), addon->cs.database, database);
144
-
145
- info.GetReturnValue().Set(info.This());
146
- }
147
-
148
- NODE_METHOD(JS_run) {
149
- STATEMENT_START(ALLOW_ANY_STATEMENT, DOES_MUTATE);
150
- sqlite3* db_handle = db->GetHandle();
151
- int total_changes_before = sqlite3_total_changes(db_handle);
152
-
153
- sqlite3_step(handle);
154
- if (sqlite3_reset(handle) == SQLITE_OK) {
155
- int changes = sqlite3_total_changes(db_handle) == total_changes_before ? 0 : sqlite3_changes(db_handle);
156
- sqlite3_int64 id = sqlite3_last_insert_rowid(db_handle);
157
- Addon* addon = db->GetAddon();
158
- UseContext;
159
- v8::Local<v8::Object> result = v8::Object::New(isolate);
160
- result->Set(ctx, addon->cs.changes.Get(isolate), v8::Int32::New(isolate, changes)).FromJust();
161
- result->Set(ctx, addon->cs.lastInsertRowid.Get(isolate),
162
- stmt->safe_ints
163
- ? v8::BigInt::New(isolate, id).As<v8::Value>()
164
- : v8::Number::New(isolate, (double)id).As<v8::Value>()
165
- ).FromJust();
166
- STATEMENT_RETURN(result);
167
- }
168
- STATEMENT_THROW();
169
- }
170
-
171
- NODE_METHOD(JS_get) {
172
- STATEMENT_START(REQUIRE_STATEMENT_RETURNS_DATA, DOES_NOT_MUTATE);
173
- int status = sqlite3_step(handle);
174
- if (status == SQLITE_ROW) {
175
- v8::Local<v8::Value> result = Data::GetRowJS(isolate, OnlyContext, handle, stmt->safe_ints, stmt->mode);
176
- sqlite3_reset(handle);
177
- STATEMENT_RETURN(result);
178
- } else if (status == SQLITE_DONE) {
179
- sqlite3_reset(handle);
180
- STATEMENT_RETURN(v8::Undefined(isolate));
181
- }
182
- sqlite3_reset(handle);
183
- STATEMENT_THROW();
184
- }
185
-
186
- NODE_METHOD(JS_all) {
187
- STATEMENT_START(REQUIRE_STATEMENT_RETURNS_DATA, DOES_NOT_MUTATE);
188
- UseContext;
189
- v8::Local<v8::Array> result = v8::Array::New(isolate, 0);
190
- uint32_t row_count = 0;
191
- const bool safe_ints = stmt->safe_ints;
192
- const char mode = stmt->mode;
193
- bool js_error = false;
194
-
195
- while (sqlite3_step(handle) == SQLITE_ROW) {
196
- if (row_count == 0xffffffff) { ThrowRangeError("Array overflow (too many rows returned)"); js_error = true; break; }
197
- result->Set(ctx, row_count++, Data::GetRowJS(isolate, ctx, handle, safe_ints, mode)).FromJust();
198
- }
199
-
200
- if (sqlite3_reset(handle) == SQLITE_OK && !js_error) {
201
- STATEMENT_RETURN(result);
202
- }
203
- if (js_error) db->GetState()->was_js_error = true;
204
- STATEMENT_THROW();
205
- }
206
-
207
- NODE_METHOD(JS_iterate) {
208
- UseAddon;
209
- UseIsolate;
210
- v8::Local<v8::Function> c = addon->StatementIterator.Get(isolate);
211
- addon->privileged_info = &info;
212
- v8::MaybeLocal<v8::Object> maybeIterator = c->NewInstance(OnlyContext, 0, NULL);
213
- addon->privileged_info = NULL;
214
- if (!maybeIterator.IsEmpty()) info.GetReturnValue().Set(maybeIterator.ToLocalChecked());
215
- }
216
-
217
- NODE_METHOD(JS_bind) {
218
- Statement* stmt = Unwrap<Statement>(info.This());
219
- if (stmt->bound) return ThrowTypeError("The bind() method can only be invoked once per statement object");
220
- REQUIRE_DATABASE_OPEN(stmt->db->GetState());
221
- REQUIRE_DATABASE_NOT_BUSY(stmt->db->GetState());
222
- REQUIRE_STATEMENT_NOT_LOCKED(stmt);
223
- STATEMENT_BIND(stmt->handle);
224
- stmt->bound = true;
225
- info.GetReturnValue().Set(info.This());
226
- }
227
-
228
- NODE_METHOD(JS_pluck) {
229
- Statement* stmt = Unwrap<Statement>(info.This());
230
- if (!stmt->returns_data) return ThrowTypeError("The pluck() method is only for statements that return data");
231
- REQUIRE_DATABASE_NOT_BUSY(stmt->db->GetState());
232
- REQUIRE_STATEMENT_NOT_LOCKED(stmt);
233
- bool use = true;
234
- if (info.Length() != 0) { REQUIRE_ARGUMENT_BOOLEAN(first, use); }
235
- stmt->mode = use ? Data::PLUCK : stmt->mode == Data::PLUCK ? Data::FLAT : stmt->mode;
236
- info.GetReturnValue().Set(info.This());
237
- }
238
-
239
- NODE_METHOD(JS_expand) {
240
- Statement* stmt = Unwrap<Statement>(info.This());
241
- if (!stmt->returns_data) return ThrowTypeError("The expand() method is only for statements that return data");
242
- REQUIRE_DATABASE_NOT_BUSY(stmt->db->GetState());
243
- REQUIRE_STATEMENT_NOT_LOCKED(stmt);
244
- bool use = true;
245
- if (info.Length() != 0) { REQUIRE_ARGUMENT_BOOLEAN(first, use); }
246
- stmt->mode = use ? Data::EXPAND : stmt->mode == Data::EXPAND ? Data::FLAT : stmt->mode;
247
- info.GetReturnValue().Set(info.This());
248
- }
249
-
250
- NODE_METHOD(JS_raw) {
251
- Statement* stmt = Unwrap<Statement>(info.This());
252
- if (!stmt->returns_data) return ThrowTypeError("The raw() method is only for statements that return data");
253
- REQUIRE_DATABASE_NOT_BUSY(stmt->db->GetState());
254
- REQUIRE_STATEMENT_NOT_LOCKED(stmt);
255
- bool use = true;
256
- if (info.Length() != 0) { REQUIRE_ARGUMENT_BOOLEAN(first, use); }
257
- stmt->mode = use ? Data::RAW : stmt->mode == Data::RAW ? Data::FLAT : stmt->mode;
258
- info.GetReturnValue().Set(info.This());
259
- }
260
-
261
- NODE_METHOD(JS_safeIntegers) {
262
- Statement* stmt = Unwrap<Statement>(info.This());
263
- REQUIRE_DATABASE_NOT_BUSY(stmt->db->GetState());
264
- REQUIRE_STATEMENT_NOT_LOCKED(stmt);
265
- if (info.Length() == 0) stmt->safe_ints = true;
266
- else { REQUIRE_ARGUMENT_BOOLEAN(first, stmt->safe_ints); }
267
- info.GetReturnValue().Set(info.This());
268
- }
269
-
270
- NODE_METHOD(JS_columns) {
271
- Statement* stmt = Unwrap<Statement>(info.This());
272
- if (!stmt->returns_data) return ThrowTypeError("The columns() method is only for statements that return data");
273
- REQUIRE_DATABASE_OPEN(stmt->db->GetState());
274
- REQUIRE_DATABASE_NOT_BUSY(stmt->db->GetState());
275
- Addon* addon = stmt->db->GetAddon();
276
- UseIsolate;
277
- UseContext;
278
-
279
- int column_count = sqlite3_column_count(stmt->handle);
280
- v8::Local<v8::Array> columns = v8::Array::New(isolate);
281
-
282
- v8::Local<v8::String> name = addon->cs.name.Get(isolate);
283
- v8::Local<v8::String> columnName = addon->cs.column.Get(isolate);
284
- v8::Local<v8::String> tableName = addon->cs.table.Get(isolate);
285
- v8::Local<v8::String> databaseName = addon->cs.database.Get(isolate);
286
- v8::Local<v8::String> typeName = addon->cs.type.Get(isolate);
287
-
288
- for (int i = 0; i < column_count; ++i) {
289
- v8::Local<v8::Object> column = v8::Object::New(isolate);
290
-
291
- column->Set(ctx, name,
292
- InternalizedFromUtf8OrNull(isolate, sqlite3_column_name(stmt->handle, i), -1)
293
- ).FromJust();
294
- column->Set(ctx, columnName,
295
- InternalizedFromUtf8OrNull(isolate, sqlite3_column_origin_name(stmt->handle, i), -1)
296
- ).FromJust();
297
- column->Set(ctx, tableName,
298
- InternalizedFromUtf8OrNull(isolate, sqlite3_column_table_name(stmt->handle, i), -1)
299
- ).FromJust();
300
- column->Set(ctx, databaseName,
301
- InternalizedFromUtf8OrNull(isolate, sqlite3_column_database_name(stmt->handle, i), -1)
302
- ).FromJust();
303
- column->Set(ctx, typeName,
304
- InternalizedFromUtf8OrNull(isolate, sqlite3_column_decltype(stmt->handle, i), -1)
305
- ).FromJust();
306
-
307
- columns->Set(ctx, i, column).FromJust();
308
- }
309
-
310
- info.GetReturnValue().Set(columns);
311
- }
312
-
313
- Database* const db;
314
- sqlite3_stmt* const handle;
315
- Extras* const extras;
316
- bool alive;
317
- bool locked;
318
- bool bound;
319
- bool has_bind_map;
320
- bool safe_ints;
321
- char mode;
322
- const bool returns_data;
323
- };
@@ -1,73 +0,0 @@
1
- class BindMap {
2
- public:
3
-
4
- // This nested class represents a single mapping between a parameter name
5
- // and its associated parameter index in a prepared statement.
6
- class Pair { friend class BindMap;
7
- public:
8
-
9
- inline int GetIndex() {
10
- return index;
11
- }
12
-
13
- inline v8::Local<v8::String> GetName(v8::Isolate* isolate) {
14
- return name.Get(isolate);
15
- }
16
-
17
- private:
18
-
19
- explicit Pair(v8::Isolate* isolate, const char* name, int index)
20
- : name(isolate, InternalizedFromUtf8(isolate, name, -1)), index(index) {}
21
-
22
- explicit Pair(v8::Isolate* isolate, Pair* pair)
23
- : name(isolate, pair->name), index(pair->index) {}
24
-
25
- const CopyablePersistent<v8::String> name;
26
- const int index;
27
- };
28
-
29
- explicit BindMap(char _) {
30
- assert(_ == 0);
31
- pairs = NULL;
32
- capacity = 0;
33
- length = 0;
34
- }
35
-
36
- ~BindMap() {
37
- while (length) pairs[--length].~Pair();
38
- FREE_ARRAY<Pair>(pairs);
39
- }
40
-
41
- inline Pair* GetPairs() {
42
- return pairs;
43
- }
44
-
45
- inline int GetSize() {
46
- return length;
47
- }
48
-
49
- // Adds a pair to the bind map, expanding the capacity if necessary.
50
- void Add(v8::Isolate* isolate, const char* name, int index) {
51
- assert(name != NULL);
52
- if (capacity == length) Grow(isolate);
53
- new (pairs + length++) Pair(isolate, name, index);
54
- }
55
-
56
- private:
57
-
58
- void Grow(v8::Isolate* isolate) {
59
- assert(capacity == length);
60
- capacity = (capacity << 1) | 2;
61
- Pair* new_pairs = ALLOC_ARRAY<Pair>(capacity);
62
- for (int i = 0; i < length; ++i) {
63
- new (new_pairs + i) Pair(isolate, pairs + i);
64
- pairs[i].~Pair();
65
- }
66
- FREE_ARRAY<Pair>(pairs);
67
- pairs = new_pairs;
68
- }
69
-
70
- Pair* pairs;
71
- int capacity;
72
- int length;
73
- };
@@ -1,190 +0,0 @@
1
- class Binder {
2
- public:
3
-
4
- explicit Binder(sqlite3_stmt* _handle) {
5
- handle = _handle;
6
- param_count = sqlite3_bind_parameter_count(_handle);
7
- anon_index = 0;
8
- success = true;
9
- }
10
-
11
- bool Bind(NODE_ARGUMENTS info, int argc, Statement* stmt) {
12
- assert(anon_index == 0);
13
- Result result = BindArgs(info, argc, stmt);
14
- if (success && result.count != param_count) {
15
- if (result.count < param_count) {
16
- if (!result.bound_object && stmt->GetBindMap(OnlyIsolate)->GetSize()) {
17
- Fail(ThrowTypeError, "Missing named parameters");
18
- } else {
19
- Fail(ThrowRangeError, "Too few parameter values were provided");
20
- }
21
- } else {
22
- Fail(ThrowRangeError, "Too many parameter values were provided");
23
- }
24
- }
25
- return success;
26
- }
27
-
28
- private:
29
-
30
- struct Result {
31
- int count;
32
- bool bound_object;
33
- };
34
-
35
- static bool IsPlainObject(v8::Isolate* isolate, v8::Local<v8::Object> obj) {
36
- v8::Local<v8::Value> proto = obj->GetPrototype();
37
- v8::Local<v8::Context> ctx = obj->CreationContext();
38
- ctx->Enter();
39
- v8::Local<v8::Value> baseProto = v8::Object::New(isolate)->GetPrototype();
40
- ctx->Exit();
41
- return proto->StrictEquals(baseProto) || proto->StrictEquals(v8::Null(isolate));
42
- }
43
-
44
- void Fail(void (*Throw)(const char* _), const char* message) {
45
- assert(success == true);
46
- assert((Throw == NULL) == (message == NULL));
47
- assert(Throw == ThrowError || Throw == ThrowTypeError || Throw == ThrowRangeError || Throw == NULL);
48
- if (Throw) Throw(message);
49
- success = false;
50
- }
51
-
52
- int NextAnonIndex() {
53
- while (sqlite3_bind_parameter_name(handle, ++anon_index) != NULL) {}
54
- return anon_index;
55
- }
56
-
57
- // Binds the value at the given index or throws an appropriate error.
58
- void BindValue(v8::Isolate* isolate, v8::Local<v8::Value> value, int index) {
59
- int status = Data::BindValueFromJS(isolate, handle, index, value);
60
- if (status != SQLITE_OK) {
61
- switch (status) {
62
- case -1:
63
- return Fail(ThrowTypeError, "SQLite3 can only bind numbers, strings, bigints, buffers, and null");
64
- case SQLITE_TOOBIG:
65
- return Fail(ThrowRangeError, "The bound string, buffer, or bigint is too big");
66
- case SQLITE_RANGE:
67
- return Fail(ThrowRangeError, "Too many parameter values were provided");
68
- case SQLITE_NOMEM:
69
- return Fail(ThrowError, "Out of memory");
70
- default:
71
- return Fail(ThrowError, "An unexpected error occured while trying to bind parameters");
72
- }
73
- assert(false);
74
- }
75
- }
76
-
77
- // Binds each value in the array or throws an appropriate error.
78
- // The number of successfully bound parameters is returned.
79
- int BindArray(v8::Isolate* isolate, v8::Local<v8::Array> arr) {
80
- UseContext;
81
- uint32_t length = arr->Length();
82
- if (length > INT_MAX) {
83
- Fail(ThrowRangeError, "Too many parameter values were provided");
84
- return 0;
85
- }
86
- int len = static_cast<int>(length);
87
- for (int i = 0; i < len; ++i) {
88
- v8::MaybeLocal<v8::Value> maybeValue = arr->Get(ctx, i);
89
- if (maybeValue.IsEmpty()) {
90
- Fail(NULL, NULL);
91
- return i;
92
- }
93
- BindValue(isolate, maybeValue.ToLocalChecked(), NextAnonIndex());
94
- if (!success) {
95
- return i;
96
- }
97
- }
98
- return len;
99
- }
100
-
101
- // Binds all named parameters using the values found in the given object.
102
- // The number of successfully bound parameters is returned.
103
- // If a named parameter is missing from the object, an error is thrown.
104
- // This should only be invoked once per instance.
105
- int BindObject(v8::Isolate* isolate, v8::Local<v8::Object> obj, Statement* stmt) {
106
- UseContext;
107
- BindMap* bind_map = stmt->GetBindMap(isolate);
108
- BindMap::Pair* pairs = bind_map->GetPairs();
109
- int len = bind_map->GetSize();
110
-
111
- for (int i = 0; i < len; ++i) {
112
- v8::Local<v8::String> key = pairs[i].GetName(isolate);
113
-
114
- // Check if the named parameter was provided.
115
- v8::Maybe<bool> has_property = obj->HasOwnProperty(ctx, key);
116
- if (has_property.IsNothing()) {
117
- Fail(NULL, NULL);
118
- return i;
119
- }
120
- if (!has_property.FromJust()) {
121
- v8::String::Utf8Value param_name(isolate, key);
122
- Fail(ThrowRangeError, (std::string("Missing named parameter \"") + *param_name + "\"").c_str());
123
- return i;
124
- }
125
-
126
- // Get the current property value.
127
- v8::MaybeLocal<v8::Value> maybeValue = obj->Get(ctx, key);
128
- if (maybeValue.IsEmpty()) {
129
- Fail(NULL, NULL);
130
- return i;
131
- }
132
-
133
- BindValue(isolate, maybeValue.ToLocalChecked(), pairs[i].GetIndex());
134
- if (!success) {
135
- return i;
136
- }
137
- }
138
-
139
- return len;
140
- }
141
-
142
- // Binds all parameters using the values found in the arguments object.
143
- // Anonymous parameter values can be directly in the arguments object or in an Array.
144
- // Named parameter values can be provided in a plain Object argument.
145
- // Only one plain Object argument may be provided.
146
- // If an error occurs, an appropriate error is thrown.
147
- // The return value is a struct indicating how many parameters were successfully bound
148
- // and whether or not it tried to bind an object.
149
- Result BindArgs(NODE_ARGUMENTS info, int argc, Statement* stmt) {
150
- UseIsolate;
151
- int count = 0;
152
- bool bound_object = false;
153
-
154
- for (int i = 0; i < argc; ++i) {
155
- v8::Local<v8::Value> arg = info[i];
156
-
157
- if (arg->IsArray()) {
158
- count += BindArray(isolate, arg.As<v8::Array>());
159
- if (!success) break;
160
- continue;
161
- }
162
-
163
- if (arg->IsObject() && !node::Buffer::HasInstance(arg)) {
164
- v8::Local<v8::Object> obj = arg.As<v8::Object>();
165
- if (IsPlainObject(isolate, obj)) {
166
- if (bound_object) {
167
- Fail(ThrowTypeError, "You cannot specify named parameters in two different objects");
168
- break;
169
- }
170
- bound_object = true;
171
-
172
- count += BindObject(isolate, obj, stmt);
173
- if (!success) break;
174
- continue;
175
- }
176
- }
177
-
178
- BindValue(isolate, arg, NextAnonIndex());
179
- if (!success) break;
180
- count += 1;
181
- }
182
-
183
- return { count, bound_object };
184
- }
185
-
186
- sqlite3_stmt* handle;
187
- int param_count;
188
- int anon_index; // This value should only be used by NextAnonIndex()
189
- bool success; // This value should only be set by Fail()
190
- };