pyturso 0.4.1__tar.gz → 0.4.2__tar.gz

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 (270) hide show
  1. {pyturso-0.4.1 → pyturso-0.4.2}/Cargo.lock +31 -31
  2. {pyturso-0.4.1 → pyturso-0.4.2}/Cargo.toml +12 -12
  3. {pyturso-0.4.1 → pyturso-0.4.2}/PKG-INFO +1 -1
  4. {pyturso-0.4.1 → pyturso-0.4.2}/core/mvcc/cursor.rs +1 -2
  5. {pyturso-0.4.1 → pyturso-0.4.2}/core/mvcc/database/mod.rs +53 -18
  6. {pyturso-0.4.1 → pyturso-0.4.2}/core/mvcc/database/tests.rs +50 -0
  7. {pyturso-0.4.1 → pyturso-0.4.2}/core/storage/btree.rs +25 -1
  8. {pyturso-0.4.1 → pyturso-0.4.2}/core/storage/pager.rs +55 -8
  9. {pyturso-0.4.1 → pyturso-0.4.2}/core/storage/wal.rs +27 -6
  10. {pyturso-0.4.1 → pyturso-0.4.2}/core/vdbe/execute.rs +9 -2
  11. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/Cargo.toml +0 -0
  12. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/README.md +0 -0
  13. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/build.rs +0 -0
  14. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/example.py +0 -0
  15. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/py-bindings-db-aio.mdx +0 -0
  16. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/py-bindings-db.mdx +0 -0
  17. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/py-bindings-sync-aio.mdx +0 -0
  18. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/py-bindings-sync.mdx +0 -0
  19. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/py-bindings-tests-aio.mdx +0 -0
  20. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/py-bindings-tests.mdx +0 -0
  21. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/requirements-dev.txt +0 -0
  22. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/requirements.txt +0 -0
  23. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/src/lib.rs +0 -0
  24. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/src/turso.rs +0 -0
  25. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/src/turso_sync.rs +0 -0
  26. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/tests/__init__.py +0 -0
  27. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/tests/test_database.py +0 -0
  28. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/tests/test_database_aio.py +0 -0
  29. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/tests/test_database_sync.py +0 -0
  30. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/tests/test_database_sync_aio.py +0 -0
  31. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/tests/utils.py +0 -0
  32. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/turso/__init__.py +0 -0
  33. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/turso/aio/__init__.py +0 -0
  34. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/turso/aio/sync/__init__.py +0 -0
  35. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/turso/lib.py +0 -0
  36. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/turso/lib_aio.py +0 -0
  37. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/turso/lib_sync.py +0 -0
  38. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/turso/lib_sync_aio.py +0 -0
  39. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/turso/py.typed +0 -0
  40. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/turso/sync/__init__.py +0 -0
  41. {pyturso-0.4.1 → pyturso-0.4.2}/bindings/python/turso/worker.py +0 -0
  42. {pyturso-0.4.1 → pyturso-0.4.2}/core/Cargo.toml +0 -0
  43. {pyturso-0.4.1 → pyturso-0.4.2}/core/assert.rs +0 -0
  44. {pyturso-0.4.1 → pyturso-0.4.2}/core/benches/benchmark.rs +0 -0
  45. {pyturso-0.4.1 → pyturso-0.4.2}/core/benches/json_benchmark.rs +0 -0
  46. {pyturso-0.4.1 → pyturso-0.4.2}/core/benches/mvcc_benchmark.rs +0 -0
  47. {pyturso-0.4.1 → pyturso-0.4.2}/core/benches/tpc_h_benchmark.rs +0 -0
  48. {pyturso-0.4.1 → pyturso-0.4.2}/core/build.rs +0 -0
  49. {pyturso-0.4.1 → pyturso-0.4.2}/core/busy.rs +0 -0
  50. {pyturso-0.4.1 → pyturso-0.4.2}/core/error.rs +0 -0
  51. {pyturso-0.4.1 → pyturso-0.4.2}/core/ext/dynamic.rs +0 -0
  52. {pyturso-0.4.1 → pyturso-0.4.2}/core/ext/mod.rs +0 -0
  53. {pyturso-0.4.1 → pyturso-0.4.2}/core/ext/vtab_xconnect.rs +0 -0
  54. {pyturso-0.4.1 → pyturso-0.4.2}/core/fast_lock.rs +0 -0
  55. {pyturso-0.4.1 → pyturso-0.4.2}/core/function.rs +0 -0
  56. {pyturso-0.4.1 → pyturso-0.4.2}/core/functions/datetime.rs +0 -0
  57. {pyturso-0.4.1 → pyturso-0.4.2}/core/functions/mod.rs +0 -0
  58. {pyturso-0.4.1 → pyturso-0.4.2}/core/functions/printf.rs +0 -0
  59. {pyturso-0.4.1 → pyturso-0.4.2}/core/functions/strftime.rs +0 -0
  60. {pyturso-0.4.1 → pyturso-0.4.2}/core/incremental/aggregate_operator.rs +0 -0
  61. {pyturso-0.4.1 → pyturso-0.4.2}/core/incremental/compiler.rs +0 -0
  62. {pyturso-0.4.1 → pyturso-0.4.2}/core/incremental/cursor.rs +0 -0
  63. {pyturso-0.4.1 → pyturso-0.4.2}/core/incremental/dbsp.rs +0 -0
  64. {pyturso-0.4.1 → pyturso-0.4.2}/core/incremental/expr_compiler.rs +0 -0
  65. {pyturso-0.4.1 → pyturso-0.4.2}/core/incremental/filter_operator.rs +0 -0
  66. {pyturso-0.4.1 → pyturso-0.4.2}/core/incremental/input_operator.rs +0 -0
  67. {pyturso-0.4.1 → pyturso-0.4.2}/core/incremental/join_operator.rs +0 -0
  68. {pyturso-0.4.1 → pyturso-0.4.2}/core/incremental/merge_operator.rs +0 -0
  69. {pyturso-0.4.1 → pyturso-0.4.2}/core/incremental/mod.rs +0 -0
  70. {pyturso-0.4.1 → pyturso-0.4.2}/core/incremental/operator.rs +0 -0
  71. {pyturso-0.4.1 → pyturso-0.4.2}/core/incremental/persistence.rs +0 -0
  72. {pyturso-0.4.1 → pyturso-0.4.2}/core/incremental/project_operator.rs +0 -0
  73. {pyturso-0.4.1 → pyturso-0.4.2}/core/incremental/view.rs +0 -0
  74. {pyturso-0.4.1 → pyturso-0.4.2}/core/index_method/backing_btree.rs +0 -0
  75. {pyturso-0.4.1 → pyturso-0.4.2}/core/index_method/mod.rs +0 -0
  76. {pyturso-0.4.1 → pyturso-0.4.2}/core/index_method/toy_vector_sparse_ivf.rs +0 -0
  77. {pyturso-0.4.1 → pyturso-0.4.2}/core/info.rs +0 -0
  78. {pyturso-0.4.1 → pyturso-0.4.2}/core/io/clock.rs +0 -0
  79. {pyturso-0.4.1 → pyturso-0.4.2}/core/io/common.rs +0 -0
  80. {pyturso-0.4.1 → pyturso-0.4.2}/core/io/completions.rs +0 -0
  81. {pyturso-0.4.1 → pyturso-0.4.2}/core/io/generic.rs +0 -0
  82. {pyturso-0.4.1 → pyturso-0.4.2}/core/io/io_uring.rs +0 -0
  83. {pyturso-0.4.1 → pyturso-0.4.2}/core/io/memory.rs +0 -0
  84. {pyturso-0.4.1 → pyturso-0.4.2}/core/io/mod.rs +0 -0
  85. {pyturso-0.4.1 → pyturso-0.4.2}/core/io/unix.rs +0 -0
  86. {pyturso-0.4.1 → pyturso-0.4.2}/core/io/vfs.rs +0 -0
  87. {pyturso-0.4.1 → pyturso-0.4.2}/core/io/windows.rs +0 -0
  88. {pyturso-0.4.1 → pyturso-0.4.2}/core/json/cache.rs +0 -0
  89. {pyturso-0.4.1 → pyturso-0.4.2}/core/json/error.rs +0 -0
  90. {pyturso-0.4.1 → pyturso-0.4.2}/core/json/jsonb.rs +0 -0
  91. {pyturso-0.4.1 → pyturso-0.4.2}/core/json/mod.rs +0 -0
  92. {pyturso-0.4.1 → pyturso-0.4.2}/core/json/ops.rs +0 -0
  93. {pyturso-0.4.1 → pyturso-0.4.2}/core/json/path.rs +0 -0
  94. {pyturso-0.4.1 → pyturso-0.4.2}/core/json/vtab.rs +0 -0
  95. {pyturso-0.4.1 → pyturso-0.4.2}/core/lib.rs +0 -0
  96. {pyturso-0.4.1 → pyturso-0.4.2}/core/mvcc/clock.rs +0 -0
  97. {pyturso-0.4.1 → pyturso-0.4.2}/core/mvcc/database/checkpoint_state_machine.rs +0 -0
  98. {pyturso-0.4.1 → pyturso-0.4.2}/core/mvcc/mod.rs +0 -0
  99. {pyturso-0.4.1 → pyturso-0.4.2}/core/mvcc/persistent_storage/logical_log.rs +0 -0
  100. {pyturso-0.4.1 → pyturso-0.4.2}/core/mvcc/persistent_storage/mod.rs +0 -0
  101. {pyturso-0.4.1 → pyturso-0.4.2}/core/numeric/mod.rs +0 -0
  102. {pyturso-0.4.1 → pyturso-0.4.2}/core/numeric/nonnan.rs +0 -0
  103. {pyturso-0.4.1 → pyturso-0.4.2}/core/parameters.rs +0 -0
  104. {pyturso-0.4.1 → pyturso-0.4.2}/core/pragma.rs +0 -0
  105. {pyturso-0.4.1 → pyturso-0.4.2}/core/pseudo.rs +0 -0
  106. {pyturso-0.4.1 → pyturso-0.4.2}/core/schema.rs +0 -0
  107. {pyturso-0.4.1 → pyturso-0.4.2}/core/series.rs +0 -0
  108. {pyturso-0.4.1 → pyturso-0.4.2}/core/state_machine.rs +0 -0
  109. {pyturso-0.4.1 → pyturso-0.4.2}/core/statement.rs +0 -0
  110. {pyturso-0.4.1 → pyturso-0.4.2}/core/stats.rs +0 -0
  111. {pyturso-0.4.1 → pyturso-0.4.2}/core/storage/buffer_pool.rs +0 -0
  112. {pyturso-0.4.1 → pyturso-0.4.2}/core/storage/checksum.rs +0 -0
  113. {pyturso-0.4.1 → pyturso-0.4.2}/core/storage/database.rs +0 -0
  114. {pyturso-0.4.1 → pyturso-0.4.2}/core/storage/encryption.rs +0 -0
  115. {pyturso-0.4.1 → pyturso-0.4.2}/core/storage/journal_mode.rs +0 -0
  116. {pyturso-0.4.1 → pyturso-0.4.2}/core/storage/mod.rs +0 -0
  117. {pyturso-0.4.1 → pyturso-0.4.2}/core/storage/page_cache.rs +0 -0
  118. {pyturso-0.4.1 → pyturso-0.4.2}/core/storage/slot_bitmap.rs +0 -0
  119. {pyturso-0.4.1 → pyturso-0.4.2}/core/storage/sqlite3_ondisk.rs +0 -0
  120. {pyturso-0.4.1 → pyturso-0.4.2}/core/storage/state_machines.rs +0 -0
  121. {pyturso-0.4.1 → pyturso-0.4.2}/core/storage/subjournal.rs +0 -0
  122. {pyturso-0.4.1 → pyturso-0.4.2}/core/time/internal.rs +0 -0
  123. {pyturso-0.4.1 → pyturso-0.4.2}/core/time/mod.rs +0 -0
  124. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/aggregation.rs +0 -0
  125. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/alter.rs +0 -0
  126. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/analyze.rs +0 -0
  127. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/attach.rs +0 -0
  128. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/collate.rs +0 -0
  129. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/compound_select.rs +0 -0
  130. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/delete.rs +0 -0
  131. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/display.rs +0 -0
  132. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/emitter.rs +0 -0
  133. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/expr.rs +0 -0
  134. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/expression_index.rs +0 -0
  135. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/fkeys.rs +0 -0
  136. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/group_by.rs +0 -0
  137. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/index.rs +0 -0
  138. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/insert.rs +0 -0
  139. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/integrity_check.rs +0 -0
  140. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/logical.rs +0 -0
  141. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/main_loop.rs +0 -0
  142. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/mod.rs +0 -0
  143. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/optimizer/OPTIMIZER.md +0 -0
  144. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/optimizer/access_method.rs +0 -0
  145. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/optimizer/constraints.rs +0 -0
  146. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/optimizer/cost.rs +0 -0
  147. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/optimizer/join.rs +0 -0
  148. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/optimizer/lift_common_subexpressions.rs +0 -0
  149. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/optimizer/mod.rs +0 -0
  150. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/optimizer/order.rs +0 -0
  151. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/order_by.rs +0 -0
  152. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/plan.rs +0 -0
  153. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/planner.rs +0 -0
  154. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/pragma.rs +0 -0
  155. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/result_row.rs +0 -0
  156. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/rollback.rs +0 -0
  157. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/schema.rs +0 -0
  158. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/select.rs +0 -0
  159. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/subquery.rs +0 -0
  160. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/transaction.rs +0 -0
  161. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/trigger.rs +0 -0
  162. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/trigger_exec.rs +0 -0
  163. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/update.rs +0 -0
  164. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/upsert.rs +0 -0
  165. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/values.rs +0 -0
  166. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/view.rs +0 -0
  167. {pyturso-0.4.1 → pyturso-0.4.2}/core/translate/window.rs +0 -0
  168. {pyturso-0.4.1 → pyturso-0.4.2}/core/types.rs +0 -0
  169. {pyturso-0.4.1 → pyturso-0.4.2}/core/util.rs +0 -0
  170. {pyturso-0.4.1 → pyturso-0.4.2}/core/uuid.rs +0 -0
  171. {pyturso-0.4.1 → pyturso-0.4.2}/core/vdbe/affinity.rs +0 -0
  172. {pyturso-0.4.1 → pyturso-0.4.2}/core/vdbe/bloom_filter.rs +0 -0
  173. {pyturso-0.4.1 → pyturso-0.4.2}/core/vdbe/builder.rs +0 -0
  174. {pyturso-0.4.1 → pyturso-0.4.2}/core/vdbe/explain.rs +0 -0
  175. {pyturso-0.4.1 → pyturso-0.4.2}/core/vdbe/hash_table.rs +0 -0
  176. {pyturso-0.4.1 → pyturso-0.4.2}/core/vdbe/insn.rs +0 -0
  177. {pyturso-0.4.1 → pyturso-0.4.2}/core/vdbe/likeop.rs +0 -0
  178. {pyturso-0.4.1 → pyturso-0.4.2}/core/vdbe/metrics.rs +0 -0
  179. {pyturso-0.4.1 → pyturso-0.4.2}/core/vdbe/mod.rs +0 -0
  180. {pyturso-0.4.1 → pyturso-0.4.2}/core/vdbe/rowset.rs +0 -0
  181. {pyturso-0.4.1 → pyturso-0.4.2}/core/vdbe/sorter.rs +0 -0
  182. {pyturso-0.4.1 → pyturso-0.4.2}/core/vdbe/value.rs +0 -0
  183. {pyturso-0.4.1 → pyturso-0.4.2}/core/vector/mod.rs +0 -0
  184. {pyturso-0.4.1 → pyturso-0.4.2}/core/vector/operations/concat.rs +0 -0
  185. {pyturso-0.4.1 → pyturso-0.4.2}/core/vector/operations/convert.rs +0 -0
  186. {pyturso-0.4.1 → pyturso-0.4.2}/core/vector/operations/distance_cos.rs +0 -0
  187. {pyturso-0.4.1 → pyturso-0.4.2}/core/vector/operations/distance_dot.rs +0 -0
  188. {pyturso-0.4.1 → pyturso-0.4.2}/core/vector/operations/distance_l2.rs +0 -0
  189. {pyturso-0.4.1 → pyturso-0.4.2}/core/vector/operations/jaccard.rs +0 -0
  190. {pyturso-0.4.1 → pyturso-0.4.2}/core/vector/operations/mod.rs +0 -0
  191. {pyturso-0.4.1 → pyturso-0.4.2}/core/vector/operations/serialize.rs +0 -0
  192. {pyturso-0.4.1 → pyturso-0.4.2}/core/vector/operations/slice.rs +0 -0
  193. {pyturso-0.4.1 → pyturso-0.4.2}/core/vector/operations/text.rs +0 -0
  194. {pyturso-0.4.1 → pyturso-0.4.2}/core/vector/vector_types.rs +0 -0
  195. {pyturso-0.4.1 → pyturso-0.4.2}/core/vtab.rs +0 -0
  196. {pyturso-0.4.1 → pyturso-0.4.2}/extensions/core/Cargo.toml +0 -0
  197. {pyturso-0.4.1 → pyturso-0.4.2}/extensions/core/README.md +0 -0
  198. {pyturso-0.4.1 → pyturso-0.4.2}/extensions/core/build.rs +0 -0
  199. {pyturso-0.4.1 → pyturso-0.4.2}/extensions/core/src/functions.rs +0 -0
  200. {pyturso-0.4.1 → pyturso-0.4.2}/extensions/core/src/lib.rs +0 -0
  201. {pyturso-0.4.1 → pyturso-0.4.2}/extensions/core/src/types.rs +0 -0
  202. {pyturso-0.4.1 → pyturso-0.4.2}/extensions/core/src/vfs_modules.rs +0 -0
  203. {pyturso-0.4.1 → pyturso-0.4.2}/extensions/core/src/vtabs.rs +0 -0
  204. {pyturso-0.4.1 → pyturso-0.4.2}/macros/Cargo.toml +0 -0
  205. {pyturso-0.4.1 → pyturso-0.4.2}/macros/src/atomic_enum.rs +0 -0
  206. {pyturso-0.4.1 → pyturso-0.4.2}/macros/src/ext/agg_derive.rs +0 -0
  207. {pyturso-0.4.1 → pyturso-0.4.2}/macros/src/ext/match_ignore_ascii_case.rs +0 -0
  208. {pyturso-0.4.1 → pyturso-0.4.2}/macros/src/ext/mod.rs +0 -0
  209. {pyturso-0.4.1 → pyturso-0.4.2}/macros/src/ext/scalars.rs +0 -0
  210. {pyturso-0.4.1 → pyturso-0.4.2}/macros/src/ext/vfs_derive.rs +0 -0
  211. {pyturso-0.4.1 → pyturso-0.4.2}/macros/src/ext/vtab_derive.rs +0 -0
  212. {pyturso-0.4.1 → pyturso-0.4.2}/macros/src/lib.rs +0 -0
  213. {pyturso-0.4.1 → pyturso-0.4.2}/macros/src/test.rs +0 -0
  214. {pyturso-0.4.1 → pyturso-0.4.2}/parser/Cargo.toml +0 -0
  215. {pyturso-0.4.1 → pyturso-0.4.2}/parser/README.md +0 -0
  216. {pyturso-0.4.1 → pyturso-0.4.2}/parser/benches/parser_benchmark.rs +0 -0
  217. {pyturso-0.4.1 → pyturso-0.4.2}/parser/src/ast/check.rs +0 -0
  218. {pyturso-0.4.1 → pyturso-0.4.2}/parser/src/ast/fmt.rs +0 -0
  219. {pyturso-0.4.1 → pyturso-0.4.2}/parser/src/ast.rs +0 -0
  220. {pyturso-0.4.1 → pyturso-0.4.2}/parser/src/error.rs +0 -0
  221. {pyturso-0.4.1 → pyturso-0.4.2}/parser/src/lexer.rs +0 -0
  222. {pyturso-0.4.1 → pyturso-0.4.2}/parser/src/lib.rs +0 -0
  223. {pyturso-0.4.1 → pyturso-0.4.2}/parser/src/parser.rs +0 -0
  224. {pyturso-0.4.1 → pyturso-0.4.2}/parser/src/token.rs +0 -0
  225. {pyturso-0.4.1 → pyturso-0.4.2}/pyproject.toml +0 -0
  226. {pyturso-0.4.1 → pyturso-0.4.2}/sdk-kit/Cargo.toml +0 -0
  227. {pyturso-0.4.1 → pyturso-0.4.2}/sdk-kit/README.md +0 -0
  228. {pyturso-0.4.1 → pyturso-0.4.2}/sdk-kit/bindgen.sh +0 -0
  229. {pyturso-0.4.1 → pyturso-0.4.2}/sdk-kit/readme-sdk-kit.mdx +0 -0
  230. {pyturso-0.4.1 → pyturso-0.4.2}/sdk-kit/src/bindings.rs +0 -0
  231. {pyturso-0.4.1 → pyturso-0.4.2}/sdk-kit/src/capi.rs +0 -0
  232. {pyturso-0.4.1 → pyturso-0.4.2}/sdk-kit/src/lib.rs +0 -0
  233. {pyturso-0.4.1 → pyturso-0.4.2}/sdk-kit/src/rsapi.rs +0 -0
  234. {pyturso-0.4.1 → pyturso-0.4.2}/sdk-kit/turso.h +0 -0
  235. {pyturso-0.4.1 → pyturso-0.4.2}/sdk-kit-macros/Cargo.toml +0 -0
  236. {pyturso-0.4.1 → pyturso-0.4.2}/sdk-kit-macros/src/lib.rs +0 -0
  237. {pyturso-0.4.1 → pyturso-0.4.2}/sync/engine/.gitignore +0 -0
  238. {pyturso-0.4.1 → pyturso-0.4.2}/sync/engine/Cargo.toml +0 -0
  239. {pyturso-0.4.1 → pyturso-0.4.2}/sync/engine/src/database_replay_generator.rs +0 -0
  240. {pyturso-0.4.1 → pyturso-0.4.2}/sync/engine/src/database_sync_engine.rs +0 -0
  241. {pyturso-0.4.1 → pyturso-0.4.2}/sync/engine/src/database_sync_engine_io.rs +0 -0
  242. {pyturso-0.4.1 → pyturso-0.4.2}/sync/engine/src/database_sync_lazy_storage.rs +0 -0
  243. {pyturso-0.4.1 → pyturso-0.4.2}/sync/engine/src/database_sync_operations.rs +0 -0
  244. {pyturso-0.4.1 → pyturso-0.4.2}/sync/engine/src/database_tape.rs +0 -0
  245. {pyturso-0.4.1 → pyturso-0.4.2}/sync/engine/src/errors.rs +0 -0
  246. {pyturso-0.4.1 → pyturso-0.4.2}/sync/engine/src/io_operations.rs +0 -0
  247. {pyturso-0.4.1 → pyturso-0.4.2}/sync/engine/src/lib.rs +0 -0
  248. {pyturso-0.4.1 → pyturso-0.4.2}/sync/engine/src/server_proto.rs +0 -0
  249. {pyturso-0.4.1 → pyturso-0.4.2}/sync/engine/src/sparse_io.rs +0 -0
  250. {pyturso-0.4.1 → pyturso-0.4.2}/sync/engine/src/types.rs +0 -0
  251. {pyturso-0.4.1 → pyturso-0.4.2}/sync/engine/src/wal_session.rs +0 -0
  252. {pyturso-0.4.1 → pyturso-0.4.2}/sync/sdk-kit/Cargo.toml +0 -0
  253. {pyturso-0.4.1 → pyturso-0.4.2}/sync/sdk-kit/bindgen.sh +0 -0
  254. {pyturso-0.4.1 → pyturso-0.4.2}/sync/sdk-kit/src/bindings.rs +0 -0
  255. {pyturso-0.4.1 → pyturso-0.4.2}/sync/sdk-kit/src/capi.rs +0 -0
  256. {pyturso-0.4.1 → pyturso-0.4.2}/sync/sdk-kit/src/lib.rs +0 -0
  257. {pyturso-0.4.1 → pyturso-0.4.2}/sync/sdk-kit/src/rsapi.rs +0 -0
  258. {pyturso-0.4.1 → pyturso-0.4.2}/sync/sdk-kit/src/sync_engine_io.rs +0 -0
  259. {pyturso-0.4.1 → pyturso-0.4.2}/sync/sdk-kit/src/turso_async_operation.rs +0 -0
  260. {pyturso-0.4.1 → pyturso-0.4.2}/sync/sdk-kit/turso_sync.h +0 -0
  261. {pyturso-0.4.1 → pyturso-0.4.2}/turso/__init__.py +0 -0
  262. {pyturso-0.4.1 → pyturso-0.4.2}/turso/aio/__init__.py +0 -0
  263. {pyturso-0.4.1 → pyturso-0.4.2}/turso/aio/sync/__init__.py +0 -0
  264. {pyturso-0.4.1 → pyturso-0.4.2}/turso/lib.py +0 -0
  265. {pyturso-0.4.1 → pyturso-0.4.2}/turso/lib_aio.py +0 -0
  266. {pyturso-0.4.1 → pyturso-0.4.2}/turso/lib_sync.py +0 -0
  267. {pyturso-0.4.1 → pyturso-0.4.2}/turso/lib_sync_aio.py +0 -0
  268. {pyturso-0.4.1 → pyturso-0.4.2}/turso/py.typed +0 -0
  269. {pyturso-0.4.1 → pyturso-0.4.2}/turso/sync/__init__.py +0 -0
  270. {pyturso-0.4.1 → pyturso-0.4.2}/turso/worker.py +0 -0
