koffi 2.2.0 → 2.2.2-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/ChangeLog.md +6 -0
  2. package/package.json +2 -2
  3. package/src/koffi/build/2.2.2-beta.1/koffi_darwin_arm64.tar.gz +0 -0
  4. package/src/koffi/build/2.2.2-beta.1/koffi_darwin_x64.tar.gz +0 -0
  5. package/src/koffi/build/2.2.2-beta.1/koffi_freebsd_arm64.tar.gz +0 -0
  6. package/src/koffi/build/2.2.2-beta.1/koffi_freebsd_ia32.tar.gz +0 -0
  7. package/src/koffi/build/2.2.2-beta.1/koffi_freebsd_x64.tar.gz +0 -0
  8. package/src/koffi/build/2.2.2-beta.1/koffi_linux_arm32hf.tar.gz +0 -0
  9. package/src/koffi/build/2.2.2-beta.1/koffi_linux_arm64.tar.gz +0 -0
  10. package/src/koffi/build/2.2.2-beta.1/koffi_linux_ia32.tar.gz +0 -0
  11. package/src/koffi/build/2.2.2-beta.1/koffi_linux_riscv64hf64.tar.gz +0 -0
  12. package/src/koffi/build/2.2.2-beta.1/koffi_linux_x64.tar.gz +0 -0
  13. package/src/koffi/build/2.2.2-beta.1/koffi_openbsd_ia32.tar.gz +0 -0
  14. package/src/koffi/build/2.2.2-beta.1/koffi_openbsd_x64.tar.gz +0 -0
  15. package/src/koffi/build/2.2.2-beta.1/koffi_win32_arm64.tar.gz +0 -0
  16. package/src/koffi/build/2.2.2-beta.1/koffi_win32_ia32.tar.gz +0 -0
  17. package/src/koffi/build/2.2.2-beta.1/koffi_win32_x64.tar.gz +0 -0
  18. package/src/koffi/qemu/qemu.js +12 -10
  19. package/src/koffi/src/abi_arm32.cc +7 -11
  20. package/src/koffi/src/abi_arm64.cc +7 -11
  21. package/src/koffi/src/abi_riscv64.cc +7 -11
  22. package/src/koffi/src/abi_x64_sysv.cc +7 -11
  23. package/src/koffi/src/abi_x64_win.cc +7 -11
  24. package/src/koffi/src/abi_x86.cc +7 -11
  25. package/src/koffi/src/call.cc +53 -2
  26. package/src/koffi/src/call.hh +6 -1
  27. package/src/koffi/src/ffi.cc +66 -12
  28. package/src/koffi/src/ffi.hh +2 -0
  29. package/src/koffi/src/index.js +6 -2
  30. package/src/koffi/test/CMakeLists.txt +1 -1
  31. package/src/koffi/test/async.js +3 -0
  32. package/src/koffi/test/callbacks.js +30 -0
  33. package/src/koffi/test/misc.c +11 -0
  34. package/vendor/{sqlite3mc → sqlite3}/sqlite3.c +139 -43
  35. package/vendor/{sqlite3mc → sqlite3}/sqlite3.h +10 -3
  36. package/vendor/{sqlite3mc → sqlite3}/sqlite3ext.h +0 -0
  37. package/vendor/{sqlite3mc → sqlite3}/sqlite3mc.c +156 -53
  38. package/vendor/{sqlite3mc → sqlite3}/sqlite3mc.def +0 -0
  39. package/vendor/{sqlite3mc → sqlite3}/sqlite3mc.h +12 -5
  40. package/vendor/sqlite3/wasm/README.txt +23 -0
  41. package/vendor/sqlite3/wasm/common/SqliteTestUtil.js +236 -0
  42. package/vendor/sqlite3/wasm/common/emscripten.css +24 -0
  43. package/vendor/sqlite3/wasm/common/testing.css +63 -0
  44. package/vendor/sqlite3/wasm/demo-123-worker.html +44 -0
  45. package/vendor/sqlite3/wasm/demo-123.html +24 -0
  46. package/vendor/sqlite3/wasm/demo-123.js +289 -0
  47. package/vendor/sqlite3/wasm/demo-jsstorage.html +49 -0
  48. package/vendor/sqlite3/wasm/demo-jsstorage.js +114 -0
  49. package/vendor/sqlite3/wasm/demo-worker1-promiser.html +34 -0
  50. package/vendor/sqlite3/wasm/demo-worker1-promiser.js +270 -0
  51. package/vendor/sqlite3/wasm/demo-worker1.html +34 -0
  52. package/vendor/sqlite3/wasm/demo-worker1.js +345 -0
  53. package/vendor/sqlite3/wasm/index.html +90 -0
  54. package/vendor/sqlite3/wasm/jswasm/sqlite3-opfs-async-proxy.js +830 -0
  55. package/vendor/sqlite3/wasm/jswasm/sqlite3-worker1-promiser.js +259 -0
  56. package/vendor/sqlite3/wasm/jswasm/sqlite3-worker1.js +49 -0
  57. package/vendor/sqlite3/wasm/jswasm/sqlite3.js +10119 -0
  58. package/vendor/sqlite3/wasm/jswasm/sqlite3.wasm +0 -0
  59. package/vendor/sqlite3/wasm/tester1-worker.html +63 -0
  60. package/vendor/sqlite3/wasm/tester1.html +28 -0
  61. package/vendor/sqlite3/wasm/tester1.js +1864 -0
  62. package/src/koffi/build/2.2.0/koffi_darwin_arm64.tar.gz +0 -0
  63. package/src/koffi/build/2.2.0/koffi_darwin_x64.tar.gz +0 -0
  64. package/src/koffi/build/2.2.0/koffi_freebsd_arm64.tar.gz +0 -0
  65. package/src/koffi/build/2.2.0/koffi_freebsd_ia32.tar.gz +0 -0
  66. package/src/koffi/build/2.2.0/koffi_freebsd_x64.tar.gz +0 -0
  67. package/src/koffi/build/2.2.0/koffi_linux_arm32hf.tar.gz +0 -0
  68. package/src/koffi/build/2.2.0/koffi_linux_arm64.tar.gz +0 -0
  69. package/src/koffi/build/2.2.0/koffi_linux_ia32.tar.gz +0 -0
  70. package/src/koffi/build/2.2.0/koffi_linux_riscv64hf64.tar.gz +0 -0
  71. package/src/koffi/build/2.2.0/koffi_linux_x64.tar.gz +0 -0
  72. package/src/koffi/build/2.2.0/koffi_openbsd_ia32.tar.gz +0 -0
  73. package/src/koffi/build/2.2.0/koffi_openbsd_x64.tar.gz +0 -0
  74. package/src/koffi/build/2.2.0/koffi_win32_arm64.tar.gz +0 -0
  75. package/src/koffi/build/2.2.0/koffi_win32_ia32.tar.gz +0 -0
  76. package/src/koffi/build/2.2.0/koffi_win32_x64.tar.gz +0 -0
