@photostructure/sqlite 0.0.1 → 0.2.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 (56) hide show
  1. package/CHANGELOG.md +36 -2
  2. package/README.md +45 -484
  3. package/SECURITY.md +27 -84
  4. package/binding.gyp +69 -22
  5. package/dist/index.cjs +185 -18
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.d.cts +552 -100
  8. package/dist/index.d.mts +552 -100
  9. package/dist/index.d.ts +552 -100
  10. package/dist/index.mjs +183 -18
  11. package/dist/index.mjs.map +1 -1
  12. package/package.json +51 -41
  13. package/prebuilds/darwin-arm64/@photostructure+sqlite.glibc.node +0 -0
  14. package/prebuilds/darwin-x64/@photostructure+sqlite.glibc.node +0 -0
  15. package/prebuilds/linux-arm64/@photostructure+sqlite.glibc.node +0 -0
  16. package/prebuilds/linux-arm64/@photostructure+sqlite.musl.node +0 -0
  17. package/prebuilds/linux-x64/@photostructure+sqlite.glibc.node +0 -0
  18. package/prebuilds/linux-x64/@photostructure+sqlite.musl.node +0 -0
  19. package/prebuilds/test_extension.so +0 -0
  20. package/prebuilds/win32-x64/@photostructure+sqlite.glibc.node +0 -0
  21. package/src/aggregate_function.cpp +503 -235
  22. package/src/aggregate_function.h +57 -42
  23. package/src/binding.cpp +117 -14
  24. package/src/dirname.ts +1 -1
  25. package/src/index.ts +122 -332
  26. package/src/lru-cache.ts +84 -0
  27. package/src/shims/env-inl.h +6 -15
  28. package/src/shims/node_errors.h +4 -0
  29. package/src/shims/sqlite_errors.h +162 -0
  30. package/src/shims/util.h +29 -4
  31. package/src/sql-tag-store.ts +140 -0
  32. package/src/sqlite_exception.h +49 -0
  33. package/src/sqlite_impl.cpp +711 -127
  34. package/src/sqlite_impl.h +84 -6
  35. package/src/{stack_path.ts → stack-path.ts} +7 -1
  36. package/src/types/aggregate-options.ts +22 -0
  37. package/src/types/changeset-apply-options.ts +18 -0
  38. package/src/types/database-sync-instance.ts +203 -0
  39. package/src/types/database-sync-options.ts +69 -0
  40. package/src/types/session-options.ts +10 -0
  41. package/src/types/sql-tag-store-instance.ts +51 -0
  42. package/src/types/sqlite-authorization-actions.ts +77 -0
  43. package/src/types/sqlite-authorization-results.ts +15 -0
  44. package/src/types/sqlite-changeset-conflict-types.ts +19 -0
  45. package/src/types/sqlite-changeset-resolution.ts +15 -0
  46. package/src/types/sqlite-open-flags.ts +50 -0
  47. package/src/types/statement-sync-instance.ts +73 -0
  48. package/src/types/user-functions-options.ts +14 -0
  49. package/src/upstream/node_sqlite.cc +960 -259
  50. package/src/upstream/node_sqlite.h +127 -2
  51. package/src/upstream/sqlite.js +1 -14
  52. package/src/upstream/sqlite3.c +4510 -1411
  53. package/src/upstream/sqlite3.h +390 -195
  54. package/src/upstream/sqlite3ext.h +7 -0
  55. package/src/user_function.cpp +88 -36
  56. package/src/user_function.h +2 -1
@@ -24,7 +24,9 @@ using v8::BigInt;
24
24
  using v8::Boolean;
25
25
  using v8::ConstructorBehavior;
26
26
  using v8::Context;
27
+ using v8::DictionaryTemplate;
27
28
  using v8::DontDelete;
29
+ using v8::EscapableHandleScope;
28
30
  using v8::Exception;
29
31
  using v8::Function;
30
32
  using v8::FunctionCallback;
@@ -35,11 +37,14 @@ using v8::HandleScope;
35
37
  using v8::Int32;
36
38
  using v8::Integer;
37
39
  using v8::Isolate;
40
+ using v8::JustVoid;
38
41
  using v8::Local;
39
42
  using v8::LocalVector;
43
+ using v8::Maybe;
40
44
  using v8::MaybeLocal;
41
45
  using v8::Name;
42
46
  using v8::NewStringType;
47
+ using v8::Nothing;
43
48
  using v8::Null;
44
49
  using v8::Number;
45
50
  using v8::Object;
@@ -116,6 +121,18 @@ using v8::Value;
116
121
  } \
117
122
  } while (0)
118
123
 
