@photostructure/sqlite 0.3.0 → 0.5.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 (41) hide show
  1. package/CHANGELOG.md +65 -16
  2. package/README.md +5 -10
  3. package/binding.gyp +2 -2
  4. package/dist/index.cjs +314 -11
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.d.cts +346 -89
  7. package/dist/index.d.mts +346 -89
  8. package/dist/index.d.ts +346 -89
  9. package/dist/index.mjs +311 -10
  10. package/dist/index.mjs.map +1 -1
  11. package/package.json +72 -63
  12. package/prebuilds/darwin-arm64/@photostructure+sqlite.glibc.node +0 -0
  13. package/prebuilds/darwin-x64/@photostructure+sqlite.glibc.node +0 -0
  14. package/prebuilds/linux-arm64/@photostructure+sqlite.glibc.node +0 -0
  15. package/prebuilds/linux-arm64/@photostructure+sqlite.musl.node +0 -0
  16. package/prebuilds/linux-x64/@photostructure+sqlite.glibc.node +0 -0
  17. package/prebuilds/linux-x64/@photostructure+sqlite.musl.node +0 -0
  18. package/prebuilds/test_extension.so +0 -0
  19. package/prebuilds/win32-arm64/@photostructure+sqlite.glibc.node +0 -0
  20. package/prebuilds/win32-x64/@photostructure+sqlite.glibc.node +0 -0
  21. package/src/aggregate_function.cpp +222 -114
  22. package/src/aggregate_function.h +5 -6
  23. package/src/binding.cpp +30 -21
  24. package/src/enhance.ts +552 -0
  25. package/src/index.ts +84 -9
  26. package/src/shims/node_errors.h +34 -15
  27. package/src/shims/sqlite_errors.h +34 -8
  28. package/src/sql-tag-store.ts +6 -9
  29. package/src/sqlite_impl.cpp +1044 -394
  30. package/src/sqlite_impl.h +46 -7
  31. package/src/transaction.ts +178 -0
  32. package/src/types/database-sync-instance.ts +6 -40
  33. package/src/types/pragma-options.ts +23 -0
  34. package/src/types/statement-sync-instance.ts +38 -12
  35. package/src/types/transaction.ts +72 -0
  36. package/src/upstream/node_sqlite.cc +143 -43
  37. package/src/upstream/node_sqlite.h +15 -11
  38. package/src/upstream/sqlite3.c +102 -58
  39. package/src/upstream/sqlite3.h +5 -5
  40. package/src/user_function.cpp +138 -141
  41. package/src/user_function.h +3 -0
