@quereus/quereus 4.3.1 → 4.4.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 (788) hide show
  1. package/README.md +25 -7
  2. package/dist/src/common/types.d.ts +9 -59
  3. package/dist/src/common/types.d.ts.map +1 -1
  4. package/dist/src/common/types.js.map +1 -1
  5. package/dist/src/core/database-assertions.d.ts +2 -2
  6. package/dist/src/core/database-assertions.d.ts.map +1 -1
  7. package/dist/src/core/database-assertions.js +4 -3
  8. package/dist/src/core/database-assertions.js.map +1 -1
  9. package/dist/src/core/database-external-changes.d.ts +3 -3
  10. package/dist/src/core/database-external-changes.d.ts.map +1 -1
  11. package/dist/src/core/database-external-changes.js +13 -10
  12. package/dist/src/core/database-external-changes.js.map +1 -1
  13. package/dist/src/core/database-internal.d.ts.map +1 -1
  14. package/dist/src/core/database-materialized-views-analysis.d.ts +199 -0
  15. package/dist/src/core/database-materialized-views-analysis.d.ts.map +1 -0
  16. package/dist/src/core/database-materialized-views-analysis.js +502 -0
  17. package/dist/src/core/database-materialized-views-analysis.js.map +1 -0
  18. package/dist/src/core/database-materialized-views-apply.d.ts +422 -0
  19. package/dist/src/core/database-materialized-views-apply.d.ts.map +1 -0
  20. package/dist/src/core/database-materialized-views-apply.js +929 -0
  21. package/dist/src/core/database-materialized-views-apply.js.map +1 -0
  22. package/dist/src/core/database-materialized-views-plan-builders.d.ts +267 -0
  23. package/dist/src/core/database-materialized-views-plan-builders.d.ts.map +1 -0
  24. package/dist/src/core/database-materialized-views-plan-builders.js +1423 -0
  25. package/dist/src/core/database-materialized-views-plan-builders.js.map +1 -0
  26. package/dist/src/core/database-materialized-views-plans.d.ts +641 -0
  27. package/dist/src/core/database-materialized-views-plans.d.ts.map +1 -0
  28. package/dist/src/core/database-materialized-views-plans.js +13 -0
  29. package/dist/src/core/database-materialized-views-plans.js.map +1 -0
  30. package/dist/src/core/database-materialized-views.d.ts +108 -860
  31. package/dist/src/core/database-materialized-views.d.ts.map +1 -1
  32. package/dist/src/core/database-materialized-views.js +212 -2165
  33. package/dist/src/core/database-materialized-views.js.map +1 -1
  34. package/dist/src/core/database-transaction.d.ts +10 -1
  35. package/dist/src/core/database-transaction.d.ts.map +1 -1
  36. package/dist/src/core/database-transaction.js +16 -4
  37. package/dist/src/core/database-transaction.js.map +1 -1
  38. package/dist/src/core/database-watchers.d.ts.map +1 -1
  39. package/dist/src/core/database-watchers.js +2 -1
  40. package/dist/src/core/database-watchers.js.map +1 -1
  41. package/dist/src/core/database.d.ts +99 -13
  42. package/dist/src/core/database.d.ts.map +1 -1
  43. package/dist/src/core/database.js +270 -50
  44. package/dist/src/core/database.js.map +1 -1
  45. package/dist/src/core/derived-row-validator.d.ts +1 -1
  46. package/dist/src/core/derived-row-validator.d.ts.map +1 -1
  47. package/dist/src/core/derived-row-validator.js +5 -3
  48. package/dist/src/core/derived-row-validator.js.map +1 -1
  49. package/dist/src/core/statement.d.ts +8 -0
  50. package/dist/src/core/statement.d.ts.map +1 -1
  51. package/dist/src/core/statement.js +98 -18
  52. package/dist/src/core/statement.js.map +1 -1
  53. package/dist/src/emit/ast-stringify.d.ts.map +1 -1
  54. package/dist/src/emit/ast-stringify.js +24 -13
  55. package/dist/src/emit/ast-stringify.js.map +1 -1
  56. package/dist/src/func/builtins/aggregate.d.ts.map +1 -1
  57. package/dist/src/func/builtins/aggregate.js +127 -21
  58. package/dist/src/func/builtins/aggregate.js.map +1 -1
  59. package/dist/src/func/builtins/explain.d.ts.map +1 -1
  60. package/dist/src/func/builtins/explain.js +2 -1
  61. package/dist/src/func/builtins/explain.js.map +1 -1
  62. package/dist/src/func/builtins/json.d.ts.map +1 -1
  63. package/dist/src/func/builtins/json.js +2 -1
  64. package/dist/src/func/builtins/json.js.map +1 -1
  65. package/dist/src/func/builtins/mutation.d.ts.map +1 -1
  66. package/dist/src/func/builtins/mutation.js +3 -2
  67. package/dist/src/func/builtins/mutation.js.map +1 -1
  68. package/dist/src/func/registration.d.ts +6 -1
  69. package/dist/src/func/registration.d.ts.map +1 -1
  70. package/dist/src/func/registration.js +16 -0
  71. package/dist/src/func/registration.js.map +1 -1
  72. package/dist/src/index.d.ts +16 -6
  73. package/dist/src/index.d.ts.map +1 -1
  74. package/dist/src/index.js +33 -7
  75. package/dist/src/index.js.map +1 -1
  76. package/dist/src/parser/ast.d.ts +2 -2
  77. package/dist/src/parser/lexer.d.ts +11 -1
  78. package/dist/src/parser/lexer.d.ts.map +1 -1
  79. package/dist/src/parser/lexer.js +40 -34
  80. package/dist/src/parser/lexer.js.map +1 -1
  81. package/dist/src/parser/parser.d.ts.map +1 -1
  82. package/dist/src/parser/parser.js +16 -9
  83. package/dist/src/parser/parser.js.map +1 -1
  84. package/dist/src/planner/analysis/authored-inverse.js +1 -1
  85. package/dist/src/planner/analysis/comparison-collation.d.ts +52 -0
  86. package/dist/src/planner/analysis/comparison-collation.d.ts.map +1 -1
  87. package/dist/src/planner/analysis/comparison-collation.js +84 -7
  88. package/dist/src/planner/analysis/comparison-collation.js.map +1 -1
  89. package/dist/src/planner/analysis/constraint-extractor.d.ts.map +1 -1
  90. package/dist/src/planner/analysis/constraint-extractor.js +64 -17
  91. package/dist/src/planner/analysis/constraint-extractor.js.map +1 -1
  92. package/dist/src/planner/analysis/coverage-prover.d.ts +1 -1
  93. package/dist/src/planner/analysis/coverage-prover.js +1 -1
  94. package/dist/src/planner/analysis/equi-correlation.d.ts +26 -0
  95. package/dist/src/planner/analysis/equi-correlation.d.ts.map +1 -0
  96. package/dist/src/planner/analysis/equi-correlation.js +62 -0
  97. package/dist/src/planner/analysis/equi-correlation.js.map +1 -0
  98. package/dist/src/planner/analysis/query-rewrite-matcher.d.ts +54 -18
  99. package/dist/src/planner/analysis/query-rewrite-matcher.d.ts.map +1 -1
  100. package/dist/src/planner/analysis/query-rewrite-matcher.js +86 -42
  101. package/dist/src/planner/analysis/query-rewrite-matcher.js.map +1 -1
  102. package/dist/src/planner/analysis/sat-checker.d.ts +8 -1
  103. package/dist/src/planner/analysis/sat-checker.d.ts.map +1 -1
  104. package/dist/src/planner/analysis/sat-checker.js +117 -22
  105. package/dist/src/planner/analysis/sat-checker.js.map +1 -1
  106. package/dist/src/planner/analysis/scalar-invertibility.d.ts +13 -4
  107. package/dist/src/planner/analysis/scalar-invertibility.d.ts.map +1 -1
  108. package/dist/src/planner/analysis/scalar-invertibility.js +12 -3
  109. package/dist/src/planner/analysis/scalar-invertibility.js.map +1 -1
  110. package/dist/src/planner/analysis/scalar-subqueries.d.ts +28 -0
  111. package/dist/src/planner/analysis/scalar-subqueries.d.ts.map +1 -0
  112. package/dist/src/planner/analysis/scalar-subqueries.js +60 -0
  113. package/dist/src/planner/analysis/scalar-subqueries.js.map +1 -0
  114. package/dist/src/planner/analysis/update-lineage.d.ts +1 -1
  115. package/dist/src/planner/analysis/update-lineage.js +1 -1
  116. package/dist/src/planner/analysis/update-lineage.js.map +1 -1
  117. package/dist/src/planner/analysis/view-complement.d.ts +2 -2
  118. package/dist/src/planner/building/delete.js +2 -2
  119. package/dist/src/planner/building/delete.js.map +1 -1
  120. package/dist/src/planner/building/dml-target.d.ts +2 -2
  121. package/dist/src/planner/building/dml-target.js +2 -2
  122. package/dist/src/planner/building/insert.d.ts.map +1 -1
  123. package/dist/src/planner/building/insert.js +53 -2
  124. package/dist/src/planner/building/insert.js.map +1 -1
  125. package/dist/src/planner/building/schema-resolution.d.ts +3 -0
  126. package/dist/src/planner/building/schema-resolution.d.ts.map +1 -1
  127. package/dist/src/planner/building/schema-resolution.js +4 -5
  128. package/dist/src/planner/building/schema-resolution.js.map +1 -1
  129. package/dist/src/planner/building/select.d.ts.map +1 -1
  130. package/dist/src/planner/building/select.js +18 -4
  131. package/dist/src/planner/building/select.js.map +1 -1
  132. package/dist/src/planner/building/update.js +2 -2
  133. package/dist/src/planner/building/update.js.map +1 -1
  134. package/dist/src/planner/building/view-mutation-builder.js +7 -7
  135. package/dist/src/planner/building/view-mutation-builder.js.map +1 -1
  136. package/dist/src/planner/building/with.d.ts.map +1 -1
  137. package/dist/src/planner/building/with.js +5 -8
  138. package/dist/src/planner/building/with.js.map +1 -1
  139. package/dist/src/planner/cache/materialization-advisory.d.ts +34 -2
  140. package/dist/src/planner/cache/materialization-advisory.d.ts.map +1 -1
  141. package/dist/src/planner/cache/materialization-advisory.js +185 -42
  142. package/dist/src/planner/cache/materialization-advisory.js.map +1 -1
  143. package/dist/src/planner/cache/reference-graph.d.ts +14 -5
  144. package/dist/src/planner/cache/reference-graph.d.ts.map +1 -1
  145. package/dist/src/planner/cache/reference-graph.js +31 -39
  146. package/dist/src/planner/cache/reference-graph.js.map +1 -1
  147. package/dist/src/planner/cost/index.d.ts +30 -5
  148. package/dist/src/planner/cost/index.d.ts.map +1 -1
  149. package/dist/src/planner/cost/index.js +26 -0
  150. package/dist/src/planner/cost/index.js.map +1 -1
  151. package/dist/src/planner/debug.d.ts +3 -2
  152. package/dist/src/planner/debug.d.ts.map +1 -1
  153. package/dist/src/planner/debug.js +9 -3
  154. package/dist/src/planner/debug.js.map +1 -1
  155. package/dist/src/planner/framework/characteristics.d.ts +46 -19
  156. package/dist/src/planner/framework/characteristics.d.ts.map +1 -1
  157. package/dist/src/planner/framework/characteristics.js +50 -134
  158. package/dist/src/planner/framework/characteristics.js.map +1 -1
  159. package/dist/src/planner/framework/context.d.ts +8 -44
  160. package/dist/src/planner/framework/context.d.ts.map +1 -1
  161. package/dist/src/planner/framework/context.js +0 -91
  162. package/dist/src/planner/framework/context.js.map +1 -1
  163. package/dist/src/planner/framework/pass.d.ts +7 -0
  164. package/dist/src/planner/framework/pass.d.ts.map +1 -1
  165. package/dist/src/planner/framework/pass.js +84 -0
  166. package/dist/src/planner/framework/pass.js.map +1 -1
  167. package/dist/src/planner/framework/registry.d.ts +13 -42
  168. package/dist/src/planner/framework/registry.d.ts.map +1 -1
  169. package/dist/src/planner/framework/registry.js +14 -182
  170. package/dist/src/planner/framework/registry.js.map +1 -1
  171. package/dist/src/planner/mutation/backward-body.d.ts +2 -2
  172. package/dist/src/planner/mutation/cte-flatten.js +1 -1
  173. package/dist/src/planner/mutation/decomposition.d.ts +2 -2
  174. package/dist/src/planner/mutation/decomposition.js +1 -1
  175. package/dist/src/planner/mutation/lens-enforcement.d.ts.map +1 -1
  176. package/dist/src/planner/mutation/lens-enforcement.js +2 -1
  177. package/dist/src/planner/mutation/lens-enforcement.js.map +1 -1
  178. package/dist/src/planner/mutation/multi-source.d.ts +8 -8
  179. package/dist/src/planner/mutation/multi-source.js +11 -11
  180. package/dist/src/planner/mutation/multi-source.js.map +1 -1
  181. package/dist/src/planner/mutation/propagate.d.ts +1 -1
  182. package/dist/src/planner/mutation/propagate.js +1 -1
  183. package/dist/src/planner/mutation/scope-transform.d.ts +2 -2
  184. package/dist/src/planner/mutation/scope-transform.js +3 -3
  185. package/dist/src/planner/mutation/scope-transform.js.map +1 -1
  186. package/dist/src/planner/mutation/set-op.d.ts +1 -1
  187. package/dist/src/planner/mutation/set-op.d.ts.map +1 -1
  188. package/dist/src/planner/mutation/set-op.js +3 -2
  189. package/dist/src/planner/mutation/set-op.js.map +1 -1
  190. package/dist/src/planner/mutation/single-source.d.ts +3 -3
  191. package/dist/src/planner/mutation/single-source.js +9 -9
  192. package/dist/src/planner/mutation/single-source.js.map +1 -1
  193. package/dist/src/planner/nodes/aggregate-function.d.ts +3 -1
  194. package/dist/src/planner/nodes/aggregate-function.d.ts.map +1 -1
  195. package/dist/src/planner/nodes/aggregate-function.js +1 -0
  196. package/dist/src/planner/nodes/aggregate-function.js.map +1 -1
  197. package/dist/src/planner/nodes/aggregate-node.d.ts +1 -0
  198. package/dist/src/planner/nodes/aggregate-node.d.ts.map +1 -1
  199. package/dist/src/planner/nodes/aggregate-node.js +8 -1
  200. package/dist/src/planner/nodes/aggregate-node.js.map +1 -1
  201. package/dist/src/planner/nodes/alias-node.d.ts.map +1 -1
  202. package/dist/src/planner/nodes/alias-node.js +3 -1
  203. package/dist/src/planner/nodes/alias-node.js.map +1 -1
  204. package/dist/src/planner/nodes/asof-scan-node.d.ts.map +1 -1
  205. package/dist/src/planner/nodes/asof-scan-node.js +3 -2
  206. package/dist/src/planner/nodes/asof-scan-node.js.map +1 -1
  207. package/dist/src/planner/nodes/asserted-keys-node.d.ts +1 -1
  208. package/dist/src/planner/nodes/asserted-keys-node.d.ts.map +1 -1
  209. package/dist/src/planner/nodes/asserted-keys-node.js +5 -2
  210. package/dist/src/planner/nodes/asserted-keys-node.js.map +1 -1
  211. package/dist/src/planner/nodes/async-gather-node.d.ts.map +1 -1
  212. package/dist/src/planner/nodes/async-gather-node.js +3 -1
  213. package/dist/src/planner/nodes/async-gather-node.js.map +1 -1
  214. package/dist/src/planner/nodes/block.js +3 -3
  215. package/dist/src/planner/nodes/block.js.map +1 -1
  216. package/dist/src/planner/nodes/bloom-join-node.d.ts +2 -0
  217. package/dist/src/planner/nodes/bloom-join-node.d.ts.map +1 -1
  218. package/dist/src/planner/nodes/bloom-join-node.js +5 -1
  219. package/dist/src/planner/nodes/bloom-join-node.js.map +1 -1
  220. package/dist/src/planner/nodes/cache-node.d.ts +19 -2
  221. package/dist/src/planner/nodes/cache-node.d.ts.map +1 -1
  222. package/dist/src/planner/nodes/cache-node.js +43 -3
  223. package/dist/src/planner/nodes/cache-node.js.map +1 -1
  224. package/dist/src/planner/nodes/cte-node.d.ts +16 -1
  225. package/dist/src/planner/nodes/cte-node.d.ts.map +1 -1
  226. package/dist/src/planner/nodes/cte-node.js +16 -3
  227. package/dist/src/planner/nodes/cte-node.js.map +1 -1
  228. package/dist/src/planner/nodes/distinct-node.js +3 -3
  229. package/dist/src/planner/nodes/distinct-node.js.map +1 -1
  230. package/dist/src/planner/nodes/dml-executor-node.d.ts +21 -0
  231. package/dist/src/planner/nodes/dml-executor-node.d.ts.map +1 -1
  232. package/dist/src/planner/nodes/dml-executor-node.js.map +1 -1
  233. package/dist/src/planner/nodes/envelope-scan-node.d.ts +1 -1
  234. package/dist/src/planner/nodes/envelope-scan-node.js +1 -1
  235. package/dist/src/planner/nodes/fanout-lookup-join-node.d.ts.map +1 -1
  236. package/dist/src/planner/nodes/fanout-lookup-join-node.js +4 -2
  237. package/dist/src/planner/nodes/fanout-lookup-join-node.js.map +1 -1
  238. package/dist/src/planner/nodes/filter.d.ts +10 -2
  239. package/dist/src/planner/nodes/filter.d.ts.map +1 -1
  240. package/dist/src/planner/nodes/filter.js +81 -14
  241. package/dist/src/planner/nodes/filter.js.map +1 -1
  242. package/dist/src/planner/nodes/hash-aggregate.d.ts +12 -1
  243. package/dist/src/planner/nodes/hash-aggregate.d.ts.map +1 -1
  244. package/dist/src/planner/nodes/hash-aggregate.js +28 -1
  245. package/dist/src/planner/nodes/hash-aggregate.js.map +1 -1
  246. package/dist/src/planner/nodes/internal-recursive-cte-ref-node.d.ts +3 -1
  247. package/dist/src/planner/nodes/internal-recursive-cte-ref-node.d.ts.map +1 -1
  248. package/dist/src/planner/nodes/internal-recursive-cte-ref-node.js +1 -0
  249. package/dist/src/planner/nodes/internal-recursive-cte-ref-node.js.map +1 -1
  250. package/dist/src/planner/nodes/join-node.d.ts +3 -1
  251. package/dist/src/planner/nodes/join-node.d.ts.map +1 -1
  252. package/dist/src/planner/nodes/join-node.js +5 -5
  253. package/dist/src/planner/nodes/join-node.js.map +1 -1
  254. package/dist/src/planner/nodes/lens-auxiliary-access-node.d.ts.map +1 -1
  255. package/dist/src/planner/nodes/lens-auxiliary-access-node.js +4 -1
  256. package/dist/src/planner/nodes/lens-auxiliary-access-node.js.map +1 -1
  257. package/dist/src/planner/nodes/limit-offset.d.ts +1 -0
  258. package/dist/src/planner/nodes/limit-offset.d.ts.map +1 -1
  259. package/dist/src/planner/nodes/limit-offset.js +4 -3
  260. package/dist/src/planner/nodes/limit-offset.js.map +1 -1
  261. package/dist/src/planner/nodes/merge-join-node.d.ts +2 -0
  262. package/dist/src/planner/nodes/merge-join-node.d.ts.map +1 -1
  263. package/dist/src/planner/nodes/merge-join-node.js +6 -1
  264. package/dist/src/planner/nodes/merge-join-node.js.map +1 -1
  265. package/dist/src/planner/nodes/ordinal-slice-node.d.ts.map +1 -1
  266. package/dist/src/planner/nodes/ordinal-slice-node.js +3 -1
  267. package/dist/src/planner/nodes/ordinal-slice-node.js.map +1 -1
  268. package/dist/src/planner/nodes/plan-node.d.ts +68 -5
  269. package/dist/src/planner/nodes/plan-node.d.ts.map +1 -1
  270. package/dist/src/planner/nodes/plan-node.js +137 -24
  271. package/dist/src/planner/nodes/plan-node.js.map +1 -1
  272. package/dist/src/planner/nodes/project-node.d.ts +3 -2
  273. package/dist/src/planner/nodes/project-node.d.ts.map +1 -1
  274. package/dist/src/planner/nodes/project-node.js +1 -0
  275. package/dist/src/planner/nodes/project-node.js.map +1 -1
  276. package/dist/src/planner/nodes/recursive-cte-node.d.ts +30 -1
  277. package/dist/src/planner/nodes/recursive-cte-node.d.ts.map +1 -1
  278. package/dist/src/planner/nodes/recursive-cte-node.js +38 -5
  279. package/dist/src/planner/nodes/recursive-cte-node.js.map +1 -1
  280. package/dist/src/planner/nodes/reference.d.ts +5 -1
  281. package/dist/src/planner/nodes/reference.d.ts.map +1 -1
  282. package/dist/src/planner/nodes/reference.js +3 -0
  283. package/dist/src/planner/nodes/reference.js.map +1 -1
  284. package/dist/src/planner/nodes/remote-query-node.d.ts.map +1 -1
  285. package/dist/src/planner/nodes/remote-query-node.js +3 -1
  286. package/dist/src/planner/nodes/remote-query-node.js.map +1 -1
  287. package/dist/src/planner/nodes/retrieve-node.d.ts.map +1 -1
  288. package/dist/src/planner/nodes/retrieve-node.js +3 -1
  289. package/dist/src/planner/nodes/retrieve-node.js.map +1 -1
  290. package/dist/src/planner/nodes/set-operation-node.d.ts.map +1 -1
  291. package/dist/src/planner/nodes/set-operation-node.js +3 -1
  292. package/dist/src/planner/nodes/set-operation-node.js.map +1 -1
  293. package/dist/src/planner/nodes/sink-node.d.ts.map +1 -1
  294. package/dist/src/planner/nodes/sink-node.js +3 -1
  295. package/dist/src/planner/nodes/sink-node.js.map +1 -1
  296. package/dist/src/planner/nodes/sort.d.ts +2 -1
  297. package/dist/src/planner/nodes/sort.d.ts.map +1 -1
  298. package/dist/src/planner/nodes/sort.js +9 -5
  299. package/dist/src/planner/nodes/sort.js.map +1 -1
  300. package/dist/src/planner/nodes/stream-aggregate.d.ts +12 -1
  301. package/dist/src/planner/nodes/stream-aggregate.d.ts.map +1 -1
  302. package/dist/src/planner/nodes/stream-aggregate.js +32 -3
  303. package/dist/src/planner/nodes/stream-aggregate.js.map +1 -1
  304. package/dist/src/planner/nodes/table-access-nodes.d.ts +2 -1
  305. package/dist/src/planner/nodes/table-access-nodes.d.ts.map +1 -1
  306. package/dist/src/planner/nodes/table-access-nodes.js +2 -0
  307. package/dist/src/planner/nodes/table-access-nodes.js.map +1 -1
  308. package/dist/src/planner/nodes/view-mutation-node.d.ts +2 -2
  309. package/dist/src/planner/nodes/view-mutation-node.d.ts.map +1 -1
  310. package/dist/src/planner/nodes/view-mutation-node.js +5 -1
  311. package/dist/src/planner/nodes/view-mutation-node.js.map +1 -1
  312. package/dist/src/planner/nodes/window-function.d.ts +3 -1
  313. package/dist/src/planner/nodes/window-function.d.ts.map +1 -1
  314. package/dist/src/planner/nodes/window-function.js +1 -0
  315. package/dist/src/planner/nodes/window-function.js.map +1 -1
  316. package/dist/src/planner/optimizer.d.ts +52 -8
  317. package/dist/src/planner/optimizer.d.ts.map +1 -1
  318. package/dist/src/planner/optimizer.js +1014 -895
  319. package/dist/src/planner/optimizer.js.map +1 -1
  320. package/dist/src/planner/rules/access/rule-select-access-path.d.ts.map +1 -1
  321. package/dist/src/planner/rules/access/rule-select-access-path.js +235 -202
  322. package/dist/src/planner/rules/access/rule-select-access-path.js.map +1 -1
  323. package/dist/src/planner/rules/cache/rule-cte-optimization.d.ts.map +1 -1
  324. package/dist/src/planner/rules/cache/rule-cte-optimization.js +8 -1
  325. package/dist/src/planner/rules/cache/rule-cte-optimization.js.map +1 -1
  326. package/dist/src/planner/rules/cache/rule-in-subquery-cache.d.ts +7 -0
  327. package/dist/src/planner/rules/cache/rule-in-subquery-cache.d.ts.map +1 -1
  328. package/dist/src/planner/rules/cache/rule-in-subquery-cache.js +14 -1
  329. package/dist/src/planner/rules/cache/rule-in-subquery-cache.js.map +1 -1
  330. package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.d.ts +2 -2
  331. package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.d.ts.map +1 -1
  332. package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.js +55 -56
  333. package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.js.map +1 -1
  334. package/dist/src/planner/rules/cache/rule-mutating-subquery-cache.d.ts.map +1 -1
  335. package/dist/src/planner/rules/cache/rule-mutating-subquery-cache.js +6 -0
  336. package/dist/src/planner/rules/cache/rule-mutating-subquery-cache.js.map +1 -1
  337. package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.d.ts +25 -0
  338. package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.d.ts.map +1 -0
  339. package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.js +176 -0
  340. package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.js.map +1 -0
  341. package/dist/src/planner/rules/cache/rule-scalar-cse.d.ts +1 -1
  342. package/dist/src/planner/rules/cache/rule-scalar-cse.js +1 -1
  343. package/dist/src/planner/rules/cache/rule-scalar-subquery-cache.d.ts +29 -0
  344. package/dist/src/planner/rules/cache/rule-scalar-subquery-cache.d.ts.map +1 -0
  345. package/dist/src/planner/rules/cache/rule-scalar-subquery-cache.js +66 -0
  346. package/dist/src/planner/rules/cache/rule-scalar-subquery-cache.js.map +1 -0
  347. package/dist/src/planner/rules/join/rule-fanout-batched-outer.d.ts +1 -1
  348. package/dist/src/planner/rules/join/rule-fanout-batched-outer.js +1 -1
  349. package/dist/src/planner/rules/join/rule-fanout-lookup-join.d.ts.map +1 -1
  350. package/dist/src/planner/rules/join/rule-fanout-lookup-join.js +1 -54
  351. package/dist/src/planner/rules/join/rule-fanout-lookup-join.js.map +1 -1
  352. package/dist/src/planner/rules/join/rule-inner-join-existence-recovery.d.ts +1 -1
  353. package/dist/src/planner/rules/join/rule-inner-join-existence-recovery.js +1 -1
  354. package/dist/src/planner/rules/join/rule-join-elimination.d.ts +1 -1
  355. package/dist/src/planner/rules/join/rule-join-elimination.js +1 -1
  356. package/dist/src/planner/rules/parallel/rule-async-gather-zip-by-key.js +5 -6
  357. package/dist/src/planner/rules/parallel/rule-async-gather-zip-by-key.js.map +1 -1
  358. package/dist/src/planner/rules/predicate/rule-empty-relation-folding.d.ts +1 -1
  359. package/dist/src/planner/rules/predicate/rule-empty-relation-folding.js +1 -1
  360. package/dist/src/planner/rules/predicate/rule-filter-contradiction.d.ts +2 -2
  361. package/dist/src/planner/rules/predicate/rule-filter-contradiction.d.ts.map +1 -1
  362. package/dist/src/planner/rules/predicate/rule-filter-contradiction.js +4 -3
  363. package/dist/src/planner/rules/predicate/rule-filter-contradiction.js.map +1 -1
  364. package/dist/src/planner/rules/predicate/rule-filter-selectivity.d.ts +19 -0
  365. package/dist/src/planner/rules/predicate/rule-filter-selectivity.d.ts.map +1 -0
  366. package/dist/src/planner/rules/predicate/rule-filter-selectivity.js +48 -0
  367. package/dist/src/planner/rules/predicate/rule-filter-selectivity.js.map +1 -0
  368. package/dist/src/planner/rules/predicate/rule-sargable-range-rewrite.js +12 -1
  369. package/dist/src/planner/rules/predicate/rule-sargable-range-rewrite.js.map +1 -1
  370. package/dist/src/planner/rules/retrieve/rule-grow-retrieve.d.ts.map +1 -1
  371. package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js +22 -20
  372. package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js.map +1 -1
  373. package/dist/src/planner/rules/shared/index-style-context.d.ts +39 -0
  374. package/dist/src/planner/rules/shared/index-style-context.d.ts.map +1 -0
  375. package/dist/src/planner/rules/shared/index-style-context.js +26 -0
  376. package/dist/src/planner/rules/shared/index-style-context.js.map +1 -0
  377. package/dist/src/planner/rules/sort/rule-orderby-fd-pruning.d.ts +1 -1
  378. package/dist/src/planner/rules/sort/rule-orderby-fd-pruning.js +1 -1
  379. package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.d.ts +1 -1
  380. package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.js +1 -1
  381. package/dist/src/planner/rules/subquery/rule-scalar-agg-decorrelation.d.ts +191 -0
  382. package/dist/src/planner/rules/subquery/rule-scalar-agg-decorrelation.d.ts.map +1 -0
  383. package/dist/src/planner/rules/subquery/rule-scalar-agg-decorrelation.js +623 -0
  384. package/dist/src/planner/rules/subquery/rule-scalar-agg-decorrelation.js.map +1 -0
  385. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.d.ts +10 -1
  386. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.d.ts.map +1 -1
  387. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js +242 -51
  388. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js.map +1 -1
  389. package/dist/src/planner/stats/analyze.d.ts.map +1 -1
  390. package/dist/src/planner/stats/analyze.js +2 -20
  391. package/dist/src/planner/stats/analyze.js.map +1 -1
  392. package/dist/src/planner/stats/histogram.d.ts.map +1 -1
  393. package/dist/src/planner/stats/histogram.js +4 -0
  394. package/dist/src/planner/stats/histogram.js.map +1 -1
  395. package/dist/src/planner/util/fd-utils.d.ts +2 -3
  396. package/dist/src/planner/util/fd-utils.d.ts.map +1 -1
  397. package/dist/src/planner/util/fd-utils.js +2 -3
  398. package/dist/src/planner/util/fd-utils.js.map +1 -1
  399. package/dist/src/planner/validation/plan-validator.d.ts +16 -0
  400. package/dist/src/planner/validation/plan-validator.d.ts.map +1 -1
  401. package/dist/src/planner/validation/plan-validator.js +36 -0
  402. package/dist/src/planner/validation/plan-validator.js.map +1 -1
  403. package/dist/src/runtime/async-util.d.ts +26 -0
  404. package/dist/src/runtime/async-util.d.ts.map +1 -1
  405. package/dist/src/runtime/async-util.js +139 -55
  406. package/dist/src/runtime/async-util.js.map +1 -1
  407. package/dist/src/runtime/cache/shared-cache.d.ts +7 -0
  408. package/dist/src/runtime/cache/shared-cache.d.ts.map +1 -1
  409. package/dist/src/runtime/cache/shared-cache.js +34 -1
  410. package/dist/src/runtime/cache/shared-cache.js.map +1 -1
  411. package/dist/src/runtime/context-helpers.d.ts +32 -4
  412. package/dist/src/runtime/context-helpers.d.ts.map +1 -1
  413. package/dist/src/runtime/context-helpers.js +26 -9
  414. package/dist/src/runtime/context-helpers.js.map +1 -1
  415. package/dist/src/runtime/deferred-constraint-queue.d.ts.map +1 -1
  416. package/dist/src/runtime/deferred-constraint-queue.js +2 -1
  417. package/dist/src/runtime/deferred-constraint-queue.js.map +1 -1
  418. package/dist/src/runtime/emission-context.d.ts +27 -3
  419. package/dist/src/runtime/emission-context.d.ts.map +1 -1
  420. package/dist/src/runtime/emission-context.js +38 -7
  421. package/dist/src/runtime/emission-context.js.map +1 -1
  422. package/dist/src/runtime/emit/add-constraint.d.ts.map +1 -1
  423. package/dist/src/runtime/emit/add-constraint.js +7 -1
  424. package/dist/src/runtime/emit/add-constraint.js.map +1 -1
  425. package/dist/src/runtime/emit/aggregate.d.ts +2 -3
  426. package/dist/src/runtime/emit/aggregate.d.ts.map +1 -1
  427. package/dist/src/runtime/emit/aggregate.js +23 -28
  428. package/dist/src/runtime/emit/aggregate.js.map +1 -1
  429. package/dist/src/runtime/emit/alter-table.d.ts.map +1 -1
  430. package/dist/src/runtime/emit/alter-table.js +98 -9
  431. package/dist/src/runtime/emit/alter-table.js.map +1 -1
  432. package/dist/src/runtime/emit/analyze.d.ts.map +1 -1
  433. package/dist/src/runtime/emit/analyze.js +2 -1
  434. package/dist/src/runtime/emit/analyze.js.map +1 -1
  435. package/dist/src/runtime/emit/asof-scan.d.ts.map +1 -1
  436. package/dist/src/runtime/emit/asof-scan.js +13 -10
  437. package/dist/src/runtime/emit/asof-scan.js.map +1 -1
  438. package/dist/src/runtime/emit/async-gather.d.ts.map +1 -1
  439. package/dist/src/runtime/emit/async-gather.js +4 -3
  440. package/dist/src/runtime/emit/async-gather.js.map +1 -1
  441. package/dist/src/runtime/emit/between.d.ts.map +1 -1
  442. package/dist/src/runtime/emit/between.js +2 -1
  443. package/dist/src/runtime/emit/between.js.map +1 -1
  444. package/dist/src/runtime/emit/binary.d.ts.map +1 -1
  445. package/dist/src/runtime/emit/binary.js +122 -14
  446. package/dist/src/runtime/emit/binary.js.map +1 -1
  447. package/dist/src/runtime/emit/block.d.ts.map +1 -1
  448. package/dist/src/runtime/emit/block.js +2 -1
  449. package/dist/src/runtime/emit/block.js.map +1 -1
  450. package/dist/src/runtime/emit/bloom-join.d.ts.map +1 -1
  451. package/dist/src/runtime/emit/bloom-join.js +20 -8
  452. package/dist/src/runtime/emit/bloom-join.js.map +1 -1
  453. package/dist/src/runtime/emit/cache.d.ts +7 -3
  454. package/dist/src/runtime/emit/cache.d.ts.map +1 -1
  455. package/dist/src/runtime/emit/cache.js +25 -7
  456. package/dist/src/runtime/emit/cache.js.map +1 -1
  457. package/dist/src/runtime/emit/case.d.ts.map +1 -1
  458. package/dist/src/runtime/emit/case.js +66 -45
  459. package/dist/src/runtime/emit/case.js.map +1 -1
  460. package/dist/src/runtime/emit/cast.d.ts.map +1 -1
  461. package/dist/src/runtime/emit/cast.js +2 -1
  462. package/dist/src/runtime/emit/cast.js.map +1 -1
  463. package/dist/src/runtime/emit/constraint-check.d.ts.map +1 -1
  464. package/dist/src/runtime/emit/constraint-check.js +13 -7
  465. package/dist/src/runtime/emit/constraint-check.js.map +1 -1
  466. package/dist/src/runtime/emit/create-assertion.d.ts.map +1 -1
  467. package/dist/src/runtime/emit/create-assertion.js +2 -1
  468. package/dist/src/runtime/emit/create-assertion.js.map +1 -1
  469. package/dist/src/runtime/emit/create-index.d.ts.map +1 -1
  470. package/dist/src/runtime/emit/create-index.js +12 -1
  471. package/dist/src/runtime/emit/create-index.js.map +1 -1
  472. package/dist/src/runtime/emit/create-table.d.ts.map +1 -1
  473. package/dist/src/runtime/emit/create-table.js +12 -1
  474. package/dist/src/runtime/emit/create-table.js.map +1 -1
  475. package/dist/src/runtime/emit/cte-reference.d.ts.map +1 -1
  476. package/dist/src/runtime/emit/cte-reference.js +2 -1
  477. package/dist/src/runtime/emit/cte-reference.js.map +1 -1
  478. package/dist/src/runtime/emit/cte.d.ts.map +1 -1
  479. package/dist/src/runtime/emit/cte.js +45 -21
  480. package/dist/src/runtime/emit/cte.js.map +1 -1
  481. package/dist/src/runtime/emit/ddl-transaction-policy.d.ts +50 -0
  482. package/dist/src/runtime/emit/ddl-transaction-policy.d.ts.map +1 -0
  483. package/dist/src/runtime/emit/ddl-transaction-policy.js +69 -0
  484. package/dist/src/runtime/emit/ddl-transaction-policy.js.map +1 -0
  485. package/dist/src/runtime/emit/delete.d.ts.map +1 -1
  486. package/dist/src/runtime/emit/delete.js +2 -1
  487. package/dist/src/runtime/emit/delete.js.map +1 -1
  488. package/dist/src/runtime/emit/distinct.d.ts.map +1 -1
  489. package/dist/src/runtime/emit/distinct.js +2 -1
  490. package/dist/src/runtime/emit/distinct.js.map +1 -1
  491. package/dist/src/runtime/emit/dml-executor.d.ts.map +1 -1
  492. package/dist/src/runtime/emit/dml-executor.js +138 -74
  493. package/dist/src/runtime/emit/dml-executor.js.map +1 -1
  494. package/dist/src/runtime/emit/drop-assertion.d.ts.map +1 -1
  495. package/dist/src/runtime/emit/drop-assertion.js +2 -1
  496. package/dist/src/runtime/emit/drop-assertion.js.map +1 -1
  497. package/dist/src/runtime/emit/drop-index.d.ts.map +1 -1
  498. package/dist/src/runtime/emit/drop-index.js +17 -1
  499. package/dist/src/runtime/emit/drop-index.js.map +1 -1
  500. package/dist/src/runtime/emit/drop-table.d.ts.map +1 -1
  501. package/dist/src/runtime/emit/drop-table.js +11 -1
  502. package/dist/src/runtime/emit/drop-table.js.map +1 -1
  503. package/dist/src/runtime/emit/eager-prefetch.d.ts.map +1 -1
  504. package/dist/src/runtime/emit/eager-prefetch.js +2 -1
  505. package/dist/src/runtime/emit/eager-prefetch.js.map +1 -1
  506. package/dist/src/runtime/emit/envelope-scan.d.ts.map +1 -1
  507. package/dist/src/runtime/emit/envelope-scan.js +2 -1
  508. package/dist/src/runtime/emit/envelope-scan.js.map +1 -1
  509. package/dist/src/runtime/emit/fanout-lookup-join.d.ts.map +1 -1
  510. package/dist/src/runtime/emit/fanout-lookup-join.js +3 -2
  511. package/dist/src/runtime/emit/fanout-lookup-join.js.map +1 -1
  512. package/dist/src/runtime/emit/filter.d.ts.map +1 -1
  513. package/dist/src/runtime/emit/filter.js +8 -3
  514. package/dist/src/runtime/emit/filter.js.map +1 -1
  515. package/dist/src/runtime/emit/hash-aggregate.d.ts.map +1 -1
  516. package/dist/src/runtime/emit/hash-aggregate.js +16 -11
  517. package/dist/src/runtime/emit/hash-aggregate.js.map +1 -1
  518. package/dist/src/runtime/emit/insert.d.ts.map +1 -1
  519. package/dist/src/runtime/emit/insert.js +2 -1
  520. package/dist/src/runtime/emit/insert.js.map +1 -1
  521. package/dist/src/runtime/emit/join.d.ts.map +1 -1
  522. package/dist/src/runtime/emit/join.js +20 -6
  523. package/dist/src/runtime/emit/join.js.map +1 -1
  524. package/dist/src/runtime/emit/limit-offset.d.ts.map +1 -1
  525. package/dist/src/runtime/emit/limit-offset.js +2 -1
  526. package/dist/src/runtime/emit/limit-offset.js.map +1 -1
  527. package/dist/src/runtime/emit/literal.d.ts.map +1 -1
  528. package/dist/src/runtime/emit/literal.js +2 -1
  529. package/dist/src/runtime/emit/literal.js.map +1 -1
  530. package/dist/src/runtime/emit/materialized-view-helpers.d.ts +22 -0
  531. package/dist/src/runtime/emit/materialized-view-helpers.d.ts.map +1 -1
  532. package/dist/src/runtime/emit/materialized-view-helpers.js +128 -16
  533. package/dist/src/runtime/emit/materialized-view-helpers.js.map +1 -1
  534. package/dist/src/runtime/emit/materialized-view.d.ts.map +1 -1
  535. package/dist/src/runtime/emit/materialized-view.js +6 -0
  536. package/dist/src/runtime/emit/materialized-view.js.map +1 -1
  537. package/dist/src/runtime/emit/merge-join.d.ts.map +1 -1
  538. package/dist/src/runtime/emit/merge-join.js +14 -4
  539. package/dist/src/runtime/emit/merge-join.js.map +1 -1
  540. package/dist/src/runtime/emit/ordinal-slice.d.ts.map +1 -1
  541. package/dist/src/runtime/emit/ordinal-slice.js +2 -1
  542. package/dist/src/runtime/emit/ordinal-slice.js.map +1 -1
  543. package/dist/src/runtime/emit/pragma.d.ts.map +1 -1
  544. package/dist/src/runtime/emit/pragma.js +2 -1
  545. package/dist/src/runtime/emit/pragma.js.map +1 -1
  546. package/dist/src/runtime/emit/project.d.ts.map +1 -1
  547. package/dist/src/runtime/emit/project.js +7 -2
  548. package/dist/src/runtime/emit/project.js.map +1 -1
  549. package/dist/src/runtime/emit/recursive-cte.d.ts.map +1 -1
  550. package/dist/src/runtime/emit/recursive-cte.js +61 -2
  551. package/dist/src/runtime/emit/recursive-cte.js.map +1 -1
  552. package/dist/src/runtime/emit/returning.d.ts.map +1 -1
  553. package/dist/src/runtime/emit/returning.js +7 -2
  554. package/dist/src/runtime/emit/returning.js.map +1 -1
  555. package/dist/src/runtime/emit/scalar-function.d.ts.map +1 -1
  556. package/dist/src/runtime/emit/scalar-function.js +2 -1
  557. package/dist/src/runtime/emit/scalar-function.js.map +1 -1
  558. package/dist/src/runtime/emit/scan.d.ts.map +1 -1
  559. package/dist/src/runtime/emit/scan.js +55 -17
  560. package/dist/src/runtime/emit/scan.js.map +1 -1
  561. package/dist/src/runtime/emit/schema-declarative.d.ts.map +1 -1
  562. package/dist/src/runtime/emit/schema-declarative.js +6 -5
  563. package/dist/src/runtime/emit/schema-declarative.js.map +1 -1
  564. package/dist/src/runtime/emit/sequencing.d.ts.map +1 -1
  565. package/dist/src/runtime/emit/sequencing.js +2 -1
  566. package/dist/src/runtime/emit/sequencing.js.map +1 -1
  567. package/dist/src/runtime/emit/set-operation.d.ts.map +1 -1
  568. package/dist/src/runtime/emit/set-operation.js +6 -5
  569. package/dist/src/runtime/emit/set-operation.js.map +1 -1
  570. package/dist/src/runtime/emit/sink.d.ts.map +1 -1
  571. package/dist/src/runtime/emit/sink.js +2 -1
  572. package/dist/src/runtime/emit/sink.js.map +1 -1
  573. package/dist/src/runtime/emit/sort.d.ts.map +1 -1
  574. package/dist/src/runtime/emit/sort.js +2 -1
  575. package/dist/src/runtime/emit/sort.js.map +1 -1
  576. package/dist/src/runtime/emit/subquery.d.ts.map +1 -1
  577. package/dist/src/runtime/emit/subquery.js +42 -23
  578. package/dist/src/runtime/emit/subquery.js.map +1 -1
  579. package/dist/src/runtime/emit/table-valued-function.d.ts.map +1 -1
  580. package/dist/src/runtime/emit/table-valued-function.js +2 -1
  581. package/dist/src/runtime/emit/table-valued-function.js.map +1 -1
  582. package/dist/src/runtime/emit/temporal-arithmetic.d.ts.map +1 -1
  583. package/dist/src/runtime/emit/temporal-arithmetic.js +2 -1
  584. package/dist/src/runtime/emit/temporal-arithmetic.js.map +1 -1
  585. package/dist/src/runtime/emit/transaction.d.ts.map +1 -1
  586. package/dist/src/runtime/emit/transaction.js +2 -1
  587. package/dist/src/runtime/emit/transaction.js.map +1 -1
  588. package/dist/src/runtime/emit/unary.d.ts.map +1 -1
  589. package/dist/src/runtime/emit/unary.js +2 -1
  590. package/dist/src/runtime/emit/unary.js.map +1 -1
  591. package/dist/src/runtime/emit/update.d.ts.map +1 -1
  592. package/dist/src/runtime/emit/update.js +2 -1
  593. package/dist/src/runtime/emit/update.js.map +1 -1
  594. package/dist/src/runtime/emit/values.d.ts.map +1 -1
  595. package/dist/src/runtime/emit/values.js +2 -1
  596. package/dist/src/runtime/emit/values.js.map +1 -1
  597. package/dist/src/runtime/emit/view-mutation.d.ts +1 -1
  598. package/dist/src/runtime/emit/view-mutation.d.ts.map +1 -1
  599. package/dist/src/runtime/emit/view-mutation.js +6 -3
  600. package/dist/src/runtime/emit/view-mutation.js.map +1 -1
  601. package/dist/src/runtime/emit/window.d.ts.map +1 -1
  602. package/dist/src/runtime/emit/window.js +26 -9
  603. package/dist/src/runtime/emit/window.js.map +1 -1
  604. package/dist/src/runtime/emitters.d.ts +11 -3
  605. package/dist/src/runtime/emitters.d.ts.map +1 -1
  606. package/dist/src/runtime/emitters.js +13 -22
  607. package/dist/src/runtime/emitters.js.map +1 -1
  608. package/dist/src/runtime/foreign-key-actions.d.ts.map +1 -1
  609. package/dist/src/runtime/foreign-key-actions.js +39 -13
  610. package/dist/src/runtime/foreign-key-actions.js.map +1 -1
  611. package/dist/src/runtime/parallel-driver.d.ts +32 -4
  612. package/dist/src/runtime/parallel-driver.d.ts.map +1 -1
  613. package/dist/src/runtime/parallel-driver.js +88 -18
  614. package/dist/src/runtime/parallel-driver.js.map +1 -1
  615. package/dist/src/runtime/scheduler.d.ts +56 -7
  616. package/dist/src/runtime/scheduler.d.ts.map +1 -1
  617. package/dist/src/runtime/scheduler.js +223 -200
  618. package/dist/src/runtime/scheduler.js.map +1 -1
  619. package/dist/src/runtime/strict-flags.d.ts +22 -0
  620. package/dist/src/runtime/strict-flags.d.ts.map +1 -0
  621. package/dist/src/runtime/strict-flags.js +26 -0
  622. package/dist/src/runtime/strict-flags.js.map +1 -0
  623. package/dist/src/runtime/strict-fork.d.ts +4 -4
  624. package/dist/src/runtime/strict-fork.d.ts.map +1 -1
  625. package/dist/src/runtime/strict-fork.js +175 -31
  626. package/dist/src/runtime/strict-fork.js.map +1 -1
  627. package/dist/src/runtime/types.d.ts +102 -4
  628. package/dist/src/runtime/types.d.ts.map +1 -1
  629. package/dist/src/runtime/types.js +37 -0
  630. package/dist/src/runtime/types.js.map +1 -1
  631. package/dist/src/runtime/utils.d.ts.map +1 -1
  632. package/dist/src/runtime/utils.js +8 -17
  633. package/dist/src/runtime/utils.js.map +1 -1
  634. package/dist/src/schema/column.d.ts +8 -0
  635. package/dist/src/schema/column.d.ts.map +1 -1
  636. package/dist/src/schema/column.js.map +1 -1
  637. package/dist/src/schema/ddl-generator.js +5 -0
  638. package/dist/src/schema/ddl-generator.js.map +1 -1
  639. package/dist/src/schema/function.d.ts +79 -0
  640. package/dist/src/schema/function.d.ts.map +1 -1
  641. package/dist/src/schema/function.js.map +1 -1
  642. package/dist/src/schema/lens-compiler.js +2 -2
  643. package/dist/src/schema/lens-compiler.js.map +1 -1
  644. package/dist/src/schema/lens-prover.d.ts.map +1 -1
  645. package/dist/src/schema/lens-prover.js +2 -3
  646. package/dist/src/schema/lens-prover.js.map +1 -1
  647. package/dist/src/schema/lens.d.ts +1 -1
  648. package/dist/src/schema/manager.d.ts.map +1 -1
  649. package/dist/src/schema/manager.js +7 -2
  650. package/dist/src/schema/manager.js.map +1 -1
  651. package/dist/src/schema/rename-rewriter.d.ts +61 -0
  652. package/dist/src/schema/rename-rewriter.d.ts.map +1 -1
  653. package/dist/src/schema/rename-rewriter.js +77 -0
  654. package/dist/src/schema/rename-rewriter.js.map +1 -1
  655. package/dist/src/schema/table.d.ts +36 -8
  656. package/dist/src/schema/table.d.ts.map +1 -1
  657. package/dist/src/schema/table.js +61 -11
  658. package/dist/src/schema/table.js.map +1 -1
  659. package/dist/src/schema/unique-enforcement.d.ts +28 -5
  660. package/dist/src/schema/unique-enforcement.d.ts.map +1 -1
  661. package/dist/src/schema/unique-enforcement.js +37 -5
  662. package/dist/src/schema/unique-enforcement.js.map +1 -1
  663. package/dist/src/schema/view.d.ts +1 -1
  664. package/dist/src/schema/view.js +1 -1
  665. package/dist/src/types/json-type.d.ts.map +1 -1
  666. package/dist/src/types/json-type.js +18 -8
  667. package/dist/src/types/json-type.js.map +1 -1
  668. package/dist/src/types/logical-type.d.ts +26 -0
  669. package/dist/src/types/logical-type.d.ts.map +1 -1
  670. package/dist/src/types/logical-type.js.map +1 -1
  671. package/dist/src/util/comparison.d.ts +83 -59
  672. package/dist/src/util/comparison.d.ts.map +1 -1
  673. package/dist/src/util/comparison.js +191 -131
  674. package/dist/src/util/comparison.js.map +1 -1
  675. package/dist/src/util/json-canonical.d.ts +34 -0
  676. package/dist/src/util/json-canonical.d.ts.map +1 -0
  677. package/dist/src/util/json-canonical.js +32 -0
  678. package/dist/src/util/json-canonical.js.map +1 -0
  679. package/dist/src/util/key-serializer.d.ts +10 -3
  680. package/dist/src/util/key-serializer.d.ts.map +1 -1
  681. package/dist/src/util/key-serializer.js +43 -17
  682. package/dist/src/util/key-serializer.js.map +1 -1
  683. package/dist/src/util/key-tuple-codec.d.ts +37 -0
  684. package/dist/src/util/key-tuple-codec.d.ts.map +1 -0
  685. package/dist/src/util/key-tuple-codec.js +65 -0
  686. package/dist/src/util/key-tuple-codec.js.map +1 -0
  687. package/dist/src/util/latches.d.ts +29 -3
  688. package/dist/src/util/latches.d.ts.map +1 -1
  689. package/dist/src/util/latches.js +60 -6
  690. package/dist/src/util/latches.js.map +1 -1
  691. package/dist/src/util/patterns.d.ts +22 -8
  692. package/dist/src/util/patterns.d.ts.map +1 -1
  693. package/dist/src/util/patterns.js +87 -16
  694. package/dist/src/util/patterns.js.map +1 -1
  695. package/dist/src/util/qualified-name.d.ts +10 -0
  696. package/dist/src/util/qualified-name.d.ts.map +1 -0
  697. package/dist/src/util/qualified-name.js +15 -0
  698. package/dist/src/util/qualified-name.js.map +1 -0
  699. package/dist/src/vtab/backing-host.d.ts +8 -1
  700. package/dist/src/vtab/backing-host.d.ts.map +1 -1
  701. package/dist/src/vtab/backing-host.js +7 -0
  702. package/dist/src/vtab/backing-host.js.map +1 -1
  703. package/dist/src/vtab/best-access-plan.d.ts +18 -0
  704. package/dist/src/vtab/best-access-plan.d.ts.map +1 -1
  705. package/dist/src/vtab/best-access-plan.js +15 -0
  706. package/dist/src/vtab/best-access-plan.js.map +1 -1
  707. package/dist/src/vtab/capabilities.d.ts +44 -0
  708. package/dist/src/vtab/capabilities.d.ts.map +1 -1
  709. package/dist/src/vtab/filter-info.d.ts +42 -0
  710. package/dist/src/vtab/filter-info.d.ts.map +1 -1
  711. package/dist/src/vtab/filter-info.js +137 -1
  712. package/dist/src/vtab/filter-info.js.map +1 -1
  713. package/dist/src/vtab/idx-str.d.ts +62 -0
  714. package/dist/src/vtab/idx-str.d.ts.map +1 -0
  715. package/dist/src/vtab/idx-str.js +130 -0
  716. package/dist/src/vtab/idx-str.js.map +1 -0
  717. package/dist/src/vtab/index-descriptor.d.ts +122 -0
  718. package/dist/src/vtab/index-descriptor.d.ts.map +1 -0
  719. package/dist/src/vtab/index-descriptor.js +104 -0
  720. package/dist/src/vtab/index-descriptor.js.map +1 -0
  721. package/dist/src/vtab/mapping-advertisement.d.ts +1 -1
  722. package/dist/src/vtab/memory/index.d.ts +12 -4
  723. package/dist/src/vtab/memory/index.d.ts.map +1 -1
  724. package/dist/src/vtab/memory/index.js +17 -9
  725. package/dist/src/vtab/memory/index.js.map +1 -1
  726. package/dist/src/vtab/memory/layer/base.d.ts +85 -31
  727. package/dist/src/vtab/memory/layer/base.d.ts.map +1 -1
  728. package/dist/src/vtab/memory/layer/base.js +127 -86
  729. package/dist/src/vtab/memory/layer/base.js.map +1 -1
  730. package/dist/src/vtab/memory/layer/connection.d.ts +27 -0
  731. package/dist/src/vtab/memory/layer/connection.d.ts.map +1 -1
  732. package/dist/src/vtab/memory/layer/connection.js +36 -1
  733. package/dist/src/vtab/memory/layer/connection.js.map +1 -1
  734. package/dist/src/vtab/memory/layer/interface.d.ts +24 -4
  735. package/dist/src/vtab/memory/layer/interface.d.ts.map +1 -1
  736. package/dist/src/vtab/memory/layer/manager.d.ts +212 -16
  737. package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
  738. package/dist/src/vtab/memory/layer/manager.js +754 -170
  739. package/dist/src/vtab/memory/layer/manager.js.map +1 -1
  740. package/dist/src/vtab/memory/layer/plan-filter.d.ts +26 -1
  741. package/dist/src/vtab/memory/layer/plan-filter.d.ts.map +1 -1
  742. package/dist/src/vtab/memory/layer/plan-filter.js +29 -11
  743. package/dist/src/vtab/memory/layer/plan-filter.js.map +1 -1
  744. package/dist/src/vtab/memory/layer/safe-iterate.d.ts +2 -2
  745. package/dist/src/vtab/memory/layer/safe-iterate.d.ts.map +1 -1
  746. package/dist/src/vtab/memory/layer/safe-iterate.js +2 -2
  747. package/dist/src/vtab/memory/layer/safe-iterate.js.map +1 -1
  748. package/dist/src/vtab/memory/layer/scan-layer.d.ts +5 -1
  749. package/dist/src/vtab/memory/layer/scan-layer.d.ts.map +1 -1
  750. package/dist/src/vtab/memory/layer/scan-layer.js +59 -24
  751. package/dist/src/vtab/memory/layer/scan-layer.js.map +1 -1
  752. package/dist/src/vtab/memory/layer/scan-plan.d.ts.map +1 -1
  753. package/dist/src/vtab/memory/layer/scan-plan.js +13 -21
  754. package/dist/src/vtab/memory/layer/scan-plan.js.map +1 -1
  755. package/dist/src/vtab/memory/layer/transaction.d.ts +169 -7
  756. package/dist/src/vtab/memory/layer/transaction.d.ts.map +1 -1
  757. package/dist/src/vtab/memory/layer/transaction.js +334 -9
  758. package/dist/src/vtab/memory/layer/transaction.js.map +1 -1
  759. package/dist/src/vtab/memory/module.d.ts +11 -4
  760. package/dist/src/vtab/memory/module.d.ts.map +1 -1
  761. package/dist/src/vtab/memory/module.js +35 -16
  762. package/dist/src/vtab/memory/module.js.map +1 -1
  763. package/dist/src/vtab/memory/table.d.ts +30 -4
  764. package/dist/src/vtab/memory/table.d.ts.map +1 -1
  765. package/dist/src/vtab/memory/table.js +63 -15
  766. package/dist/src/vtab/memory/table.js.map +1 -1
  767. package/dist/src/vtab/memory/utils/predicate.d.ts +9 -1
  768. package/dist/src/vtab/memory/utils/predicate.d.ts.map +1 -1
  769. package/dist/src/vtab/memory/utils/predicate.js +35 -14
  770. package/dist/src/vtab/memory/utils/predicate.js.map +1 -1
  771. package/dist/src/vtab/memory/utils/primary-key-encode.d.ts.map +1 -1
  772. package/dist/src/vtab/memory/utils/primary-key-encode.js +12 -6
  773. package/dist/src/vtab/memory/utils/primary-key-encode.js.map +1 -1
  774. package/dist/src/vtab/memory/utils/primary-key.d.ts +6 -1
  775. package/dist/src/vtab/memory/utils/primary-key.d.ts.map +1 -1
  776. package/dist/src/vtab/memory/utils/primary-key.js +12 -8
  777. package/dist/src/vtab/memory/utils/primary-key.js.map +1 -1
  778. package/dist/src/vtab/module.d.ts +38 -14
  779. package/dist/src/vtab/module.d.ts.map +1 -1
  780. package/dist/src/vtab/table.d.ts +41 -2
  781. package/dist/src/vtab/table.d.ts.map +1 -1
  782. package/dist/src/vtab/table.js +19 -0
  783. package/dist/src/vtab/table.js.map +1 -1
  784. package/package.json +5 -4
  785. package/dist/src/planner/rules/cache/rule-materialization-advisory.d.ts +0 -18
  786. package/dist/src/planner/rules/cache/rule-materialization-advisory.d.ts.map +0 -1
  787. package/dist/src/planner/rules/cache/rule-materialization-advisory.js +0 -65
  788. package/dist/src/planner/rules/cache/rule-materialization-advisory.js.map +0 -1