@@ -44,6 +44,8 @@ namespace RG {
44
44
  const int TypeInfoMarker = 0xDEADBEEF;
45
45
  const int CastMarker = 0xDEADBEEF;
46
46
 
47
+ static RG_THREAD_LOCAL CallData *exec_call;
48
+
47
49
  static bool ChangeSize(const char *name, Napi::Value value, Size min_size, Size max_size, Size *out_size)
48
50
  {
49
51
  Napi::Env env = value.Env();
@@ -972,16 +974,16 @@ static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
972
974
  Napi::Object members = Napi::Object::New(env);
973
975
 
974
976
  for (const RecordMember &member: type->members) {
975
- Napi::Object info = Napi::Object::New(env);
977
+ Napi::Object obj = Napi::Object::New(env);
976
978
 
977
979
  Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)member.type);
978
980
  SetValueTag(instance, external, &TypeInfoMarker);
979
981
 
980
- info.Set("name", member.name);
981
- info.Set("type", external);
982
- info.Set("offset", member.offset);
982
+ obj.Set("name", member.name);
983
+ obj.Set("type", external);
984
+ obj.Set("offset", member.offset);
983
985
 
984
- members.Set(member.name, info);
986
+ members.Set(member.name, obj);
985
987
  }
986
988
 
987
989
  defn.Set("members", members);
@@ -1057,7 +1059,10 @@ static Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info)
1057
1059
  }
1058
1060
 
1059
1061
  InstanceMemory *mem = instance->memories[0];
1060
- CallData call(env, instance, func, mem);
1062
+ CallData call(env, instance, func, mem, false);
1063
+
1064
+ RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
1065
+ exec_call = &call;
1061
1066
 
1062
1067
  if (!RG_UNLIKELY(call.Prepare(info)))
1063
1068
  return env.Null();
@@ -1065,7 +1070,14 @@ static Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info)
1065
1070
  if (instance->debug) {
1066
1071
  call.DumpForward();
1067
1072
  }
1068
- call.Execute();
1073
+
1074
+ // Execute call
1075
+ {
1076
+ RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
1077
+ exec_call = &call;
1078
+
1079
+ call.Execute();
1080
+ }
1069
1081
 
1070
1082
  return call.Complete();
1071
1083
  }
@@ -1124,7 +1136,7 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
1124
1136
  return env.Null();
1125
1137
 
1126
1138
  InstanceMemory *mem = instance->memories[0];
1127
- CallData call(env, instance, &func, mem);
1139
+ CallData call(env, instance, &func, mem, false);
1128
1140
 
1129
1141
  if (!RG_UNLIKELY(call.Prepare(info)))
1130
1142
  return env.Null();
@@ -1132,7 +1144,14 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
1132
1144
  if (instance->debug) {
1133
1145
  call.DumpForward();
1134
1146
  }
1135
- call.Execute();
1147
+
1148
+ // Execute call
1149
+ {
1150
+ RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
1151
+ exec_call = &call;
1152
+
1153
+ call.Execute();
1154
+ }
1136
1155
 
1137
1156
  return call.Complete();
1138
1157
  }