@@ -896,7 +896,7 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
896
896
 
897
897
  [[package]]
898
898
  name = "core_tester"
899
- version = "0.4.1"
899
+ version = "0.4.2"
900
900
  dependencies = [
901
901
  "anyhow",
902
902
  "assert_cmd",
@@ -2729,7 +2729,7 @@ dependencies = [
2729
2729
 
2730
2730
  [[package]]
2731
2731
  name = "limbo_completion"
2732
- version = "0.4.1"
2732
+ version = "0.4.2"
2733
2733
  dependencies = [
2734
2734
  "mimalloc",
2735
2735
  "turso_ext",
@@ -2737,7 +2737,7 @@ dependencies = [
2737
2737
 
2738
2738
  [[package]]
2739
2739
  name = "limbo_crypto"
2740
- version = "0.4.1"
2740
+ version = "0.4.2"
2741
2741
  dependencies = [
2742
2742
  "blake3",
2743
2743
  "data-encoding",
@@ -2750,7 +2750,7 @@ dependencies = [
2750
2750
 
2751
2751
  [[package]]
2752
2752
  name = "limbo_csv"
2753
- version = "0.4.1"
2753
+ version = "0.4.2"
2754
2754
  dependencies = [
2755
2755
  "csv",
2756
2756
  "mimalloc",
@@ -2760,7 +2760,7 @@ dependencies = [
2760
2760
 
2761
2761
  [[package]]
2762
2762
  name = "limbo_fuzzy"
2763
- version = "0.4.1"
2763
+ version = "0.4.2"
2764
2764
  dependencies = [
2765
2765
  "mimalloc",
2766
2766
  "turso_ext",
@@ -2768,7 +2768,7 @@ dependencies = [
2768
2768
 
2769
2769
  [[package]]
2770
2770
  name = "limbo_ipaddr"
2771
- version = "0.4.1"
2771
+ version = "0.4.2"
2772
2772
  dependencies = [
2773
2773
  "ipnetwork",
2774
2774
  "mimalloc",
@@ -2777,7 +2777,7 @@ dependencies = [
2777
2777
 
2778
2778
  [[package]]
2779
2779
  name = "limbo_percentile"
2780
- version = "0.4.1"
2780
+ version = "0.4.2"
2781
2781
  dependencies = [
2782
2782
  "mimalloc",
2783
2783
  "turso_ext",
@@ -2785,7 +2785,7 @@ dependencies = [
2785
2785
 
2786
2786
  [[package]]
2787
2787
  name = "limbo_regexp"
2788
- version = "0.4.1"
2788
+ version = "0.4.2"
2789
2789
  dependencies = [
2790
2790
  "mimalloc",
2791
2791
  "regex",
@@ -2794,7 +2794,7 @@ dependencies = [
2794
2794
 
2795
2795
  [[package]]
2796
2796
  name = "limbo_sim"
2797
- version = "0.4.1"
2797
+ version = "0.4.2"
2798
2798
  dependencies = [
2799
2799
  "anyhow",
2800
2800
  "bitflags 2.9.4",
@@ -2831,7 +2831,7 @@ dependencies = [
2831
2831
 
2832
2832
  [[package]]
2833
2833
  name = "limbo_sqlite_test_ext"
2834
- version = "0.4.1"
2834
+ version = "0.4.2"
2835
2835
  dependencies = [
2836
2836
  "cc",
2837
2837
  ]
@@ -3718,7 +3718,7 @@ dependencies = [
3718
3718
 
3719
3719
  [[package]]
3720
3720
  name = "py-turso"
3721
- version = "0.4.1"
3721
+ version = "0.4.2"
3722
3722
  dependencies = [
3723
3723
  "anyhow",
3724
3724
  "pyo3",
@@ -4595,7 +4595,7 @@ checksum = "d372029cb5195f9ab4e4b9aef550787dce78b124fcaee8d82519925defcd6f0d"
4595
4595
 
4596
4596
  [[package]]
4597
4597
  name = "sql_generation"
4598
- version = "0.4.1"
4598
+ version = "0.4.2"
4599
4599
  dependencies = [
4600
4600
  "anarchist-readable-name-generator-lib",
4601
4601
  "anyhow",
@@ -5299,7 +5299,7 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
5299
5299
 
5300
5300
  [[package]]
5301
5301
  name = "turso"
5302
- version = "0.4.1"
5302
+ version = "0.4.2"
5303
5303
  dependencies = [
5304
5304
  "anyhow",
5305
5305
  "bytes",
@@ -5323,14 +5323,14 @@ dependencies = [
5323
5323
 
5324
5324
  [[package]]
5325
5325
  name = "turso-dotnet"
5326
- version = "0.4.1"
5326
+ version = "0.4.2"
5327
5327
  dependencies = [
5328
5328
  "turso_core",
5329
5329
  ]
5330
5330
 
5331
5331
  [[package]]
5332
5332
  name = "turso-java"
5333
- version = "0.4.1"
5333
+ version = "0.4.2"
5334
5334
  dependencies = [
5335
5335
  "jni",
5336
5336
  "thiserror 2.0.16",
@@ -5339,7 +5339,7 @@ dependencies = [
5339
5339
 
5340
5340
  [[package]]
5341
5341
  name = "turso_cli"
5342
- version = "0.4.1"
5342
+ version = "0.4.2"
5343
5343
  dependencies = [
5344
5344
  "anyhow",
5345
5345
  "bytes",
@@ -5380,7 +5380,7 @@ dependencies = [
5380
5380
 
5381
5381
  [[package]]
5382
5382
  name = "turso_core"
5383
- version = "0.4.1"
5383
+ version = "0.4.2"
5384
5384
  dependencies = [
5385
5385
  "aegis",
5386
5386
  "aes",
@@ -5447,7 +5447,7 @@ dependencies = [
5447
5447
 
5448
5448
  [[package]]
5449
5449
  name = "turso_dart"
5450
- version = "0.4.1"
5450
+ version = "0.4.2"
5451
5451
  dependencies = [
5452
5452
  "flutter_rust_bridge",
5453
5453
  "turso_core",
@@ -5455,7 +5455,7 @@ dependencies = [
5455
5455
 
5456
5456
  [[package]]
5457
5457
  name = "turso_ext"
5458
- version = "0.4.1"
5458
+ version = "0.4.2"
5459
5459
  dependencies = [
5460
5460
  "chrono",
5461
5461
  "getrandom 0.3.2",
@@ -5464,7 +5464,7 @@ dependencies = [
5464
5464
 
5465
5465
  [[package]]
5466
5466
  name = "turso_ext_tests"
5467
- version = "0.4.1"
5467
+ version = "0.4.2"
5468
5468
  dependencies = [
5469
5469
  "env_logger 0.11.7",
5470
5470
  "lazy_static",
@@ -5475,7 +5475,7 @@ dependencies = [
5475
5475
 
5476
5476
  [[package]]
5477
5477
  name = "turso_macros"
5478
- version = "0.4.1"
5478
+ version = "0.4.2"
5479
5479
  dependencies = [
5480
5480
  "proc-macro2",
5481
5481
  "quote",
@@ -5484,7 +5484,7 @@ dependencies = [
5484
5484
 
5485
5485
  [[package]]
5486
5486
  name = "turso_node"
5487
- version = "0.4.1"
5487
+ version = "0.4.2"
5488
5488
  dependencies = [
5489
5489
  "chrono",
5490
5490
  "napi",
@@ -5497,7 +5497,7 @@ dependencies = [
5497
5497
 
5498
5498
  [[package]]
5499
5499
  name = "turso_parser"
5500
- version = "0.4.1"
5500
+ version = "0.4.2"
5501
5501
  dependencies = [
5502
5502
  "bitflags 2.9.4",
5503
5503
  "criterion",
@@ -5514,7 +5514,7 @@ dependencies = [
5514
5514
 
5515
5515
  [[package]]
5516
5516
  name = "turso_sdk_kit"
5517
- version = "0.4.1"
5517
+ version = "0.4.2"
5518
5518
  dependencies = [
5519
5519
  "bindgen",
5520
5520
  "env_logger 0.11.7",
@@ -5527,7 +5527,7 @@ dependencies = [
5527
5527
 
5528
5528
  [[package]]
5529
5529
  name = "turso_sdk_kit_macros"
5530
- version = "0.4.1"
5530
+ version = "0.4.2"
5531
5531
  dependencies = [
5532
5532
  "proc-macro2",
5533
5533
  "quote",
@@ -5536,7 +5536,7 @@ dependencies = [
5536
5536
 
5537
5537
  [[package]]
5538
5538
  name = "turso_sqlite3"
5539
- version = "0.4.1"
5539
+ version = "0.4.2"
5540
5540
  dependencies = [
5541
5541
  "env_logger 0.11.7",
5542
5542
  "libc",
@@ -5549,7 +5549,7 @@ dependencies = [
5549
5549
 
5550
5550
  [[package]]
5551
5551
  name = "turso_stress"
5552
- version = "0.4.1"
5552
+ version = "0.4.2"
5553
5553
  dependencies = [
5554
5554
  "antithesis_sdk",
5555
5555
  "clap",
@@ -5565,7 +5565,7 @@ dependencies = [
5565
5565
 
5566
5566
  [[package]]
5567
5567
  name = "turso_sync_engine"
5568
- version = "0.4.1"
5568
+ version = "0.4.2"
5569
5569
  dependencies = [
5570
5570
  "base64 0.22.1",
5571
5571
  "bytes",
@@ -5592,7 +5592,7 @@ dependencies = [
5592
5592
 
5593
5593
  [[package]]
5594
5594
  name = "turso_sync_js"
5595
- version = "0.4.1"
5595
+ version = "0.4.2"
5596
5596
  dependencies = [
5597
5597
  "genawaiter",
5598
5598
  "napi",
@@ -5607,7 +5607,7 @@ dependencies = [
5607
5607
 
5608
5608
  [[package]]
5609
5609
  name = "turso_sync_sdk_kit"
5610
- version = "0.4.1"
5610
+ version = "0.4.2"
5611
5611
  dependencies = [
5612
5612
  "bindgen",
5613
5613
  "env_logger 0.11.7",
@@ -5624,7 +5624,7 @@ dependencies = [
5624
5624
 
5625
5625
  [[package]]
5626
5626
  name = "turso_whopper"
5627
- version = "0.4.1"
5627
+ version = "0.4.2"
5628
5628
  dependencies = [
5629
5629
  "anyhow",
5630
5630
  "clap",
@@ -6,24 +6,24 @@ members = ["bindings/python"]
6
6
  exclude = ["perf/latency/limbo", "turso-test-runner"]
7
7
 
8
8
  [workspace.package]
9
- version = "0.4.1"
9
+ version = "0.4.2"
10
10
  authors = ["the Limbo authors"]
11
11
  edition = "2021"
12
12
  license = "MIT"
13
13
  repository = "https://github.com/tursodatabase/turso"
14
14
 
15
15
  [workspace.dependencies]
16
- turso = { path = "bindings/rust", version = "0.4.1" }
17
- turso_node = { path = "bindings/javascript", version = "0.4.1" }
18
- turso_sdk_kit = { path = "sdk-kit", version = "0.4.1" }
19
- turso_sdk_kit_macros = { path = "sdk-kit-macros", version = "0.4.1" }
20
- turso_sync_sdk_kit = { path = "sync/sdk-kit", version = "0.4.1" }
21
- limbo_completion = { path = "extensions/completion", version = "0.4.1" }
22
- turso_core = { path = "core", version = "0.4.1" }
23
- turso_sync_engine = { path = "sync/engine", version = "0.4.1" }
24
- turso_ext = { path = "extensions/core", version = "0.4.1" }
25
- turso_macros = { path = "macros", version = "0.4.1" }
26
- turso_parser = { path = "parser", version = "0.4.1" }
16
+ turso = { path = "bindings/rust", version = "0.4.2" }
17
+ turso_node = { path = "bindings/javascript", version = "0.4.2" }
18
+ turso_sdk_kit = { path = "sdk-kit", version = "0.4.2" }
19
+ turso_sdk_kit_macros = { path = "sdk-kit-macros", version = "0.4.2" }
20
+ turso_sync_sdk_kit = { path = "sync/sdk-kit", version = "0.4.2" }
21
+ limbo_completion = { path = "extensions/completion", version = "0.4.2" }
22
+ turso_core = { path = "core", version = "0.4.2" }
23
+ turso_sync_engine = { path = "sync/engine", version = "0.4.2" }
24
+ turso_ext = { path = "extensions/core", version = "0.4.2" }
25
+ turso_macros = { path = "macros", version = "0.4.2" }
26
+ turso_parser = { path = "parser", version = "0.4.2" }
27
27
  sql_generation = { path = "sql_generation" }
28
28
  strum = { version = "0.26", features = ["derive"] }
29
29
  strum_macros = "0.26"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyturso
3
- Version: 0.4.1
3
+ Version: 0.4.2
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Programming Language :: Python
6
6
  Classifier: Programming Language :: Python :: 3
@@ -437,8 +437,7 @@ impl<Clock: LogicalClock + 'static> MvccLazyCursor<Clock> {
437
437
  }
438
438
 
439
439
  fn is_btree_allocated(&self) -> bool {
440
- let maybe_root_page = self.db.table_id_to_rootpage.get(&self.table_id);
441
- maybe_root_page.is_some_and(|entry| entry.value().is_some())
440
+ self.db.is_btree_allocated(&self.table_id)
442
441
  }
443
442
 
444
443
  fn query_btree_version_is_valid(&self, key: &RowKey) -> bool {
@@ -2310,23 +2310,7 @@ impl<Clock: LogicalClock> MvStore<Clock> {
2310
2310
 
2311
2311
  for rowid in &tx.write_set {
2312
2312
  let rowid = rowid.value();
2313
- if let Some(row_versions) = self.rows.get(rowid) {
2314
- let mut row_versions = row_versions.value().write();
2315
- for rv in row_versions.iter_mut() {
2316
- if let Some(TxTimestampOrID::TxID(id)) = rv.begin {
2317
- assert_eq!(id, tx_id);
2318
- // If the transaction has aborted,
2319
- // it marks all its new versions as garbage and sets their Begin
2320
- // and End timestamps to infinity to make them invisible
2321
- // See section 2.4: https://www.cs.cmu.edu/~15721-f24/papers/Hekaton.pdf
2322
- rv.begin = None;
2323
- rv.end = None;
2324
- } else if rv.end == Some(TxTimestampOrID::TxID(tx_id)) {
2325
- // undo deletions by this transaction
2326
- rv.end = None;
2327
- }
2328
- }
2329
- }
2313
+ self.rollback_rowid(tx_id, rowid);
2330
2314
  }
2331
2315
 
2332
2316
  if connection.schema.read().schema_version > connection.db.schema.lock().schema_version {
@@ -2342,6 +2326,38 @@ impl<Clock: LogicalClock> MvStore<Clock> {
2342
2326
  self.remove_tx(tx_id);
2343
2327
  }
2344
2328
 
2329
+ fn rollback_rowid(&self, tx_id: u64, rowid: &RowID) {
2330
+ if rowid.row_id.is_int_key() {
2331
+ self.rollback_table_rowid(tx_id, rowid);
2332
+ } else {
2333
+ self.rollback_index_rowid(tx_id, rowid);
2334
+ }
2335
+ }
2336
+
2337
+ fn rollback_index_rowid(&self, tx_id: u64, rowid: &RowID) {
2338
+ if let Some(index) = self.index_rows.get(&rowid.table_id) {
2339
+ let index = index.value();
2340
+ let RowKey::Record(ref index_key) = rowid.row_id else {
2341
+ panic!("Index writes must have a record key");
2342
+ };
2343
+ if let Some(row_versions) = index.get(index_key) {
2344
+ let mut row_versions = row_versions.value().write();
2345
+ for rv in row_versions.iter_mut() {
2346
+ rollback_row_version(tx_id, rv);
2347
+ }
2348
+ }
2349
+ }
2350
+ }
2351
+
2352
+ fn rollback_table_rowid(&self, tx_id: u64, rowid: &RowID) {
2353
+ if let Some(row_versions) = self.rows.get(rowid) {
2354
+ let mut row_versions = row_versions.value().write();
2355
+ for rv in row_versions.iter_mut() {
2356
+ rollback_row_version(tx_id, rv);
2357
+ }
2358
+ }
2359
+ }
2360
+
2345
2361
  /// Returns true if the given transaction is the exclusive transaction.
2346
2362
  #[inline]
2347
2363
  pub fn is_exclusive_tx(&self, tx_id: &TxID) -> bool {
@@ -2808,6 +2824,25 @@ impl<Clock: LogicalClock> MvStore<Clock> {
2808
2824
  allocator
2809
2825
  }
2810
2826
  }
2827
+
2828
+ pub fn is_btree_allocated(&self, table_id: &MVTableId) -> bool {
2829
+ let maybe_root_page = self.table_id_to_rootpage.get(table_id);
2830
+ maybe_root_page.is_some_and(|entry| entry.value().is_some())
2831
+ }
2832
+ }
2833
+
2834
+ fn rollback_row_version(tx_id: u64, rv: &mut RowVersion) {
2835
+ if rv.begin == Some(TxTimestampOrID::TxID(tx_id)) {
2836
+ // If the transaction has aborted,
2837
+ // it marks all its new versions as garbage and sets their Begin
2838
+ // and End timestamps to infinity to make them invisible
2839
+ // See section 2.4: https://www.cs.cmu.edu/~15721-f24/papers/Hekaton.pdf
2840
+ rv.begin = None;
2841
+ rv.end = None;
2842
+ } else if rv.end == Some(TxTimestampOrID::TxID(tx_id)) {
2843
+ // undo deletions by this transaction
2844
+ rv.end = None;
2845
+ }
2811
2846
  }
2812
2847
 
2813
2848
  impl RowidAllocator {
@@ -2925,7 +2960,7 @@ fn is_begin_visible(txs: &SkipMap<TxID, Transaction>, tx: &Transaction, rv: &Row
2925
2960
  Some(TxTimestampOrID::TxID(rv_begin)) => {
2926
2961
  let tb = txs
2927
2962
  .get(&rv_begin)
2928
- .expect("transaction should exist in txs map");
2963
+ .unwrap_or_else(|| panic!("transaction {rv_begin:?} should exist in txs map"));
2929
2964
  let tb = tb.value();
2930
2965
  let visible = match tb.state.load() {
2931
2966
  TransactionState::Active => tx.tx_id == tb.tx_id && rv.end.is_none(),
@@ -1956,3 +1956,53 @@ fn test_skips_updated_rowid() {
1956
1956
  assert_eq!(rows.len(), 1);
1957
1957
  assert_eq!(rows[0][1].as_int().unwrap(), 3);
1958
1958
  }
1959
+
1960
+ #[test]
1961
+ fn test_mvcc_integrity_check() {
1962
+ tracing_subscriber::fmt()
1963
+ .with_ansi(false)
1964
+ .with_max_level(tracing_subscriber::filter::LevelFilter::TRACE)
1965
+ .init();
1966
+ let db = MvccTestDbNoConn::new_with_random_db();
1967
+ let conn = db.connect();
1968
+
1969
+ conn.execute("CREATE TABLE t(a INTEGER PRIMARY KEY)")
1970
+ .unwrap();
1971
+
1972
+ // we insert with default values
1973
+ conn.execute("INSERT INTO t values(1)").unwrap();
1974
+
1975
+ let ensure_integrity = || {
1976
+ let rows = get_rows(&conn, "PRAGMA integrity_check");
1977
+ assert_eq!(rows.len(), 1);
1978
+ assert_eq!(&rows[0][0].cast_text().unwrap(), "ok");
1979
+ };
1980
+
1981
+ ensure_integrity();
1982
+
1983
+ conn.execute("PRAGMA wal_checkpoint(TRUNCATE)").unwrap();
1984
+
1985
+ ensure_integrity();
1986
+ }
1987
+
1988
+ #[test]
1989
+ fn test_rollback_with_index() {
1990
+ let db = MvccTestDbNoConn::new_with_random_db();
1991
+ let conn = db.connect();
1992
+
1993
+ conn.execute("CREATE TABLE t(a INTEGER PRIMARY KEY, b INTEGER UNIQUE)")
1994
+ .unwrap();
1995
+
1996
+ // we insert with default values
1997
+ conn.execute("BEGIN CONCURRENT").unwrap();
1998
+ conn.execute("INSERT INTO t values (1, 1)").unwrap();
1999
+ conn.execute("ROLLBACK").unwrap();
2000
+
2001
+ // This query will try to use index to find the row, if we rollback correctly it shouldn't panic
2002
+ let rows = get_rows(&conn, "SELECT * FROM t where b = 1");
2003
+ assert_eq!(rows.len(), 0);
2004
+
2005
+ let rows = get_rows(&conn, "PRAGMA integrity_check");
2006
+ assert_eq!(rows.len(), 1);
2007
+ assert_eq!(&rows[0][0].to_string(), "ok");
2008
+ }
@@ -25,7 +25,7 @@ use crate::{
25
25
  SeekResult,
26
26
  },
27
27
  util::IOExt,
28
- Completion,
28
+ Completion, MvStore,
29
29
  };
30
30
 
31
31
  use crate::{
@@ -5800,8 +5800,28 @@ pub fn integrity_check(
5800
5800
  state: &mut IntegrityCheckState,
5801
5801
  errors: &mut Vec<IntegrityCheckError>,
5802
5802
  pager: &Arc<Pager>,
5803
+ mv_store: Option<&Arc<MvStore>>,
5803
5804
  ) -> Result<IOResult<()>> {
5805
+ if let Some(mv_store) = mv_store {
5806
+ let Some(IntegrityCheckPageEntry {
5807
+ page_idx: root_page,
5808
+ ..
5809
+ }) = state.page_stack.last().cloned()
5810
+ else {
5811
+ panic!("Page stack is empty on integrity_check start");
5812
+ };
5813
+ if root_page < 0 {
5814
+ let table_id = mv_store.get_table_id_from_root_page(root_page);
5815
+ turso_assert!(
5816
+ !mv_store.is_btree_allocated(&table_id),
5817
+ "we got a negative page index that is reported as allocated"
5818
+ );
5819
+ state.page_stack.pop();
5820
+ return Ok(IOResult::Done(()));
5821
+ }
5822
+ }
5804
5823
  if state.db_size == 0 {
5824
+ state.page_stack.pop();
5805
5825
  return Ok(IOResult::Done(()));
5806
5826
  }
5807
5827
  loop {
@@ -5814,6 +5834,10 @@ pub fn integrity_check(
5814
5834
  else {
5815
5835
  return Ok(IOResult::Done(()));
5816
5836
  };
5837
+ turso_assert!(
5838
+ page_idx >= 0,
5839
+ "pages should be positive during integrity check"
5840
+ );
5817
5841
  let page = match state.page.take() {
5818
5842
  Some(page) => page,
5819
5843
  None => {
@@ -959,6 +959,9 @@ enum CheckpointPhase {
959
959
  TruncateDbFile {
960
960
  sync_mode: crate::SyncMode,
961
961
  clear_page_cache: bool,
962
+ /// Whether we've invalidated page 1 from cache (needed because checkpoint may write
963
+ /// pages directly from WALto DB file, so cached page 1 of the checkpointer connection may have stale database_size)
964
+ page1_invalidated: bool,
962
965
  },
963
966
  /// Sync the database file after checkpoint (if sync_mode != Off and we backfilled any frames from the WAL).
964
967
  SyncDbFile { clear_page_cache: bool },
@@ -1092,15 +1095,27 @@ pub struct Savepoint {
1092
1095
  /// If the database grows during the savepoint and a rollback to the savepoint is performed,
1093
1096
  /// the pages exceeding the database size at the start of the savepoint will be ignored.
1094
1097
  db_size: AtomicU32,
1098
+ /// We might want to rollback.
1099
+ /// WAL max frame at the start of the savepoint.
1100
+ wal_max_frame: AtomicU64,
1101
+ /// WAL checksum at the start of the savepoint.
1102
+ wal_checksum: RwLock<(u32, u32)>,
1095
1103
  }
1096
1104
 
1097
1105
  impl Savepoint {
1098
- pub fn new(subjournal_offset: u64, db_size: u32) -> Self {
1106
+ pub fn new(
1107
+ subjournal_offset: u64,
1108
+ db_size: u32,
1109
+ wal_max_frame: u64,
1110
+ wal_checksum: (u32, u32),
1111
+ ) -> Self {
1099
1112
  Self {
1100
1113
  start_offset: AtomicU64::new(subjournal_offset),
1101
1114
  write_offset: AtomicU64::new(subjournal_offset),
1102
1115
  page_bitmap: RwLock::new(RoaringBitmap::new()),
1103
1116
  db_size: AtomicU32::new(db_size),
1117
+ wal_max_frame: AtomicU64::new(wal_max_frame),
1118
+ wal_checksum: RwLock::new(wal_checksum),
1104
1119
  }
1105
1120
  }
1106
1121
 
@@ -1486,7 +1501,12 @@ impl Pager {
1486
1501
  // the subjournal offset should always be 0 as we should only have max 1 savepoint
1487
1502
  // opened at any given time.
1488
1503
  turso_assert!(subjournal_offset == 0, "subjournal offset should be 0");
1489
- let savepoint = Savepoint::new(subjournal_offset, db_size);
1504
+ let (wal_max_frame, wal_checksum) = if let Some(wal) = &self.wal {
1505
+ (wal.get_max_frame(), wal.get_last_checksum())
1506
+ } else {
1507
+ (0, (0, 0))
1508
+ };
1509
+ let savepoint = Savepoint::new(subjournal_offset, db_size, wal_max_frame, wal_checksum);
1490
1510
  let mut savepoints = self.savepoints.write();
1491
1511
  turso_assert!(
1492
1512
  savepoints.is_empty(),
@@ -1613,6 +1633,12 @@ impl Pager {
1613
1633
 
1614
1634
  self.page_cache.write().truncate(db_size as usize)?;
1615
1635
 
1636
+ if let Some(wal) = &self.wal {
1637
+ let wal_max_frame = savepoint.wal_max_frame.load(Ordering::SeqCst);
1638
+ let wal_checksum = *savepoint.wal_checksum.read();
1639
+ wal.rollback(Some(wal_max_frame), Some(wal_checksum));
1640
+ }
1641
+
1616
1642
  Ok(true)
1617
1643
  }
1618
1644
 
@@ -3336,10 +3362,16 @@ impl Pager {
3336
3362
  }
3337
3363
 
3338
3364
  fn reset_checkpoint_state(&self) {
3365
+ self.clear_checkpoint_state();
3366
+ self.commit_info.write().state = CommitState::PrepareWal;
3367
+ }
3368
+
3369
+ /// Reset checkpoint state machine to initial state.
3370
+ /// Use this to clean up after a failed explicit checkpoint (PRAGMA wal_checkpoint).
3371
+ pub fn clear_checkpoint_state(&self) {
3339
3372
  let mut state = self.checkpoint_state.write();
3340
3373
  state.phase = CheckpointPhase::NotCheckpointing;
3341
3374
  state.result = None;
3342
- self.commit_info.write().state = CommitState::PrepareWal;
3343
3375
  }
3344
3376
 
3345
3377
  /// Clean up after a checkpoint failure. The WAL commit succeeded but checkpoint failed.
@@ -3398,6 +3430,7 @@ impl Pager {
3398
3430
  state.phase = CheckpointPhase::TruncateDbFile {
3399
3431
  sync_mode,
3400
3432
  clear_page_cache,
3433
+ page1_invalidated: false,
3401
3434
  };
3402
3435
  } else if res.num_backfilled == 0 || sync_mode == crate::SyncMode::Off {
3403
3436
  state.phase = CheckpointPhase::Finalize { clear_page_cache };
@@ -3409,6 +3442,7 @@ impl Pager {
3409
3442
  CheckpointPhase::TruncateDbFile {
3410
3443
  sync_mode,
3411
3444
  clear_page_cache,
3445
+ page1_invalidated,
3412
3446
  } => {
3413
3447
  let should_skip_truncate = {
3414
3448
  let state = self.checkpoint_state.read();
@@ -3426,6 +3460,18 @@ impl Pager {
3426
3460
  }
3427
3461
  continue;
3428
3462
  }
3463
+ // Invalidate page 1 (header) in cache before reading - checkpoint potentially wrote pages
3464
+ // directly to DB file from the WAL, so the checkpointer connections' page 1 may have stale database_size.
3465
+ if !page1_invalidated {
3466
+ let page1_key = PageCacheKey::new(DatabaseHeader::PAGE_ID);
3467
+ self.page_cache.write().delete(page1_key)?;
3468
+ let mut state = self.checkpoint_state.write();
3469
+ state.phase = CheckpointPhase::TruncateDbFile {
3470
+ sync_mode,
3471
+ clear_page_cache,
3472
+ page1_invalidated: true,
3473
+ };
3474
+ }
3429
3475
 
3430
3476
  // Truncate the database file unless already at correct size
3431
3477
  let db_size =
@@ -3489,18 +3535,19 @@ impl Pager {
3489
3535
  CheckpointPhase::Finalize { clear_page_cache } => {
3490
3536
  let mut state = self.checkpoint_state.write();
3491
3537
  let mut res = state.result.take().expect("result should be set");
3492
-
3493
- // Release checkpoint guard
3494
- res.release_guard();
3538
+ state.phase = CheckpointPhase::NotCheckpointing;
3495
3539
 
3496
3540
  // Clear page cache only if requested (explicit checkpoints do this, auto-checkpoint does not)
3497
3541
  if clear_page_cache {
3498
3542
  self.page_cache.write().clear(false).map_err(|e| {
3543
+ res.release_guard();
3499
3544
  LimboError::InternalError(format!("Failed to clear page cache: {e:?}"))
3500
3545
  })?;
3501
3546
  }
3502
3547
 
3503
- state.phase = CheckpointPhase::NotCheckpointing;
3548
+ // Release checkpoint guard
3549
+ res.release_guard();
3550
+
3504
3551
  return Ok(IOResult::Done(res));
3505
3552
  }
3506
3553
  }
@@ -4109,7 +4156,7 @@ impl Pager {
4109
4156
  }
4110
4157
  if is_write {
4111
4158
  if let Some(wal) = self.wal.as_ref() {
4112
- wal.rollback();
4159
+ wal.rollback(None, None);
4113
4160
  }
4114
4161
  }
4115
4162
  }