@@ -1,16 +1,15 @@
1
1
  import { buildColumnIndexMap, columnDefToSchema, resolvePkDefaultConflict, resolveNamedConstraintClass, validateCollationForType } from '../../../schema/table.js';
2
2
  import { BTree } from 'inheritree';
3
3
  import { StatusCode } from '../../../common/types.js';
4
- import { BaseLayer } from './base.js';
4
+ import { BaseLayer, iteratePrimaryRows, populateIndexFromRows, populateIndexFromRowsAsync } from './base.js';
5
5
  import { TransactionLayer } from './transaction.js';
6
6
  import { MemoryTableConnection } from './connection.js';
7
7
  import { MemoryVirtualTableConnection } from '../connection.js';
8
- import { Latches } from '../../../util/latches.js';
9
8
  import { QuereusError } from '../../../common/errors.js';
10
9
  import { ConflictResolution } from '../../../common/constants.js';
11
10
  import { buildUniqueConstraintSchema, buildForeignKeyConstraintSchema, buildCheckConstraintSchema, validateForeignKeyOverExistingRows, maintainedTableUniqueViolationError } from '../../../schema/constraint-builder.js';
12
- import { uniqueEnforcementCollations } from '../../../schema/unique-enforcement.js';
13
- import { compareSqlValues, rowsValueIdentical, normalizeCollationName } from '../../../util/comparison.js';
11
+ import { indexEnforcesUnique, uniqueEnforcementCollations } from '../../../schema/unique-enforcement.js';
12
+ import { compareSqlValues, compareSqlValuesFast, rowsValueIdentical, normalizeCollationName } from '../../../util/comparison.js';
14
13
  import { scanLayer as scanLayerImpl } from './scan-layer.js';