124
+ namespace {
125
+ Local<DictionaryTemplate> getLazyIterTemplate(Environment* env) {
126
+ auto iter_template = env->iter_template();
127
+ if (iter_template.IsEmpty()) {
128
+ static constexpr std::string_view iter_keys[] = {"done", "value"};
129
+ iter_template = DictionaryTemplate::New(env->isolate(), iter_keys);
130
+ env->set_iter_template(iter_template);
131
+ }
132
+ return iter_template;
133
+ }
134
+ } // namespace
135
+
119
136
  inline MaybeLocal<Object> CreateSQLiteError(Isolate* isolate,
120
137
  const char* message) {
121
138
  Local<String> js_msg;
@@ -507,8 +524,7 @@ class BackupJob : public ThreadPoolWork {
507
524
 
508
525
  Local<Value> argv[] = {progress_info};
509
526
  TryCatch try_catch(env()->isolate());
510
- fn->Call(env()->context(), Null(env()->isolate()), 1, argv)
511
- .FromMaybe(Local<Value>());
527
+ USE(fn->Call(env()->context(), Null(env()->isolate()), 1, argv));
512
528
  if (try_catch.HasCaught()) {
513
529
  Finalize();
514
530
  resolver->Reject(env()->context(), try_catch.Exception()).ToChecked();
@@ -737,6 +753,14 @@ bool DatabaseSync::Open() {
737
753
  CHECK_ERROR_OR_THROW(env()->isolate(), this, r, SQLITE_OK, false);
738
754
  CHECK_EQ(foreign_keys_enabled, open_config_.get_enable_foreign_keys());
739
755
 
756
+ int defensive_enabled;
757
+ r = sqlite3_db_config(connection_,
758
+ SQLITE_DBCONFIG_DEFENSIVE,
759
+ static_cast<int>(open_config_.get_enable_defensive()),
760
+ &defensive_enabled);
761
+ CHECK_ERROR_OR_THROW(env()->isolate(), this, r, SQLITE_OK, false);
762
+ CHECK_EQ(defensive_enabled, open_config_.get_enable_defensive());
763
+
740
764
  sqlite3_busy_timeout(connection_, open_config_.get_timeout());
741
765
 
742
766
  if (allow_load_extension_) {
@@ -794,6 +818,29 @@ bool DatabaseSync::ShouldIgnoreSQLiteError() {
794
818
  return ignore_next_sqlite_error_;
795
819
  }
796
820
 
821
+ void DatabaseSync::CreateTagStore(const FunctionCallbackInfo<Value>& args) {
822
+ DatabaseSync* db = BaseObject::Unwrap<DatabaseSync>(args.This());
823
+ Environment* env = Environment::GetCurrent(args);
824
+
825
+ if (!db->IsOpen()) {
826
+ THROW_ERR_INVALID_STATE(env, "database is not open");
827
+ return;
828
+ }
829
+ int capacity = 1000;
830
+ if (args.Length() > 0 && args[0]->IsNumber()) {
831
+ capacity = args[0].As<Number>()->Value();
832
+ }
833
+
834
+ BaseObjectPtr<SQLTagStore> session =
835
+ SQLTagStore::Create(env, BaseObjectWeakPtr<DatabaseSync>(db), capacity);
836
+ if (!session) {
837
+ // Handle error if creation failed
838
+ THROW_ERR_SQLITE_ERROR(env->isolate(), "Failed to create SQLTagStore");
839
+ return;
840
+ }
841
+ args.GetReturnValue().Set(session->object());
842
+ }
843
+
797
844
  std::optional<std::string> ValidateDatabasePath(Environment* env,
798
845
  Local<Value> path,
799
846
  const std::string& field_name) {
@@ -966,6 +1013,81 @@ void DatabaseSync::New(const FunctionCallbackInfo<Value>& args) {
966
1013
 
967
1014
  open_config.set_timeout(timeout_v.As<Int32>()->Value());
968
1015
  }
1016
+
1017
+ Local<Value> read_bigints_v;
1018
+ if (options->Get(env->context(), env->read_bigints_string())
1019
+ .ToLocal(&read_bigints_v)) {
1020
+ if (!read_bigints_v->IsUndefined()) {
1021
+ if (!read_bigints_v->IsBoolean()) {
1022
+ THROW_ERR_INVALID_ARG_TYPE(
1023
+ env->isolate(),
1024
+ R"(The "options.readBigInts" argument must be a boolean.)");
1025
+ return;
1026
+ }
1027
+ open_config.set_use_big_ints(read_bigints_v.As<Boolean>()->Value());
1028
+ }
1029
+ }
1030
+
1031
+ Local<Value> return_arrays_v;
1032
+ if (options->Get(env->context(), env->return_arrays_string())
1033
+ .ToLocal(&return_arrays_v)) {
1034
+ if (!return_arrays_v->IsUndefined()) {
1035
+ if (!return_arrays_v->IsBoolean()) {
1036
+ THROW_ERR_INVALID_ARG_TYPE(
1037
+ env->isolate(),
1038
+ R"(The "options.returnArrays" argument must be a boolean.)");
1039
+ return;
1040
+ }
1041
+ open_config.set_return_arrays(return_arrays_v.As<Boolean>()->Value());
1042
+ }
1043
+ }
1044
+
1045
+ Local<Value> allow_bare_named_params_v;
1046
+ if (options->Get(env->context(), env->allow_bare_named_params_string())
1047
+ .ToLocal(&allow_bare_named_params_v)) {
1048
+ if (!allow_bare_named_params_v->IsUndefined()) {
1049
+ if (!allow_bare_named_params_v->IsBoolean()) {
1050
+ THROW_ERR_INVALID_ARG_TYPE(
1051
+ env->isolate(),
1052
+ R"(The "options.allowBareNamedParameters" )"
1053
+ "argument must be a boolean.");
1054
+ return;
1055
+ }
1056
+ open_config.set_allow_bare_named_params(
1057
+ allow_bare_named_params_v.As<Boolean>()->Value());
1058
+ }
1059
+ }
1060
+
1061
+ Local<Value> allow_unknown_named_params_v;
1062
+ if (options->Get(env->context(), env->allow_unknown_named_params_string())
1063
+ .ToLocal(&allow_unknown_named_params_v)) {
1064
+ if (!allow_unknown_named_params_v->IsUndefined()) {
1065
+ if (!allow_unknown_named_params_v->IsBoolean()) {
1066
+ THROW_ERR_INVALID_ARG_TYPE(
1067
+ env->isolate(),
1068
+ R"(The "options.allowUnknownNamedParameters" )"
1069
+ "argument must be a boolean.");
1070
+ return;
1071
+ }
1072
+ open_config.set_allow_unknown_named_params(
1073
+ allow_unknown_named_params_v.As<Boolean>()->Value());
1074
+ }
1075
+ }
1076
+
1077
+ Local<Value> defensive_v;
1078
+ if (!options->Get(env->context(), env->defensive_string())
1079
+ .ToLocal(&defensive_v)) {
1080
+ return;
1081
+ }
1082
+ if (!defensive_v->IsUndefined()) {
1083
+ if (!defensive_v->IsBoolean()) {
1084
+ THROW_ERR_INVALID_ARG_TYPE(
1085
+ env->isolate(),
1086
+ "The \"options.defensive\" argument must be a boolean.");
1087
+ return;
1088
+ }
1089
+ open_config.set_enable_defensive(defensive_v.As<Boolean>()->Value());
1090
+ }
969
1091
  }
970
1092
 
971
1093
  new DatabaseSync(
@@ -1005,6 +1127,14 @@ void DatabaseSync::Close(const FunctionCallbackInfo<Value>& args) {
1005
1127
  db->connection_ = nullptr;
1006
1128
  }
1007
1129
 
1130
+ void DatabaseSync::Dispose(const v8::FunctionCallbackInfo<v8::Value>& args) {
1131
+ v8::TryCatch try_catch(args.GetIsolate());
1132
+ Close(args);
1133
+ if (try_catch.HasCaught()) {
1134
+ CHECK(try_catch.CanContinue());
1135
+ }
1136
+ }
1137
+
1008
1138
  void DatabaseSync::Prepare(const FunctionCallbackInfo<Value>& args) {
1009
1139
  DatabaseSync* db;
1010
1140
  ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
@@ -1020,6 +1150,7 @@ void DatabaseSync::Prepare(const FunctionCallbackInfo<Value>& args) {
1020
1150
  Utf8Value sql(env->isolate(), args[0].As<String>());
1021
1151
  sqlite3_stmt* s = nullptr;
1022
1152
  int r = sqlite3_prepare_v2(db->connection_, *sql, -1, &s, 0);
1153
+
1023
1154
  CHECK_ERROR_OR_THROW(env->isolate(), db, r, SQLITE_OK, void());
1024
1155
  BaseObjectPtr<StatementSync> stmt =
1025
1156
  StatementSync::Create(env, BaseObjectPtr<DatabaseSync>(db), s);
@@ -1157,9 +1288,7 @@ void DatabaseSync::CustomFunction(const FunctionCallbackInfo<Value>& args) {
1157
1288
  argc = -1;
1158
1289
  } else {
1159
1290
  Local<Value> js_len;
1160
- if (!fn->Get(env->context(),
1161
- FIXED_ONE_BYTE_STRING(env->isolate(), "length"))
1162
- .ToLocal(&js_len)) {
1291
+ if (!fn->Get(env->context(), env->length_string()).ToLocal(&js_len)) {
1163
1292
  return;
1164
1293
  }
1165
1294
  argc = js_len.As<Int32>()->Value();
@@ -1390,7 +1519,7 @@ void DatabaseSync::CreateSession(const FunctionCallbackInfo<Value>& args) {
1390
1519
 
1391
1520
  Local<Object> options = args[0].As<Object>();
1392
1521
 
1393
- Local<String> table_key = FIXED_ONE_BYTE_STRING(env->isolate(), "table");
1522
+ Local<String> table_key = env->table_string();
1394
1523
  bool hasIt;
1395
1524
  if (!options->HasOwnProperty(env->context(), table_key).To(&hasIt)) {
1396
1525
  return;
@@ -1402,8 +1531,7 @@ void DatabaseSync::CreateSession(const FunctionCallbackInfo<Value>& args) {
1402
1531
  }
1403
1532
 
1404
1533
  if (table_value->IsString()) {
1405
- String::Utf8Value str(env->isolate(), table_value);
1406
- table = *str;
1534
+ table = Utf8Value(env->isolate(), table_value).ToString();
1407
1535
  } else {
1408
1536
  THROW_ERR_INVALID_ARG_TYPE(
1409
1537
  env->isolate(), "The \"options.table\" argument must be a string.");
@@ -1423,8 +1551,7 @@ void DatabaseSync::CreateSession(const FunctionCallbackInfo<Value>& args) {
1423
1551
  return;
1424
1552
  }
1425
1553
  if (db_value->IsString()) {
1426
- String::Utf8Value str(env->isolate(), db_value);
1427
- db_name = std::string(*str);
1554
+ db_name = Utf8Value(env->isolate(), db_value).ToString();
1428
1555
  } else {
1429
1556
  THROW_ERR_INVALID_ARG_TYPE(
1430
1557
  env->isolate(), "The \"options.db\" argument must be a string.");
@@ -1564,26 +1691,28 @@ void Backup(const FunctionCallbackInfo<Value>& args) {
1564
1691
  job->ScheduleBackup();
1565
1692
  }
1566
1693
 
1694
+ struct ConflictCallbackContext {
1695
+ std::function<bool(std::string_view)> filterCallback;
1696
+ std::function<int(int)> conflictCallback;
1697
+ };
1698
+
1567
1699
  // the reason for using static functions here is that SQLite needs a
1568
1700
  // function pointer
1569
- static std::function<int(int)> conflictCallback;
1570
1701
 
1571
1702
  static int xConflict(void* pCtx, int eConflict, sqlite3_changeset_iter* pIter) {
1572
- if (!conflictCallback) return SQLITE_CHANGESET_ABORT;
1573
- return conflictCallback(eConflict);
1703
+ auto ctx = static_cast<ConflictCallbackContext*>(pCtx);
1704
+ if (!ctx->conflictCallback) return SQLITE_CHANGESET_ABORT;
1705
+ return ctx->conflictCallback(eConflict);
1574
1706
  }
1575
1707
 
1576
- static std::function<bool(std::string)> filterCallback;
1577
-
1578
1708
  static int xFilter(void* pCtx, const char* zTab) {
1579
- if (!filterCallback) return 1;
1580
-
1581
- return filterCallback(zTab) ? 1 : 0;
1709
+ auto ctx = static_cast<ConflictCallbackContext*>(pCtx);
1710
+ if (!ctx->filterCallback) return 1;
1711
+ return ctx->filterCallback(zTab) ? 1 : 0;
1582
1712
  }
1583
1713
 
1584
1714
  void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {
1585
- conflictCallback = nullptr;
1586
- filterCallback = nullptr;
1715
+ ConflictCallbackContext context;
1587
1716
 
1588
1717
  DatabaseSync* db;
1589
1718
  ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
@@ -1619,7 +1748,7 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {
1619
1748
  return;
1620
1749
  }
1621
1750
  Local<Function> conflictFunc = conflictValue.As<Function>();
1622
- conflictCallback = [env, conflictFunc](int conflictType) -> int {
1751
+ context.conflictCallback = [env, conflictFunc](int conflictType) -> int {
1623
1752
  Local<Value> argv[] = {Integer::New(env->isolate(), conflictType)};
1624
1753
  TryCatch try_catch(env->isolate());
1625
1754
  Local<Value> result =
@@ -1657,18 +1786,27 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {
1657
1786
 
1658
1787
  Local<Function> filterFunc = filterValue.As<Function>();
1659
1788
 
1660
- filterCallback = [env, filterFunc](std::string item) -> bool {
1661
- // TODO(@jasnell): The use of ToLocalChecked here means that if
1662
- // the filter function throws an error the process will crash.
1663
- // The filterCallback should be updated to avoid the check and
1664
- // propagate the error correctly.
1665
- Local<Value> argv[] = {String::NewFromUtf8(env->isolate(),
1666
- item.c_str(),
1667
- NewStringType::kNormal)
1668
- .ToLocalChecked()};
1669
- Local<Value> result =
1670
- filterFunc->Call(env->context(), Null(env->isolate()), 1, argv)
1671
- .ToLocalChecked();
1789
+ context.filterCallback = [&](std::string_view item) -> bool {
1790
+ // If there was an error in the previous call to the filter's
1791
+ // callback, we skip calling it again.
1792
+ if (db->ignore_next_sqlite_error_) {
1793
+ return false;
1794
+ }
1795
+
1796
+ Local<Value> argv[1];
1797
+ if (!ToV8Value(env->context(), item, env->isolate())
1798
+ .ToLocal(&argv[0])) {
1799
+ db->SetIgnoreNextSQLiteError(true);
1800
+ return false;
1801
+ }
1802
+
1803
+ Local<Value> result;
1804
+ if (!filterFunc->Call(env->context(), Null(env->isolate()), 1, argv)
1805
+ .ToLocal(&result)) {
1806
+ db->SetIgnoreNextSQLiteError(true);
1807
+ return false;
1808
+ }
1809
+
1672
1810
  return result->BooleanValue(env->isolate());
1673
1811
  };
1674
1812
  }
@@ -1681,7 +1819,7 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {
1681
1819
  const_cast<void*>(static_cast<const void*>(buf.data())),
1682
1820
  xFilter,
1683
1821
  xConflict,
1684
- nullptr);
1822
+ static_cast<void*>(&context));
1685
1823
  if (r == SQLITE_OK) {
1686
1824
  args.GetReturnValue().Set(true);
1687
1825
  return;
@@ -1698,15 +1836,14 @@ void DatabaseSync::EnableLoadExtension(
1698
1836
  const FunctionCallbackInfo<Value>& args) {
1699
1837
  DatabaseSync* db;
1700
1838
  ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
1701
- Environment* env = Environment::GetCurrent(args);
1839
+ auto isolate = args.GetIsolate();
1702
1840
  if (!args[0]->IsBoolean()) {
1703
- THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
1841
+ THROW_ERR_INVALID_ARG_TYPE(isolate,
1704
1842
  "The \"allow\" argument must be a boolean.");
1705
1843
  return;
1706
1844
  }
1707
1845
 
1708
1846
  const int enable = args[0].As<Boolean>()->Value();
1709
- auto isolate = env->isolate();
1710
1847
 
1711
1848
  if (db->allow_load_extension_ == false && enable == true) {
1712
1849
  THROW_ERR_INVALID_STATE(
@@ -1721,6 +1858,26 @@ void DatabaseSync::EnableLoadExtension(
1721
1858
  CHECK_ERROR_OR_THROW(isolate, db, load_extension_ret, SQLITE_OK, void());
1722
1859
  }
1723
1860
 
1861
+ void DatabaseSync::EnableDefensive(const FunctionCallbackInfo<Value>& args) {
1862
+ DatabaseSync* db;
1863
+ ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
1864
+ Environment* env = Environment::GetCurrent(args);
1865
+ THROW_AND_RETURN_ON_BAD_STATE(env, !db->IsOpen(), "database is not open");
1866
+
1867
+ auto isolate = args.GetIsolate();
1868
+ if (!args[0]->IsBoolean()) {
1869
+ THROW_ERR_INVALID_ARG_TYPE(isolate,
1870
+ "The \"active\" argument must be a boolean.");
1871
+ return;
1872
+ }
1873
+
1874
+ const int enable = args[0].As<Boolean>()->Value();
1875
+ int defensive_enabled;
1876
+ const int defensive_ret = sqlite3_db_config(
1877
+ db->connection_, SQLITE_DBCONFIG_DEFENSIVE, enable, &defensive_enabled);
1878
+ CHECK_ERROR_OR_THROW(isolate, db, defensive_ret, SQLITE_OK, void());
1879
+ }
1880
+
1724
1881
  void DatabaseSync::LoadExtension(const FunctionCallbackInfo<Value>& args) {
1725
1882
  DatabaseSync* db;
1726
1883
  ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
@@ -1757,6 +1914,113 @@ void DatabaseSync::LoadExtension(const FunctionCallbackInfo<Value>& args) {
1757
1914
  }
1758
1915
  }
1759
1916
 
1917
+ void DatabaseSync::SetAuthorizer(const FunctionCallbackInfo<Value>& args) {
1918
+ DatabaseSync* db;
1919
+ ASSIGN_OR_RETURN_UNWRAP(&db, args.This());
1920
+ Environment* env = Environment::GetCurrent(args);
1921
+ Isolate* isolate = env->isolate();
1922
+
1923
+ if (args[0]->IsNull()) {
1924
+ // Clear the authorizer
1925
+ sqlite3_set_authorizer(db->connection_, nullptr, nullptr);
1926
+ db->object()->SetInternalField(kAuthorizerCallback, Null(isolate));
1927
+ return;
1928
+ }
1929
+
1930
+ if (!args[0]->IsFunction()) {
1931
+ THROW_ERR_INVALID_ARG_TYPE(
1932
+ isolate, "The \"callback\" argument must be a function or null.");
1933
+ return;
1934
+ }
1935
+
1936
+ Local<Function> fn = args[0].As<Function>();
1937
+
1938
+ db->object()->SetInternalField(kAuthorizerCallback, fn);
1939
+
1940
+ int r = sqlite3_set_authorizer(
1941
+ db->connection_, DatabaseSync::AuthorizerCallback, db);
1942
+
1943
+ if (r != SQLITE_OK) {
1944
+ CHECK_ERROR_OR_THROW(isolate, db, r, SQLITE_OK, void());
1945
+ }
1946
+ }
1947
+
1948
+ int DatabaseSync::AuthorizerCallback(void* user_data,
1949
+ int action_code,
1950
+ const char* param1,
1951
+ const char* param2,
1952
+ const char* param3,
1953
+ const char* param4) {
1954
+ DatabaseSync* db = static_cast<DatabaseSync*>(user_data);
1955
+ Environment* env = db->env();
1956
+ Isolate* isolate = env->isolate();
1957
+ HandleScope handle_scope(isolate);
1958
+ Local<Context> context = env->context();
1959
+
1960
+ Local<Value> cb =
1961
+ db->object()->GetInternalField(kAuthorizerCallback).template As<Value>();
1962
+
1963
+ CHECK(cb->IsFunction());
1964
+
1965
+ Local<Function> callback = cb.As<Function>();
1966
+ LocalVector<Value> js_argv(isolate);
1967
+
1968
+ // Convert SQLite authorizer parameters to JavaScript values
1969
+ js_argv.emplace_back(Integer::New(isolate, action_code));
1970
+ js_argv.emplace_back(
1971
+ NullableSQLiteStringToValue(isolate, param1).ToLocalChecked());
1972
+ js_argv.emplace_back(
1973
+ NullableSQLiteStringToValue(isolate, param2).ToLocalChecked());
1974
+ js_argv.emplace_back(
1975
+ NullableSQLiteStringToValue(isolate, param3).ToLocalChecked());
1976
+ js_argv.emplace_back(
1977
+ NullableSQLiteStringToValue(isolate, param4).ToLocalChecked());
1978
+
1979
+ MaybeLocal<Value> retval = callback->Call(
1980
+ context, Undefined(isolate), js_argv.size(), js_argv.data());
1981
+
1982
+ Local<Value> result;
1983
+
1984
+ if (!retval.ToLocal(&result)) {
1985
+ db->SetIgnoreNextSQLiteError(true);
1986
+ return SQLITE_DENY;
1987
+ }
1988
+
1989
+ Local<String> error_message;
1990
+
1991
+ if (!result->IsInt32()) {
1992
+ if (!String::NewFromUtf8(
1993
+ isolate,
1994
+ "Authorizer callback must return an integer authorization code")
1995
+ .ToLocal(&error_message)) {
1996
+ return SQLITE_DENY;
1997
+ }
1998
+
1999
+ Local<Value> err = Exception::TypeError(error_message);
2000
+ isolate->ThrowException(err);
2001
+ db->SetIgnoreNextSQLiteError(true);
2002
+ return SQLITE_DENY;
2003
+ }
2004
+
2005
+ int32_t int_result = result.As<Int32>()->Value();
2006
+ if (int_result != SQLITE_OK && int_result != SQLITE_DENY &&
2007
+ int_result != SQLITE_IGNORE) {
2008
+ if (!String::NewFromUtf8(
2009
+ isolate,
2010
+ "Authorizer callback returned a invalid authorization code")
2011
+ .ToLocal(&error_message)) {
2012
+ return SQLITE_DENY;
2013
+ }
2014
+
2015
+ Local<Value> err = Exception::RangeError(error_message);
2016
+ isolate->ThrowException(err);
2017
+ db->SetIgnoreNextSQLiteError(true);
2018
+ return SQLITE_DENY;
2019
+ }
2020
+
2021
+ return int_result;
2022
+ }
2023
+
1760
2024
  StatementSync::StatementSync(Environment* env,
1761
2025
  Local<Object> object,
1762
2026
  BaseObjectPtr<DatabaseSync> db,
@@ -1764,12 +2028,11 @@ StatementSync::StatementSync(Environment* env,
1764
2028
  : BaseObject(env, object), db_(std::move(db)) {
1765
2029
  MakeWeak();
1766
2030
  statement_ = stmt;
1767
- // In the future, some of these options could be set at the database
1768
- // connection level and inherited by statements to reduce boilerplate.
1769
- return_arrays_ = false;
1770
- use_big_ints_ = false;
1771
- allow_bare_named_params_ = true;
1772
- allow_unknown_named_params_ = false;
2031
+ use_big_ints_ = db_->use_big_ints();
2032
+ return_arrays_ = db_->return_arrays();
2033
+ allow_bare_named_params_ = db_->allow_bare_named_params();
2034
+ allow_unknown_named_params_ = db_->allow_unknown_named_params();
2035
+
1773
2036
  bare_named_params_ = std::nullopt;
1774
2037
  }
1775
2038
 
@@ -1798,7 +2061,7 @@ bool StatementSync::BindParams(const FunctionCallbackInfo<Value>& args) {
1798
2061
 
1799
2062
  if (args[0]->IsObject() && !args[0]->IsArrayBufferView()) {
1800
2063
  Local<Object> obj = args[0].As<Object>();
1801
- Local<Context> context = obj->GetIsolate()->GetCurrentContext();
2064
+ Local<Context> context = Isolate::GetCurrent()->GetCurrentContext();
1802
2065
  Local<Array> keys;
1803
2066
  if (!obj->GetOwnPropertyNames(context).ToLocal(&keys)) {
1804
2067
  return false;
@@ -1856,7 +2119,7 @@ bool StatementSync::BindParams(const FunctionCallbackInfo<Value>& args) {
1856
2119
  continue;
1857
2120
  } else {
1858
2121
  THROW_ERR_INVALID_STATE(
1859
- env(), "Unknown named parameter '%s'", *utf8_key);
2122
+ env(), "Unknown named parameter '%s'", utf8_key);
1860
2123
  return false;
1861
2124
  }
1862
2125
  }
@@ -1875,7 +2138,9 @@ bool StatementSync::BindParams(const FunctionCallbackInfo<Value>& args) {
1875
2138
  }
1876
2139
 
1877
2140
  for (int i = anon_start; i < args.Length(); ++i) {
1878
- while (sqlite3_bind_parameter_name(statement_, anon_idx) != nullptr) {
2141
+ while (1) {
2142
+ const char* param = sqlite3_bind_parameter_name(statement_, anon_idx);
2143
+ if (param == nullptr || param[0] == '?') break;
1879
2144
  anon_idx++;
1880
2145
  }
1881
2146
 
@@ -1930,11 +2195,8 @@ bool StatementSync::BindValue(const Local<Value>& value, const int index) {
1930
2195
  }
1931
2196
 
1932
2197
  MaybeLocal<Value> StatementSync::ColumnToValue(const int column) {
1933
- Isolate* isolate = env()->isolate();
1934
- MaybeLocal<Value> js_val = MaybeLocal<Value>();
1935
- SQLITE_VALUE_TO_JS(
1936
- column, isolate, use_big_ints_, js_val, statement_, column);
1937
- return js_val;
2198
+ return StatementExecutionHelper::ColumnToValue(
2199
+ env(), statement_, column, use_big_ints_);
1938
2200
  }
1939
2201
 
1940
2202
  MaybeLocal<Name> StatementSync::ColumnNameToName(const int column) {
@@ -1947,60 +2209,82 @@ MaybeLocal<Name> StatementSync::ColumnNameToName(const int column) {
1947
2209
  return String::NewFromUtf8(env()->isolate(), col_name).As<Name>();
1948
2210
  }
1949
2211
 
1950
- void StatementSync::MemoryInfo(MemoryTracker* tracker) const {}
1951
-
1952
- void StatementSync::All(const FunctionCallbackInfo<Value>& args) {
1953
- StatementSync* stmt;
1954
- ASSIGN_OR_RETURN_UNWRAP(&stmt, args.This());
1955
- Environment* env = Environment::GetCurrent(args);
1956
- THROW_AND_RETURN_ON_BAD_STATE(
1957
- env, stmt->IsFinalized(), "statement has been finalized");
2212
+ MaybeLocal<Value> StatementExecutionHelper::ColumnToValue(Environment* env,
2213
+ sqlite3_stmt* stmt,
2214
+ const int column,
2215
+ bool use_big_ints) {
1958
2216
  Isolate* isolate = env->isolate();
1959
- int r = sqlite3_reset(stmt->statement_);
1960
- CHECK_ERROR_OR_THROW(isolate, stmt->db_.get(), r, SQLITE_OK, void());
2217
+ MaybeLocal<Value> js_val = MaybeLocal<Value>();
2218
+ SQLITE_VALUE_TO_JS(column, isolate, use_big_ints, js_val, stmt, column);
2219
+ return js_val;
2220
+ }
1961
2221
 
1962
- if (!stmt->BindParams(args)) {
1963
- return;
2222
+ MaybeLocal<Name> StatementExecutionHelper::ColumnNameToName(Environment* env,
2223
+ sqlite3_stmt* stmt,
2224
+ const int column) {
2225
+ const char* col_name = sqlite3_column_name(stmt, column);
2226
+ if (col_name == nullptr) {
2227
+ THROW_ERR_INVALID_STATE(env, "Cannot get name of column %d", column);
2228
+ return MaybeLocal<Name>();
1964
2229
  }
1965
2230
 
1966
- auto reset = OnScopeLeave([&]() { sqlite3_reset(stmt->statement_); });
1967
- int num_cols = sqlite3_column_count(stmt->statement_);
2231
+ return String::NewFromUtf8(env->isolate(), col_name).As<Name>();
2232
+ }
2233
+
2234
+ void StatementSync::MemoryInfo(MemoryTracker* tracker) const {}
2235
+
2236
+ Maybe<void> ExtractRowValues(Environment* env,
2237
+ sqlite3_stmt* stmt,
2238
+ int num_cols,
2239
+ bool use_big_ints,
2240
+ LocalVector<Value>* row_values) {
2241
+ row_values->clear();
2242
+ row_values->reserve(num_cols);
2243
+ for (int i = 0; i < num_cols; ++i) {
2244
+ Local<Value> val;
2245
+ if (!StatementExecutionHelper::ColumnToValue(env, stmt, i, use_big_ints)
2246
+ .ToLocal(&val)) {
2247
+ return Nothing<void>();
2248
+ }
2249
+ row_values->emplace_back(val);
2250
+ }
2251
+ return JustVoid();
2252
+ }
2253
+
2254
+ MaybeLocal<Value> StatementExecutionHelper::All(Environment* env,
2255
+ DatabaseSync* db,
2256
+ sqlite3_stmt* stmt,
2257
+ bool return_arrays,
2258
+ bool use_big_ints) {
2259
+ Isolate* isolate = env->isolate();
2260
+ EscapableHandleScope scope(isolate);
2261
+ int r;
2262
+ int num_cols = sqlite3_column_count(stmt);
1968
2263
  LocalVector<Value> rows(isolate);
2264
+ LocalVector<Value> row_values(isolate);
2265
+ LocalVector<Name> row_keys(isolate);
1969
2266
 
1970
- if (stmt->return_arrays_) {
1971
- while ((r = sqlite3_step(stmt->statement_)) == SQLITE_ROW) {
1972
- LocalVector<Value> array_values(isolate);
1973
- array_values.reserve(num_cols);
1974
- for (int i = 0; i < num_cols; ++i) {
1975
- Local<Value> val;
1976
- if (!stmt->ColumnToValue(i).ToLocal(&val)) return;
1977
- array_values.emplace_back(val);
1978
- }
1979
- Local<Array> row_array =
1980
- Array::New(isolate, array_values.data(), array_values.size());
1981
- rows.emplace_back(row_array);
2267
+ while ((r = sqlite3_step(stmt)) == SQLITE_ROW) {
2268
+ if (ExtractRowValues(env, stmt, num_cols, use_big_ints, &row_values)
2269
+ .IsNothing()) {
2270
+ return MaybeLocal<Value>();
1982
2271
  }
1983
- } else {
1984
- LocalVector<Name> row_keys(isolate);
1985
2272
 
1986
- while ((r = sqlite3_step(stmt->statement_)) == SQLITE_ROW) {
2273
+ if (return_arrays) {
2274
+ Local<Array> row_array =
2275
+ Array::New(isolate, row_values.data(), row_values.size());
2276
+ rows.emplace_back(row_array);
2277
+ } else {
1987
2278
  if (row_keys.size() == 0) {
1988
2279
  row_keys.reserve(num_cols);
1989
2280
  for (int i = 0; i < num_cols; ++i) {
1990
2281
  Local<Name> key;
1991
- if (!stmt->ColumnNameToName(i).ToLocal(&key)) return;
2282
+ if (!ColumnNameToName(env, stmt, i).ToLocal(&key)) {
2283
+ return MaybeLocal<Value>();
2284
+ }
1992
2285
  row_keys.emplace_back(key);
1993
2286
  }
1994
2287
  }
1995
-
1996
- LocalVector<Value> row_values(isolate);
1997
- row_values.reserve(num_cols);
1998
- for (int i = 0; i < num_cols; ++i) {
1999
- Local<Value> val;
2000
- if (!stmt->ColumnToValue(i).ToLocal(&val)) return;
2001
- row_values.emplace_back(val);
2002
- }
2003
-
2004
2288
  DCHECK_EQ(row_keys.size(), row_values.size());
2005
2289
  Local<Object> row_obj = Object::New(
2006
2290
  isolate, Null(isolate), row_keys.data(), row_values.data(), num_cols);
@@ -2008,52 +2292,128 @@ void StatementSync::All(const FunctionCallbackInfo<Value>& args) {
2008
2292
  }
2009
2293
  }
2010
2294
 
2011
- CHECK_ERROR_OR_THROW(isolate, stmt->db_.get(), r, SQLITE_DONE, void());
2012
- args.GetReturnValue().Set(Array::New(isolate, rows.data(), rows.size()));
2295
+ CHECK_ERROR_OR_THROW(isolate, db, r, SQLITE_DONE, MaybeLocal<Value>());
2296
+ return scope.Escape(Array::New(isolate, rows.data(), rows.size()));
2013
2297
  }
2014
2298
 
2015
- void StatementSync::Iterate(const FunctionCallbackInfo<Value>& args) {
2016
- StatementSync* stmt;
2017
- ASSIGN_OR_RETURN_UNWRAP(&stmt, args.This());
2018
- Environment* env = Environment::GetCurrent(args);
2019
- THROW_AND_RETURN_ON_BAD_STATE(
2020
- env, stmt->IsFinalized(), "statement has been finalized");
2021
- auto isolate = env->isolate();
2022
- auto context = env->context();
2023
- int r = sqlite3_reset(stmt->statement_);
2024
- CHECK_ERROR_OR_THROW(isolate, stmt->db_.get(), r, SQLITE_OK, void());
2299
+ MaybeLocal<Object> StatementExecutionHelper::Run(Environment* env,
2300
+ DatabaseSync* db,
2301
+ sqlite3_stmt* stmt,
2302
+ bool use_big_ints) {
2303
+ Isolate* isolate = env->isolate();
2304
+ EscapableHandleScope scope(isolate);
2305
+ sqlite3_step(stmt);
2306
+ int r = sqlite3_reset(stmt);
2307
+ CHECK_ERROR_OR_THROW(isolate, db, r, SQLITE_OK, MaybeLocal<Object>());
2308
+ Local<Object> result = Object::New(isolate);
2309
+ sqlite3_int64 last_insert_rowid = sqlite3_last_insert_rowid(db->Connection());
2310
+ sqlite3_int64 changes = sqlite3_changes64(db->Connection());
2311
+ Local<Value> last_insert_rowid_val;
2312
+ Local<Value> changes_val;
2025
2313
 
2026
- if (!stmt->BindParams(args)) {
2027
- return;
2314
+ if (use_big_ints) {
2315
+ last_insert_rowid_val = BigInt::New(isolate, last_insert_rowid);
2316
+ changes_val = BigInt::New(isolate, changes);
2317
+ } else {
2318
+ last_insert_rowid_val = Number::New(isolate, last_insert_rowid);
2319
+ changes_val = Number::New(isolate, changes);
2028
2320
  }
2029
2321
 
2322
+ if (result
2323
+ ->Set(env->context(),
2324
+ env->last_insert_rowid_string(),
2325
+ last_insert_rowid_val)
2326
+ .IsNothing() ||
2327
+ result->Set(env->context(), env->changes_string(), changes_val)
2328
+ .IsNothing()) {
2329
+ return MaybeLocal<Object>();
2330
+ }
2331
+
2332
+ return scope.Escape(result);
2333
+ }
2334
+
2335
+ BaseObjectPtr<StatementSyncIterator> StatementExecutionHelper::Iterate(
2336
+ Environment* env, BaseObjectPtr<StatementSync> stmt) {
2337
+ Local<Context> context = env->context();
2030
2338
  Local<Object> global = context->Global();
2031
2339
  Local<Value> js_iterator;
2032
2340
  Local<Value> js_iterator_prototype;
2033
2341
  if (!global->Get(context, env->iterator_string()).ToLocal(&js_iterator)) {
2034
- return;
2342
+ return BaseObjectPtr<StatementSyncIterator>();
2035
2343
  }
2036
2344
  if (!js_iterator.As<Object>()
2037
2345
  ->Get(context, env->prototype_string())
2038
2346
  .ToLocal(&js_iterator_prototype)) {
2039
- return;
2347
+ return BaseObjectPtr<StatementSyncIterator>();
2040
2348
  }
2041
2349
 
2042
2350
  BaseObjectPtr<StatementSyncIterator> iter =
2043
- StatementSyncIterator::Create(env, BaseObjectPtr<StatementSync>(stmt));
2351
+ StatementSyncIterator::Create(env, stmt);
2352
+
2353
+ if (!iter) {
2354
+ // Error in iterator creation, likely already threw in Create
2355
+ return BaseObjectPtr<StatementSyncIterator>();
2356
+ }
2044
2357
 
2045
2358
  if (iter->object()
2046
- ->GetPrototype()
2359
+ ->GetPrototypeV2()
2047
2360
  .As<Object>()
2048
- ->SetPrototype(context, js_iterator_prototype)
2361
+ ->SetPrototypeV2(context, js_iterator_prototype)
2049
2362
  .IsNothing()) {
2050
- return;
2363
+ return BaseObjectPtr<StatementSyncIterator>();
2051
2364
  }
2052
2365
 
2053
- args.GetReturnValue().Set(iter->object());
2366
+ return iter;
2054
2367
  }
2055
2368
 
2056
- void StatementSync::Get(const FunctionCallbackInfo<Value>& args) {
2369
+ MaybeLocal<Value> StatementExecutionHelper::Get(Environment* env,
2370
+ DatabaseSync* db,
2371
+ sqlite3_stmt* stmt,
2372
+ bool return_arrays,
2373
+ bool use_big_ints) {
2374
+ Isolate* isolate = env->isolate();
2375
+ EscapableHandleScope scope(isolate);
2376
+ auto reset = OnScopeLeave([&]() { sqlite3_reset(stmt); });
2377
+
2378
+ int r = sqlite3_step(stmt);
2379
+ if (r == SQLITE_DONE) return scope.Escape(Undefined(isolate));
2380
+ if (r != SQLITE_ROW) {
2381
+ THROW_ERR_SQLITE_ERROR(isolate, db);
2382
+ return MaybeLocal<Value>();
2383
+ }
2384
+
2385
+ int num_cols = sqlite3_column_count(stmt);
2386
+ if (num_cols == 0) {
2387
+ return Undefined(isolate);
2388
+ }
2389
+
2390
+ LocalVector<Value> row_values(isolate);
2391
+ if (ExtractRowValues(env, stmt, num_cols, use_big_ints, &row_values)
2392
+ .IsNothing()) {
2393
+ return MaybeLocal<Value>();
2394
+ }
2395
+
2396
+ if (return_arrays) {
2397
+ return scope.Escape(
2398
+ Array::New(isolate, row_values.data(), row_values.size()));
2399
+ } else {
2400
+ LocalVector<Name> keys(isolate);
2401
+ keys.reserve(num_cols);
2402
+ for (int i = 0; i < num_cols; ++i) {
2403
+ Local<Name> key;
2404
+ if (!ColumnNameToName(env, stmt, i).ToLocal(&key)) {
2405
+ return MaybeLocal<Value>();
2406
+ }
2407
+ keys.emplace_back(key);
2408
+ }
2409
+
2410
+ DCHECK_EQ(keys.size(), row_values.size());
2411
+ return scope.Escape(Object::New(
2412
+ isolate, Null(isolate), keys.data(), row_values.data(), num_cols));
2413
+ }
2414
+ }
2415
+
2416
+ void StatementSync::All(const FunctionCallbackInfo<Value>& args) {
2057
2417
  StatementSync* stmt;
2058
2418
  ASSIGN_OR_RETURN_UNWRAP(&stmt, args.This());
2059
2419
  Environment* env = Environment::GetCurrent(args);
@@ -2068,48 +2428,61 @@ void StatementSync::Get(const FunctionCallbackInfo<Value>& args) {
2068
2428
  }
2069
2429
 
2070
2430
  auto reset = OnScopeLeave([&]() { sqlite3_reset(stmt->statement_); });
2071
- r = sqlite3_step(stmt->statement_);
2072
- if (r == SQLITE_DONE) return;
2073
- if (r != SQLITE_ROW) {
2074
- THROW_ERR_SQLITE_ERROR(isolate, stmt->db_.get());
2431
+
2432
+ Local<Value> result;
2433
+ if (StatementExecutionHelper::All(env,
2434
+ stmt->db_.get(),
2435
+ stmt->statement_,
2436
+ stmt->return_arrays_,
2437
+ stmt->use_big_ints_)
2438
+ .ToLocal(&result)) {
2439
+ args.GetReturnValue().Set(result);
2440
+ }
2441
+ }
2442
+
2443
+ void StatementSync::Iterate(const FunctionCallbackInfo<Value>& args) {
2444
+ StatementSync* stmt;
2445
+ ASSIGN_OR_RETURN_UNWRAP(&stmt, args.This());
2446
+ Environment* env = Environment::GetCurrent(args);
2447
+ THROW_AND_RETURN_ON_BAD_STATE(
2448
+ env, stmt->IsFinalized(), "statement has been finalized");
2449
+ int r = sqlite3_reset(stmt->statement_);
2450
+ CHECK_ERROR_OR_THROW(env->isolate(), stmt->db_.get(), r, SQLITE_OK, void());
2451
+
2452
+ if (!stmt->BindParams(args)) {
2075
2453
  return;
2076
2454
  }
2077
2455
 
2078
- int num_cols = sqlite3_column_count(stmt->statement_);
2079
- if (num_cols == 0) {
2456
+ BaseObjectPtr<StatementSyncIterator> iter = StatementExecutionHelper::Iterate(
2457
+ env, BaseObjectPtr<StatementSync>(stmt));
2458
+
2459
+ if (!iter) {
2080
2460
  return;
2081
2461
  }
2082
2462
 
2083
- if (stmt->return_arrays_) {
2084
- LocalVector<Value> array_values(isolate);
2085
- array_values.reserve(num_cols);
2086
- for (int i = 0; i < num_cols; ++i) {
2087
- Local<Value> val;
2088
- if (!stmt->ColumnToValue(i).ToLocal(&val)) return;
2089
- array_values.emplace_back(val);
2090
- }
2091
- Local<Array> result =
2092
- Array::New(isolate, array_values.data(), array_values.size());
2093
- args.GetReturnValue().Set(result);
2094
- } else {
2095
- LocalVector<Name> keys(isolate);
2096
- keys.reserve(num_cols);
2097
- LocalVector<Value> values(isolate);
2098
- values.reserve(num_cols);
2463
+ args.GetReturnValue().Set(iter->object());
2464
+ }
2099
2465
 
2100
- for (int i = 0; i < num_cols; ++i) {
2101
- Local<Name> key;
2102
- if (!stmt->ColumnNameToName(i).ToLocal(&key)) return;
2103
- Local<Value> val;
2104
- if (!stmt->ColumnToValue(i).ToLocal(&val)) return;
2105
- keys.emplace_back(key);
2106
- values.emplace_back(val);
2107
- }
2466
+ void StatementSync::Get(const FunctionCallbackInfo<Value>& args) {
2467
+ StatementSync* stmt;
2468
+ ASSIGN_OR_RETURN_UNWRAP(&stmt, args.This());
2469
+ Environment* env = Environment::GetCurrent(args);
2470
+ THROW_AND_RETURN_ON_BAD_STATE(
2471
+ env, stmt->IsFinalized(), "statement has been finalized");
2472
+ int r = sqlite3_reset(stmt->statement_);
2473
+ CHECK_ERROR_OR_THROW(env->isolate(), stmt->db_.get(), r, SQLITE_OK, void());
2108
2474
 
2109
- DCHECK_EQ(keys.size(), values.size());
2110
- Local<Object> result = Object::New(
2111
- isolate, Null(isolate), keys.data(), values.data(), num_cols);
2475
+ if (!stmt->BindParams(args)) {
2476
+ return;
2477
+ }
2112
2478
 
2479
+ Local<Value> result;
2480
+ if (StatementExecutionHelper::Get(env,
2481
+ stmt->db_.get(),
2482
+ stmt->statement_,
2483
+ stmt->return_arrays_,
2484
+ stmt->use_big_ints_)
2485
+ .ToLocal(&result)) {
2113
2486
  args.GetReturnValue().Set(result);
2114
2487
  }
2115
2488
  }
@@ -2127,35 +2500,12 @@ void StatementSync::Run(const FunctionCallbackInfo<Value>& args) {
2127
2500
  return;
2128
2501
  }
2129
2502
 
2130
- sqlite3_step(stmt->statement_);
2131
- r = sqlite3_reset(stmt->statement_);
2132
- CHECK_ERROR_OR_THROW(env->isolate(), stmt->db_.get(), r, SQLITE_OK, void());
2133
- Local<Object> result = Object::New(env->isolate());
2134
- sqlite3_int64 last_insert_rowid =
2135
- sqlite3_last_insert_rowid(stmt->db_->Connection());
2136
- sqlite3_int64 changes = sqlite3_changes64(stmt->db_->Connection());
2137
- Local<Value> last_insert_rowid_val;
2138
- Local<Value> changes_val;
2139
-
2140
- if (stmt->use_big_ints_) {
2141
- last_insert_rowid_val = BigInt::New(env->isolate(), last_insert_rowid);
2142
- changes_val = BigInt::New(env->isolate(), changes);
2143
- } else {
2144
- last_insert_rowid_val = Number::New(env->isolate(), last_insert_rowid);
2145
- changes_val = Number::New(env->isolate(), changes);
2146
- }
2147
-
2148
- if (result
2149
- ->Set(env->context(),
2150
- env->last_insert_rowid_string(),
2151
- last_insert_rowid_val)
2152
- .IsNothing() ||
2153
- result->Set(env->context(), env->changes_string(), changes_val)
2154
- .IsNothing()) {
2155
- return;
2503
+ Local<Object> result;
2504
+ if (StatementExecutionHelper::Run(
2505
+ env, stmt->db_.get(), stmt->statement_, stmt->use_big_ints_)
2506
+ .ToLocal(&result)) {
2507
+ args.GetReturnValue().Set(result);
2156
2508
  }
2157
-
2158
- args.GetReturnValue().Set(result);
2159
2509
  }
2160
2510
 
2161
2511
  void StatementSync::Columns(const FunctionCallbackInfo<Value>& args) {
@@ -2167,58 +2517,35 @@ void StatementSync::Columns(const FunctionCallbackInfo<Value>& args) {
2167
2517
  int num_cols = sqlite3_column_count(stmt->statement_);
2168
2518
  Isolate* isolate = env->isolate();
2169
2519
  LocalVector<Value> cols(isolate);
2170
- LocalVector<Name> col_keys(isolate,
2171
- {env->column_string(),
2172
- env->database_string(),
2173
- env->name_string(),
2174
- env->table_string(),
2175
- env->type_string()});
2176
- Local<Value> value;
2520
+ auto sqlite_column_template = env->sqlite_column_template();
2521
+ if (sqlite_column_template.IsEmpty()) {
2522
+ static constexpr std::string_view col_keys[] = {
2523
+ "column", "database", "name", "table", "type"};
2524
+ sqlite_column_template = DictionaryTemplate::New(isolate, col_keys);
2525
+ env->set_sqlite_column_template(sqlite_column_template);
2526
+ }
2177
2527
 
2178
2528
  cols.reserve(num_cols);
2179
2529
  for (int i = 0; i < num_cols; ++i) {
2180
- LocalVector<Value> col_values(isolate);
2181
- col_values.reserve(col_keys.size());
2182
-
2183
- if (!NullableSQLiteStringToValue(
2184
- isolate, sqlite3_column_origin_name(stmt->statement_, i))
2185
- .ToLocal(&value)) {
2530
+ MaybeLocal<Value> values[] = {
2531
+ NullableSQLiteStringToValue(
2532
+ isolate, sqlite3_column_origin_name(stmt->statement_, i)),
2533
+ NullableSQLiteStringToValue(
2534
+ isolate, sqlite3_column_database_name(stmt->statement_, i)),
2535
+ stmt->ColumnNameToName(i),
2536
+ NullableSQLiteStringToValue(
2537
+ isolate, sqlite3_column_table_name(stmt->statement_, i)),
2538
+ NullableSQLiteStringToValue(
2539
+ isolate, sqlite3_column_decltype(stmt->statement_, i)),
2540
+ };
2541
+
2542
+ Local<Object> col;
2543
+ if (!NewDictionaryInstanceNullProto(
2544
+ env->context(), sqlite_column_template, values)
2545
+ .ToLocal(&col)) {
2186
2546
  return;
2187
2547
  }
2188
- col_values.emplace_back(value);
2189
-
2190
- if (!NullableSQLiteStringToValue(
2191
- isolate, sqlite3_column_database_name(stmt->statement_, i))
2192
- .ToLocal(&value)) {
2193
- return;
2194
- }
2195
- col_values.emplace_back(value);
2196
-
2197
- if (!stmt->ColumnNameToName(i).ToLocal(&value)) {
2198
- return;
2199
- }
2200
- col_values.emplace_back(value);
2201
-
2202
- if (!NullableSQLiteStringToValue(
2203
- isolate, sqlite3_column_table_name(stmt->statement_, i))
2204
- .ToLocal(&value)) {
2205
- return;
2206
- }
2207
- col_values.emplace_back(value);
2208
-
2209
- if (!NullableSQLiteStringToValue(
2210
- isolate, sqlite3_column_decltype(stmt->statement_, i))
2211
- .ToLocal(&value)) {
2212
- return;
2213
- }
2214
- col_values.emplace_back(value);
2215
-
2216
- Local<Object> column = Object::New(isolate,
2217
- Null(isolate),
2218
- col_keys.data(),
2219
- col_values.data(),
2220
- col_keys.size());
2221
- cols.emplace_back(column);
2548
+ cols.emplace_back(col);
2222
2549
  }
2223
2550
 
2224
2551
  args.GetReturnValue().Set(Array::New(isolate, cols.data(), cols.size()));
@@ -2331,6 +2658,17 @@ void IllegalConstructor(const FunctionCallbackInfo<Value>& args) {
2331
2658
  THROW_ERR_ILLEGAL_CONSTRUCTOR(Environment::GetCurrent(args));
2332
2659
  }
2333
2660
 
2661
+ SQLTagStore::SQLTagStore(Environment* env,
2662
+ Local<Object> object,
2663
+ BaseObjectWeakPtr<DatabaseSync> database,
2664
+ int capacity)
2665
+ : BaseObject(env, object),
2666
+ database_(std::move(database)),
2667
+ sql_tags_(capacity),
2668
+ capacity_(capacity) {
2669
+ MakeWeak();
2670
+ }
2671
+
2334
2672
  static inline void SetSideEffectFreeGetter(
2335
2673
  Isolate* isolate,
2336
2674
  Local<FunctionTemplate> class_template,
@@ -2348,6 +2686,299 @@ static inline void SetSideEffectFreeGetter(
2348
2686
  name, getter, Local<FunctionTemplate>(), DontDelete);
2349
2687
  }
2350
2688
 
2689
+ SQLTagStore::~SQLTagStore() {}
2690
+
2691
+ Local<FunctionTemplate> SQLTagStore::GetConstructorTemplate(Environment* env) {
2692
+ Isolate* isolate = env->isolate();
2693
+ Local<FunctionTemplate> tmpl =
2694
+ NewFunctionTemplate(isolate, IllegalConstructor);
2695
+ tmpl->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "SQLTagStore"));
2696
+ tmpl->InstanceTemplate()->SetInternalFieldCount(
2697
+ SQLTagStore::kInternalFieldCount);
2698
+ SetProtoMethod(isolate, tmpl, "get", Get);
2699
+ SetProtoMethod(isolate, tmpl, "all", All);
2700
+ SetProtoMethod(isolate, tmpl, "iterate", Iterate);
2701
+ SetProtoMethod(isolate, tmpl, "run", Run);
2702
+ SetProtoMethod(isolate, tmpl, "clear", Clear);
2703
+ SetProtoMethod(isolate, tmpl, "size", Size);
2704
+ SetSideEffectFreeGetter(
2705
+ isolate, tmpl, FIXED_ONE_BYTE_STRING(isolate, "capacity"), Capacity);
2706
+ SetSideEffectFreeGetter(
2707
+ isolate, tmpl, FIXED_ONE_BYTE_STRING(isolate, "db"), DatabaseGetter);
2708
+ return tmpl;
2709
+ }
2710
+
2711
+ BaseObjectPtr<SQLTagStore> SQLTagStore::Create(
2712
+ Environment* env, BaseObjectWeakPtr<DatabaseSync> database, int capacity) {
2713
+ Local<Object> obj;
2714
+ if (!GetConstructorTemplate(env)
2715
+ ->InstanceTemplate()
2716
+ ->NewInstance(env->context())
2717
+ .ToLocal(&obj)) {
2718
+ return nullptr;
2719
+ }
2720
+ return MakeBaseObject<SQLTagStore>(env, obj, std::move(database), capacity);
2721
+ }
2722
+
2723
+ void SQLTagStore::DatabaseGetter(const FunctionCallbackInfo<Value>& args) {
2724
+ SQLTagStore* store;
2725
+ ASSIGN_OR_RETURN_UNWRAP(&store, args.This());
2726
+ args.GetReturnValue().Set(store->database_->object());
2727
+ }
2728
+
2729
+ void SQLTagStore::Run(const FunctionCallbackInfo<Value>& info) {
2730
+ SQLTagStore* session;
2731
+ ASSIGN_OR_RETURN_UNWRAP(&session, info.This());
2732
+ Environment* env = Environment::GetCurrent(info);
2733
+
2734
+ THROW_AND_RETURN_ON_BAD_STATE(
2735
+ env, !session->database_->IsOpen(), "database is not open");
2736
+
2737
+ BaseObjectPtr<StatementSync> stmt = PrepareStatement(info);
2738
+
2739
+ if (!stmt) {
2740
+ return;
2741
+ }
2742
+
2743
+ uint32_t n_params = info.Length() - 1;
2744
+ int r = sqlite3_reset(stmt->statement_);
2745
+ CHECK_ERROR_OR_THROW(env->isolate(), stmt->db_.get(), r, SQLITE_OK, void());
2746
+ int param_count = sqlite3_bind_parameter_count(stmt->statement_);
2747
+ for (int i = 0; i < static_cast<int>(n_params) && i < param_count; ++i) {
2748
+ Local<Value> value = info[i + 1];
2749
+ if (!stmt->BindValue(value, i + 1)) {
2750
+ return;
2751
+ }
2752
+ }
2753
+
2754
+ Local<Object> result;
2755
+ if (StatementExecutionHelper::Run(
2756
+ env, stmt->db_.get(), stmt->statement_, stmt->use_big_ints_)
2757
+ .ToLocal(&result)) {
2758
+ info.GetReturnValue().Set(result);
2759
+ }
2760
+ }
2761
+
2762
+ void SQLTagStore::Iterate(const FunctionCallbackInfo<Value>& args) {
2763
+ SQLTagStore* session;
2764
+ ASSIGN_OR_RETURN_UNWRAP(&session, args.This());
2765
+ Environment* env = Environment::GetCurrent(args);
2766
+
2767
+ THROW_AND_RETURN_ON_BAD_STATE(
2768
+ env, !session->database_->IsOpen(), "database is not open");
2769
+
2770
+ BaseObjectPtr<StatementSync> stmt = PrepareStatement(args);
2771
+
2772
+ if (!stmt) {
2773
+ return;
2774
+ }
2775
+
2776
+ uint32_t n_params = args.Length() - 1;
2777
+ int r = sqlite3_reset(stmt->statement_);
2778
+ CHECK_ERROR_OR_THROW(env->isolate(), stmt->db_.get(), r, SQLITE_OK, void());
2779
+ int param_count = sqlite3_bind_parameter_count(stmt->statement_);
2780
+ for (int i = 0; i < static_cast<int>(n_params) && i < param_count; ++i) {
2781
+ Local<Value> value = args[i + 1];
2782
+ if (!stmt->BindValue(value, i + 1)) {
2783
+ return;
2784
+ }
2785
+ }
2786
+
2787
+ BaseObjectPtr<StatementSyncIterator> iter = StatementExecutionHelper::Iterate(
2788
+ env, BaseObjectPtr<StatementSync>(stmt));
2789
+
2790
+ if (!iter) {
2791
+ return;
2792
+ }
2793
+
2794
+ args.GetReturnValue().Set(iter->object());
2795
+ }
2796
+
2797
+ void SQLTagStore::Get(const FunctionCallbackInfo<Value>& args) {
2798
+ SQLTagStore* session;
2799
+ ASSIGN_OR_RETURN_UNWRAP(&session, args.This());
2800
+ Environment* env = Environment::GetCurrent(args);
2801
+
2802
+ THROW_AND_RETURN_ON_BAD_STATE(
2803
+ env, !session->database_->IsOpen(), "database is not open");
2804
+
2805
+ BaseObjectPtr<StatementSync> stmt = PrepareStatement(args);
2806
+
2807
+ if (!stmt) {
2808
+ return;
2809
+ }
2810
+
2811
+ uint32_t n_params = args.Length() - 1;
2812
+ Isolate* isolate = env->isolate();
2813
+
2814
+ int r = sqlite3_reset(stmt->statement_);
2815
+ CHECK_ERROR_OR_THROW(isolate, stmt->db_.get(), r, SQLITE_OK, void());
2816
+
2817
+ int param_count = sqlite3_bind_parameter_count(stmt->statement_);
2818
+ for (int i = 0; i < static_cast<int>(n_params) && i < param_count; ++i) {
2819
+ Local<Value> value = args[i + 1];
2820
+ if (!stmt->BindValue(value, i + 1)) {
2821
+ return;
2822
+ }
2823
+ }
2824
+
2825
+ Local<Value> result;
2826
+ if (StatementExecutionHelper::Get(env,
2827
+ stmt->db_.get(),
2828
+ stmt->statement_,
2829
+ stmt->return_arrays_,
2830
+ stmt->use_big_ints_)
2831
+ .ToLocal(&result)) {
2832
+ args.GetReturnValue().Set(result);
2833
+ }
2834
+ }
2835
+
2836
+ void SQLTagStore::All(const FunctionCallbackInfo<Value>& args) {
2837
+ SQLTagStore* session;
2838
+ ASSIGN_OR_RETURN_UNWRAP(&session, args.This());
2839
+ Environment* env = Environment::GetCurrent(args);
2840
+
2841
+ THROW_AND_RETURN_ON_BAD_STATE(
2842
+ env, !session->database_->IsOpen(), "database is not open");
2843
+
2844
+ BaseObjectPtr<StatementSync> stmt = PrepareStatement(args);
2845
+
2846
+ if (!stmt) {
2847
+ return;
2848
+ }
2849
+
2850
+ uint32_t n_params = args.Length() - 1;
2851
+ Isolate* isolate = env->isolate();
2852
+
2853
+ int r = sqlite3_reset(stmt->statement_);
2854
+ CHECK_ERROR_OR_THROW(isolate, stmt->db_.get(), r, SQLITE_OK, void());
2855
+
2856
+ int param_count = sqlite3_bind_parameter_count(stmt->statement_);
2857
+ for (int i = 0; i < static_cast<int>(n_params) && i < param_count; ++i) {
2858
+ Local<Value> value = args[i + 1];
2859
+ if (!stmt->BindValue(value, i + 1)) {
2860
+ return;
2861
+ }
2862
+ }
2863
+
2864
+ auto reset = OnScopeLeave([&]() { sqlite3_reset(stmt->statement_); });
2865
+ Local<Value> result;
2866
+ if (StatementExecutionHelper::All(env,
2867
+ stmt->db_.get(),
2868
+ stmt->statement_,
2869
+ stmt->return_arrays_,
2870
+ stmt->use_big_ints_)
2871
+ .ToLocal(&result)) {
2872
+ args.GetReturnValue().Set(result);
2873
+ }
2874
+ }
2875
+
2876
+ void SQLTagStore::Size(const FunctionCallbackInfo<Value>& info) {
2877
+ SQLTagStore* store;
2878
+ ASSIGN_OR_RETURN_UNWRAP(&store, info.This());
2879
+ info.GetReturnValue().Set(
2880
+ Integer::New(info.GetIsolate(), store->sql_tags_.Size()));
2881
+ }
2882
+
2883
+ void SQLTagStore::Capacity(const FunctionCallbackInfo<Value>& info) {
2884
+ SQLTagStore* store;
2885
+ ASSIGN_OR_RETURN_UNWRAP(&store, info.This());
2886
+ info.GetReturnValue().Set(
2887
+ Integer::New(info.GetIsolate(), store->sql_tags_.Capacity()));
2888
+ }
2889
+
2890
+ void SQLTagStore::Clear(const FunctionCallbackInfo<Value>& info) {
2891
+ SQLTagStore* store;
2892
+ ASSIGN_OR_RETURN_UNWRAP(&store, info.This());
2893
+ store->sql_tags_.Clear();
2894
+ }
2895
+
2896
+ BaseObjectPtr<StatementSync> SQLTagStore::PrepareStatement(
2897
+ const FunctionCallbackInfo<Value>& args) {
2898
+ SQLTagStore* session = BaseObject::FromJSObject<SQLTagStore>(args.This());
2899
+ if (!session) {
2900
+ THROW_ERR_INVALID_ARG_TYPE(
2901
+ Environment::GetCurrent(args)->isolate(),
2902
+ "This method can only be called on SQLTagStore instances.");
2903
+ return BaseObjectPtr<StatementSync>();
2904
+ }
2905
+ Environment* env = Environment::GetCurrent(args);
2906
+ Isolate* isolate = env->isolate();
2907
+ Local<Context> context = isolate->GetCurrentContext();
2908
+
2909
+ if (args.Length() < 1 || !args[0]->IsArray()) {
2910
+ THROW_ERR_INVALID_ARG_TYPE(
2911
+ isolate,
2912
+ "First argument must be an array of strings (template literal).");
2913
+ return BaseObjectPtr<StatementSync>();
2914
+ }
2915
+
2916
+ Local<Array> strings = args[0].As<Array>();
2917
+ uint32_t n_strings = strings->Length();
2918
+ uint32_t n_params = args.Length() - 1;
2919
+
2920
+ std::string sql;
2921
+ for (uint32_t i = 0; i < n_strings; ++i) {
2922
+ Local<Value> str_val;
2923
+ if (!strings->Get(context, i).ToLocal(&str_val) || !str_val->IsString()) {
2924
+ THROW_ERR_INVALID_ARG_TYPE(isolate,
2925
+ "Template literal parts must be strings.");
2926
+ return BaseObjectPtr<StatementSync>();
2927
+ }
2928
+ Utf8Value part(isolate, str_val);
2929
+ sql += part.ToStringView();
2930
+ if (i < n_params) {
2931
+ sql += "?";
2932
+ }
2933
+ }
2934
+
2935
+ BaseObjectPtr<StatementSync> stmt = nullptr;
2936
+ if (session->sql_tags_.Exists(sql)) {
2937
+ stmt = session->sql_tags_.Get(sql);
2938
+ if (stmt->IsFinalized()) {
2939
+ session->sql_tags_.Erase(sql);
2940
+ stmt = nullptr;
2941
+ }
2942
+ }
2943
+
2944
+ if (stmt == nullptr) {
2945
+ sqlite3_stmt* s = nullptr;
2946
+ int r = sqlite3_prepare_v2(
2947
+ session->database_->connection_, sql.data(), sql.size(), &s, 0);
2948
+
2949
+ if (r != SQLITE_OK) {
2950
+ THROW_ERR_SQLITE_ERROR(isolate, "Failed to prepare statement");
2951
+ sqlite3_finalize(s);
2952
+ return BaseObjectPtr<StatementSync>();
2953
+ }
2954
+
2955
+ BaseObjectPtr<StatementSync> stmt_obj = StatementSync::Create(
2956
+ env, BaseObjectPtr<DatabaseSync>(session->database_), s);
2957
+
2958
+ if (!stmt_obj) {
2959
+ THROW_ERR_SQLITE_ERROR(isolate, "Failed to create StatementSync");
2960
+ sqlite3_finalize(s);
2961
+ return BaseObjectPtr<StatementSync>();
2962
+ }
2963
+
2964
+ session->sql_tags_.Put(sql, stmt_obj);
2965
+ stmt = stmt_obj;
2966
+ }
2967
+
2968
+ return stmt;
2969
+ }
2970
+
2971
+ void SQLTagStore::MemoryInfo(MemoryTracker* tracker) const {
2972
+ tracker->TrackFieldWithSize(MemoryInfoName(), SelfSize());
2973
+ tracker->TrackField("database", database_);
2974
+ size_t cache_content_size = 0;
2975
+ for (const auto& pair : sql_tags_) {
2976
+ cache_content_size += pair.first.capacity();
2977
+ cache_content_size += sizeof(pair.second);
2978
+ }
2979
+ tracker->TrackFieldWithSize("sql_tags_cache", cache_content_size);
2980
+ }
2981
+
2351
2982
  Local<FunctionTemplate> StatementSync::GetConstructorTemplate(
2352
2983
  Environment* env) {
2353
2984
  Local<FunctionTemplate> tmpl =
@@ -2450,15 +3081,19 @@ void StatementSyncIterator::Next(const FunctionCallbackInfo<Value>& args) {
2450
3081
  THROW_AND_RETURN_ON_BAD_STATE(
2451
3082
  env, iter->stmt_->IsFinalized(), "statement has been finalized");
2452
3083
  Isolate* isolate = env->isolate();
2453
- LocalVector<Name> keys(isolate, {env->done_string(), env->value_string()});
3084
+
3085
+ auto iter_template = getLazyIterTemplate(env);
2454
3086
 
2455
3087
  if (iter->done_) {
2456
- LocalVector<Value> values(isolate,
2457
- {Boolean::New(isolate, true), Null(isolate)});
2458
- DCHECK_EQ(values.size(), keys.size());
2459
- Local<Object> result = Object::New(
2460
- isolate, Null(isolate), keys.data(), values.data(), keys.size());
2461
- args.GetReturnValue().Set(result);
3088
+ MaybeLocal<Value> values[]{
3089
+ Boolean::New(isolate, true),
3090
+ Null(isolate),
3091
+ };
3092
+ Local<Object> result;
3093
+ if (NewDictionaryInstanceNullProto(env->context(), iter_template, values)
3094
+ .ToLocal(&result)) {
3095
+ args.GetReturnValue().Set(result);
3096
+ }
2462
3097
  return;
2463
3098
  }
2464
3099
 
@@ -2467,39 +3102,37 @@ void StatementSyncIterator::Next(const FunctionCallbackInfo<Value>& args) {
2467
3102
  CHECK_ERROR_OR_THROW(
2468
3103
  env->isolate(), iter->stmt_->db_.get(), r, SQLITE_DONE, void());
2469
3104
  sqlite3_reset(iter->stmt_->statement_);
2470
- LocalVector<Value> values(isolate,
2471
- {Boolean::New(isolate, true), Null(isolate)});
2472
- DCHECK_EQ(values.size(), keys.size());
2473
- Local<Object> result = Object::New(
2474
- isolate, Null(isolate), keys.data(), values.data(), keys.size());
2475
- args.GetReturnValue().Set(result);
3105
+ MaybeLocal<Value> values[] = {Boolean::New(isolate, true), Null(isolate)};
3106
+ Local<Object> result;
3107
+ if (NewDictionaryInstanceNullProto(env->context(), iter_template, values)
3108
+ .ToLocal(&result)) {
3109
+ args.GetReturnValue().Set(result);
3110
+ }
2476
3111
  return;
2477
3112
  }
2478
3113
 
2479
3114
  int num_cols = sqlite3_column_count(iter->stmt_->statement_);
2480
3115
  Local<Value> row_value;
3116
+ LocalVector<Name> row_keys(isolate);
3117
+ LocalVector<Value> row_values(isolate);
3118
+
3119
+ if (ExtractRowValues(env,
3120
+ iter->stmt_->statement_,
3121
+ num_cols,
3122
+ iter->stmt_->use_big_ints_,
3123
+ &row_values)
3124
+ .IsNothing()) {
3125
+ return;
3126
+ }
2481
3127
 
2482
3128
  if (iter->stmt_->return_arrays_) {
2483
- LocalVector<Value> array_values(isolate);
2484
- array_values.reserve(num_cols);
2485
- for (int i = 0; i < num_cols; ++i) {
2486
- Local<Value> val;
2487
- if (!iter->stmt_->ColumnToValue(i).ToLocal(&val)) return;
2488
- array_values.emplace_back(val);
2489
- }
2490
- row_value = Array::New(isolate, array_values.data(), array_values.size());
3129
+ row_value = Array::New(isolate, row_values.data(), row_values.size());
2491
3130
  } else {
2492
- LocalVector<Name> row_keys(isolate);
2493
- LocalVector<Value> row_values(isolate);
2494
3131
  row_keys.reserve(num_cols);
2495
- row_values.reserve(num_cols);
2496
3132
  for (int i = 0; i < num_cols; ++i) {
2497
3133
  Local<Name> key;
2498
3134
  if (!iter->stmt_->ColumnNameToName(i).ToLocal(&key)) return;
2499
- Local<Value> val;
2500
- if (!iter->stmt_->ColumnToValue(i).ToLocal(&val)) return;
2501
3135
  row_keys.emplace_back(key);
2502
- row_values.emplace_back(val);
2503
3136
  }
2504
3137
 
2505
3138
  DCHECK_EQ(row_keys.size(), row_values.size());
@@ -2507,11 +3140,12 @@ void StatementSyncIterator::Next(const FunctionCallbackInfo<Value>& args) {
2507
3140
  isolate, Null(isolate), row_keys.data(), row_values.data(), num_cols);
2508
3141
  }
2509
3142
 
2510
- LocalVector<Value> values(isolate, {Boolean::New(isolate, false), row_value});
2511
- DCHECK_EQ(keys.size(), values.size());
2512
- Local<Object> result = Object::New(
2513
- isolate, Null(isolate), keys.data(), values.data(), keys.size());
2514
- args.GetReturnValue().Set(result);
3143
+ MaybeLocal<Value> values[] = {Boolean::New(isolate, false), row_value};
3144
+ Local<Object> result;
3145
+ if (NewDictionaryInstanceNullProto(env->context(), iter_template, values)
3146
+ .ToLocal(&result)) {
3147
+ args.GetReturnValue().Set(result);
3148
+ }
2515
3149
  }
2516
3150
 
2517
3151
  void StatementSyncIterator::Return(const FunctionCallbackInfo<Value>& args) {
@@ -2524,14 +3158,15 @@ void StatementSyncIterator::Return(const FunctionCallbackInfo<Value>& args) {
2524
3158
 
2525
3159
  sqlite3_reset(iter->stmt_->statement_);
2526
3160
  iter->done_ = true;
2527
- LocalVector<Name> keys(isolate, {env->done_string(), env->value_string()});
2528
- LocalVector<Value> values(isolate,
2529
- {Boolean::New(isolate, true), Null(isolate)});
2530
3161
 
2531
- DCHECK_EQ(keys.size(), values.size());
2532
- Local<Object> result = Object::New(
2533
- isolate, Null(isolate), keys.data(), values.data(), keys.size());
2534
- args.GetReturnValue().Set(result);
3162
+ auto iter_template = getLazyIterTemplate(env);
3163
+ MaybeLocal<Value> values[] = {Boolean::New(isolate, true), Null(isolate)};
3164
+
3165
+ Local<Object> result;
3166
+ if (NewDictionaryInstanceNullProto(env->context(), iter_template, values)
3167
+ .ToLocal(&result)) {
3168
+ args.GetReturnValue().Set(result);
3169
+ }
2535
3170
  }
2536
3171
 
2537
3172
  Session::Session(Environment* env,
@@ -2577,6 +3212,7 @@ Local<FunctionTemplate> Session::GetConstructorTemplate(Environment* env) {
2577
3212
  SetProtoMethod(
2578
3213
  isolate, tmpl, "patchset", Session::Changeset<sqlite3session_patchset>);
2579
3214
  SetProtoMethod(isolate, tmpl, "close", Session::Close);
3215
+ SetProtoDispose(isolate, tmpl, Session::Dispose);
2580
3216
  env->set_sqlite_session_constructor_template(tmpl);
2581
3217
  }
2582
3218
  return tmpl;
@@ -2621,6 +3257,14 @@ void Session::Close(const FunctionCallbackInfo<Value>& args) {
2621
3257
  session->Delete();
2622
3258
  }
2623
3259
 
3260
+ void Session::Dispose(const v8::FunctionCallbackInfo<v8::Value>& args) {
3261
+ v8::TryCatch try_catch(args.GetIsolate());
3262
+ Close(args);
3263
+ if (try_catch.HasCaught()) {
3264
+ CHECK(try_catch.CanContinue());
3265
+ }
3266
+ }
3267
+
2624
3268
  void Session::Delete() {
2625
3269
  if (!database_ || !database_->connection_ || session_ == nullptr) return;
2626
3270
  sqlite3session_delete(session_);
@@ -2638,6 +3282,47 @@ void DefineConstants(Local<Object> target) {
2638
3282
  NODE_DEFINE_CONSTANT(target, SQLITE_CHANGESET_CONFLICT);
2639
3283
  NODE_DEFINE_CONSTANT(target, SQLITE_CHANGESET_CONSTRAINT);
2640
3284
  NODE_DEFINE_CONSTANT(target, SQLITE_CHANGESET_FOREIGN_KEY);
3285
+
3286
+ // Authorization result codes
3287
+ NODE_DEFINE_CONSTANT(target, SQLITE_OK);
3288
+ NODE_DEFINE_CONSTANT(target, SQLITE_DENY);
3289
+ NODE_DEFINE_CONSTANT(target, SQLITE_IGNORE);
3290
+
3291
+ // Authorization action codes
3292
+ NODE_DEFINE_CONSTANT(target, SQLITE_CREATE_INDEX);
3293
+ NODE_DEFINE_CONSTANT(target, SQLITE_CREATE_TABLE);
3294
+ NODE_DEFINE_CONSTANT(target, SQLITE_CREATE_TEMP_INDEX);
3295
+ NODE_DEFINE_CONSTANT(target, SQLITE_CREATE_TEMP_TABLE);
3296
+ NODE_DEFINE_CONSTANT(target, SQLITE_CREATE_TEMP_TRIGGER);
3297
+ NODE_DEFINE_CONSTANT(target, SQLITE_CREATE_TEMP_VIEW);
3298
+ NODE_DEFINE_CONSTANT(target, SQLITE_CREATE_TRIGGER);
3299
+ NODE_DEFINE_CONSTANT(target, SQLITE_CREATE_VIEW);
3300
+ NODE_DEFINE_CONSTANT(target, SQLITE_DELETE);
3301
+ NODE_DEFINE_CONSTANT(target, SQLITE_DROP_INDEX);
3302
+ NODE_DEFINE_CONSTANT(target, SQLITE_DROP_TABLE);
3303
+ NODE_DEFINE_CONSTANT(target, SQLITE_DROP_TEMP_INDEX);
3304
+ NODE_DEFINE_CONSTANT(target, SQLITE_DROP_TEMP_TABLE);
3305
+ NODE_DEFINE_CONSTANT(target, SQLITE_DROP_TEMP_TRIGGER);
3306
+ NODE_DEFINE_CONSTANT(target, SQLITE_DROP_TEMP_VIEW);
3307
+ NODE_DEFINE_CONSTANT(target, SQLITE_DROP_TRIGGER);
3308
+ NODE_DEFINE_CONSTANT(target, SQLITE_DROP_VIEW);
3309
+ NODE_DEFINE_CONSTANT(target, SQLITE_INSERT);
3310
+ NODE_DEFINE_CONSTANT(target, SQLITE_PRAGMA);
3311
+ NODE_DEFINE_CONSTANT(target, SQLITE_READ);
3312
+ NODE_DEFINE_CONSTANT(target, SQLITE_SELECT);
3313
+ NODE_DEFINE_CONSTANT(target, SQLITE_TRANSACTION);
3314
+ NODE_DEFINE_CONSTANT(target, SQLITE_UPDATE);
3315
+ NODE_DEFINE_CONSTANT(target, SQLITE_ATTACH);
3316
+ NODE_DEFINE_CONSTANT(target, SQLITE_DETACH);
3317
+ NODE_DEFINE_CONSTANT(target, SQLITE_ALTER_TABLE);
3318
+ NODE_DEFINE_CONSTANT(target, SQLITE_REINDEX);
3319
+ NODE_DEFINE_CONSTANT(target, SQLITE_ANALYZE);
3320
+ NODE_DEFINE_CONSTANT(target, SQLITE_CREATE_VTABLE);
3321
+ NODE_DEFINE_CONSTANT(target, SQLITE_DROP_VTABLE);
3322
+ NODE_DEFINE_CONSTANT(target, SQLITE_FUNCTION);
3323
+ NODE_DEFINE_CONSTANT(target, SQLITE_SAVEPOINT);
3324
+ NODE_DEFINE_CONSTANT(target, SQLITE_COPY);
3325
+ NODE_DEFINE_CONSTANT(target, SQLITE_RECURSIVE);
2641
3326
  }
2642
3327
 
2643
3328
  static void Initialize(Local<Object> target,
@@ -2656,9 +3341,12 @@ static void Initialize(Local<Object> target,
2656
3341
 
2657
3342
  SetProtoMethod(isolate, db_tmpl, "open", DatabaseSync::Open);
2658
3343
  SetProtoMethod(isolate, db_tmpl, "close", DatabaseSync::Close);
3344
+ SetProtoDispose(isolate, db_tmpl, DatabaseSync::Dispose);
2659
3345
  SetProtoMethod(isolate, db_tmpl, "prepare", DatabaseSync::Prepare);
2660
3346
  SetProtoMethod(isolate, db_tmpl, "exec", DatabaseSync::Exec);
2661
3347
  SetProtoMethod(isolate, db_tmpl, "function", DatabaseSync::CustomFunction);
3348
+ SetProtoMethod(
3349
+ isolate, db_tmpl, "createTagStore", DatabaseSync::CreateTagStore);
2662
3350
  SetProtoMethodNoSideEffect(
2663
3351
  isolate, db_tmpl, "location", DatabaseSync::Location);
2664
3352
  SetProtoMethod(
@@ -2671,8 +3359,12 @@ static void Initialize(Local<Object> target,
2671
3359
  db_tmpl,
2672
3360
  "enableLoadExtension",
2673
3361
  DatabaseSync::EnableLoadExtension);
3362
+ SetProtoMethod(
3363
+ isolate, db_tmpl, "enableDefensive", DatabaseSync::EnableDefensive);
2674
3364
  SetProtoMethod(
2675
3365
  isolate, db_tmpl, "loadExtension", DatabaseSync::LoadExtension);
3366
+ SetProtoMethod(
3367
+ isolate, db_tmpl, "setAuthorizer", DatabaseSync::SetAuthorizer);
2676
3368
  SetSideEffectFreeGetter(isolate,
2677
3369
  db_tmpl,
2678
3370
  FIXED_ONE_BYTE_STRING(isolate, "isOpen"),
@@ -2681,11 +3373,20 @@ static void Initialize(Local<Object> target,
2681
3373
  db_tmpl,
2682
3374
  FIXED_ONE_BYTE_STRING(isolate, "isTransaction"),
2683
3375
  DatabaseSync::IsTransactionGetter);
3376
+ Local<String> sqlite_type_key = FIXED_ONE_BYTE_STRING(isolate, "sqlite-type");
3377
+ Local<v8::Symbol> sqlite_type_symbol =
3378
+ v8::Symbol::For(isolate, sqlite_type_key);
3379
+ Local<String> database_sync_string =
3380
+ FIXED_ONE_BYTE_STRING(isolate, "node:sqlite");
3381
+ db_tmpl->InstanceTemplate()->Set(sqlite_type_symbol, database_sync_string);
3382
+
2684
3383
  SetConstructorFunction(context, target, "DatabaseSync", db_tmpl);
2685
3384
  SetConstructorFunction(context,
2686
3385
  target,
2687
3386
  "StatementSync",
2688
3387
  StatementSync::GetConstructorTemplate(env));
3388
+ SetConstructorFunction(
3389
+ context, target, "Session", Session::GetConstructorTemplate(env));
2689
3390
 
2690
3391
  target->Set(context, env->constants_string(), constants).Check();
2691
3392