@@ -322,6 +322,8 @@ class CustomAggregate {
322
322
 
323
323
  auto recv = Undefined(isolate);
324
324
  LocalVector<Value> js_argv(isolate);
325
+ js_argv.reserve(argc + 1);
326
+
325
327
  js_argv.emplace_back(Local<Value>::New(isolate, agg->value));
326
328
 
327
329
  for (int i = 0; i < argc; ++i) {
@@ -625,6 +627,7 @@ void UserDefinedFunction::xFunc(sqlite3_context* ctx,
625
627
  auto recv = Undefined(isolate);
626
628
  auto fn = self->fn_.Get(isolate);
627
629
  LocalVector<Value> js_argv(isolate);
630
+ js_argv.reserve(argc);
628
631
 
629
632
  for (int i = 0; i < argc; ++i) {
630
633
  sqlite3_value* value = argv[i];
@@ -1147,14 +1150,114 @@ void DatabaseSync::Prepare(const FunctionCallbackInfo<Value>& args) {
1147
1150
  return;
1148
1151
  }
1149
1152
 
1153
+ std::optional<bool> return_arrays;
1154
+ std::optional<bool> use_big_ints;
1155
+ std::optional<bool> allow_bare_named_params;
1156
+ std::optional<bool> allow_unknown_named_params;
1157
+
1158
+ if (args.Length() > 1 && !args[1]->IsUndefined()) {
1159
+ if (!args[1]->IsObject()) {
1160
+ THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
1161
+ "The \"options\" argument must be an object.");
1162
+ return;
1163
+ }
1164
+ Local<Object> options = args[1].As<Object>();
1165
+
1166
+ Local<Value> return_arrays_v;
1167
+ if (!options
1168
+ ->Get(env->context(),
1169
+ FIXED_ONE_BYTE_STRING(env->isolate(), "returnArrays"))
1170
+ .ToLocal(&return_arrays_v)) {
1171
+ return;
1172
+ }
1173
+ if (!return_arrays_v->IsUndefined()) {
1174
+ if (!return_arrays_v->IsBoolean()) {
1175
+ THROW_ERR_INVALID_ARG_TYPE(
1176
+ env->isolate(),
1177
+ "The \"options.returnArrays\" argument must be a boolean.");
1178
+ return;
1179
+ }
1180
+ return_arrays = return_arrays_v->IsTrue();
1181
+ }
1182
+
1183
+ Local<Value> read_big_ints_v;
1184
+ if (!options
1185
+ ->Get(env->context(),
1186
+ FIXED_ONE_BYTE_STRING(env->isolate(), "readBigInts"))
1187
+ .ToLocal(&read_big_ints_v)) {
1188
+ return;
1189
+ }
1190
+ if (!read_big_ints_v->IsUndefined()) {
1191
+ if (!read_big_ints_v->IsBoolean()) {
1192
+ THROW_ERR_INVALID_ARG_TYPE(
1193
+ env->isolate(),
1194
+ "The \"options.readBigInts\" argument must be a boolean.");
1195
+ return;
1196
+ }
1197
+ use_big_ints = read_big_ints_v->IsTrue();
1198
+ }
1199
+
1200
+ Local<Value> allow_bare_named_params_v;
1201
+ if (!options
1202
+ ->Get(env->context(),
1203
+ FIXED_ONE_BYTE_STRING(env->isolate(),
1204
+ "allowBareNamedParameters"))
1205
+ .ToLocal(&allow_bare_named_params_v)) {
1206
+ return;
1207
+ }
1208
+ if (!allow_bare_named_params_v->IsUndefined()) {
1209
+ if (!allow_bare_named_params_v->IsBoolean()) {
1210
+ THROW_ERR_INVALID_ARG_TYPE(
1211
+ env->isolate(),
1212
+ "The \"options.allowBareNamedParameters\" argument must be a "
1213
+ "boolean.");
1214
+ return;
1215
+ }
1216
+ allow_bare_named_params = allow_bare_named_params_v->IsTrue();
1217
+ }
1218
+
1219
+ Local<Value> allow_unknown_named_params_v;
1220
+ if (!options
1221
+ ->Get(env->context(),
1222
+ FIXED_ONE_BYTE_STRING(env->isolate(),
1223
+ "allowUnknownNamedParameters"))
1224
+ .ToLocal(&allow_unknown_named_params_v)) {
1225
+ return;
1226
+ }
1227
+ if (!allow_unknown_named_params_v->IsUndefined()) {
1228
+ if (!allow_unknown_named_params_v->IsBoolean()) {
1229
+ THROW_ERR_INVALID_ARG_TYPE(
1230
+ env->isolate(),
1231
+ "The \"options.allowUnknownNamedParameters\" argument must be a "
1232
+ "boolean.");
1233
+ return;
1234
+ }
1235
+ allow_unknown_named_params = allow_unknown_named_params_v->IsTrue();
1236
+ }
1237
+ }
1238
+
1150
1239
  Utf8Value sql(env->isolate(), args[0].As<String>());
1151
1240
  sqlite3_stmt* s = nullptr;
1152
- int r = sqlite3_prepare_v2(db->connection_, *sql, -1, &s, 0);
1241
+ int r = sqlite3_prepare_v2(db->connection_, *sql, -1, &s, nullptr);
1153
1242
 
1154
1243
  CHECK_ERROR_OR_THROW(env->isolate(), db, r, SQLITE_OK, void());
1155
1244
  BaseObjectPtr<StatementSync> stmt =
1156
1245
  StatementSync::Create(env, BaseObjectPtr<DatabaseSync>(db), s);
1157
1246
  db->statements_.insert(stmt.get());
1247
+
1248
+ if (return_arrays.has_value()) {
1249
+ stmt->return_arrays_ = return_arrays.value();
1250
+ }
1251
+ if (use_big_ints.has_value()) {
1252
+ stmt->use_big_ints_ = use_big_ints.value();
1253
+ }
1254
+ if (allow_bare_named_params.has_value()) {
1255
+ stmt->allow_bare_named_params_ = allow_bare_named_params.value();
1256
+ }
1257
+ if (allow_unknown_named_params.has_value()) {
1258
+ stmt->allow_unknown_named_params_ = allow_unknown_named_params.value();
1259
+ }
1260
+
1158
1261
  args.GetReturnValue().Set(stmt->object());
1159
1262
  }
1160
1263
 
@@ -1963,18 +2066,16 @@ int DatabaseSync::AuthorizerCallback(void* user_data,
1963
2066
  CHECK(cb->IsFunction());
1964
2067
 
1965
2068
  Local<Function> callback = cb.As<Function>();
1966
- LocalVector<Value> js_argv(isolate);
1967
2069
 
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());
2070
+ LocalVector<Value> js_argv(
2071
+ isolate,
2072
+ {
2073
+ Integer::New(isolate, action_code),
2074
+ NullableSQLiteStringToValue(isolate, param1).ToLocalChecked(),
2075
+ NullableSQLiteStringToValue(isolate, param2).ToLocalChecked(),
2076
+ NullableSQLiteStringToValue(isolate, param3).ToLocalChecked(),
2077
+ NullableSQLiteStringToValue(isolate, param4).ToLocalChecked(),
2078
+ });
1978
2079
 
1979
2080
  MaybeLocal<Value> retval = callback->Call(
1980
2081
  context, Undefined(isolate), js_argv.size(), js_argv.data());
@@ -2664,8 +2765,7 @@ SQLTagStore::SQLTagStore(Environment* env,
2664
2765
  int capacity)
2665
2766
  : BaseObject(env, object),
2666
2767
  database_(std::move(database)),
2667
- sql_tags_(capacity),
2668
- capacity_(capacity) {
2768
+ sql_tags_(capacity) {
2669
2769
  MakeWeak();
2670
2770
  }
2671
2771
 
@@ -2700,11 +2800,13 @@ Local<FunctionTemplate> SQLTagStore::GetConstructorTemplate(Environment* env) {
2700
2800
  SetProtoMethod(isolate, tmpl, "iterate", Iterate);
2701
2801
  SetProtoMethod(isolate, tmpl, "run", Run);
2702
2802
  SetProtoMethod(isolate, tmpl, "clear", Clear);
2703
- SetProtoMethod(isolate, tmpl, "size", Size);
2704
- SetSideEffectFreeGetter(
2705
- isolate, tmpl, FIXED_ONE_BYTE_STRING(isolate, "capacity"), Capacity);
2803
+ SetSideEffectFreeGetter(isolate,
2804
+ tmpl,
2805
+ FIXED_ONE_BYTE_STRING(isolate, "capacity"),
2806
+ CapacityGetter);
2706
2807
  SetSideEffectFreeGetter(
2707
2808
  isolate, tmpl, FIXED_ONE_BYTE_STRING(isolate, "db"), DatabaseGetter);
2809
+ SetSideEffectFreeGetter(isolate, tmpl, env->size_string(), SizeGetter);
2708
2810
  return tmpl;
2709
2811
  }
2710
2812
 
@@ -2717,35 +2819,47 @@ BaseObjectPtr<SQLTagStore> SQLTagStore::Create(
2717
2819
  .ToLocal(&obj)) {
2718
2820
  return nullptr;
2719
2821
  }
2822
+ obj->SetInternalField(kDatabaseObject, database->object());
2720
2823
  return MakeBaseObject<SQLTagStore>(env, obj, std::move(database), capacity);
2721
2824
  }
2722
2825
 
2826
+ void SQLTagStore::CapacityGetter(const FunctionCallbackInfo<Value>& args) {
2827
+ SQLTagStore* store;
2828
+ ASSIGN_OR_RETURN_UNWRAP(&store, args.This());
2829
+ args.GetReturnValue().Set(static_cast<double>(store->sql_tags_.Capacity()));
2830
+ }
2831
+
2723
2832
  void SQLTagStore::DatabaseGetter(const FunctionCallbackInfo<Value>& args) {
2833
+ args.GetReturnValue().Set(
2834
+ args.This()->GetInternalField(kDatabaseObject).As<Value>());
2835
+ }
2836
+
2837
+ void SQLTagStore::SizeGetter(const FunctionCallbackInfo<Value>& args) {
2724
2838
  SQLTagStore* store;
2725
2839
  ASSIGN_OR_RETURN_UNWRAP(&store, args.This());
2726
- args.GetReturnValue().Set(store->database_->object());
2840
+ args.GetReturnValue().Set(static_cast<double>(store->sql_tags_.Size()));
2727
2841
  }
2728
2842
 
2729
- void SQLTagStore::Run(const FunctionCallbackInfo<Value>& info) {
2843
+ void SQLTagStore::Run(const FunctionCallbackInfo<Value>& args) {
2730
2844
  SQLTagStore* session;
2731
- ASSIGN_OR_RETURN_UNWRAP(&session, info.This());
2732
- Environment* env = Environment::GetCurrent(info);
2845
+ ASSIGN_OR_RETURN_UNWRAP(&session, args.This());
2846
+ Environment* env = Environment::GetCurrent(args);
2733
2847
 
2734
2848
  THROW_AND_RETURN_ON_BAD_STATE(
2735
2849
  env, !session->database_->IsOpen(), "database is not open");
2736
2850
 
2737
- BaseObjectPtr<StatementSync> stmt = PrepareStatement(info);
2851
+ BaseObjectPtr<StatementSync> stmt = PrepareStatement(args);
2738
2852
 
2739
2853
  if (!stmt) {
2740
2854
  return;
2741
2855
  }
2742
2856
 
2743
- uint32_t n_params = info.Length() - 1;
2857
+ uint32_t n_params = args.Length() - 1;
2744
2858
  int r = sqlite3_reset(stmt->statement_);
2745
2859
  CHECK_ERROR_OR_THROW(env->isolate(), stmt->db_.get(), r, SQLITE_OK, void());
2746
2860
  int param_count = sqlite3_bind_parameter_count(stmt->statement_);
2747
2861
  for (int i = 0; i < static_cast<int>(n_params) && i < param_count; ++i) {
2748
- Local<Value> value = info[i + 1];
2862
+ Local<Value> value = args[i + 1];
2749
2863
  if (!stmt->BindValue(value, i + 1)) {
2750
2864
  return;
2751
2865
  }
@@ -2755,7 +2869,7 @@ void SQLTagStore::Run(const FunctionCallbackInfo<Value>& info) {
2755
2869
  if (StatementExecutionHelper::Run(
2756
2870
  env, stmt->db_.get(), stmt->statement_, stmt->use_big_ints_)
2757
2871
  .ToLocal(&result)) {
2758
- info.GetReturnValue().Set(result);
2872
+ args.GetReturnValue().Set(result);
2759
2873
  }
2760
2874
  }
2761
2875
 
@@ -2873,23 +2987,9 @@ void SQLTagStore::All(const FunctionCallbackInfo<Value>& args) {
2873
2987
  }
2874
2988
  }
2875
2989
 
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) {
2990
+ void SQLTagStore::Clear(const FunctionCallbackInfo<Value>& args) {
2884
2991
  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());
2992
+ ASSIGN_OR_RETURN_UNWRAP(&store, args.This());
2893
2993
  store->sql_tags_.Clear();
2894
2994
  }
2895
2995
 
@@ -2944,10 +3044,10 @@ BaseObjectPtr<StatementSync> SQLTagStore::PrepareStatement(
2944
3044
  if (stmt == nullptr) {
2945
3045
  sqlite3_stmt* s = nullptr;
2946
3046
  int r = sqlite3_prepare_v2(
2947
- session->database_->connection_, sql.data(), sql.size(), &s, 0);
3047
+ session->database_->connection_, sql.data(), sql.size(), &s, nullptr);
2948
3048
 
2949
3049
  if (r != SQLITE_OK) {
2950
- THROW_ERR_SQLITE_ERROR(isolate, "Failed to prepare statement");
3050
+ THROW_ERR_SQLITE_ERROR(isolate, session->database_.get());
2951
3051
  sqlite3_finalize(s);
2952
3052
  return BaseObjectPtr<StatementSync>();
2953
3053
  }
@@ -79,7 +79,7 @@ class DatabaseOpenConfiguration {
79
79
  bool return_arrays_ = false;
80
80
  bool allow_bare_named_params_ = true;
81
81
  bool allow_unknown_named_params_ = false;
82
- bool defensive_ = false;
82
+ bool defensive_ = true;
83
83
  };
84
84
 
85
85
  class DatabaseSync;
@@ -246,6 +246,7 @@ class StatementSync : public BaseObject {
246
246
  bool BindParams(const v8::FunctionCallbackInfo<v8::Value>& args);
247
247
  bool BindValue(const v8::Local<v8::Value>& value, const int index);
248
248
 
249
+ friend class DatabaseSync;
249
250
  friend class StatementSyncIterator;
250
251
  friend class SQLTagStore;
251
252
  friend class StatementExecutionHelper;
@@ -304,6 +305,11 @@ class Session : public BaseObject {
304
305
 
305
306
  class SQLTagStore : public BaseObject {
306
307
  public:
308
+ enum InternalFields {
309
+ kDatabaseObject = BaseObject::kInternalFieldCount,
310
+ kInternalFieldCount
311
+ };
312
+
307
313
  SQLTagStore(Environment* env,
308
314
  v8::Local<v8::Object> object,
309
315
  BaseObjectWeakPtr<DatabaseSync> database,
@@ -313,15 +319,14 @@ class SQLTagStore : public BaseObject {
313
319
  Environment* env, BaseObjectWeakPtr<DatabaseSync> database, int capacity);
314
320
  static v8::Local<v8::FunctionTemplate> GetConstructorTemplate(
315
321
  Environment* env);
316
- static void All(const v8::FunctionCallbackInfo<v8::Value>& info);
317
- static void Get(const v8::FunctionCallbackInfo<v8::Value>& info);
318
- static void Iterate(const v8::FunctionCallbackInfo<v8::Value>& info);
319
- static void Run(const v8::FunctionCallbackInfo<v8::Value>& info);
320
- static void Size(const v8::FunctionCallbackInfo<v8::Value>& info);
321
- static void Capacity(const v8::FunctionCallbackInfo<v8::Value>& info);
322
- static void Reset(const v8::FunctionCallbackInfo<v8::Value>& info);
323
- static void Clear(const v8::FunctionCallbackInfo<v8::Value>& info);
324
- static void DatabaseGetter(const v8::FunctionCallbackInfo<v8::Value>& info);
322
+ static void All(const v8::FunctionCallbackInfo<v8::Value>& args);
323
+ static void Get(const v8::FunctionCallbackInfo<v8::Value>& args);
324
+ static void Iterate(const v8::FunctionCallbackInfo<v8::Value>& args);
325
+ static void Run(const v8::FunctionCallbackInfo<v8::Value>& args);
326
+ static void Clear(const v8::FunctionCallbackInfo<v8::Value>& args);
327
+ static void CapacityGetter(const v8::FunctionCallbackInfo<v8::Value>& args);
328
+ static void DatabaseGetter(const v8::FunctionCallbackInfo<v8::Value>& args);
329
+ static void SizeGetter(const v8::FunctionCallbackInfo<v8::Value>& args);
325
330
  void MemoryInfo(MemoryTracker* tracker) const override;
326
331
  SET_MEMORY_INFO_NAME(SQLTagStore)
327
332
  SET_SELF_SIZE(SQLTagStore)
@@ -331,7 +336,6 @@ class SQLTagStore : public BaseObject {
331
336
  const v8::FunctionCallbackInfo<v8::Value>& args);
332
337
  BaseObjectWeakPtr<DatabaseSync> database_;
333
338
  LRUCache<std::string, BaseObjectPtr<StatementSync>> sql_tags_;
334
- int capacity_;
335
339
  friend class StatementExecutionHelper;
336
340
  };
337
341
 
@@ -1,6 +1,6 @@
1
1
  /******************************************************************************
2
2
  ** This file is an amalgamation of many separate C source files from SQLite
3
- ** version 3.51.1. By combining all the individual C code files into this
3
+ ** version 3.51.2. By combining all the individual C code files into this
4
4
  ** single large file, the entire code can be compiled as a single translation
5
5
  ** unit. This allows many compilers to do optimizations that would not be
6
6
  ** possible if the files were compiled separately. Performance improvements
@@ -18,7 +18,7 @@
18
18
  ** separate file. This file contains only code for the core SQLite library.
19
19
  **
20
20
  ** The content in this amalgamation comes from Fossil check-in
21
- ** 281fc0e9afc38674b9b0991943b9e9d1e64c with changes in files:
21
+ ** b270f8339eb13b504d0b2ba154ebca966b7d with changes in files:
22
22
  **
23
23
  **
24
24
  */
@@ -467,12 +467,12 @@ extern "C" {
467
467
  ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
468
468
  ** [sqlite_version()] and [sqlite_source_id()].
469
469
  */
470
- #define SQLITE_VERSION "3.51.1"
471
- #define SQLITE_VERSION_NUMBER 3051001
472
- #define SQLITE_SOURCE_ID "2025-11-28 17:28:25 281fc0e9afc38674b9b0991943b9e9d1e64c6cbdb133d35f6f5c87ff6af38a88"
470
+ #define SQLITE_VERSION "3.51.2"
471
+ #define SQLITE_VERSION_NUMBER 3051002
472
+ #define SQLITE_SOURCE_ID "2026-01-09 17:27:48 b270f8339eb13b504d0b2ba154ebca966b7dde08e40c3ed7d559749818cb2075"
473
473
  #define SQLITE_SCM_BRANCH "branch-3.51"
474
- #define SQLITE_SCM_TAGS "release version-3.51.1"
475
- #define SQLITE_SCM_DATETIME "2025-11-28T17:28:25.933Z"
474
+ #define SQLITE_SCM_TAGS "release version-3.51.2"
475
+ #define SQLITE_SCM_DATETIME "2026-01-09T17:27:48.405Z"
476
476
 
477
477
  /*
478
478
  ** CAPI3REF: Run-Time Library Version Numbers
@@ -41228,12 +41228,18 @@ static int unixLock(sqlite3_file *id, int eFileLock){
41228
41228
  pInode->nLock++;
41229
41229
  pInode->nShared = 1;
41230
41230
  }
41231
- }else if( (eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1)
41232
- || unixIsSharingShmNode(pFile)
41233
- ){
41231
+ }else if( eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1 ){
41234
41232
  /* We are trying for an exclusive lock but another thread in this
41235
41233
  ** same process is still holding a shared lock. */
41236
41234
  rc = SQLITE_BUSY;
41235
+ }else if( unixIsSharingShmNode(pFile) ){
41236
+ /* We are in WAL mode and attempting to delete the SHM and WAL
41237
+ ** files due to closing the connection or changing out of WAL mode,
41238
+ ** but another process still holds locks on the SHM file, thus
41239
+ ** indicating that database locks have been broken, perhaps due
41240
+ ** to a rogue close(open(dbFile)) or similar.
41241
+ */
41242
+ rc = SQLITE_BUSY;
41237
41243
  }else{
41238
41244
  /* The request was for a RESERVED or EXCLUSIVE lock. It is
41239
41245
  ** assumed that there is a SHARED or greater lock on the file
@@ -43872,26 +43878,21 @@ static int unixFcntlExternalReader(unixFile *pFile, int *piOut){
43872
43878
  ** still not a disaster.
43873
43879
  */
43874
43880
  static int unixIsSharingShmNode(unixFile *pFile){
43875
- int rc;
43876
43881
  unixShmNode *pShmNode;
43882
+ struct flock lock;
43877
43883
  if( pFile->pShm==0 ) return 0;
43878
43884
  if( pFile->ctrlFlags & UNIXFILE_EXCL ) return 0;
43879
43885
  pShmNode = pFile->pShm->pShmNode;
43880
- rc = 1;
43881
- unixEnterMutex();
43882
- if( ALWAYS(pShmNode->nRef==1) ){
43883
- struct flock lock;
43884
- lock.l_whence = SEEK_SET;
43885
- lock.l_start = UNIX_SHM_DMS;
43886
- lock.l_len = 1;
43887
- lock.l_type = F_WRLCK;
43888
- osFcntl(pShmNode->hShm, F_GETLK, &lock);
43889
- if( lock.l_type==F_UNLCK ){
43890
- rc = 0;
43891
- }
43892
- }
43893
- unixLeaveMutex();
43894
- return rc;
43886
+ #if SQLITE_ATOMIC_INTRINSICS
43887
+ assert( AtomicLoad(&pShmNode->nRef)==1 );
43888
+ #endif
43889
+ memset(&lock, 0, sizeof(lock));
43890
+ lock.l_whence = SEEK_SET;
43891
+ lock.l_start = UNIX_SHM_DMS;
43892
+ lock.l_len = 1;
43893
+ lock.l_type = F_WRLCK;
43894
+ osFcntl(pShmNode->hShm, F_GETLK, &lock);
43895
+ return (lock.l_type!=F_UNLCK);
43895
43896
  }
43896
43897
 
43897
43898
  /*
@@ -115316,9 +115317,22 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
115316
115317
  pParse->nMem += nReg;
115317
115318
  if( pExpr->op==TK_SELECT ){
115318
115319
  dest.eDest = SRT_Mem;
115319
- dest.iSdst = dest.iSDParm;
115320
+ if( (pSel->selFlags&SF_Distinct) && pSel->pLimit && pSel->pLimit->pRight ){
115321
+ /* If there is both a DISTINCT and an OFFSET clause, then allocate
115322
+ ** a separate dest.iSdst array for sqlite3Select() and other
115323
+ ** routines to populate. In this case results will be copied over
115324
+ ** into the dest.iSDParm array only after OFFSET processing. This
115325
+ ** ensures that in the case where OFFSET excludes all rows, the
115326
+ ** dest.iSDParm array is not left populated with the contents of the
115327
+ ** last row visited - it should be all NULLs if all rows were
115328
+ ** excluded by OFFSET. */
115329
+ dest.iSdst = pParse->nMem+1;
115330
+ pParse->nMem += nReg;
115331
+ }else{
115332
+ dest.iSdst = dest.iSDParm;
115333
+ }
115320
115334
  dest.nSdst = nReg;
115321
- sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSDParm, dest.iSDParm+nReg-1);
115335
+ sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSDParm, pParse->nMem);
115322
115336
  VdbeComment((v, "Init subquery result"));
115323
115337
  }else{
115324
115338
  dest.eDest = SRT_Exists;
@@ -148186,9 +148200,14 @@ static void selectInnerLoop(
148186
148200
  assert( nResultCol<=pDest->nSdst );
148187
148201
  pushOntoSorter(
148188
148202
  pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg);
148203
+ pDest->iSDParm = regResult;
148189
148204
  }else{
148190
148205
  assert( nResultCol==pDest->nSdst );
148191
- assert( regResult==iParm );
148206
+ if( regResult!=iParm ){
148207
+ /* This occurs in cases where the SELECT had both a DISTINCT and
148208
+ ** an OFFSET clause. */
148209
+ sqlite3VdbeAddOp3(v, OP_Copy, regResult, iParm, nResultCol-1);
148210
+ }
148192
148211
  /* The LIMIT clause will jump out of the loop for us */
148193
148212
  }
148194
148213
  break;
@@ -154203,12 +154222,24 @@ static SQLITE_NOINLINE void existsToJoin(
154203
154222
  && (pSub->selFlags & SF_Aggregate)==0
154204
154223
  && !pSub->pSrc->a[0].fg.isSubquery
154205
154224
  && pSub->pLimit==0
154225
+ && pSub->pPrior==0
154206
154226
  ){
154227
+ /* Before combining the sub-select with the parent, renumber the
154228
+ ** cursor used by the subselect. This is because the EXISTS expression
154229
+ ** might be a copy of another EXISTS expression from somewhere
154230
+ ** else in the tree, and in this case it is important that it use
154231
+ ** a unique cursor number. */
154232
+ sqlite3 *db = pParse->db;
154233
+ int *aCsrMap = sqlite3DbMallocZero(db, (pParse->nTab+2)*sizeof(int));
154234
+ if( aCsrMap==0 ) return;
154235
+ aCsrMap[0] = (pParse->nTab+1);
154236
+ renumberCursors(pParse, pSub, -1, aCsrMap);
154237
+ sqlite3DbFree(db, aCsrMap);
154238
+
154207
154239
  memset(pWhere, 0, sizeof(*pWhere));
154208
154240
  pWhere->op = TK_INTEGER;
154209
154241
  pWhere->u.iValue = 1;
154210
154242
  ExprSetProperty(pWhere, EP_IntValue);
154211
-
154212
154243
  assert( p->pWhere!=0 );
154213
154244
  pSub->pSrc->a[0].fg.fromExists = 1;
154214
154245
  pSub->pSrc->a[0].fg.jointype |= JT_CROSS;
@@ -174001,6 +174032,9 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
174001
174032
  sqlite3 *db = pParse->db;
174002
174033
  int iEnd = sqlite3VdbeCurrentAddr(v);
174003
174034
  int nRJ = 0;
174035
+ #ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
174036
+ int addrSeek = 0;
174037
+ #endif
174004
174038
 
174005
174039
  /* Generate loop termination code.
174006
174040
  */
@@ -174013,7 +174047,10 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
174013
174047
  ** the RIGHT JOIN table */
174014
174048
  WhereRightJoin *pRJ = pLevel->pRJ;
174015
174049
  sqlite3VdbeResolveLabel(v, pLevel->addrCont);
174016
- pLevel->addrCont = 0;
174050
+ /* Replace addrCont with a new label that will never be used, just so
174051
+ ** the subsequent call to resolve pLevel->addrCont will have something
174052
+ ** to resolve. */
174053
+ pLevel->addrCont = sqlite3VdbeMakeLabel(pParse);
174017
174054
  pRJ->endSubrtn = sqlite3VdbeCurrentAddr(v);
174018
174055
  sqlite3VdbeAddOp3(v, OP_Return, pRJ->regReturn, pRJ->addrSubrtn, 1);
174019
174056
  VdbeCoverage(v);
@@ -174022,7 +174059,6 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
174022
174059
  pLoop = pLevel->pWLoop;
174023
174060
  if( pLevel->op!=OP_Noop ){
174024
174061
  #ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
174025
- int addrSeek = 0;
174026
174062
  Index *pIdx;
174027
174063
  int n;
174028
174064
  if( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED
@@ -174045,25 +174081,26 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
174045
174081
  sqlite3VdbeAddOp2(v, OP_Goto, 1, pLevel->p2);
174046
174082
  }
174047
174083
  #endif /* SQLITE_DISABLE_SKIPAHEAD_DISTINCT */
174048
- if( pTabList->a[pLevel->iFrom].fg.fromExists && i==pWInfo->nLevel-1 ){
174049
- /* If the EXISTS-to-JOIN optimization was applied, then the EXISTS
174050
- ** loop(s) will be the inner-most loops of the join. There might be
174051
- ** multiple EXISTS loops, but they will all be nested, and the join
174052
- ** order will not have been changed by the query planner. If the
174053
- ** inner-most EXISTS loop sees a single successful row, it should
174054
- ** break out of *all* EXISTS loops. But only the inner-most of the
174055
- ** nested EXISTS loops should do this breakout. */
174056
- int nOuter = 0; /* Nr of outer EXISTS that this one is nested within */
174057
- while( nOuter<i ){
174058
- if( !pTabList->a[pLevel[-nOuter-1].iFrom].fg.fromExists ) break;
174059
- nOuter++;
174060
- }
174061
- testcase( nOuter>0 );
174062
- sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel[-nOuter].addrBrk);
174063
- VdbeComment((v, "EXISTS break"));
174064
- }
174065
- /* The common case: Advance to the next row */
174066
- if( pLevel->addrCont ) sqlite3VdbeResolveLabel(v, pLevel->addrCont);
174084
+ }
174085
+ if( pTabList->a[pLevel->iFrom].fg.fromExists && i==pWInfo->nLevel-1 ){
174086
+ /* If the EXISTS-to-JOIN optimization was applied, then the EXISTS
174087
+ ** loop(s) will be the inner-most loops of the join. There might be
174088
+ ** multiple EXISTS loops, but they will all be nested, and the join
174089
+ ** order will not have been changed by the query planner. If the
174090
+ ** inner-most EXISTS loop sees a single successful row, it should
174091
+ ** break out of *all* EXISTS loops. But only the inner-most of the
174092
+ ** nested EXISTS loops should do this breakout. */
174093
+ int nOuter = 0; /* Nr of outer EXISTS that this one is nested within */
174094
+ while( nOuter<i ){
174095
+ if( !pTabList->a[pLevel[-nOuter-1].iFrom].fg.fromExists ) break;
174096
+ nOuter++;
174097
+ }
174098
+ testcase( nOuter>0 );
174099
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel[-nOuter].addrBrk);
174100
+ VdbeComment((v, "EXISTS break"));
174101
+ }
174102
+ sqlite3VdbeResolveLabel(v, pLevel->addrCont);
174103
+ if( pLevel->op!=OP_Noop ){
174067
174104
  sqlite3VdbeAddOp3(v, pLevel->op, pLevel->p1, pLevel->p2, pLevel->p3);
174068
174105
  sqlite3VdbeChangeP5(v, pLevel->p5);
174069
174106
  VdbeCoverage(v);
@@ -174076,10 +174113,11 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
174076
174113
  VdbeCoverage(v);
174077
174114
  }
174078
174115
  #ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
174079
- if( addrSeek ) sqlite3VdbeJumpHere(v, addrSeek);
174116
+ if( addrSeek ){
174117
+ sqlite3VdbeJumpHere(v, addrSeek);
174118
+ addrSeek = 0;
174119
+ }
174080
174120
  #endif
174081
- }else if( pLevel->addrCont ){
174082
- sqlite3VdbeResolveLabel(v, pLevel->addrCont);
174083
174121
  }
174084
174122
  if( (pLoop->wsFlags & WHERE_IN_ABLE)!=0 && pLevel->u.in.nIn>0 ){
174085
174123
  struct InLoop *pIn;
@@ -219453,7 +219491,7 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
219453
219491
  if( node.zData==0 ) return;
219454
219492
  nData = sqlite3_value_bytes(apArg[1]);
219455
219493
  if( nData<4 ) return;
219456
- if( nData<NCELL(&node)*tree.nBytesPerCell ) return;
219494
+ if( nData<4+NCELL(&node)*tree.nBytesPerCell ) return;
219457
219495
 
219458
219496
  pOut = sqlite3_str_new(0);
219459
219497
  for(ii=0; ii<NCELL(&node); ii++){
@@ -238534,7 +238572,13 @@ typedef sqlite3_uint64 u64;
238534
238572
  # define FLEXARRAY 1
238535
238573
  #endif
238536
238574
 
238537
- #endif
238575
+ #endif /* SQLITE_AMALGAMATION */
238576
+
238577
+ /*
238578
+ ** Constants for the largest and smallest possible 32-bit signed integers.
238579
+ */
238580
+ # define LARGEST_INT32 ((int)(0x7fffffff))
238581
+ # define SMALLEST_INT32 ((int)((-1) - LARGEST_INT32))
238538
238582
 
238539
238583
  /* Truncate very long tokens to this many bytes. Hard limit is
238540
238584
  ** (65536-1-1-4-9)==65521 bytes. The limiting factor is the 16-bit offset
@@ -253097,7 +253141,7 @@ static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
253097
253141
  fts5StructureRelease(pStruct);
253098
253142
  pStruct = pNew;
253099
253143
  nMin = 1;
253100
- nMerge = nMerge*-1;
253144
+ nMerge = (nMerge==SMALLEST_INT32 ? LARGEST_INT32 : (nMerge*-1));
253101
253145
  }
253102
253146
  if( pStruct && pStruct->nLevel ){
253103
253147
  if( fts5IndexMerge(p, &pStruct, nMerge, nMin) ){
@@ -260304,7 +260348,7 @@ static void fts5SourceIdFunc(
260304
260348
  ){
260305
260349
  assert( nArg==0 );
260306
260350
  UNUSED_PARAM2(nArg, apUnused);
260307
- sqlite3_result_text(pCtx, "fts5: 2025-11-28 17:28:25 281fc0e9afc38674b9b0991943b9e9d1e64c6cbdb133d35f6f5c87ff6af38a88", -1, SQLITE_TRANSIENT);
260351
+ sqlite3_result_text(pCtx, "fts5: 2026-01-09 17:27:48 b270f8339eb13b504d0b2ba154ebca966b7dde08e40c3ed7d559749818cb2075", -1, SQLITE_TRANSIENT);
260308
260352
  }
260309
260353
 
260310
260354
  /*
@@ -146,12 +146,12 @@ extern "C" {
146
146
  ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
147
147
  ** [sqlite_version()] and [sqlite_source_id()].
148
148
  */
149
- #define SQLITE_VERSION "3.51.1"
150
- #define SQLITE_VERSION_NUMBER 3051001
151
- #define SQLITE_SOURCE_ID "2025-11-28 17:28:25 281fc0e9afc38674b9b0991943b9e9d1e64c6cbdb133d35f6f5c87ff6af38a88"
149
+ #define SQLITE_VERSION "3.51.2"
150
+ #define SQLITE_VERSION_NUMBER 3051002
151
+ #define SQLITE_SOURCE_ID "2026-01-09 17:27:48 b270f8339eb13b504d0b2ba154ebca966b7dde08e40c3ed7d559749818cb2075"
152
152
  #define SQLITE_SCM_BRANCH "branch-3.51"
153
- #define SQLITE_SCM_TAGS "release version-3.51.1"
154
- #define SQLITE_SCM_DATETIME "2025-11-28T17:28:25.933Z"
153
+ #define SQLITE_SCM_TAGS "release version-3.51.2"
154
+ #define SQLITE_SCM_DATETIME "2026-01-09T17:27:48.405Z"
155
155
 
156
156
  /*
157
157
  ** CAPI3REF: Run-Time Library Version Numbers