@rocicorp/zero-sqlite3 1.0.12 → 1.0.13

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.
package/lib/index.d.ts CHANGED
@@ -44,6 +44,7 @@ declare namespace BetterSqlite3 {
44
44
  scanStatusV2(idx: number, opcode: ScanStatOpcode.SQLITE_SCANSTAT_NCYCLE, resetFlag: number): number | undefined;
45
45
  scanStatusV2(idx: number, opcode: ScanStatOpcode, resetFlag: number): number | string | undefined;
46
46
  scanStatusReset(): this;
47
+ explainQueryPlan(...params: BindParameters | []): Result[];
47
48
  }
48
49
 
49
50
  interface ColumnDefinition {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rocicorp/zero-sqlite3",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "description": "better-sqlite3 on bedrock",
5
5
  "homepage": "https://github.com/rocicorp/zero-sqlite3",
6
6
  "author": "Rocicorp",
@@ -66,6 +66,7 @@ INIT(Statement::Init) {
66
66
  SetPrototypeMethod(isolate, data, t, "columns", JS_columns);
67
67
  SetPrototypeMethod(isolate, data, t, "scanStatusV2", JS_scanStatusV2);
68
68
  SetPrototypeMethod(isolate, data, t, "scanStatusReset", JS_scanStatusReset);
69
+ SetPrototypeMethod(isolate, data, t, "explainQueryPlan", JS_explainQueryPlan);
69
70
  SetPrototypeGetter(isolate, data, t, "busy", JS_busy);
70
71
  return t->GetFunction(OnlyContext).ToLocalChecked();
71
72
  }
@@ -227,6 +228,90 @@ NODE_METHOD(Statement::JS_all) {
227
228
  #endif
228
229
  }
229
230
 
231
+ NODE_METHOD(Statement::JS_explainQueryPlan) {
232
+ Statement* stmt = Unwrap<Statement>(info.This());
233
+ REQUIRE_STATEMENT_RETURNS_DATA();
234
+ sqlite3_stmt* handle = stmt->handle;
235
+ Database* db = stmt->db;
236
+ REQUIRE_DATABASE_OPEN(db->GetState());
237
+ REQUIRE_DATABASE_NOT_BUSY(db->GetState());
238
+ REQUIRE_STATEMENT_NOT_LOCKED(stmt);
239
+
240
+ // Binding is OPTIONAL: bind if params provided, skip if not
241
+ const bool pre_bound = stmt->bound;
242
+ bool did_bind = false;
243
+ if (!pre_bound && info.Length() > 0) {
244
+ STATEMENT_BIND(handle);
245
+ did_bind = true;
246
+ } else if (pre_bound && info.Length() > 0) {
247
+ return ThrowTypeError("This statement already has bound parameters");
248
+ }
249
+
250
+ db->GetState()->busy = true;
251
+ UseIsolate;
252
+ if (db->Log(isolate, handle)) {
253
+ db->GetState()->busy = false;
254
+ if (did_bind) { sqlite3_clear_bindings(handle); }
255
+ db->ThrowDatabaseError();
256
+ return;
257
+ }
258
+
259
+ UseContext;
260
+ const bool safe_ints = stmt->safe_ints;
261
+ const char mode = stmt->mode;
262
+
263
+ #if !defined(NODE_MODULE_VERSION) || NODE_MODULE_VERSION < 127
264
+ bool js_error = false;
265
+ uint32_t row_count = 0;
266
+ v8::Local<v8::Array> result = v8::Array::New(isolate, 0);
267
+
268
+ while (sqlite3_step(handle) == SQLITE_ROW) {
269
+ if (row_count == 0xffffffff) { ThrowRangeError("Array overflow (too many rows returned)"); js_error = true; break; }
270
+ result->Set(ctx, row_count++, Data::GetRowJS(isolate, ctx, handle, safe_ints, mode)).FromJust();
271
+ }
272
+
273
+ if (sqlite3_reset(handle) == SQLITE_OK && !js_error) {
274
+ db->GetState()->busy = false;
275
+ if (did_bind) { sqlite3_clear_bindings(handle); }
276
+ info.GetReturnValue().Set(result);
277
+ return;
278
+ }
279
+ if (js_error) db->GetState()->was_js_error = true;
280
+ db->GetState()->busy = false;
281
+ if (did_bind) { sqlite3_clear_bindings(handle); }
282
+ db->ThrowDatabaseError();
283
+ #else
284
+ v8::LocalVector<v8::Value> rows(isolate);
285
+ rows.reserve(8);
286
+
287
+ if (mode == Data::FLAT) {
288
+ RowBuilder rowBuilder(isolate, handle, safe_ints);
289
+ while (sqlite3_step(handle) == SQLITE_ROW) {
290
+ rows.emplace_back(rowBuilder.GetRowJS());
291
+ }
292
+ } else {
293
+ while (sqlite3_step(handle) == SQLITE_ROW) {
294
+ rows.emplace_back(Data::GetRowJS(isolate, ctx, handle, safe_ints, mode));
295
+ }
296
+ }
297
+
298
+ if (sqlite3_reset(handle) == SQLITE_OK) {
299
+ if (rows.size() > 0xffffffff) {
300
+ ThrowRangeError("Array overflow (too many rows returned)");
301
+ db->GetState()->was_js_error = true;
302
+ } else {
303
+ db->GetState()->busy = false;
304
+ if (did_bind) { sqlite3_clear_bindings(handle); }
305
+ info.GetReturnValue().Set(v8::Array::New(isolate, rows.data(), rows.size()));
306
+ return;
307
+ }
308
+ }
309
+ db->GetState()->busy = false;
310
+ if (did_bind) { sqlite3_clear_bindings(handle); }
311
+ db->ThrowDatabaseError();
312
+ #endif
313
+ }
314
+
230
315
  NODE_METHOD(Statement::JS_iterate) {
231
316
  UseAddon;
232
317
  UseIsolate;
@@ -45,6 +45,7 @@ private:
45
45
  static NODE_METHOD(JS_columns);
46
46
  static NODE_METHOD(JS_scanStatusV2);
47
47
  static NODE_METHOD(JS_scanStatusReset);
48
+ static NODE_METHOD(JS_explainQueryPlan);
48
49
  static NODE_GETTER(JS_busy);
49
50
 
50
51
  Database* const db;