@@ -1148,7 +1167,7 @@ public:
1148
1167
  AsyncCall(Napi::Env env, InstanceData *instance, const FunctionInfo *func,
1149
1168
  InstanceMemory *mem, Napi::Function &callback)
1150
1169
  : Napi::AsyncWorker(callback), env(env), func(func->Ref()),
1151
- call(env, instance, func, mem) {}
1170
+ call(env, instance, func, mem, true) {}
1152
1171
  ~AsyncCall() { func->Unref(); }
1153
1172
 
1154
1173
  bool Prepare(const Napi::CallbackInfo &info) {
@@ -1170,6 +1189,9 @@ public:
1170
1189
  void AsyncCall::Execute()
1171
1190
  {
1172
1191
  if (prepared) {
1192
+ RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
1193
+ exec_call = &call;
1194
+
1173
1195
  call.Execute();
1174
1196
  }
1175
1197
  }
@@ -1673,6 +1695,10 @@ InstanceData::~InstanceData()
1673
1695
  for (InstanceMemory *mem: memories) {
1674
1696
  delete mem;
1675
1697
  }
1698
+
1699
+ if (broker) {
1700
+ napi_release_threadsafe_function(broker, napi_tsfn_abort);
1701
+ }
1676
1702
  }
1677
1703
 
1678
1704
  static Napi::Value CastValue(const Napi::CallbackInfo &info)
@@ -1828,6 +1854,30 @@ static Napi::Value DecodeValue(const Napi::CallbackInfo &info)
1828
1854
  return env.Null();
1829
1855
  }
1830
1856
 
1857
+ extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
1858
+ {
1859
+ exec_call->RelaySafe(idx, own_sp, caller_sp, out_reg);
1860
+ }
1861
+
1862
+ static InstanceData *CreateInstance(Napi::Env env)
1863
+ {
1864
+ InstanceData *instance = new InstanceData();
1865
+ RG_DEFER_N(err_guard) { delete instance; };
1866
+
1867
+ Napi::String resource_name = Napi::String::New(env, "Koffi Async Callback Broker");
1868
+
1869
+ if (napi_create_threadsafe_function(env, nullptr, nullptr, resource_name,
1870
+ 0, 1, nullptr, nullptr, nullptr,
1871
+ CallData::RelayAsync, &instance->broker) != napi_ok) {
1872
+ LogError("Failed to create async callback broker");
1873
+ return nullptr;
1874
+ }
1875
+ napi_unref_threadsafe_function(env, instance->broker);
1876
+
1877
+ err_guard.Disable();
1878
+ return instance;
1879
+ }
1880
+
1831
1881
  template <typename Func>
1832
1882
  static void SetExports(Napi::Env env, Func func)
1833
1883
  {
@@ -1906,7 +1956,9 @@ static void InitInternal(v8::Local<v8::Object> target, v8::Local<v8::Value>,
1906
1956
  delete env_napi;
1907
1957
  }, env_napi);
1908
1958
 
1909
- InstanceData *instance = new InstanceData();
1959
+ InstanceData *instance = CreateInstance(env_cxx);
1960
+ RG_CRITICAL(instance, "Failed to initialize Koffi");
1961
+
1910
1962
  env_cxx.SetInstanceData(instance);
1911
1963
 
1912
1964
  instance->debug = GetDebugFlag("DUMP_CALLS");
@@ -1922,7 +1974,9 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
1922
1974
  {
1923
1975
  using namespace RG;
1924
1976
 
1925
- InstanceData *instance = new InstanceData();
1977
+ InstanceData *instance = CreateInstance(env);
1978
+ RG_CRITICAL(instance, "Failed to initialize Koffi");
1979
+
1926
1980
  env.SetInstanceData(instance);
1927
1981
 
1928
1982
  instance->debug = GetDebugFlag("DUMP_CALLS");
@@ -263,6 +263,8 @@ struct InstanceData {
263
263
  int16_t temp_trampolines = 0;
264
264
  uint32_t registered_trampolines = 0;
265
265
 
266
+ napi_threadsafe_function broker = nullptr;
267
+
266
268
  BlockAllocator str_alloc;
267
269
 
268
270
  Size sync_stack_size = DefaultSyncStackSize;
@@ -18,6 +18,10 @@
18
18
  const util = require('util');
19
19
 
20
20
  let filename = __dirname + '/../build/koffi.node';
21
- module.exports = require(filename);
22
21
 
23
- module.exports.handle = util.deprecate(module.exports.opaque, 'The koffi.handle() function was deprecated in Koffi 2.1, use koffi.opaque() instead', 'KOFFI001');
22
+ module.exports = {
23
+ ...require(filename),
24
+
25
+ // Deprecated functions
26
+ handle: util.deprecate(module.exports.opaque, 'The koffi.handle() function was deprecated in Koffi 2.1, use koffi.opaque() instead', 'KOFFI001');
27
+ };
@@ -100,7 +100,7 @@ endif()
100
100
 
101
101
  # ---- SQLite ----
102
102
 
103
- add_library(sqlite3 SHARED ../../../vendor/sqlite3mc/sqlite3.c)
103
+ add_library(sqlite3 SHARED ../../../vendor/sqlite3/sqlite3.c)
104
104
  set_target_properties(sqlite3 PROPERTIES PREFIX "")
105
105
 
106
106
  if(WIN32)
@@ -28,6 +28,8 @@ const PackedBFG = koffi.pack('PackedBFG', {
28
28
  })
29
29
  });