15
14
  import { createPrimaryKeyFunctions, buildPrimaryKeyFromValues } from '../utils/primary-key.js';
16
15
  import { createMemoryTableLoggers } from '../utils/logging.js';
@@ -18,6 +17,8 @@ import { tryFoldLiteral } from '../../../parser/utils.js';
18
17
  import { validateAndParse } from '../../../types/validation.js';
19
18
  import { inferType } from '../../../types/registry.js';
20
19
  import { compilePredicate } from '../utils/predicate.js';
20
+ import { renameColumnInIndexPredicates } from '../../../schema/rename-rewriter.js';
21
+ import { MemoryIndex } from '../index.js';
21
22
  let tableManagerCounter = 0;
22
23
  const logger = createMemoryTableLoggers('layer:manager');
23
24
  export class MemoryTableManager {
@@ -31,6 +32,13 @@ export class MemoryTableManager {
31
32
  connections = new Map();
32
33
  isReadOnly;
33
34
  tableSchema;
35
+ /**
36
+ * `db.getCollationResolver()`, bound once. Every comparator this manager or its
37
+ * layers build — primary key, secondary index, UNIQUE enforcement, scan bounds —
38
+ * resolves names through it, so a collation registered on *this* database is
39
+ * honored and one registered on no database raises instead of byte-ordering.
40
+ */
41
+ collationResolver;
34
42
  primaryKeyFunctions;
35
43
  /**
36
44
  * Implicit covering structures: constraint identity → the auto-index that
@@ -46,6 +54,7 @@ export class MemoryTableManager {
46
54
  constructor(db, _moduleName, schemaName, tableName, initialSchema, readOnly = false, eventEmitter) {
47
55
  this.managerId = tableManagerCounter++;
48
56
  this.db = db;
57
+ this.collationResolver = db.getCollationResolver();
49
58
  this.schemaName = schemaName;
50
59
  this._tableName = tableName;
51
60
  this.tableSchema = initialSchema;
@@ -63,11 +72,11 @@ export class MemoryTableManager {
63
72
  this.ensureUniqueConstraintIndexes();
64
73
  }
65
74
  this.initializePrimaryKeyFunctions();
66
- this.baseLayer = new BaseLayer(this.tableSchema);
75
+ this.baseLayer = new BaseLayer(this.tableSchema, this.collationResolver);
67
76
  this._currentCommittedLayer = this.baseLayer;
68
77
  }
69
78
  initializePrimaryKeyFunctions() {
70
- this.primaryKeyFunctions = createPrimaryKeyFunctions(this.tableSchema);
79
+ this.primaryKeyFunctions = createPrimaryKeyFunctions(this.tableSchema, this.collationResolver);
71
80
  }
72
81
  /**
73
82
  * One-bit guard on `Schema.kind` (docs/lens.md § Departures): true when this
@@ -324,70 +333,84 @@ export class MemoryTableManager {
324
333
  connection.readLayer = this._currentCommittedLayer;
325
334
  return;
326
335
  }
327
- // Capture changes from pendingLayer and any ancestor TransactionLayers
328
- // up to (but not including) the currentCommittedLayer. Ancestor layers
329
- // in the chain are typically savepoint-promoted in-transaction layers
330
- // whose pendingChanges were never emitted (they were never directly
331
- // committed). Walking the chain ensures events from earlier writes
332
- // in the same transaction aren't dropped just because a SAVEPOINT
333
- // promotion swapped the pending layer mid-transaction.
334
- const eventChunks = [];
335
- {
336
- let layer = pendingLayer;
337
- while (layer && layer !== this._currentCommittedLayer) {
338
- if (layer instanceof TransactionLayer) {
339
- const events = layer.getPendingChanges();
340
- if (events.length > 0)
341
- eventChunks.push(events);
342
- }
343
- layer = layer.getParent();
344
- }
345
- }
346
- // Chunks are newest-layer-first; reverse to chronological order while
347
- // preserving intra-layer event order.
348
- const changes = eventChunks.reverse().flat();
349
336
  const lockKey = `MemoryTable.Commit:${this.schemaName}.${this._tableName}`;
350
- const release = await Latches.acquire(lockKey);
337
+ const release = await this.db.latches.acquire(lockKey);
351
338
  logger.debugLog(`[Commit ${connection.connectionId}] Acquired lock for ${this._tableName}`);
352
339
  try {
353
- // Walk up the parent chain to find if the current committed layer is an ancestor
354
- // This handles savepoint chains properly
355
- let currentParent = pendingLayer.getParent();
356
- let foundCommittedLayer = false;
357
- while (currentParent) {
358
- if (currentParent === this._currentCommittedLayer) {
359
- foundCommittedLayer = true;
360
- break;
361
- }
362
- currentParent = currentParent.getParent();
363
- }
364
- // Also check if the current committed layer and pending layer are siblings
365
- // (both children of the same parent) - this handles coordinated multi-connection commits
366
- if (!foundCommittedLayer) {
367
- const pendingParent = pendingLayer.getParent();
368
- let committedAncestor = this._currentCommittedLayer;
369
- while (committedAncestor) {
370
- if (committedAncestor === pendingParent) {
371
- foundCommittedLayer = true;
340
+ // Relate the pending layer's chain to the current committed head.
341
+ //
342
+ // Case A — the head is an ancestor of the pending layer: pending forked
343
+ // off (a descendant of) the current head, so its chain already
344
+ // contains everything committed so far. Publish it wholesale.
345
+ // Case B the head advanced past the pending layer's fork point
346
+ // (a sibling connection committed a disjoint change to the same table
347
+ // in a coordinated multi-connection commit): pending and head share a
348
+ // common ancestor — the fork point — that is a *proper* ancestor of
349
+ // the head. Rebase pending's own writes onto the head so the sibling's
350
+ // already-committed rows are not discarded (the bug this guards).
351
+ // Case C no common ancestor reachable: a genuinely stale commit. Roll
352
+ // back with BUSY outside a coordinated commit (the caller can retry);
353
+ // inside one, preserve the prior wholesale fallback.
354
+ let headIsAncestorOfPending = false;
355
+ {
356
+ let cur = pendingLayer;
357
+ while (cur) {
358
+ if (cur === this._currentCommittedLayer) {
359
+ headIsAncestorOfPending = true;
372
360
  break;
373
361
  }
374
- committedAncestor = committedAncestor.getParent();
362
+ cur = cur.getParent();
375
363
  }
376
364
  }
377
- if (!foundCommittedLayer) {
378
- // During coordinated multi-connection commits (explicit COMMIT or implicit transaction commit),
379
- // sibling layers are allowed. Only enforce strict validation outside coordinated commits.
380
- if (!this.db._inCoordinatedCommit()) {
365
+ let committedLayer;
366
+ let changes;
367
+ if (headIsAncestorOfPending) {
368
+ // Case A: the un-emitted in-transaction event span ends at the head.
369
+ changes = this.collectPendingChanges(pendingLayer, this._currentCommittedLayer);
370
+ pendingLayer.markCommitted();
371
+ committedLayer = pendingLayer;
372
+ }
373
+ else {
374
+ // Find the fork point: the deepest layer present in BOTH chains.
375
+ const headChain = this.layerChainSet(this._currentCommittedLayer);
376
+ let forkPoint = pendingLayer.getParent();
377
+ while (forkPoint && !headChain.has(forkPoint)) {
378
+ forkPoint = forkPoint.getParent();
379
+ }
380
+ if (forkPoint) {
381
+ // Schema drift: an ALTER consolidated the head to a different schema
382
+ // since the pending layer forked. Replaying stale-schema rows onto
383
+ // the new-schema head is unsafe — abort with BUSY rather than corrupt
384
+ // the committed head (mirrors the stale-ancestor caution above).
385
+ if (pendingLayer.getSchema() !== this.tableSchema) {
386
+ connection.pendingTransactionLayer = null;
387
+ connection.clearSavepoints();
388
+ logger.warn('Commit Transaction', this._tableName, 'Schema drift under sibling commit, rolling back', { connectionId: connection.connectionId });
389
+ throw new QuereusError(`Commit failed: schema changed under transaction on table ${this._tableName}. Retry.`, StatusCode.BUSY);
390
+ }
391
+ // Case B: rebase. Events come from the same fork-bounded pending-chain
392
+ // span; structural writes are replayed onto the advanced head.
393
+ changes = this.collectPendingChanges(pendingLayer, forkPoint);
394
+ committedLayer = this.rebaseLayerOntoHead(pendingLayer, forkPoint);
395
+ }
396
+ else if (!this.db._inCoordinatedCommit()) {
381
397
  connection.pendingTransactionLayer = null;
382
398
  connection.clearSavepoints();
383
399
  logger.warn('Commit Transaction', this._tableName, 'Stale commit detected, rolling back', { connectionId: connection.connectionId });
384
400
  throw new QuereusError(`Commit failed: concurrent update on table ${this._tableName}. Retry.`, StatusCode.BUSY);
385
401
  }
402
+ else {
403
+ // Case C fallback inside a coordinated commit: no safe rebase target,
404
+ // but aborting would roll back every connection. Preserve the prior
405
+ // wholesale publish.
406
+ changes = this.collectPendingChanges(pendingLayer, this._currentCommittedLayer);
407
+ pendingLayer.markCommitted();
408
+ committedLayer = pendingLayer;
409
+ }
386
410
  }
387
- pendingLayer.markCommitted();
388
- this._currentCommittedLayer = pendingLayer;
389
- logger.debugLog(`[Commit ${connection.connectionId}] CurrentCommittedLayer set to ${pendingLayer.getLayerId()} for ${this._tableName}`);
390
- connection.readLayer = pendingLayer;
411
+ this._currentCommittedLayer = committedLayer;
412
+ logger.debugLog(`[Commit ${connection.connectionId}] CurrentCommittedLayer set to ${committedLayer.getLayerId()} for ${this._tableName}`);
413
+ connection.readLayer = committedLayer;
391
414
  connection.pendingTransactionLayer = null;
392
415
  connection.clearSavepoints();
393
416
  // Emit data change events after successful commit
@@ -414,11 +437,92 @@ export class MemoryTableManager {
414
437
  logger.debugLog(`[Commit ${connection.connectionId}] Released lock for ${this._tableName}`);
415
438
  }
416
439
  }
440
+ /** All layers in `layer`'s parent chain, including `layer` itself. */
441
+ layerChainSet(layer) {
442
+ const chain = new Set();
443
+ let cur = layer;
444
+ while (cur) {
445
+ chain.add(cur);
446
+ cur = cur.getParent();
447
+ }
448
+ return chain;
449
+ }
450
+ /**
451
+ * Collect pending change events from `fromLayer` up to (but not including)
452
+ * `boundary`, in chronological order (oldest layer first, intra-layer order
453
+ * preserved). Mirrors the in-transaction event span whose writes are being
454
+ * committed: savepoint-promoted ancestor layers whose events were never
455
+ * directly emitted are included; already-committed layers at/below the
456
+ * boundary are not (their events were emitted when they committed).
457
+ */
458
+ collectPendingChanges(fromLayer, boundary) {
459
+ const eventChunks = [];
460
+ let layer = fromLayer;
461
+ while (layer && layer !== boundary) {
462
+ if (layer instanceof TransactionLayer) {
463
+ const events = layer.getPendingChanges();
464
+ if (events.length > 0)
465
+ eventChunks.push(events);
466
+ }
467
+ layer = layer.getParent();
468
+ }
469
+ // Chunks are newest-layer-first; reverse to chronological order while
470
+ // preserving intra-layer event order.
471
+ return eventChunks.reverse().flat();
472
+ }
473
+ /**
474
+ * Rebase a pending layer onto the current committed head after a sibling
475
+ * connection advanced the head past this layer's fork point. Replays the
476
+ * pending chain's own structural writes (pending + in-transaction ancestors
477
+ * down to, but not including, `forkPoint`) onto a fresh {@link TransactionLayer}
478
+ * parented on the head, so the sibling's already-committed rows survive.
479
+ *
480
+ * The head becomes the new layer's base, so every row the sibling committed is
481
+ * inherited automatically; only this branch's own writes are replayed on top.
482
+ */
483
+ rebaseLayerOntoHead(pendingLayer, forkPoint) {
484
+ // Gather own-writes from pendingLayer up to (excluding) the fork point.
485
+ // Chunks are newest-layer-first; reverse so the oldest layer replays first.
486
+ const writeChunks = [];
487
+ let layer = pendingLayer;
488
+ while (layer && layer !== forkPoint) {
489
+ if (layer instanceof TransactionLayer) {
490
+ writeChunks.push(layer.getOwnWrites());
491
+ }
492
+ layer = layer.getParent();
493
+ }
494
+ const ownWrites = writeChunks.reverse().flat();
495
+ const rebased = new TransactionLayer(this._currentCommittedLayer);
496
+ if (this.eventEmitter?.hasDataListeners?.()) {
497
+ rebased.enableChangeTracking();
498
+ }
499
+ for (const write of ownWrites) {
500
+ // Re-derive the effective row at this PK on the NEW head (including
501
+ // earlier replays in this loop) and pass it as the old row, so
502
+ // secondary-index maintenance removes the correct pre-existing entry.
503
+ // NOTE: a primary key OR a secondary-UNIQUE value written by BOTH
504
+ // siblings resolves last-writer-wins to the rebasing writer's row —
505
+ // every non-contended key from both siblings survives. recordUpsert is
506
+ // the raw structural write and does not re-run checkUniqueConstraints, so
507
+ // a UNIQUE collision existing only BETWEEN the two siblings' rows is not
508
+ // detected here. This matches the memory manager's read-your-own-writes
509
+ // model (snapshot-isolation conflict detection lives in quereus-isolation).
510
+ const effective = this.lookupEffectiveRow(write.primaryKey, rebased);
511
+ if (write.type === 'upsert') {
512
+ rebased.recordUpsert(write.primaryKey, write.newRow, effective);
513
+ }
514
+ else if (effective) {
515
+ rebased.recordDelete(write.primaryKey, effective);
516
+ }
517
+ }
518
+ rebased.markCommitted();
519
+ return rebased;
520
+ }
417
521
  async tryCollapseLayers() {
418
522
  const lockKey = `MemoryTable.Collapse:${this.schemaName}.${this._tableName}`;
419
523
  let release = null;
420
524
  try {
421
- const acquirePromise = Latches.acquire(lockKey);
525
+ const acquirePromise = this.db.latches.acquire(lockKey);
422
526
  const timeoutPromise = new Promise((resolve) => setTimeout(() => resolve(null), 10)); // Short timeout
423
527
  const result = await Promise.race([
424
528
  acquirePromise.then(releaseFn => ({ release: releaseFn })),
@@ -466,9 +570,7 @@ export class MemoryTableManager {
466
570
  // by examining if this layer can be promoted above its (now detached) parent
467
571
  logger.debugLog(`[Collapse] Layer ${layerToPromote.getLayerId()} is now independent for ${this._tableName}`);
468
572
  }
469
- // Trigger garbage collection of unreferenced layers
470
573
  if (collapsedCount > 0) {
471
- void this.cleanupUnreferencedLayers();
472
574
  logger.operation('Collapse Layers', this._tableName, { collapsedCount, iterations });
473
575
  }
474
576
  else {
@@ -517,26 +619,6 @@ export class MemoryTableManager {
517
619
  }
518
620
  return false;
519
621
  }
520
- /**
521
- * Performs garbage collection of layers that are no longer referenced
522
- * by any connections or the current committed layer chain.
523
- */
524
- cleanupUnreferencedLayers() {
525
- // For now, this is a no-op since JavaScript's garbage collector
526
- // will handle cleanup of unreferenced objects automatically.
527
- // In the future, we could implement more aggressive cleanup
528
- // or tracking of layer references for memory monitoring.
529
- logger.debugLog(`[Cleanup] Triggering garbage collection hint for ${this._tableName}`);
530
- // Optional: Force garbage collection if available (Node.js with --expose-gc)
531
- if (typeof global !== 'undefined' && global.gc) {
532
- try {
533
- global.gc();
534
- }
535
- catch {
536
- // Ignore errors - gc() might not be available
537
- }
538
- }
539
- }
540
622
  // With inherited BTrees, lookupEffectiveRow is much simpler
541
623
  lookupEffectiveRow(primaryKey, startLayer) {
542
624
  // With inherited BTrees, a simple get() will traverse the inheritance chain automatically
@@ -767,7 +849,7 @@ export class MemoryTableManager {
767
849
  // which columns can transition the row across the predicate's scope.
768
850
  const referenced = covering?.kind === 'memory-index'
769
851
  ? covering.index.predicate?.referencedColumns
770
- : compilePredicate(uc.predicate, schema.columns).referencedColumns;
852
+ : compilePredicate(uc.predicate, schema.columns, schema.name).referencedColumns;
771
853
  if (referenced) {
772
854
  for (const colIdx of referenced) {
773
855
  if (compareSqlValues(oldRow[colIdx], newRow[colIdx]) !== 0)
@@ -813,7 +895,7 @@ export class MemoryTableManager {
813
895
  }
814
896
  if (covering?.kind === 'materialized-view'
815
897
  && uc.predicate
816
- && compilePredicate(uc.predicate, schema.columns).evaluate(newRowData) !== true) {
898
+ && compilePredicate(uc.predicate, schema.columns, schema.name).evaluate(newRowData) !== true) {
817
899
  return null;
818
900
  }
819
901
  // Resolve effective action: statement OR > constraint default > ABORT.
@@ -901,6 +983,13 @@ export class MemoryTableManager {
901
983
  checkUniqueViaIndex(targetLayer, schema, uc, index, newRowData, newPrimaryKey, onConflict, evicted) {
902
984
  const indexKey = index.keyFromRow(newRowData);
903
985
  const existingPKs = index.getPrimaryKeys(indexKey);
986
+ // The overwhelmingly common insert has no candidate at all; bail before paying
987
+ // for the collation resolves below.
988
+ if (existingPKs.length === 0)
989
+ return null;
990
+ // Resolve the per-column enforcement collations once, ahead of the candidate loop
991
+ // (which collation governs, and why, is spelled out at the compare below).
992
+ const enforcementCollations = uc.columns.map((col, i) => this.collationResolver(index.specColumns[i]?.collation ?? schema.columns[col].collation ?? 'BINARY'));
904
993
  for (const existingPK of existingPKs) {
905
994
  if (this.comparePrimaryKeys(newPrimaryKey, existingPK) === 0)
906
995
  continue;
@@ -939,7 +1028,7 @@ export class MemoryTableManager {
939
1028
  const conflictingRow = this.lookupEffectiveRow(existingPK, targetLayer);
940
1029
  if (!conflictingRow)
941
1030
  continue;
942
- if (!uc.columns.every((col, i) => compareSqlValues(newRowData[col], conflictingRow[col], index.specColumns[i]?.collation ?? schema.columns[col].collation) === 0))
1031
+ if (!uc.columns.every((col, i) => compareSqlValuesFast(newRowData[col], conflictingRow[col], enforcementCollations[i]) === 0))
943
1032
  continue;
944
1033
  if (index.predicate && !index.rowMatchesPredicate(conflictingRow))
945
1034
  continue;
@@ -995,7 +1084,7 @@ export class MemoryTableManager {
995
1084
  // index-derived UNIQUE whose declared candidate set could be a subset is declined
996
1085
  // upstream by findRowTimeCoveringStructure's collation gate, so only BINARY-floor
997
1086
  // or equal-collation MVs ever reach here.
998
- const collations = uniqueEnforcementCollations(schema, uc);
1087
+ const collations = uniqueEnforcementCollations(schema, uc).map(name => this.collationResolver(name ?? 'BINARY'));
999
1088
  for (const conflict of conflicts) {
1000
1089
  const existingPK = buildPrimaryKeyFromValues(conflict.pk, schema.primaryKeyDefinition);
1001
1090
  if (this.comparePrimaryKeys(newPrimaryKey, existingPK) === 0)
@@ -1004,7 +1093,7 @@ export class MemoryTableManager {
1004
1093
  const conflictingRow = this.lookupEffectiveRow(existingPK, targetLayer);
1005
1094
  if (!conflictingRow)
1006
1095
  continue;
1007
- if (!uc.columns.every((col, i) => compareSqlValues(newRowData[col], conflictingRow[col], collations[i]) === 0))
1096
+ if (!uc.columns.every((col, i) => compareSqlValuesFast(newRowData[col], conflictingRow[col], collations[i]) === 0))
1008
1097
  continue;
1009
1098
  if (onConflict === ConflictResolution.IGNORE) {
1010
1099
  return { status: 'ok', row: undefined };
@@ -1032,8 +1121,10 @@ export class MemoryTableManager {
1032
1121
  // Compile partial-UNIQUE predicate ad-hoc (cold path: an auto-index normally
1033
1122
  // services this check, so this branch fires only for pathological schemas).
1034
1123
  const predicate = uc.predicate
1035
- ? compilePredicate(uc.predicate, schema.columns)
1124
+ ? compilePredicate(uc.predicate, schema.columns, schema.name)
1036
1125
  : undefined;
1126
+ // One resolve per column, not per scanned row.
1127
+ const collations = uc.columns.map(colIdx => this.collationResolver(schema.columns[colIdx].collation ?? 'BINARY'));
1037
1128
  for (const path of primaryTree.ascending(primaryTree.first())) {
1038
1129
  const existingRow = primaryTree.at(path);
1039
1130
  const existingPK = this.primaryKeyFromRow(existingRow);
@@ -1041,7 +1132,7 @@ export class MemoryTableManager {
1041
1132
  continue;
1042
1133
  if (predicate && predicate.evaluate(existingRow) !== true)
1043
1134
  continue;
1044
- const allMatch = uc.columns.every(colIdx => compareSqlValues(newRowData[colIdx], existingRow[colIdx], schema.columns[colIdx].collation) === 0);
1135
+ const allMatch = uc.columns.every((colIdx, i) => compareSqlValuesFast(newRowData[colIdx], existingRow[colIdx], collations[i]) === 0);
1045
1136
  if (!allMatch)
1046
1137
  continue;
1047
1138
  if (onConflict === ConflictResolution.IGNORE) {
@@ -1121,13 +1212,13 @@ export class MemoryTableManager {
1121
1212
  throw new QuereusError(`Table '${this._tableName}' is read-only`, StatusCode.READONLY);
1122
1213
  }
1123
1214
  const lockKey = `MemoryTable.SchemaChange:${this.schemaName}.${this._tableName}`;
1124
- const release = await Latches.acquire(lockKey);
1215
+ const release = await this.db.latches.acquire(lockKey);
1125
1216
  try {
1126
1217
  // Drain any in-flight transaction layers down to the base so the swap
1127
1218
  // below isn't shadowed by a committed transaction layer ahead of base.
1128
1219
  await this.ensureSchemaChangeSafety();
1129
1220
  const oldBase = this.baseLayer;
1130
- const newBase = new BaseLayer(this.tableSchema);
1221
+ const newBase = new BaseLayer(this.tableSchema, this.collationResolver);
1131
1222
  for (const row of rows) {
1132
1223
  const key = this.primaryKeyFunctions.extractFromRow(row);
1133
1224
  const path = newBase.primaryTree.find(key);
@@ -1240,7 +1331,7 @@ export class MemoryTableManager {
1240
1331
  // Collect-then-delete avoids mutating the tree mid-iteration.
1241
1332
  const scanPlan = { indexName: 'primary', descending: false, equalityPrefix: op.keyPrefix };
1242
1333
  const matched = [];
1243
- for await (const row of scanLayerImpl(layer, scanPlan)) {
1334
+ for (const row of scanLayerImpl(layer, scanPlan)) {
1244
1335
  matched.push({ key: this.primaryKeyFunctions.extractFromRow(row), row });
1245
1336
  }
1246
1337
  for (const { key, row } of matched) {
@@ -1262,7 +1353,7 @@ export class MemoryTableManager {
1262
1353
  // delete that would leak secondary-index bookkeeping. VALUE fidelity of a paired
1263
1354
  // row is byte-faithful (`rowsValueIdentical`, below) — one discipline, not two.
1264
1355
  const oldByKey = new BTree(e => e.key, this.comparePrimaryKeys);
1265
- for await (const row of scanLayerImpl(layer, { indexName: 'primary', descending: false })) {
1356
+ for (const row of scanLayerImpl(layer, { indexName: 'primary', descending: false })) {
1266
1357
  oldByKey.insert({ key: this.primaryKeyFunctions.extractFromRow(row), row });
1267
1358
  }
1268
1359
  // New-row keys (same PK comparator) for the delete pass's membership test.
@@ -1313,7 +1404,7 @@ export class MemoryTableManager {
1313
1404
  * Declared secondary-UNIQUE enforcement for maintenance writes — the
1314
1405
  * collision-shaped half of the derived-row constraint contract (CHECK / FK
1315
1406
  * are per-row properties and validate engine-side; see
1316
- * docs/materialized-views.md § Derived-row constraint validation). The
1407
+ * docs/mv-constraints.md § Derived-row constraint validation). The
1317
1408
  * privileged surface bypasses the DML constraint pipeline, so without this
1318
1409
  * the batch above would store two derived rows colliding on a declared
1319
1410
  * UNIQUE silently.
@@ -1366,7 +1457,7 @@ export class MemoryTableManager {
1366
1457
  if (this.isReadOnly)
1367
1458
  throw new QuereusError(`Table '${this._tableName}' is read-only`, StatusCode.READONLY);
1368
1459
  const lockKey = `MemoryTable.SchemaChange:${this.schemaName}.${this._tableName}`;
1369
- const release = await Latches.acquire(lockKey);
1460
+ const release = await this.db.latches.acquire(lockKey);
1370
1461
  const originalManagerSchema = this.tableSchema;
1371
1462
  try {
1372
1463
  await this.ensureSchemaChangeSafety();
@@ -1377,7 +1468,7 @@ export class MemoryTableManager {
1377
1468
  // COLLATE, matching the CREATE path (and the differ's resolved-COLLATE emission) so
1378
1469
  // an ADD-COLUMN-ed text column gets the same collation a CREATE-d one would.
1379
1470
  // resolveDefaultCollation falls non-text types back to BINARY automatically.
1380
- const newColumnSchema = columnDefToSchema(columnDefAst, defaultNotNull, this.db.options.getStringOption('default_collation'));
1471
+ const newColumnSchema = columnDefToSchema(columnDefAst, defaultNotNull, this.db.options.getStringOption('default_collation'), (n) => this.db.isCollationRegistered(n));
1381
1472
  if (this.tableSchema.columns.some(c => c.name.toLowerCase() === newColumnSchema.name.toLowerCase())) {
1382
1473
  throw new QuereusError(`Duplicate column name: ${newColumnSchema.name}`, StatusCode.ERROR);
1383
1474
  }
@@ -1445,7 +1536,7 @@ export class MemoryTableManager {
1445
1536
  if (this.isReadOnly)
1446
1537
  throw new QuereusError(`Table '${this._tableName}' is read-only`, StatusCode.READONLY);
1447
1538
  const lockKey = `MemoryTable.SchemaChange:${this.schemaName}.${this._tableName}`;
1448
- const release = await Latches.acquire(lockKey);
1539
+ const release = await this.db.latches.acquire(lockKey);
1449
1540
  const originalManagerSchema = this.tableSchema;
1450
1541
  try {
1451
1542
  await this.ensureSchemaChangeSafety();
@@ -1536,8 +1627,11 @@ export class MemoryTableManager {
1536
1627
  if (this.isReadOnly)
1537
1628
  throw new QuereusError(`Table '${this._tableName}' is read-only`, StatusCode.READONLY);
1538
1629
  const lockKey = `MemoryTable.SchemaChange:${this.schemaName}.${this._tableName}`;
1539
- const release = await Latches.acquire(lockKey);
1630
+ const release = await this.db.latches.acquire(lockKey);
1540
1631
  const originalManagerSchema = this.tableSchema;
1632
+ const schemaManager = this.db.schemaManager;
1633
+ const resolveColumnInSource = (s, t, col) => schemaManager.getSchema(s)?.getTable(t)?.columnIndexMap.has(col.toLowerCase()) ?? false;
1634
+ let predicatesRewritten = false;
1541
1635
  try {
1542
1636
  await this.ensureSchemaChangeSafety();
1543
1637
  const oldNameLower = oldName.toLowerCase();
@@ -1552,7 +1646,7 @@ export class MemoryTableManager {
1552
1646
  // Get default nullability setting from database options
1553
1647
  const defaultNullability = this.db.options.getStringOption('default_column_nullability');
1554
1648
  const defaultNotNull = defaultNullability === 'not_null';
1555
- const newColumnSchemaAtIndex = columnDefToSchema(newColumnDefAst, defaultNotNull);
1649
+ const newColumnSchemaAtIndex = columnDefToSchema(newColumnDefAst, defaultNotNull, 'BINARY', (n) => this.db.isCollationRegistered(n));
1556
1650
  const updatedCols = this.tableSchema.columns.map((c, i) => i === colIndex ? newColumnSchemaAtIndex : c);
1557
1651
  const updatedIndexes = (this.tableSchema.indexes || []).map(idx => ({
1558
1652
  ...idx,
@@ -1565,6 +1659,28 @@ export class MemoryTableManager {
1565
1659
  primaryKeyDefinition: Object.freeze(this.tableSchema.primaryKeyDefinition),
1566
1660
  indexes: Object.freeze(updatedIndexes),
1567
1661
  });
1662
+ // Rewrite partial-index predicates into the new column name BEFORE the
1663
+ // rebuild that `handleColumnRename()` triggers: `createSecondaryIndexes`
1664
+ // compiles each predicate against the new column list, so a `WHERE` still
1665
+ // naming the old column cannot build.
1666
+ //
1667
+ // The window is narrow. `ensureSchemaChangeSafety()` above consolidates the
1668
+ // transaction layers into the base and rebuilds every secondary index against
1669
+ // the OLD column list — an already-rewritten predicate would break that. So
1670
+ // the rewrite belongs here and nowhere earlier (in particular, not before the
1671
+ // engine calls `module.alterTable`).
1672
+ //
1673
+ // In place, so the catalog's `TableSchema` and a unique partial index's derived
1674
+ // UNIQUE constraint — which share the `Expression` by reference — follow along.
1675
+ // `propagateColumnRename` re-runs the same rewrite once the engine regains
1676
+ // control and finds nothing left to do.
1677
+ // Armed BEFORE the call, not from its return value: the rewrite walks the
1678
+ // indexes one at a time, so a throw partway through would otherwise leave the
1679
+ // already-rewritten predicates renamed with the flag still false. The reverse
1680
+ // pass is a no-op when nothing names `newColumnName`, so arming it eagerly
1681
+ // costs nothing when the rewrite finds no predicate to touch.
1682
+ predicatesRewritten = true;
1683
+ renameColumnInIndexPredicates(finalNewTableSchema.indexes, this._tableName, oldName, newColumnName, this.schemaName, resolveColumnInSource);
1568
1684
  this.baseLayer.updateSchema(finalNewTableSchema);
1569
1685
  await this.baseLayer.handleColumnRename();
1570
1686
  this.tableSchema = finalNewTableSchema;
@@ -1581,6 +1697,12 @@ export class MemoryTableManager {
1581
1697
  logger.operation('Rename Column', this._tableName, { oldName, newName: newColumnName });
1582
1698
  }
1583
1699
  catch (e) {
1700
+ // The predicate ASTs are shared with the catalog's TableSchema, so restoring
1701
+ // `originalManagerSchema` does not undo the rewrite — run it in reverse. The
1702
+ // flag keeps a failure raised *before* the rewrite from un-renaming anything.
1703
+ if (predicatesRewritten) {
1704
+ renameColumnInIndexPredicates(originalManagerSchema.indexes, this._tableName, newColumnDefAst.name, oldName, this.schemaName, resolveColumnInSource);
1705
+ }
1584
1706
  this.baseLayer.updateSchema(originalManagerSchema);
1585
1707
  this.tableSchema = originalManagerSchema;
1586
1708
  this.initializePrimaryKeyFunctions();
@@ -1596,12 +1718,14 @@ export class MemoryTableManager {
1596
1718
  * The caller supplies exactly one populated change; multi-attribute combinations
1597
1719
  * are rejected by the runtime before reaching this method.
1598
1720
  */
1599
- async alterColumn(change) {
1721
+ async alterColumn(change, rows) {
1600
1722
  if (this.isReadOnly)
1601
1723
  throw new QuereusError(`Table '${this._tableName}' is read-only`, StatusCode.READONLY);
1602
1724
  const lockKey = `MemoryTable.SchemaChange:${this.schemaName}.${this._tableName}`;
1603
- const release = await Latches.acquire(lockKey);
1725
+ const release = await this.db.latches.acquire(lockKey);
1604
1726
  const originalManagerSchema = this.tableSchema;
1727
+ /** The base primary tree `rebuildPrimaryTreeStrict` replaced, for the catch's rollback. */
1728
+ let basePrimaryTreeBeforeRekey = null;
1605
1729
  try {
1606
1730
  await this.ensureSchemaChangeSafety();
1607
1731
  const colNameLower = change.columnName.toLowerCase();
@@ -1614,8 +1738,18 @@ export class MemoryTableManager {
1614
1738
  // A collation change re-keys any PK / UNIQUE / index that orders by this
1615
1739
  // column, so it needs the structure re-sort + uniqueness re-validation below.
1616
1740
  let collationChanged = false;
1741
+ // Set to the per-value conversion function when a physical value rewrite is needed:
1742
+ // SET DATA TYPE (retype every value) or SET NOT NULL backfill (map null → DEFAULT).
1743
+ // Both REPLACE the base primary tree with a freshly-built one (never an in-place
1744
+ // mutation, which inheritree forbids while the open transaction's layers derive from
1745
+ // it) and convert the transaction's own-written rows in every open layer, after
1746
+ // `updateSchema` (see the rebuild section and convertColumnOnOpenLayers).
1747
+ let valueConvert = null;
1748
+ // SET NOT NULL backfill also routes NULL values through `valueConvert`; SET DATA TYPE
1749
+ // leaves nulls untouched. Selects the null-including path in convertBaseRows/convertColumn.
1750
+ let convertNulls = false;
1617
1751
  if (change.setCollation !== undefined) {
1618
- const normalized = validateCollationForType(change.setCollation, oldCol.logicalType, change.columnName);
1752
+ const normalized = validateCollationForType(change.setCollation, oldCol.logicalType, change.columnName, (n) => this.db.isCollationRegistered(n));
1619
1753
  const nameMatches = normalized === (oldCol.collation || 'BINARY');
1620
1754
  if (nameMatches && oldCol.collationExplicit) {
1621
1755
  return; // already explicit in the desired collation — nothing to do
@@ -1634,30 +1768,43 @@ export class MemoryTableManager {
1634
1768
  }
1635
1769
  else if (change.setNotNull !== undefined) {
1636
1770
  if (change.setNotNull === true && !oldCol.notNull) {
1637
- // Tightening: scan for NULLs. If DEFAULT present, backfill first.
1771
+ // Tightening: scan the DDL transaction's EFFECTIVE rows for NULLs committed rows
1772
+ // overlaid with this transaction's own pending writes — exactly as the setDataType
1773
+ // arm does. A pending NULL the transaction can SEE rejects the ALTER; one only in a
1774
+ // row it has DELETED does not block it. `rows` is the wrapper-supplied effective set
1775
+ // (the isolation overlay); when absent, effectiveDdlRows() is the layered view.
1638
1776
  const defaultExpr = oldCol.defaultValue;
1639
- let defaultLiteral;
1640
- if (defaultExpr) {
1641
- defaultLiteral = tryFoldLiteral(defaultExpr);
1777
+ const defaultLiteral = defaultExpr ? tryFoldLiteral(defaultExpr) : undefined;
1778
+ let anyNull = false;
1779
+ if (rows) {
1780
+ for await (const row of rows()) {
1781
+ if (row[colIndex] === null) {
1782
+ anyNull = true;
1783
+ break;
1784
+ }
1785
+ }
1642
1786
  }
1643
- const tree = this.baseLayer.primaryTree;
1644
- const nullRows = [];
1645
- for (const path of tree.ascending(tree.first())) {
1646
- const row = tree.at(path);
1647
- if (row[colIndex] === null)
1648
- nullRows.push(row);
1787
+ else {
1788
+ for (const row of this.effectiveDdlRows()) {
1789
+ if (row[colIndex] === null) {
1790
+ anyNull = true;
1791
+ break;
1792
+ }
1793
+ }
1649
1794
  }
1650
- if (nullRows.length > 0) {
1795
+ if (anyNull) {
1651
1796
  if (defaultLiteral === undefined || defaultLiteral === null) {
1652
1797
  throw new QuereusError(`column ${change.columnName} contains NULL values`, StatusCode.CONSTRAINT);
1653
1798
  }
1654
- // Backfill NULLs with the default literal.
1655
- for (const row of nullRows) {
1656
- const newRow = row.map((v, i) => i === colIndex ? defaultLiteral : v);
1657
- // replace in-place: same PK, mutate row array. BTree keys by PK extraction,
1658
- // so overwriting the value at the same key is sufficient.
1659
- tree.insert(newRow);
1660
- }
1799
+ // Backfill: map null the folded DEFAULT literal, routed through the SAME
1800
+ // base-replacement + open-layer conversion machinery setDataType uses — no
1801
+ // logical-type change, no PK re-key, no in-place base mutation. The old in-place
1802
+ // `tree.upsert` backfill could not fill the transaction's pending rows (they live
1803
+ // in the pending layer, not the base) and mutated a base the open layers derive
1804
+ // from — both fixed by the unified path.
1805
+ const literal = defaultLiteral;
1806
+ valueConvert = (v) => (v === null ? literal : v);
1807
+ convertNulls = true;
1661
1808
  }
1662
1809
  newCol = { ...oldCol, notNull: true };
1663
1810
  }
@@ -1678,27 +1825,49 @@ export class MemoryTableManager {
1678
1825
  newCol = { ...oldCol, logicalType: newLogicalType };
1679
1826
  }
1680
1827
  else {
1681
- // Physical conversion required. Iterate rows and convert.
1682
- const tree = this.baseLayer.primaryTree;
1683
- const toConvert = [];
1684
- for (const path of tree.ascending(tree.first())) {
1685
- const row = tree.at(path);
1686
- toConvert.push({ path, row });
1828
+ // Retyping a PRIMARY KEY column changes the physical key bytes. The in-place
1829
+ // base rewrite below cannot re-key the primary tree (an upsert of a row whose
1830
+ // PK value changed physical type lands at a NEW key, orphaning the old entry),
1831
+ // and the transaction-layer conversion deliberately leaves every layer's primary
1832
+ // tree keyed as-is. Reject rather than corrupt it — the type-change analogue of
1833
+ // the SET COLLATE primary-key carve-out (`alter-collate-pk-in-transaction`).
1834
+ if (this.tableSchema.primaryKeyDefinition.some(def => def.index === colIndex)) {
1835
+ throw new QuereusError(`Cannot change the data type of primary key column '${change.columnName}' of table '${this._tableName}'.`, StatusCode.CONSTRAINT);
1687
1836
  }
1688
- for (const { row } of toConvert) {
1689
- const oldVal = row[colIndex];
1690
- if (oldVal === null)
1691
- continue;
1692
- let newVal;
1837
+ const convert = (v) => {
1693
1838
  try {
1694
- newVal = validateAndParse(oldVal, newLogicalType, change.columnName);
1839
+ return validateAndParse(v, newLogicalType, change.columnName);
1695
1840
  }
1696
1841
  catch {
1697
1842
  throw new QuereusError(`Cannot convert value in '${change.columnName}' to ${change.setDataType}`, StatusCode.MISMATCH);
1698
1843
  }
1699
- const newRow = row.map((v, i) => i === colIndex ? newVal : v);
1700
- tree.insert(newRow);
1844
+ };
1845
+ // Validate BEFORE any mutation, over the DDL transaction's EFFECTIVE rows
1846
+ // (committed rows overlaid with this transaction's own pending writes): an
1847
+ // unconvertible value the transaction can SEE rejects the ALTER, and one only in
1848
+ // a row it has DELETED does not block it. A throw here leaves the schema, the base
1849
+ // and the transaction untouched. `rows` is the wrapper-supplied effective set (the
1850
+ // isolation overlay); when absent, `effectiveDdlRows()` is the layered view.
1851
+ if (rows) {
1852
+ for await (const row of rows()) {
1853
+ const val = row[colIndex];
1854
+ if (val !== null)
1855
+ convert(val);
1856
+ }
1701
1857
  }
1858
+ else {
1859
+ for (const row of this.effectiveDdlRows()) {
1860
+ const val = row[colIndex];
1861
+ if (val !== null)
1862
+ convert(val);
1863
+ }
1864
+ }
1865
+ // The base rows are converted below, AFTER `updateSchema`, by REPLACING the base
1866
+ // primary tree with a fresh one (see the `valueConvert` branch) — never by an
1867
+ // in-place mutation, which inheritree forbids while the open transaction's layers
1868
+ // derive from that tree (`MutatedBaseError`). `valueConvert` drives both the base
1869
+ // replacement and the transaction-layer conversion.
1870
+ valueConvert = convert;
1702
1871
  newCol = { ...oldCol, logicalType: newLogicalType };
1703
1872
  }
1704
1873
  }
@@ -1727,20 +1896,89 @@ export class MemoryTableManager {
1727
1896
  primaryKeyDefinition: Object.freeze(updatedPkDef),
1728
1897
  indexes: updatedIndexes ? Object.freeze(updatedIndexes) : updatedIndexes,
1729
1898
  });
1899
+ const pkColumnRekeyed = collationChanged && updatedPkDef.some(def => def.index === colIndex);
1900
+ // Validate BEFORE any mutation, over the DDL transaction's EFFECTIVE rows: a pair
1901
+ // the transaction inserted that collides under the NEW collation must reject the
1902
+ // change, and one it has deleted must not block it. A throw here leaves the schema,
1903
+ // the base layer and the index map exactly as they were.
1904
+ //
1905
+ // The primary key gets a stricter pre-pass (`validateRekeyedPrimaryKey`): no layer in
1906
+ // the chain, base included, may hold a collision. That is what lets every step below
1907
+ // succeed unconditionally, and what `TransactionLayer.rekeyPrimaryKey` relies on.
1908
+ if (collationChanged) {
1909
+ await this.validateRekeyedUniqueStructures(finalNewTableSchema, colIndex, rows);
1910
+ // NOTE: `validateRekeyedPrimaryKey` deliberately ignores `rows`. It asserts that no
1911
+ // LAYER of this manager's own chain holds a PK collision under the new comparator —
1912
+ // a physical property of the structures it is about to re-key, which a wrapper's
1913
+ // merged row stream cannot speak to. A wrapper's staged rows live in the wrapper's
1914
+ // own overlay, which enforces the PK itself, so the pair "one staged row + one
1915
+ // committed row that collide only under the new collation" is checked by neither
1916
+ // side. Rejecting it here would need the wrapper to expose its overlay's PK set, not
1917
+ // just its merged rows.
1918
+ if (pkColumnRekeyed)
1919
+ this.validateRekeyedPrimaryKey(finalNewTableSchema);
1920
+ }
1730
1921
  this.baseLayer.updateSchema(finalNewTableSchema);
1731
- // A collation change re-sorts structures that order by the column and
1732
- // re-validates uniqueness under the new collation. Rebuild the secondary
1733
- // indexes FIRST (strict a UNIQUE collision throws CONSTRAINT) and the
1734
- // primary tree LAST (also strict a PK collision throws), so a throw at
1735
- // either step leaves the live primary tree intact for the catch's rollback.
1922
+ // A collation change re-sorts the structures that order by the column. The
1923
+ // secondary rebuild is NON-enforcing (the pre-pass above owns uniqueness, and the
1924
+ // base's rows are not a subset of the effective rows); the primary tree rebuild is
1925
+ // strict, since a PK collision cannot be represented at all — the pre-pass has
1926
+ // already proved the base collision-free, so the strict rebuild is a live invariant
1927
+ // check, not the enforcement path. It runs LAST so its throw leaves the live tree
1928
+ // intact for the catch's rollback.
1736
1929
  if (collationChanged) {
1737
- this.baseLayer.rebuildAllSecondaryIndexesStrict();
1738
- if (updatedPkDef.some(def => def.index === colIndex)) {
1930
+ this.baseLayer.rebuildAllSecondaryIndexes();
1931
+ if (pkColumnRekeyed) {
1932
+ basePrimaryTreeBeforeRekey = this.baseLayer.primaryTree;
1739
1933
  this.baseLayer.rebuildPrimaryTreeStrict();
1740
1934
  }
1741
1935
  }
1936
+ else if (valueConvert) {
1937
+ // SET DATA TYPE / SET NOT NULL backfill: convert the committed base rows and REPLACE
1938
+ // the primary tree with a fresh one holding them (not an in-place upsert — inheritree
1939
+ // forbids mutating a base while the open transaction's layers derive from it).
1940
+ // `rebuildPrimaryTreeFromRows` also rebuilds every secondary index from the converted
1941
+ // rows, so index-backed lookups see the new values. The old tree is saved for the
1942
+ // catch's rollback, exactly as the PK-rekey path does.
1943
+ // NOTE: rebuilds EVERY secondary index, not only those covering the altered column;
1944
+ // if a wide-index table ever shows this as slow, filter to indexes whose columns
1945
+ // include colIndex. Mirrors the collationChanged path's unconditional rebuild.
1946
+ //
1947
+ // SET DATA TYPE: a base value that fails to convert is kept as-is — validation over
1948
+ // the effective view already rejected any unconvertible value the transaction can SEE,
1949
+ // so a surviving one is shadowed by a pending delete/overwrite and is never read back
1950
+ // (a ROLLBACK re-exposes it under the new type — DDL is not undone by rollback, the
1951
+ // known behavior of `feat-ddl-transaction-capability`).
1952
+ // SET NOT NULL (`convertNulls`): null base values are mapped to the DEFAULT literal.
1953
+ const convertedBaseRows = this.convertBaseRows(colIndex, valueConvert, convertNulls);
1954
+ basePrimaryTreeBeforeRekey = this.baseLayer.primaryTree;
1955
+ this.baseLayer.rebuildPrimaryTreeFromRows(convertedBaseRows);
1956
+ }
1742
1957
  this.tableSchema = finalNewTableSchema;
1743
1958
  this.initializePrimaryKeyFunctions();
1959
+ // The base rebuild handed every secondary index a fresh tree under the new
1960
+ // collation; the DDL transaction's own layers still inherit the old ones and froze
1961
+ // the old schema at construction. Re-key them, or the rest of the transaction — and
1962
+ // everything after the pending layer becomes the committed head at commit — keeps
1963
+ // comparing under the old collation.
1964
+ //
1965
+ // When the altered column is part of the primary key, `rebuildPrimaryTreeStrict` also
1966
+ // swapped the base primary tree object out from under those layers' copy-on-write
1967
+ // bases and invalidated their `pkFunctions`; `rekeyPrimaryKey` rebuilds both, plus
1968
+ // every secondary index (each derives its PK comparator/encoder from the PK
1969
+ // definition). Outside a transaction there are no open layers and both are no-ops.
1970
+ if (collationChanged) {
1971
+ this.adoptSchemaOnOpenLayers(finalNewTableSchema, pkColumnRekeyed);
1972
+ }
1973
+ else if (valueConvert) {
1974
+ // SET DATA TYPE / SET NOT NULL backfill converted the base above; the DDL
1975
+ // transaction's own open layers still froze the old schema and hold their own-written
1976
+ // rows unconverted. Swap the schema and convert those values so the rest of the
1977
+ // transaction — and the committed head at commit — read the new value. For SET NOT
1978
+ // NULL this fills the transaction's OWN pending NULL rows (which live in the pending
1979
+ // layer, never reached by the old in-place base upsert). No-op in autocommit.
1980
+ this.convertColumnOnOpenLayers(finalNewTableSchema, colIndex, valueConvert, convertNulls);
1981
+ }
1744
1982
  this.eventEmitter?.emitSchemaChange?.({
1745
1983
  type: 'alter',
1746
1984
  objectType: 'column',
@@ -1751,11 +1989,21 @@ export class MemoryTableManager {
1751
1989
  logger.operation('Alter Column', this._tableName, { columnName: change.columnName });
1752
1990
  }
1753
1991
  catch (e) {
1754
- // Restore the prior schema, then rebuild secondary indexes (non-strict) so
1755
- // a partially-cleared strict rebuild can't strand the index map in an
1756
- // inconsistent state. The primary tree is only swapped on full success, so
1757
- // it is already the original here.
1992
+ // Restore the prior schema and primary tree, then re-key the secondary indexes back
1993
+ // to it. Both pre-passes now run before any mutation, so nothing below `updateSchema`
1994
+ // is expected to throw; the restores are the safety net for an unexpected one (and
1995
+ // for `rebuildPrimaryTreeStrict`'s invariant check, whose precondition
1996
+ // `validateRekeyedPrimaryKey` has already established).
1997
+ //
1998
+ // NOTE: a throw from a pre-pass (or from `setNotNull`'s NULL scan) mutated nothing,
1999
+ // so this rebuild only swaps the base's index trees for fresh, content-identical
2000
+ // ones — an O(rows) cost on a pure rejection. Harmless (a pending layer keeps
2001
+ // reading its orphaned but content-correct copy-on-write base), but if a rejected
2002
+ // ALTER on a large table ever shows up as slow, gate the rebuild on a "mutation
2003
+ // started" flag set just before `updateSchema`.
1758
2004
  this.baseLayer.updateSchema(originalManagerSchema);
2005
+ if (basePrimaryTreeBeforeRekey)
2006
+ this.baseLayer.primaryTree = basePrimaryTreeBeforeRekey;
1759
2007
  this.baseLayer.rebuildAllSecondaryIndexes();
1760
2008
  this.tableSchema = originalManagerSchema;
1761
2009
  this.initializePrimaryKeyFunctions();
@@ -1766,11 +2014,11 @@ export class MemoryTableManager {
1766
2014
  release();
1767
2015
  }
1768
2016
  }
1769
- async createIndex(newIndexSchemaEntry, ifNotExistsFromAst) {
2017
+ async createIndex(newIndexSchemaEntry, ifNotExistsFromAst, rows) {
1770
2018
  if (this.isReadOnly)
1771
2019
  throw new QuereusError(`Table '${this._tableName}' is read-only`, StatusCode.READONLY);
1772
2020
  const lockKey = `MemoryTable.SchemaChange:${this.schemaName}.${this._tableName}`;
1773
- const release = await Latches.acquire(lockKey);
2021
+ const release = await this.db.latches.acquire(lockKey);
1774
2022
  const originalManagerSchema = this.tableSchema;
1775
2023
  try {
1776
2024
  await this.ensureSchemaChangeSafety();
@@ -1787,6 +2035,13 @@ export class MemoryTableManager {
1787
2035
  throw new QuereusError(`Column index ${iCol.index} for index '${indexName}' is out of bounds for table '${this._tableName}'.`, StatusCode.ERROR);
1788
2036
  }
1789
2037
  }
2038
+ // Validate BEFORE any mutation, over the DDL transaction's EFFECTIVE rows — a
2039
+ // duplicate the transaction inserted but has not committed must reject the build,
2040
+ // and one it has deleted must not. A throw here leaves schema, base layer and
2041
+ // index map exactly as they were.
2042
+ if (newIndexSchemaEntry.unique) {
2043
+ await this.validateUniqueOverEffectiveRows(newIndexSchemaEntry, this.tableSchema, rows);
2044
+ }
1790
2045
  const updatedIndexes = Object.freeze([...(this.tableSchema.indexes || []), newIndexSchemaEntry]);
1791
2046
  let updatedUniqueConstraints = this.tableSchema.uniqueConstraints;
1792
2047
  if (newIndexSchemaEntry.unique) {
@@ -1809,6 +2064,9 @@ export class MemoryTableManager {
1809
2064
  this.baseLayer.updateSchema(finalNewTableSchema);
1810
2065
  await this.baseLayer.addIndexToBase(newIndexSchemaEntry);
1811
2066
  this.tableSchema = finalNewTableSchema;
2067
+ // The DDL transaction's own layers froze their schema at creation; hand them the
2068
+ // new one so the rest of the transaction scans and enforces the new index.
2069
+ this.adoptSchemaOnOpenLayers(finalNewTableSchema);
1812
2070
  // Emit schema change event
1813
2071
  this.eventEmitter?.emitSchemaChange?.({
1814
2072
  type: 'create',
@@ -1819,7 +2077,16 @@ export class MemoryTableManager {
1819
2077
  logger.operation('Create Index', this._tableName, { indexName });
1820
2078
  }
1821
2079
  catch (e) {
2080
+ // Restore the prior schema, and drop the index if `addIndexToBase` already landed
2081
+ // it — otherwise the base layer's index map would advertise a structure the schema
2082
+ // no longer declares. Guarded on the ORIGINAL schema so the "index already exists"
2083
+ // arm never tears down the pre-existing index of the same name.
1822
2084
  this.baseLayer.updateSchema(originalManagerSchema);
2085
+ const name = newIndexSchemaEntry.name;
2086
+ const preexisting = originalManagerSchema.indexes?.some(i => i.name.toLowerCase() === name.toLowerCase()) ?? false;
2087
+ if (!preexisting && this.baseLayer.getSecondaryIndex(name)) {
2088
+ await this.baseLayer.dropIndexFromBase(name);
2089
+ }
1823
2090
  this.tableSchema = originalManagerSchema;
1824
2091
  logger.error('Create Index', this._tableName, e);
1825
2092
  throw e;
@@ -1832,7 +2099,7 @@ export class MemoryTableManager {
1832
2099
  if (this.isReadOnly)
1833
2100
  throw new QuereusError(`Table '${this._tableName}' is read-only`, StatusCode.READONLY);
1834
2101
  const lockKey = `MemoryTable.SchemaChange:${this.schemaName}.${this._tableName}`;
1835
- const release = await Latches.acquire(lockKey);
2102
+ const release = await this.db.latches.acquire(lockKey);
1836
2103
  const originalManagerSchema = this.tableSchema;
1837
2104
  try {
1838
2105
  await this.ensureSchemaChangeSafety();
@@ -1859,6 +2126,9 @@ export class MemoryTableManager {
1859
2126
  this.baseLayer.updateSchema(finalNewTableSchema);
1860
2127
  await this.baseLayer.dropIndexFromBase(indexName);
1861
2128
  this.tableSchema = finalNewTableSchema;
2129
+ // The DDL transaction's own layers froze their schema at creation; hand them the new
2130
+ // one so the rest of the transaction stops enforcing (and scanning) the dropped index.
2131
+ this.adoptSchemaOnOpenLayers(finalNewTableSchema);
1862
2132
  // Emit schema change event
1863
2133
  this.eventEmitter?.emitSchemaChange?.({
1864
2134
  type: 'drop',
@@ -1890,7 +2160,7 @@ export class MemoryTableManager {
1890
2160
  if (this.isReadOnly)
1891
2161
  throw new QuereusError(`Table '${this._tableName}' is read-only`, StatusCode.READONLY);
1892
2162
  const lockKey = `MemoryTable.SchemaChange:${this.schemaName}.${this._tableName}`;
1893
- const release = await Latches.acquire(lockKey);
2163
+ const release = await this.db.latches.acquire(lockKey);
1894
2164
  const originalManagerSchema = this.tableSchema;
1895
2165
  try {
1896
2166
  await this.ensureSchemaChangeSafety();
@@ -1933,6 +2203,10 @@ export class MemoryTableManager {
1933
2203
  await this.baseLayer.dropIndexFromBase(droppedIndexName);
1934
2204
  this.tableSchema = newSchema;
1935
2205
  this.initializePrimaryKeyFunctions();
2206
+ // Hand the new schema to the DDL transaction's own frozen layers so a dropped UNIQUE
2207
+ // stops enforcing for the rest of it; harmless for CHECK/FK (they re-freeze an
2208
+ // equivalent schema, holding no per-layer structure).
2209
+ this.adoptSchemaOnOpenLayers(newSchema);
1936
2210
  this.eventEmitter?.emitSchemaChange?.({
1937
2211
  type: 'alter',
1938
2212
  objectType: 'table',
@@ -1962,7 +2236,7 @@ export class MemoryTableManager {
1962
2236
  if (this.isReadOnly)
1963
2237
  throw new QuereusError(`Table '${this._tableName}' is read-only`, StatusCode.READONLY);
1964
2238
  const lockKey = `MemoryTable.SchemaChange:${this.schemaName}.${this._tableName}`;
1965
- const release = await Latches.acquire(lockKey);
2239
+ const release = await this.db.latches.acquire(lockKey);
1966
2240
  const originalManagerSchema = this.tableSchema;
1967
2241
  try {
1968
2242
  await this.ensureSchemaChangeSafety();
@@ -2049,16 +2323,16 @@ export class MemoryTableManager {
2049
2323
  * keeps an engine-side fallback in `runtime/emit/add-constraint.ts` only for
2050
2324
  * modules that omit `alterTable` — which cannot DROP/RENAME a constraint anyway.)
2051
2325
  */
2052
- async addConstraint(constraint) {
2326
+ async addConstraint(constraint, rows) {
2053
2327
  if (this.isReadOnly)
2054
2328
  throw new QuereusError(`Table '${this._tableName}' is read-only`, StatusCode.READONLY);
2055
2329
  const lockKey = `MemoryTable.SchemaChange:${this.schemaName}.${this._tableName}`;
2056
- const release = await Latches.acquire(lockKey);
2330
+ const release = await this.db.latches.acquire(lockKey);
2057
2331
  const originalManagerSchema = this.tableSchema;
2058
2332
  try {
2059
2333
  await this.ensureSchemaChangeSafety();
2060
2334
  if (constraint.type === 'unique') {
2061
- await this.addUniqueConstraint(constraint);
2335
+ await this.addUniqueConstraint(constraint, rows);
2062
2336
  }
2063
2337
  else if (constraint.type === 'foreignKey') {
2064
2338
  await this.addForeignKeyConstraint(constraint);
@@ -2109,12 +2383,12 @@ export class MemoryTableManager {
2109
2383
  }
2110
2384
  /**
2111
2385
  * UNIQUE arm of {@link addConstraint}. Builds the covering secondary index the
2112
- * same way {@link ensureUniqueConstraintIndexes} does (validating existing rows
2113
- * via `addIndexToBase` `populateNewIndex`), unless an existing *unique* index
2114
- * already covers the exact columns — in which case the data is already
2115
- * validated and we only register the covering structure.
2386
+ * same way {@link ensureUniqueConstraintIndexes} does (validating the DDL
2387
+ * transaction's effective rows via {@link validateUniqueOverEffectiveRows} first),
2388
+ * unless an existing *unique* index already covers the exact columns — in which
2389
+ * case the data is already validated and we only register the covering structure.
2116
2390
  */
2117
- async addUniqueConstraint(constraint) {
2391
+ async addUniqueConstraint(constraint, rows) {
2118
2392
  const uc = buildUniqueConstraintSchema(constraint, this.tableSchema.columnIndexMap);
2119
2393
  const columns = this.tableSchema.columns;
2120
2394
  const existingIndexes = this.tableSchema.indexes ?? [];
@@ -2133,6 +2407,8 @@ export class MemoryTableManager {
2133
2407
  idx.columns.every((col, i) => col.index === uc.columns[i]) &&
2134
2408
  this.indexCollationsMatchDeclared(idx, uc));
2135
2409
  if (matchingUniqueIndex) {
2410
+ // No validation pass: the reused index is UNIQUE, so its own derived constraint
2411
+ // has already rejected every colliding row — committed and pending alike.
2136
2412
  const newSchema = Object.freeze({
2137
2413
  ...this.tableSchema,
2138
2414
  uniqueConstraints: appendedUcs,
@@ -2141,6 +2417,9 @@ export class MemoryTableManager {
2141
2417
  this.tableSchema = newSchema;
2142
2418
  this.initializePrimaryKeyFunctions();
2143
2419
  this.implicitCoveringStructures.set(uc.name ?? matchingUniqueIndex.name, { indexName: matchingUniqueIndex.name, origin: 'implicit-from-unique-constraint' });
2420
+ // This arm skips addIndexToBase, but the open transaction's layers still need the
2421
+ // new `uniqueConstraints` entry or they will not enforce it.
2422
+ this.adoptSchemaOnOpenLayers(newSchema);
2144
2423
  return;
2145
2424
  }
2146
2425
  const colNames = uc.columns.map(i => columns[i]?.name ?? String(i));
@@ -2153,19 +2432,23 @@ export class MemoryTableManager {
2153
2432
  columns: uc.columns.map(colIdx => ({ index: colIdx, collation: columns[colIdx]?.collation })),
2154
2433
  predicate: uc.predicate,
2155
2434
  };
2435
+ // Validate BEFORE any mutation, over the DDL transaction's EFFECTIVE rows (throws
2436
+ // CONSTRAINT on the first in-scope duplicate). The covering index carries no
2437
+ // `unique: true` flag, so `addIndexToBase` would not check it anyway — and must
2438
+ // not: it populates from committed rows, which may still hold a duplicate this
2439
+ // transaction has deleted.
2440
+ await this.validateUniqueOverEffectiveRows(indexSchema, this.tableSchema, rows);
2156
2441
  const newSchema = Object.freeze({
2157
2442
  ...this.tableSchema,
2158
2443
  uniqueConstraints: appendedUcs,
2159
2444
  indexes: Object.freeze([...existingIndexes, indexSchema]),
2160
2445
  });
2161
- // Swap the schema FIRST so `addIndexToBase` → `indexEnforcesUnique` sees the
2162
- // new constraint and rejects duplicates, then populate (throws CONSTRAINT on
2163
- // the first in-scope duplicate). A throw rolls back via the catch in addConstraint.
2164
2446
  this.baseLayer.updateSchema(newSchema);
2165
2447
  await this.baseLayer.addIndexToBase(indexSchema);
2166
2448
  this.tableSchema = newSchema;
2167
2449
  this.initializePrimaryKeyFunctions();
2168
2450
  this.implicitCoveringStructures.set(uc.name ?? indexName, { indexName, origin: 'implicit-from-unique-constraint' });
2451
+ this.adoptSchemaOnOpenLayers(newSchema);
2169
2452
  }
2170
2453
  /**
2171
2454
  * FOREIGN KEY arm of {@link addConstraint}. Validates existing child rows
@@ -2189,14 +2472,14 @@ export class MemoryTableManager {
2189
2472
  }
2190
2473
  async destroy() {
2191
2474
  const lockKey = `MemoryTable.Destroy:${this.schemaName}.${this._tableName}`;
2192
- const release = await Latches.acquire(lockKey);
2475
+ const release = await this.db.latches.acquire(lockKey);
2193
2476
  try {
2194
2477
  for (const connection of this.connections.values()) {
2195
2478
  if (connection.pendingTransactionLayer)
2196
2479
  connection.rollback();
2197
2480
  }
2198
2481
  this.connections.clear();
2199
- this.baseLayer = new BaseLayer(this.tableSchema);
2482
+ this.baseLayer = new BaseLayer(this.tableSchema, this.collationResolver);
2200
2483
  this._currentCommittedLayer = this.baseLayer;
2201
2484
  logger.operation('Destroy', this._tableName, 'Manager destroyed and data cleared');
2202
2485
  }
@@ -2214,10 +2497,24 @@ export class MemoryTableManager {
2214
2497
  throw new QuereusError(`Cannot perform schema change on table ${this._tableName} while older transaction versions are in use by active connections. Commit/rollback active transactions and retry.`, StatusCode.BUSY);
2215
2498
  }
2216
2499
  }
2500
+ // Consolidation drains COMMITTED layers into the base; a connection's own
2501
+ // UNCOMMITTED writes are untouched by it. Those rows are invisible to the DDL's
2502
+ // transaction, so a row-validating schema change cannot be checked against them,
2503
+ // and the sibling's layers cannot be re-pointed at the new schema. Only the
2504
+ // DDL-issuing connection may hold open work — everyone else must land first.
2505
+ const ddlConnection = this.ddlConnection();
2506
+ for (const connection of this.knownConnections()) {
2507
+ if (connection === ddlConnection || !connection.hasOpenWork())
2508
+ continue;
2509
+ throw new QuereusError(`Cannot perform schema change on table ${this._tableName} while another connection has uncommitted changes. Commit/rollback active transactions and retry.`, StatusCode.BUSY);
2510
+ }
2217
2511
  // After ensuring we're at the base layer, update all connections to read from the base layer
2218
- // This is necessary because connections might still be reading from promoted/collapsed layers
2512
+ // This is necessary because connections might still be reading from promoted/collapsed layers.
2513
+ // The DDL issuer's own open transaction is exempt: its read view is a pending layer or an
2514
+ // eager savepoint snapshot holding its uncommitted rows, and re-pointing it at the base
2515
+ // would silently drop them from every later read in that transaction.
2219
2516
  for (const connection of this.connections.values()) {
2220
- if (connection.readLayer !== this.baseLayer) {
2517
+ if (connection.readLayer !== this.baseLayer && !connection.hasOpenWork()) {
2221
2518
  logger.debugLog(`[Schema Safety] Updating connection ${connection.connectionId} to read from base layer`);
2222
2519
  connection.readLayer = this.baseLayer;
2223
2520
  }
@@ -2242,6 +2539,17 @@ export class MemoryTableManager {
2242
2539
  * the Database registry but not in the manager's map.
2243
2540
  */
2244
2541
  repointRegisteredConnections() {
2542
+ for (const mc of this.registeredConnections()) {
2543
+ if (mc.hasOpenWork())
2544
+ continue;
2545
+ if (mc.readLayer === this.baseLayer)
2546
+ continue;
2547
+ logger.debugLog(`[Schema Safety] Re-pointing registered connection ${mc.connectionId} to base layer`);
2548
+ mc.readLayer = this.baseLayer;
2549
+ }
2550
+ }
2551
+ /** Every Database-registered {@link MemoryTableConnection} backed by this manager. */
2552
+ *registeredConnections() {
2245
2553
  const qualifiedName = `${this.schemaName}.${this._tableName}`;
2246
2554
  for (const c of this.db.getConnectionsForTable(qualifiedName)) {
2247
2555
  if (!(c instanceof MemoryVirtualTableConnection))
@@ -2249,18 +2557,282 @@ export class MemoryTableManager {
2249
2557
  const mc = c.getMemoryConnection();
2250
2558
  if (mc.tableManager !== this)
2251
2559
  continue;
2252
- if (mc.pendingTransactionLayer !== null)
2560
+ yield mc;
2561
+ }
2562
+ }
2563
+ /**
2564
+ * Every connection this manager can see: the ones still attached to {@link connections}
2565
+ * (including unregistered committed-snapshot readers) plus the Database-registered ones,
2566
+ * which may have been detached from the map by a post-autocommit disconnect.
2567
+ */
2568
+ *knownConnections() {
2569
+ const seen = new Set();
2570
+ for (const mc of this.connections.values()) {
2571
+ seen.add(mc);
2572
+ yield mc;
2573
+ }
2574
+ for (const mc of this.registeredConnections()) {
2575
+ if (seen.has(mc))
2253
2576
  continue;
2254
- if (mc.readLayer === this.baseLayer)
2577
+ seen.add(mc);
2578
+ yield mc;
2579
+ }
2580
+ }
2581
+ /**
2582
+ * The connection through which the current DDL statement's transaction runs, if any.
2583
+ *
2584
+ * A statement reaches a memory table through the single Database-registered connection
2585
+ * for it (`MemoryTable.ensureConnection` and `getVTableConnection` both reuse the first
2586
+ * one), so that connection's view IS this statement's transaction. In autocommit with
2587
+ * no prior scan there is no connection at all, and the committed base is the whole story.
2588
+ *
2589
+ * NOTE: takes the FIRST registered connection, matching how both reuse sites pick one.
2590
+ * If the registry ever holds more than one connection per (table, transaction), this
2591
+ * picks arbitrarily — validate against the writer instead, and treat the rest as
2592
+ * siblings.
2593
+ */
2594
+ ddlConnection() {
2595
+ for (const mc of this.registeredConnections())
2596
+ return mc;
2597
+ return undefined;
2598
+ }
2599
+ /**
2600
+ * The rows a `select` issued by the DDL statement's own transaction would see: the
2601
+ * committed base overlaid with that connection's uncommitted writes. Degenerates to the
2602
+ * base primary tree when no connection holds open work.
2603
+ *
2604
+ * `pendingTransactionLayer ?? readLayer` is exactly the layer `MemoryTable.query` scans,
2605
+ * and each layer's primary BTree is copy-on-write over its parent's, so one ascending
2606
+ * walk yields the merged view (pending inserts/updates present, pending deletes absent).
2607
+ */
2608
+ effectiveDdlRows() {
2609
+ const connection = this.ddlConnection();
2610
+ const layer = connection
2611
+ ? (connection.pendingTransactionLayer ?? connection.readLayer)
2612
+ : this.baseLayer;
2613
+ return iteratePrimaryRows(layer.getModificationTree('primary') ?? this.baseLayer.primaryTree);
2614
+ }
2615
+ /**
2616
+ * The committed base rows for `alter column … set data type` / `set not null` backfill, with the
2617
+ * value at `colIndex` run through `convert`. NULLs pass through untouched UNLESS `convertNulls` is
2618
+ * set (the SET NOT NULL backfill maps null → DEFAULT). A value that fails to convert is kept as-is:
2619
+ * the manager validated every value in the effective VIEW before calling, so a base value that
2620
+ * fails here is one a pending delete/overwrite shadows and no reader can see. The result is a fresh
2621
+ * full row list for {@link BaseLayer.rebuildPrimaryTreeFromRows} — the base primary tree is
2622
+ * REPLACED, never mutated in place (inheritree forbids mutating a tree the open transaction's
2623
+ * layers derive from).
2624
+ */
2625
+ convertBaseRows(colIndex, convert, convertNulls = false) {
2626
+ const out = [];
2627
+ for (const row of iteratePrimaryRows(this.baseLayer.primaryTree)) {
2628
+ const oldVal = row[colIndex];
2629
+ if (oldVal === null && !convertNulls) {
2630
+ out.push(row);
2255
2631
  continue;
2256
- logger.debugLog(`[Schema Safety] Re-pointing registered connection ${mc.connectionId} to base layer`);
2257
- mc.readLayer = this.baseLayer;
2632
+ }
2633
+ let newVal;
2634
+ try {
2635
+ newVal = convert(oldVal);
2636
+ }
2637
+ catch {
2638
+ out.push(row); // shadowed unconvertible value — keep as-is
2639
+ continue;
2640
+ }
2641
+ out.push(row.map((v, i) => i === colIndex ? newVal : v));
2642
+ }
2643
+ return out;
2644
+ }
2645
+ /**
2646
+ * Rejects an index/constraint whose uniqueness the DDL transaction's own effective rows
2647
+ * already violate, BEFORE anything is mutated. Builds a throwaway {@link MemoryIndex} —
2648
+ * the collation-aware, partial-predicate-aware key comparator — over those rows and lets
2649
+ * {@link populateIndexFromRows} raise CONSTRAINT on the first duplicate.
2650
+ *
2651
+ * `rows` overrides {@link effectiveDdlRows}. A wrapper module (the isolation layer) holds
2652
+ * the transaction's pending rows outside this manager, so only it can name the rows the
2653
+ * issuing connection actually sees; when it supplies them, they are the judged set and this
2654
+ * manager's own committed rows are ignored. See `vtab/module.ts` {@link EffectiveRowSource}.
2655
+ */
2656
+ async validateUniqueOverEffectiveRows(indexSchema, schema, rows) {
2657
+ const probe = new MemoryIndex(indexSchema, schema.columns, this.collationResolver, this.primaryKeyFunctions.compare, this.primaryKeyFunctions.encode, schema.name);
2658
+ if (rows) {
2659
+ await populateIndexFromRowsAsync(rows(), probe, this.primaryKeyFunctions.extractFromRow, true, this._tableName, schema.columns);
2660
+ return;
2661
+ }
2662
+ populateIndexFromRows(this.effectiveDdlRows(), probe, this.primaryKeyFunctions.extractFromRow, true, this._tableName, schema.columns);
2663
+ }
2664
+ /**
2665
+ * `ALTER COLUMN … SET COLLATE` arm of {@link validateUniqueOverEffectiveRows}: rejects the
2666
+ * change when it makes two of the DDL transaction's effective rows collide under any
2667
+ * uniqueness-enforcing structure that orders by the altered column. Runs before anything is
2668
+ * mutated, so a rejection leaves the table and schema untouched and the transaction usable.
2669
+ *
2670
+ * `newSchema` carries the post-change per-column collations, so each probe index compares
2671
+ * exactly as the rebuilt structure will. Indexes that do not mention the column keep their
2672
+ * keys and need no re-check.
2673
+ *
2674
+ * NOTE: walks `schema.indexes`, so a UNIQUE constraint covered by a row-time materialized
2675
+ * view rather than its auto-index (`findIndexForConstraint` prefers the MV) is not re-checked
2676
+ * here. The auto-index always exists alongside, so the structure is still validated — but if
2677
+ * an MV-only covering shape ever becomes reachable, this walk must follow it.
2678
+ */
2679
+ async validateRekeyedUniqueStructures(newSchema, alteredColumnIndex, rows) {
2680
+ // NOTE: the probe index carries the manager's PRE-change `primaryKeyFunctions` (the new
2681
+ // ones cannot exist before the schema swaps). Only the probe's per-entry PK bookkeeping
2682
+ // uses them, and every effective row already has a distinct PK under the old encoder, so
2683
+ // duplicate detection — which fires on the index key, before any PK is stored — is
2684
+ // unaffected. If a probe ever needs to compare PKs semantically, pass the new functions in.
2685
+ for (const indexSchema of newSchema.indexes ?? []) {
2686
+ if (!indexSchema.columns.some(c => c.index === alteredColumnIndex))
2687
+ continue;
2688
+ if (!indexEnforcesUnique(newSchema, indexSchema))
2689
+ continue;
2690
+ // `rows` is re-callable, so each structure gets a fresh stream.
2691
+ await this.validateUniqueOverEffectiveRows(indexSchema, newSchema, rows);
2692
+ }
2693
+ }
2694
+ /**
2695
+ * PRIMARY KEY arm of the `alter column … set collate` pre-pass. Runs before anything is
2696
+ * mutated, so a rejection leaves the table, the schema and the transaction untouched.
2697
+ *
2698
+ * The primary tree is a map, not a multi-map, so — unlike a secondary index — it cannot
2699
+ * physically hold two rows whose keys collapse under the new comparator. Every layer the
2700
+ * DDL connection still reads through therefore has to be collision-free, not just the
2701
+ * transaction's effective view:
2702
+ *
2703
+ * 1. **The effective view collides** → `CONSTRAINT`. The duplicate is visible to a `select`
2704
+ * in this transaction; the change is simply illegal.
2705
+ * 2. **A layer beneath it collides** → `BUSY`. Those rows are not visible now, but every
2706
+ * such layer is the copy-on-write base the view reads through, and one of them may be a
2707
+ * savepoint snapshot a `rollback to savepoint` must restore. A re-keyed tree could not
2708
+ * represent the pair at all. Committing (or rolling back) settles the transaction and
2709
+ * the ALTER can be retried — the same "commit/rollback and retry" posture as
2710
+ * {@link ensureSchemaChangeSafety}.
2711
+ *
2712
+ * Case 2 is deliberately conservative. The chain holds one immutable layer per statement
2713
+ * boundary (see `MemoryTableConnection.createSavepoint`'s eager path), so it rejects any
2714
+ * transaction that has held a colliding pair at ANY statement boundary — even one whose
2715
+ * final view is clean and whose intermediate layer no savepoint can reach. Narrowing that
2716
+ * would mean re-parenting the view's tree past the unreachable layers, which is exactly the
2717
+ * rebase that savepoint snapshots exist to avoid. The tradeoff is a rare false BUSY on a
2718
+ * statement sequence the user can retry after committing, versus losing a row on rollback.
2719
+ *
2720
+ * This precondition is also what makes `TransactionLayer.rekeyPrimaryKey`'s replay sound:
2721
+ * with no collisions anywhere in the chain, every primary key resolves to at most one row
2722
+ * in each layer under the new comparator.
2723
+ */
2724
+ validateRekeyedPrimaryKey(newSchema) {
2725
+ const newPkFunctions = createPrimaryKeyFunctions(newSchema, this.collationResolver);
2726
+ const connection = this.ddlConnection();
2727
+ const view = connection
2728
+ ? (connection.pendingTransactionLayer ?? connection.readLayer)
2729
+ : this.baseLayer;
2730
+ this.assertNoPrimaryKeyCollision(view, newPkFunctions, StatusCode.CONSTRAINT, `UNIQUE constraint failed: ${this._tableName} primary key collides under new collation`);
2731
+ // `ensureSchemaChangeSafety` has already drained every committed layer into the base and
2732
+ // rejected sibling connections with open work, so the chain below the view holds only
2733
+ // this transaction's own layers.
2734
+ for (let layer = view.getParent(); layer; layer = layer.getParent()) {
2735
+ this.assertNoPrimaryKeyCollision(layer, newPkFunctions, StatusCode.BUSY, `Cannot change the collation of a primary key column of table ${this._tableName}: `
2736
+ + `rows this transaction has removed still collide under the new collation and must survive a rollback. `
2737
+ + `Commit/rollback and retry.`);
2738
+ }
2739
+ }
2740
+ /**
2741
+ * Raises `code` when two of `layer`'s rows share a primary key under `pkFunctions`.
2742
+ *
2743
+ * NOTE: O(rows) per layer, so O(layers × rows) for a whole chain — one more full pass than
2744
+ * the base rebuild the caller is about to do anyway. Fine for a statement this rare; if a
2745
+ * deep savepoint stack over a large table ever makes an ALTER slow, note that a layer's rows
2746
+ * differ from its parent's only at the keys it wrote, so the walk can be narrowed to those.
2747
+ */
2748
+ assertNoPrimaryKeyCollision(layer, pkFunctions, code, message) {
2749
+ const tree = layer.getModificationTree('primary');
2750
+ if (!tree)
2751
+ return;
2752
+ const probe = new BTree((row) => pkFunctions.extractFromRow(row), pkFunctions.compare);
2753
+ for (const row of iteratePrimaryRows(tree)) {
2754
+ const key = pkFunctions.extractFromRow(row);
2755
+ if (probe.get(key) !== undefined)
2756
+ throw new QuereusError(message, code);
2757
+ probe.insert(row);
2758
+ }
2759
+ }
2760
+ /**
2761
+ * Propagates a schema change — a new index and/or UNIQUE constraint, or a set of structures
2762
+ * re-keyed by `alter column … set collate` — into every {@link TransactionLayer} the DDL
2763
+ * connection's open transaction still reads through: its pending layer and every savepoint
2764
+ * snapshot below it, which are exactly the transaction layers on the view layer's parent
2765
+ * chain above the base.
2766
+ *
2767
+ * Without this the transaction would keep enforcing (and scanning) its creation-time schema
2768
+ * for the rest of its life, a `rollback to savepoint` would restore a stale-schema layer,
2769
+ * and at commit the pending layer would become the committed head carrying its stale schema
2770
+ * and structures — shadowing the base's rebuilt ones. Rebasing would achieve the same but
2771
+ * invalidate those snapshots. Applied oldest-first: both
2772
+ * {@link TransactionLayer.adoptSchema} and {@link TransactionLayer.rekeyPrimaryKey} inherit
2773
+ * their parent's already-rebuilt trees.
2774
+ *
2775
+ * `rekeyPrimary` selects the heavier path, for the one change that invalidates a layer's
2776
+ * primary key functions and every structure derived from them: a collation change on a
2777
+ * primary key column.
2778
+ */
2779
+ adoptSchemaOnOpenLayers(newSchema, rekeyPrimary = false) {
2780
+ for (const layer of this.openTransactionLayersOldestFirst()) {
2781
+ if (rekeyPrimary)
2782
+ layer.rekeyPrimaryKey(newSchema);
2783
+ else
2784
+ layer.adoptSchema(newSchema);
2258
2785
  }
2259
2786
  }
2787
+ /**
2788
+ * Converts the altered column's own-written values in every open transaction layer, after
2789
+ * `alter column … set data type` / `set not null` backfill has converted the base. Runs
2790
+ * oldest-first so each layer's copy-on-write base inherits its parent's already-converted rows
2791
+ * and only the layer's OWN writes are rewritten (see {@link TransactionLayer.convertColumn}).
2792
+ * `convertNulls` routes null own-values through `convert` (the SET NOT NULL null → DEFAULT map);
2793
+ * SET DATA TYPE leaves them untouched. No-op in autocommit.
2794
+ *
2795
+ * PRIMARY-KEY columns never reach here — a physical retype of a key column is rejected before
2796
+ * any mutation, and SET NOT NULL leaves the key bytes unchanged — so the primary tree's keys are
2797
+ * stable and no re-key is needed.
2798
+ */
2799
+ convertColumnOnOpenLayers(newSchema, colIndex, convert, convertNulls = false) {
2800
+ for (const layer of this.openTransactionLayersOldestFirst()) {
2801
+ layer.convertColumn(colIndex, convert, newSchema, convertNulls);
2802
+ }
2803
+ }
2804
+ /**
2805
+ * The DDL connection's open {@link TransactionLayer}s, oldest-first, base excluded — its
2806
+ * pending layer and every savepoint snapshot below it, the layers on the view's parent chain
2807
+ * above the base. Empty in autocommit (no connection, or the view IS the base).
2808
+ *
2809
+ * Both schema adoption ({@link adoptSchemaOnOpenLayers}) and value conversion
2810
+ * ({@link convertColumnOnOpenLayers}) MUST apply oldest-first: each layer rebuilds its
2811
+ * structures over its parent's, so the parent's must already be the new/converted ones.
2812
+ *
2813
+ * NOTE: the walk takes every TransactionLayer below the view, which normally means the pending
2814
+ * layer and its savepoint snapshots. A committed layer already drained into the base by
2815
+ * `ensureSchemaChangeSafety` can also sit in the chain (the pending layer forked from it before
2816
+ * consolidation); it still shadows the base with its OWN unadapted rows while it remains the
2817
+ * view's copy-on-write base, so it must be adapted too — it cannot be skipped, since a savepoint
2818
+ * snapshot is `markCommitted()` as well. Both callers' per-layer work is idempotent and additive.
2819
+ */
2820
+ openTransactionLayersOldestFirst() {
2821
+ const connection = this.ddlConnection();
2822
+ if (!connection)
2823
+ return [];
2824
+ const view = connection.pendingTransactionLayer ?? connection.readLayer;
2825
+ const chain = [];
2826
+ for (let cur = view; cur && cur !== this.baseLayer; cur = cur.getParent()) {
2827
+ if (cur instanceof TransactionLayer)
2828
+ chain.push(cur);
2829
+ }
2830
+ return chain.reverse();
2831
+ }
2260
2832
  /** Consolidates all transaction data into the base layer for schema changes */
2261
2833
  async consolidateToBaseLayer() {
2262
2834
  const lockKey = `MemoryTable.Consolidate:${this.schemaName}.${this._tableName}`;
2263
- const release = await Latches.acquire(lockKey);
2835
+ const release = await this.db.latches.acquire(lockKey);
2264
2836
  try {
2265
2837
  logger.debugLog(`[Consolidate] Acquired lock for ${this._tableName}`);
2266
2838
  // If current committed layer is a transaction layer, we need to merge its data into the base
@@ -2305,9 +2877,21 @@ export class MemoryTableManager {
2305
2877
  // rebuilds the base secondary indexes from the new tree.
2306
2878
  this.baseLayer.rebuildPrimaryTreeFromRows(allRows);
2307
2879
  }
2308
- /** Scans a layer according to the given plan, yielding matching rows. */
2880
+ /**
2881
+ * Sync scan — the hot path (query()/internal maintenance) avoids the async hop.
2882
+ * The backing BTree (inheritree) and all per-row filter/early-term logic are
2883
+ * fully synchronous, so no async boundary belongs here.
2884
+ */
2885
+ scanLayerSync(layer, plan) {
2886
+ return scanLayerImpl(layer, plan);
2887
+ }
2888
+ /**
2889
+ * Async adapter for external `AsyncIterable<Row>` callers (tests,
2890
+ * `module.scanEffective`, the backing-host). Retained deliberately — do not
2891
+ * delete thinking it is dead; delegates to {@link scanLayerSync}.
2892
+ */
2309
2893
  async *scanLayer(layer, plan) {
2310
- yield* scanLayerImpl(layer, plan);
2894
+ yield* this.scanLayerSync(layer, plan);
2311
2895
  }
2312
2896
  }
2313
2897
  //# sourceMappingURL=manager.js.map