30
30
 
31
+ const CharCallback = koffi.callback('int CharCallback(int idx, char c)');
32
+
31
33
  main();
32
34
 
33
35
  async function main() {
@@ -46,6 +48,7 @@ async function test() {
46
48
 
47
49
  const ConcatenateToInt1 = lib.func('ConcatenateToInt1', 'int64_t', Array(12).fill('int8_t'));
48
50
  const MakePackedBFG = lib.func('PackedBFG __fastcall MakePackedBFG(int x, double y, _Out_ PackedBFG *p, const char *str)');
51
+ const CallMeChar = lib.func('int CallMeChar(CharCallback *func)');
49
52
 
50
53
  let promises = [];
51
54
 
@@ -15,6 +15,7 @@
15
15
 
16
16
  const koffi = require('./build/koffi.node');
17
17
  const assert = require('assert');
18
+ const util = require('util');
18
19
 
19
20
  const BFG = koffi.struct('BFG', {
20
21
  a: 'int8_t',
@@ -41,6 +42,7 @@ const ApplyCallback = koffi.callback('int __stdcall ApplyCallback(int a, int b,
41
42
  const IntCallback = koffi.callback('int IntCallback(int x)');
42
43
  const VectorCallback = koffi.callback('int VectorCallback(int len, Vec2 *vec)');
43
44
  const SortCallback = koffi.callback('int SortCallback(const void *ptr1, const void *ptr2)');
45
+ const CharCallback = koffi.callback('int CharCallback(int idx, char c)');
44
46
 
45
47
  const StructCallbacks = koffi.struct('StructCallbacks', {
46
48
  first: koffi.pointer(IntCallback),
@@ -75,6 +77,8 @@ async function test() {
75
77
  const CallCallback = lib.func('int CallCallback(int x)');
76
78
  const MakeVectors = lib.func('int MakeVectors(int len, VectorCallback *func)');
77
79
  const CallQSort = lib.func('void CallQSort(_Inout_ void *base, size_t nmemb, size_t size, SortCallback *cb)');
80
+ const CallMeChar = lib.func('int CallMeChar(CharCallback *func)');
81
+ const GetMinusOne1 = lib.func('int8_t GetMinusOne1(void)');
78
82
 
79
83
  // Simple test similar to README example
80
84
  {
@@ -230,4 +234,30 @@ async function test() {
230
234
 
231
235
  assert.deepEqual(array, ['123', 'bar', 'foo', 'foobar']);
232
236
  }
237
+
238
+ // Make sure thread local CallData is restored after nested call inside callback
239
+ // Regression test for issue #15
240
+ {
241
+ let chars = [97, 98];
242
+
243
+ let cb = koffi.register((idx, c) => {
244
+ assert.equal(GetMinusOne1(), -1);
245
+ assert.equal(c, chars[idx]);
246
+
247
+ return c;
248
+ }, 'CharCallback *');
249
+
250
+ let ret = CallMeChar(cb);
251
+ assert.equal(ret, 97 + 98);
252
+ }
253
+
254
+ // Test callback inside async function
255
+ {
256
+ let chars = [97, 98];
257
+
258
+ let cb = koffi.register((idx, c) => (idx + 1) * c, 'CharCallback *');
259
+ let ret = await util.promisify(CallMeChar.async)(cb);
260
+
261
+ assert.equal(ret, 97 + 2 * 98);
262
+ }
233
263
  }
@@ -169,6 +169,7 @@ typedef struct Vec2 {
169
169
 
170
170
  typedef int VectorCallback(int len, Vec2 *vec);
171
171
  typedef int SortCallback(const void *ptr1, const void *ptr2);
172
+ typedef int CharCallback(int idx, char c);
172
173
 
173
174
  EXPORT int8_t GetMinusOne1(void)
174
175
  {
@@ -776,3 +777,13 @@ EXPORT void CallQSort(void *base, size_t nmemb, size_t size, SortCallback *cb)
776
777
  {
777
778
  qsort(base, nmemb, size, cb);
778
779
  }
780
+
781
+ EXPORT int CallMeChar(CharCallback *func)
782
+ {
783
+ int ret = 0;
784
+
785
+ ret += func(0, 'a');
786
+ ret += func(1, 'b');
787
+
788
+ return ret;
789
+ }
@@ -1,6 +1,6 @@
1
1
  /******************************************************************************
2
2
  ** This file is an amalgamation of many separate C source files from SQLite
3
- ** version 3.40.0. By combining all the individual C code files into this
3
+ ** version 3.40.1. 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
@@ -452,9 +452,9 @@ extern "C" {
452
452
  ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
453
453
  ** [sqlite_version()] and [sqlite_source_id()].
454
454
  */
455
- #define SQLITE_VERSION "3.40.0"
456
- #define SQLITE_VERSION_NUMBER 3040000
457
- #define SQLITE_SOURCE_ID "2022-11-16 12:10:08 89c459e766ea7e9165d0beeb124708b955a4950d0f4792f457465d71b158d318"
455
+ #define SQLITE_VERSION "3.40.1"
456
+ #define SQLITE_VERSION_NUMBER 3040001
457
+ #define SQLITE_SOURCE_ID "2022-12-28 14:03:47 df5c253c0b3dd24916e4ec7cf77d3db5294cc9fd45ae7b9c5e82ad8197f38a24"
458
458
 
459
459
  /*
460
460
  ** CAPI3REF: Run-Time Library Version Numbers
@@ -1498,6 +1498,12 @@ struct sqlite3_io_methods {
1498
1498
  **
1499
1499
  ** <li>[[SQLITE_FCNTL_CKSM_FILE]]
1500
1500
  ** Used by the cksmvfs VFS module only.
1501
+ **
1502
+ ** <li>[[SQLITE_FCNTL_RESET_CACHE]]
1503
+ ** If there is currently no transaction open on the database, and the
1504
+ ** database is not a temp db, then this file-control purges the contents
1505
+ ** of the in-memory page cache. If there is an open transaction, or if
1506
+ ** the db is a temp-db, it is a no-op, not an error.
1501
1507
  ** </ul>
1502
1508
  */
1503
1509
  #define SQLITE_FCNTL_LOCKSTATE 1
@@ -1540,6 +1546,7 @@ struct sqlite3_io_methods {
1540
1546
  #define SQLITE_FCNTL_CKPT_START 39
1541
1547
  #define SQLITE_FCNTL_EXTERNAL_READER 40
1542
1548
  #define SQLITE_FCNTL_CKSM_FILE 41
1549
+ #define SQLITE_FCNTL_RESET_CACHE 42
1543
1550
 
1544
1551
  /* deprecated names */
1545
1552
  #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -15714,6 +15721,8 @@ SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree*, int, int *, int *);
15714
15721
 
15715
15722
  SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor*, BtCursor*, i64);
15716
15723
 
15724
+ SQLITE_PRIVATE void sqlite3BtreeClearCache(Btree*);
15725
+
15717
15726
  /*
15718
15727
  ** If we are not using shared cache, then there is no need to
15719
15728
  ** use mutexes to access the BtShared structures. So make the
@@ -27290,9 +27299,13 @@ static int memsys5Roundup(int n){
27290
27299
  if( n<=mem5.szAtom ) return mem5.szAtom;
27291
27300
  return mem5.szAtom*2;
27292
27301
  }
27293
- if( n>0x40000000 ) return 0;
27302
+ if( n>0x10000000 ){
27303
+ if( n>0x40000000 ) return 0;
27304
+ if( n>0x20000000 ) return 0x40000000;
27305
+ return 0x20000000;
27306
+ }
27294
27307
  for(iFullSz=mem5.szAtom*8; iFullSz<n; iFullSz *= 4);
27295
- if( (iFullSz/2)>=n ) return iFullSz/2;
27308
+ if( (iFullSz/2)>=(i64)n ) return iFullSz/2;
27296
27309
  return iFullSz;
27297
27310
  }
27298
27311
 
@@ -37350,6 +37363,9 @@ static int robust_open(const char *z, int f, mode_t m){
37350
37363
  break;
37351
37364
  }
37352
37365
  if( fd>=SQLITE_MINIMUM_FILE_DESCRIPTOR ) break;
37366
+ if( (f & (O_EXCL|O_CREAT))==(O_EXCL|O_CREAT) ){
37367
+ (void)osUnlink(z);
37368
+ }
37353
37369
  osClose(fd);
37354
37370
  sqlite3_log(SQLITE_WARNING,
37355
37371
  "attempt to open \"%s\" as file descriptor %d", z, fd);
@@ -51083,6 +51099,7 @@ static int memdbTruncate(sqlite3_file*, sqlite3_int64 size);
51083
51099
  static int memdbSync(sqlite3_file*, int flags);
51084
51100
  static int memdbFileSize(sqlite3_file*, sqlite3_int64 *pSize);
51085
51101
  static int memdbLock(sqlite3_file*, int);
51102
+ static int memdbUnlock(sqlite3_file*, int);
51086
51103
  /* static int memdbCheckReservedLock(sqlite3_file*, int *pResOut);// not used */
51087
51104
  static int memdbFileControl(sqlite3_file*, int op, void *pArg);
51088
51105
  /* static int memdbSectorSize(sqlite3_file*); // not used */
@@ -51141,7 +51158,7 @@ static const sqlite3_io_methods memdb_io_methods = {
51141
51158
  memdbSync, /* xSync */
51142
51159
  memdbFileSize, /* xFileSize */
51143
51160
  memdbLock, /* xLock */
51144
- memdbLock, /* xUnlock - same as xLock in this case */
51161
+ memdbUnlock, /* xUnlock */
51145
51162
  0, /* memdbCheckReservedLock, */ /* xCheckReservedLock */
51146
51163
  memdbFileControl, /* xFileControl */
51147
51164
  0, /* memdbSectorSize,*/ /* xSectorSize */
@@ -51342,39 +51359,81 @@ static int memdbLock(sqlite3_file *pFile, int eLock){
51342
51359
  MemFile *pThis = (MemFile*)pFile;
51343
51360
  MemStore *p = pThis->pStore;
51344
51361
  int rc = SQLITE_OK;
51345
- if( eLock==pThis->eLock ) return SQLITE_OK;
51362
+ if( eLock<=pThis->eLock ) return SQLITE_OK;
51346
51363
  memdbEnter(p);
51347
- if( eLock>SQLITE_LOCK_SHARED ){
51348
- if( p->mFlags & SQLITE_DESERIALIZE_READONLY ){
51349
- rc = SQLITE_READONLY;
51350
- }else if( pThis->eLock<=SQLITE_LOCK_SHARED ){
51351
- if( p->nWrLock ){
51352
- rc = SQLITE_BUSY;
51353
- }else{
51354
- p->nWrLock = 1;
51364
+
51365
+ assert( p->nWrLock==0 || p->nWrLock==1 );
51366
+ assert( pThis->eLock<=SQLITE_LOCK_SHARED || p->nWrLock==1 );
51367
+ assert( pThis->eLock==SQLITE_LOCK_NONE || p->nRdLock>=1 );
51368
+
51369
+ if( eLock>SQLITE_LOCK_SHARED && (p->mFlags & SQLITE_DESERIALIZE_READONLY) ){
51370
+ rc = SQLITE_READONLY;
51371
+ }else{
51372
+ switch( eLock ){
51373
+ case SQLITE_LOCK_SHARED: {
51374
+ assert( pThis->eLock==SQLITE_LOCK_NONE );
51375
+ if( p->nWrLock>0 ){
51376
+ rc = SQLITE_BUSY;
51377
+ }else{
51378
+ p->nRdLock++;
51379
+ }
51380
+ break;
51381
+ };
51382
+
51383
+ case SQLITE_LOCK_RESERVED:
51384
+ case SQLITE_LOCK_PENDING: {
51385
+ assert( pThis->eLock>=SQLITE_LOCK_SHARED );
51386
+ if( ALWAYS(pThis->eLock==SQLITE_LOCK_SHARED) ){
51387
+ if( p->nWrLock>0 ){
51388
+ rc = SQLITE_BUSY;
51389
+ }else{
51390
+ p->nWrLock = 1;
51391
+ }
51392
+ }
51393
+ break;
51394
+ }
51395
+
51396
+ default: {
51397
+ assert( eLock==SQLITE_LOCK_EXCLUSIVE );
51398
+ assert( pThis->eLock>=SQLITE_LOCK_SHARED );
51399
+ if( p->nRdLock>1 ){
51400
+ rc = SQLITE_BUSY;
51401
+ }else if( pThis->eLock==SQLITE_LOCK_SHARED ){
51402
+ p->nWrLock = 1;
51403
+ }
51404
+ break;
51355
51405
  }
51356
51406
  }
51357
- }else if( eLock==SQLITE_LOCK_SHARED ){
51358
- if( pThis->eLock > SQLITE_LOCK_SHARED ){
51359
- assert( p->nWrLock==1 );
51360
- p->nWrLock = 0;
51361
- }else if( p->nWrLock ){
51362
- rc = SQLITE_BUSY;
51363
- }else{
51364
- p->nRdLock++;
51407
+ }
51408
+ if( rc==SQLITE_OK ) pThis->eLock = eLock;
51409
+ memdbLeave(p);
51410
+ return rc;
51411
+ }
51412
+
51413
+ /*
51414
+ ** Unlock an memdb-file.
51415
+ */
51416
+ static int memdbUnlock(sqlite3_file *pFile, int eLock){
51417
+ MemFile *pThis = (MemFile*)pFile;
51418
+ MemStore *p = pThis->pStore;
51419
+ if( eLock>=pThis->eLock ) return SQLITE_OK;
51420
+ memdbEnter(p);
51421
+
51422
+ assert( eLock==SQLITE_LOCK_SHARED || eLock==SQLITE_LOCK_NONE );
51423
+ if( eLock==SQLITE_LOCK_SHARED ){
51424
+ if( ALWAYS(pThis->eLock>SQLITE_LOCK_SHARED) ){
51425
+ p->nWrLock--;
51365
51426
  }
51366
51427
  }else{
51367
- assert( eLock==SQLITE_LOCK_NONE );
51368
51428
  if( pThis->eLock>SQLITE_LOCK_SHARED ){
51369
- assert( p->nWrLock==1 );
51370
- p->nWrLock = 0;
51429
+ p->nWrLock--;
51371
51430
  }
51372
- assert( p->nRdLock>0 );
51373
51431
  p->nRdLock--;
51374
51432
  }
51375
- if( rc==SQLITE_OK ) pThis->eLock = eLock;
51433
+
51434
+ pThis->eLock = eLock;
51376
51435
  memdbLeave(p);
51377
- return rc;
51436
+ return SQLITE_OK;
51378
51437
  }
51379
51438
 
51380
51439
  #if 0
@@ -51484,7 +51543,7 @@ static int memdbOpen(
51484
51543
 
51485
51544
  memset(pFile, 0, sizeof(*pFile));
51486
51545
  szName = sqlite3Strlen30(zName);
51487
- if( szName>1 && zName[0]=='/' ){
51546
+ if( szName>1 && (zName[0]=='/' || zName[0]=='\\') ){
51488
51547
  int i;
51489
51548
  #ifndef SQLITE_MUTEX_OMIT
51490
51549
  sqlite3_mutex *pVfsMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1);
@@ -51831,6 +51890,13 @@ end_deserialize:
51831
51890
  return rc;
51832
51891
  }
51833
51892
 
51893
+ /*
51894
+ ** Return true if the VFS is the memvfs.
51895
+ */
51896
+ SQLITE_PRIVATE int sqlite3IsMemdb(const sqlite3_vfs *pVfs){
51897
+ return pVfs==&memdb_vfs;
51898
+ }
51899
+
51834
51900
  /*
51835
51901
  ** This routine is called when the extension is loaded.
51836
51902
  ** Register the new VFS.
@@ -79159,6 +79225,17 @@ SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *p){
79159
79225
  */
79160
79226
  SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); }
79161
79227
 
79228
+ /*
79229
+ ** If no transaction is active and the database is not a temp-db, clear
79230
+ ** the in-memory pager cache.
79231
+ */
79232
+ SQLITE_PRIVATE void sqlite3BtreeClearCache(Btree *p){
79233
+ BtShared *pBt = p->pBt;
79234
+ if( pBt->inTransaction==TRANS_NONE ){
79235
+ sqlite3PagerClearCache(pBt->pPager);
79236
+ }
79237
+ }
79238
+
79162
79239
  #if !defined(SQLITE_OMIT_SHARED_CACHE)
79163
79240
  /*
79164
79241
  ** Return true if the Btree passed as the only argument is sharable.
@@ -83398,7 +83475,7 @@ SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe *p, void *pP4, int n){
83398
83475
  if( p->db->mallocFailed ){
83399
83476
  freeP4(p->db, n, pP4);
83400
83477
  }else{
83401
- assert( pP4!=0 );
83478
+ assert( pP4!=0 || n==P4_DYNAMIC );
83402
83479
  assert( p->nOp>0 );
83403
83480
  pOp = &p->aOp[p->nOp-1];
83404
83481
  assert( pOp->p4type==P4_NOTUSED );
@@ -132310,7 +132387,7 @@ static const sqlite3_api_routines sqlite3Apis = {
132310
132387
  #endif
132311
132388
  sqlite3_db_name,
132312
132389
  /* Version 3.40.0 and later */
132313
- sqlite3_value_type
132390
+ sqlite3_value_encoding
132314
132391
  };
132315
132392
 
132316
132393
  /* True if x is the directory separator character
@@ -145451,7 +145528,7 @@ SQLITE_PRIVATE Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){
145451
145528
  if( pTrig->pTabSchema==pTab->pSchema
145452
145529
  && pTrig->table
145453
145530
  && 0==sqlite3StrICmp(pTrig->table, pTab->zName)
145454
- && pTrig->pTabSchema!=pTmpSchema
145531
+ && (pTrig->pTabSchema!=pTmpSchema || pTrig->bReturning)
145455
145532
  ){
145456
145533
  pTrig->pNext = pList;
145457
145534
  pList = pTrig;
@@ -155635,7 +155712,7 @@ SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo *pWInfo){
155635
155712
  ** block sorting is required.
155636
155713
  */
155637
155714
  SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){
155638
- return pWInfo->nOBSat;
155715
+ return pWInfo->nOBSat<0 ? 0 : pWInfo->nOBSat;
155639
155716
  }
155640
155717
 
155641
155718
  /*
@@ -174543,7 +174620,7 @@ SQLITE_API int sqlite3_overload_function(
174543
174620
  rc = sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)!=0;
174544
174621
  sqlite3_mutex_leave(db->mutex);
174545
174622
  if( rc ) return SQLITE_OK;
174546
- zCopy = sqlite3_mprintf(zName);
174623
+ zCopy = sqlite3_mprintf("%s", zName);
174547
174624
  if( zCopy==0 ) return SQLITE_NOMEM;
174548
174625
  return sqlite3_create_function_v2(db, zName, nArg, SQLITE_UTF8,
174549
174626
  zCopy, sqlite3InvalidFunction, 0, 0, sqlite3_free);
@@ -176375,6 +176452,9 @@ SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, vo
176375
176452
  sqlite3BtreeSetPageSize(pBtree, 0, iNew, 0);
176376
176453
  }
176377
176454
  rc = SQLITE_OK;
176455
+ }else if( op==SQLITE_FCNTL_RESET_CACHE ){
176456
+ sqlite3BtreeClearCache(pBtree);
176457
+ rc = SQLITE_OK;
176378
176458
  }else{
176379
176459
  int nSave = db->busyHandler.nBusy;
176380
176460
  rc = sqlite3OsFileControl(fd, op, pArg);
@@ -217790,6 +217870,22 @@ static int sessionChangesetNextOne(
217790
217870
  if( p->op==SQLITE_INSERT ) p->op = SQLITE_DELETE;
217791
217871
  else if( p->op==SQLITE_DELETE ) p->op = SQLITE_INSERT;
217792
217872
  }
217873
+
217874
+ /* If this is an UPDATE that is part of a changeset, then check that
217875
+ ** there are no fields in the old.* record that are not (a) PK fields,
217876
+ ** or (b) also present in the new.* record.
217877
+ **
217878
+ ** Such records are technically corrupt, but the rebaser was at one
217879
+ ** point generating them. Under most circumstances this is benign, but
217880
+ ** can cause spurious SQLITE_RANGE errors when applying the changeset. */
217881
+ if( p->bPatchset==0 && p->op==SQLITE_UPDATE){
217882
+ for(i=0; i<p->nCol; i++){
217883
+ if( p->abPK[i]==0 && p->apValue[i+p->nCol]==0 ){
217884
+ sqlite3ValueFree(p->apValue[i]);
217885
+ p->apValue[i] = 0;
217886
+ }
217887
+ }
217888
+ }
217793
217889
  }
217794
217890
 
217795
217891
  return SQLITE_ROW;
@@ -219986,7 +220082,7 @@ static void sessionAppendPartialUpdate(
219986
220082
  if( !pIter->abPK[i] && a1[0] ) bData = 1;
219987
220083
  memcpy(pOut, a1, n1);
219988
220084
  pOut += n1;
219989
- }else if( a2[0]!=0xFF ){
220085
+ }else if( a2[0]!=0xFF && a1[0] ){
219990
220086
  bData = 1;
219991
220087
  memcpy(pOut, a2, n2);
219992
220088
  pOut += n2;
@@ -236016,7 +236112,7 @@ static void fts5CheckTransactionState(Fts5FullTable *p, int op, int iSavepoint){
236016
236112
  break;
236017
236113
 
236018
236114
  case FTS5_SYNC:
236019
- assert( p->ts.eState==1 );
236115
+ assert( p->ts.eState==1 || p->ts.eState==2 );
236020
236116
  p->ts.eState = 2;
236021
236117
  break;
236022
236118
 
@@ -236031,21 +236127,21 @@ static void fts5CheckTransactionState(Fts5FullTable *p, int op, int iSavepoint){
236031
236127
  break;
236032
236128
 
236033
236129
  case FTS5_SAVEPOINT:
236034
- assert( p->ts.eState==1 );
236130
+ assert( p->ts.eState>=1 );
236035
236131
  assert( iSavepoint>=0 );
236036
236132
  assert( iSavepoint>=p->ts.iSavepoint );
236037
236133
  p->ts.iSavepoint = iSavepoint;
236038
236134
  break;
236039
236135
 
236040
236136
  case FTS5_RELEASE:
236041
- assert( p->ts.eState==1 );
236137
+ assert( p->ts.eState>=1 );
236042
236138
  assert( iSavepoint>=0 );
236043
236139
  assert( iSavepoint<=p->ts.iSavepoint );
236044
236140
  p->ts.iSavepoint = iSavepoint-1;
236045
236141
  break;
236046
236142
 
236047
236143
  case FTS5_ROLLBACKTO:
236048
- assert( p->ts.eState==1 );
236144
+ assert( p->ts.eState>=1 );
236049
236145
  assert( iSavepoint>=-1 );
236050
236146
  /* The following assert() can fail if another vtab strikes an error
236051
236147
  ** within an xSavepoint() call then SQLite calls xRollbackTo() - without
@@ -237381,7 +237477,7 @@ static int fts5UpdateMethod(
237381
237477
  int rc = SQLITE_OK; /* Return code */
237382
237478
 
237383
237479
  /* A transaction must be open when this is called. */
237384
- assert( pTab->ts.eState==1 );
237480
+ assert( pTab->ts.eState==1 || pTab->ts.eState==2 );
237385
237481
 
237386
237482
  assert( pVtab->zErrMsg==0 );
237387
237483
  assert( nArg==1 || nArg==(2+pConfig->nCol+2) );
@@ -238549,7 +238645,7 @@ static void fts5SourceIdFunc(
238549
238645
  ){
238550
238646
  assert( nArg==0 );
238551
238647
  UNUSED_PARAM2(nArg, apUnused);
238552
- sqlite3_result_text(pCtx, "fts5: 2022-11-16 12:10:08 89c459e766ea7e9165d0beeb124708b955a4950d0f4792f457465d71b158d318", -1, SQLITE_TRANSIENT);
238648
+ sqlite3_result_text(pCtx, "fts5: 2022-12-28 14:03:47 df5c253c0b3dd24916e4ec7cf77d3db5294cc9fd45ae7b9c5e82ad8197f38a24", -1, SQLITE_TRANSIENT);
238553
238649
  }
238554
238650
 
238555
238651
  /*