@quereus/quereus 4.5.0 → 4.7.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 (818) hide show
  1. package/README.md +5 -4
  2. package/dist/src/common/errors.d.ts +17 -0
  3. package/dist/src/common/errors.d.ts.map +1 -1
  4. package/dist/src/common/errors.js +21 -0
  5. package/dist/src/common/errors.js.map +1 -1
  6. package/dist/src/core/database-assertions.d.ts +4 -3
  7. package/dist/src/core/database-assertions.d.ts.map +1 -1
  8. package/dist/src/core/database-assertions.js +44 -14
  9. package/dist/src/core/database-assertions.js.map +1 -1
  10. package/dist/src/core/database-events.d.ts +161 -1
  11. package/dist/src/core/database-events.d.ts.map +1 -1
  12. package/dist/src/core/database-events.js +307 -5
  13. package/dist/src/core/database-events.js.map +1 -1
  14. package/dist/src/core/database-internal.d.ts +5 -2
  15. package/dist/src/core/database-internal.d.ts.map +1 -1
  16. package/dist/src/core/database-materialized-views-plan-builders.d.ts.map +1 -1
  17. package/dist/src/core/database-materialized-views-plan-builders.js +33 -4
  18. package/dist/src/core/database-materialized-views-plan-builders.js.map +1 -1
  19. package/dist/src/core/database-materialized-views-plans.d.ts +12 -2
  20. package/dist/src/core/database-materialized-views-plans.d.ts.map +1 -1
  21. package/dist/src/core/database-materialized-views.d.ts +46 -0
  22. package/dist/src/core/database-materialized-views.d.ts.map +1 -1
  23. package/dist/src/core/database-materialized-views.js +75 -4
  24. package/dist/src/core/database-materialized-views.js.map +1 -1
  25. package/dist/src/core/database-transaction.d.ts +9 -0
  26. package/dist/src/core/database-transaction.d.ts.map +1 -1
  27. package/dist/src/core/database-transaction.js +9 -0
  28. package/dist/src/core/database-transaction.js.map +1 -1
  29. package/dist/src/core/database.d.ts +16 -2
  30. package/dist/src/core/database.d.ts.map +1 -1
  31. package/dist/src/core/database.js +56 -15
  32. package/dist/src/core/database.js.map +1 -1
  33. package/dist/src/core/derived-row-validator.d.ts.map +1 -1
  34. package/dist/src/core/derived-row-validator.js +7 -1
  35. package/dist/src/core/derived-row-validator.js.map +1 -1
  36. package/dist/src/core/statement.d.ts.map +1 -1
  37. package/dist/src/core/statement.js +15 -5
  38. package/dist/src/core/statement.js.map +1 -1
  39. package/dist/src/emit/ast-stringify.d.ts +18 -2
  40. package/dist/src/emit/ast-stringify.d.ts.map +1 -1
  41. package/dist/src/emit/ast-stringify.js +22 -4
  42. package/dist/src/emit/ast-stringify.js.map +1 -1
  43. package/dist/src/func/builtins/aggregate.js +11 -11
  44. package/dist/src/func/builtins/aggregate.js.map +1 -1
  45. package/dist/src/func/builtins/builtin-window-functions.d.ts.map +1 -1
  46. package/dist/src/func/builtins/builtin-window-functions.js +15 -85
  47. package/dist/src/func/builtins/builtin-window-functions.js.map +1 -1
  48. package/dist/src/func/builtins/conversion.d.ts.map +1 -1
  49. package/dist/src/func/builtins/conversion.js +10 -9
  50. package/dist/src/func/builtins/conversion.js.map +1 -1
  51. package/dist/src/func/builtins/datetime.d.ts.map +1 -1
  52. package/dist/src/func/builtins/datetime.js +28 -10
  53. package/dist/src/func/builtins/datetime.js.map +1 -1
  54. package/dist/src/func/builtins/explain.d.ts.map +1 -1
  55. package/dist/src/func/builtins/explain.js +19 -5
  56. package/dist/src/func/builtins/explain.js.map +1 -1
  57. package/dist/src/func/builtins/json.d.ts.map +1 -1
  58. package/dist/src/func/builtins/json.js +23 -17
  59. package/dist/src/func/builtins/json.js.map +1 -1
  60. package/dist/src/func/builtins/mutation.js +2 -2
  61. package/dist/src/func/builtins/mutation.js.map +1 -1
  62. package/dist/src/func/builtins/return-types.d.ts +327 -0
  63. package/dist/src/func/builtins/return-types.d.ts.map +1 -0
  64. package/dist/src/func/builtins/return-types.js +43 -0
  65. package/dist/src/func/builtins/return-types.js.map +1 -0
  66. package/dist/src/func/builtins/scalar.d.ts.map +1 -1
  67. package/dist/src/func/builtins/scalar.js +150 -79
  68. package/dist/src/func/builtins/scalar.js.map +1 -1
  69. package/dist/src/func/builtins/schema.d.ts.map +1 -1
  70. package/dist/src/func/builtins/schema.js +43 -8
  71. package/dist/src/func/builtins/schema.js.map +1 -1
  72. package/dist/src/func/builtins/string.d.ts.map +1 -1
  73. package/dist/src/func/builtins/string.js +4 -2
  74. package/dist/src/func/builtins/string.js.map +1 -1
  75. package/dist/src/func/builtins/timespan.d.ts +3 -0
  76. package/dist/src/func/builtins/timespan.d.ts.map +1 -1
  77. package/dist/src/func/builtins/timespan.js +15 -11
  78. package/dist/src/func/builtins/timespan.js.map +1 -1
  79. package/dist/src/func/registration.d.ts +35 -1
  80. package/dist/src/func/registration.d.ts.map +1 -1
  81. package/dist/src/func/registration.js +235 -41
  82. package/dist/src/func/registration.js.map +1 -1
  83. package/dist/src/index.d.ts +14 -7
  84. package/dist/src/index.d.ts.map +1 -1
  85. package/dist/src/index.js +15 -6
  86. package/dist/src/index.js.map +1 -1
  87. package/dist/src/parser/ast.d.ts +58 -1
  88. package/dist/src/parser/ast.d.ts.map +1 -1
  89. package/dist/src/parser/parser.d.ts +46 -0
  90. package/dist/src/parser/parser.d.ts.map +1 -1
  91. package/dist/src/parser/parser.js +161 -45
  92. package/dist/src/parser/parser.js.map +1 -1
  93. package/dist/src/parser/utils.d.ts +13 -1
  94. package/dist/src/parser/utils.d.ts.map +1 -1
  95. package/dist/src/parser/utils.js +14 -0
  96. package/dist/src/parser/utils.js.map +1 -1
  97. package/dist/src/planner/analysis/assertion-classifier.d.ts.map +1 -1
  98. package/dist/src/planner/analysis/assertion-classifier.js +7 -2
  99. package/dist/src/planner/analysis/assertion-classifier.js.map +1 -1
  100. package/dist/src/planner/analysis/assertion-hoist-cache.d.ts.map +1 -1
  101. package/dist/src/planner/analysis/assertion-hoist-cache.js +5 -0
  102. package/dist/src/planner/analysis/assertion-hoist-cache.js.map +1 -1
  103. package/dist/src/planner/analysis/change-scope.d.ts +11 -3
  104. package/dist/src/planner/analysis/change-scope.d.ts.map +1 -1
  105. package/dist/src/planner/analysis/change-scope.js +5 -4
  106. package/dist/src/planner/analysis/change-scope.js.map +1 -1
  107. package/dist/src/planner/analysis/check-extraction.d.ts.map +1 -1
  108. package/dist/src/planner/analysis/check-extraction.js +37 -4
  109. package/dist/src/planner/analysis/check-extraction.js.map +1 -1
  110. package/dist/src/planner/analysis/comparison-collation.d.ts +20 -22
  111. package/dist/src/planner/analysis/comparison-collation.d.ts.map +1 -1
  112. package/dist/src/planner/analysis/comparison-collation.js +29 -26
  113. package/dist/src/planner/analysis/comparison-collation.js.map +1 -1
  114. package/dist/src/planner/analysis/constraint-extractor.d.ts +0 -7
  115. package/dist/src/planner/analysis/constraint-extractor.d.ts.map +1 -1
  116. package/dist/src/planner/analysis/constraint-extractor.js +59 -59
  117. package/dist/src/planner/analysis/constraint-extractor.js.map +1 -1
  118. package/dist/src/planner/analysis/coverage-prover.d.ts.map +1 -1
  119. package/dist/src/planner/analysis/coverage-prover.js +13 -5
  120. package/dist/src/planner/analysis/coverage-prover.js.map +1 -1
  121. package/dist/src/planner/analysis/equi-correlation.d.ts +6 -1
  122. package/dist/src/planner/analysis/equi-correlation.d.ts.map +1 -1
  123. package/dist/src/planner/analysis/equi-correlation.js +8 -1
  124. package/dist/src/planner/analysis/equi-correlation.js.map +1 -1
  125. package/dist/src/planner/analysis/predicate-dependencies.d.ts +34 -0
  126. package/dist/src/planner/analysis/predicate-dependencies.d.ts.map +1 -0
  127. package/dist/src/planner/analysis/predicate-dependencies.js +60 -0
  128. package/dist/src/planner/analysis/predicate-dependencies.js.map +1 -0
  129. package/dist/src/planner/analysis/query-rewrite-matcher.d.ts +1 -1
  130. package/dist/src/planner/analysis/query-rewrite-matcher.d.ts.map +1 -1
  131. package/dist/src/planner/analysis/query-rewrite-matcher.js +0 -26
  132. package/dist/src/planner/analysis/query-rewrite-matcher.js.map +1 -1
  133. package/dist/src/planner/building/alter-table.d.ts.map +1 -1
  134. package/dist/src/planner/building/alter-table.js +117 -43
  135. package/dist/src/planner/building/alter-table.js.map +1 -1
  136. package/dist/src/planner/building/coercion.d.ts +21 -45
  137. package/dist/src/planner/building/coercion.d.ts.map +1 -1
  138. package/dist/src/planner/building/coercion.js +42 -91
  139. package/dist/src/planner/building/coercion.js.map +1 -1
  140. package/dist/src/planner/building/constraint-builder.d.ts.map +1 -1
  141. package/dist/src/planner/building/constraint-builder.js +9 -5
  142. package/dist/src/planner/building/constraint-builder.js.map +1 -1
  143. package/dist/src/planner/building/create-assertion.d.ts.map +1 -1
  144. package/dist/src/planner/building/create-assertion.js +72 -1
  145. package/dist/src/planner/building/create-assertion.js.map +1 -1
  146. package/dist/src/planner/building/create-view.d.ts +6 -1
  147. package/dist/src/planner/building/create-view.d.ts.map +1 -1
  148. package/dist/src/planner/building/create-view.js +12 -3
  149. package/dist/src/planner/building/create-view.js.map +1 -1
  150. package/dist/src/planner/building/ddl.d.ts.map +1 -1
  151. package/dist/src/planner/building/ddl.js +6 -2
  152. package/dist/src/planner/building/ddl.js.map +1 -1
  153. package/dist/src/planner/building/delete.d.ts.map +1 -1
  154. package/dist/src/planner/building/delete.js +23 -10
  155. package/dist/src/planner/building/delete.js.map +1 -1
  156. package/dist/src/planner/building/dml-target.d.ts.map +1 -1
  157. package/dist/src/planner/building/dml-target.js +4 -0
  158. package/dist/src/planner/building/dml-target.js.map +1 -1
  159. package/dist/src/planner/building/drop-assertion.d.ts.map +1 -1
  160. package/dist/src/planner/building/drop-assertion.js +3 -1
  161. package/dist/src/planner/building/drop-assertion.js.map +1 -1
  162. package/dist/src/planner/building/expression.d.ts +17 -0
  163. package/dist/src/planner/building/expression.d.ts.map +1 -1
  164. package/dist/src/planner/building/expression.js +28 -17
  165. package/dist/src/planner/building/expression.js.map +1 -1
  166. package/dist/src/planner/building/foreign-key-builder.d.ts.map +1 -1
  167. package/dist/src/planner/building/foreign-key-builder.js +7 -5
  168. package/dist/src/planner/building/foreign-key-builder.js.map +1 -1
  169. package/dist/src/planner/building/function-call.d.ts +35 -0
  170. package/dist/src/planner/building/function-call.d.ts.map +1 -1
  171. package/dist/src/planner/building/function-call.js +60 -42
  172. package/dist/src/planner/building/function-call.js.map +1 -1
  173. package/dist/src/planner/building/insert.d.ts.map +1 -1
  174. package/dist/src/planner/building/insert.js +185 -48
  175. package/dist/src/planner/building/insert.js.map +1 -1
  176. package/dist/src/planner/building/materialized-view.d.ts.map +1 -1
  177. package/dist/src/planner/building/materialized-view.js +3 -1
  178. package/dist/src/planner/building/materialized-view.js.map +1 -1
  179. package/dist/src/planner/building/schema-authored-context.d.ts +69 -0
  180. package/dist/src/planner/building/schema-authored-context.d.ts.map +1 -0
  181. package/dist/src/planner/building/schema-authored-context.js +75 -0
  182. package/dist/src/planner/building/schema-authored-context.js.map +1 -0
  183. package/dist/src/planner/building/schema-resolution.d.ts.map +1 -1
  184. package/dist/src/planner/building/schema-resolution.js +7 -4
  185. package/dist/src/planner/building/schema-resolution.js.map +1 -1
  186. package/dist/src/planner/building/select-aggregates.d.ts +188 -3
  187. package/dist/src/planner/building/select-aggregates.d.ts.map +1 -1
  188. package/dist/src/planner/building/select-aggregates.js +449 -65
  189. package/dist/src/planner/building/select-aggregates.js.map +1 -1
  190. package/dist/src/planner/building/select-compound.js +2 -2
  191. package/dist/src/planner/building/select-compound.js.map +1 -1
  192. package/dist/src/planner/building/select-context.d.ts +98 -0
  193. package/dist/src/planner/building/select-context.d.ts.map +1 -1
  194. package/dist/src/planner/building/select-context.js +120 -37
  195. package/dist/src/planner/building/select-context.js.map +1 -1
  196. package/dist/src/planner/building/select-modifiers.d.ts +10 -3
  197. package/dist/src/planner/building/select-modifiers.d.ts.map +1 -1
  198. package/dist/src/planner/building/select-modifiers.js +29 -8
  199. package/dist/src/planner/building/select-modifiers.js.map +1 -1
  200. package/dist/src/planner/building/select-ordinal.d.ts +64 -19
  201. package/dist/src/planner/building/select-ordinal.d.ts.map +1 -1
  202. package/dist/src/planner/building/select-ordinal.js +79 -30
  203. package/dist/src/planner/building/select-ordinal.js.map +1 -1
  204. package/dist/src/planner/building/select-projections.d.ts +1 -1
  205. package/dist/src/planner/building/select-projections.d.ts.map +1 -1
  206. package/dist/src/planner/building/select-projections.js +18 -11
  207. package/dist/src/planner/building/select-projections.js.map +1 -1
  208. package/dist/src/planner/building/select-window.d.ts +13 -3
  209. package/dist/src/planner/building/select-window.d.ts.map +1 -1
  210. package/dist/src/planner/building/select-window.js +142 -37
  211. package/dist/src/planner/building/select-window.js.map +1 -1
  212. package/dist/src/planner/building/select.d.ts +37 -1
  213. package/dist/src/planner/building/select.d.ts.map +1 -1
  214. package/dist/src/planner/building/select.js +240 -109
  215. package/dist/src/planner/building/select.js.map +1 -1
  216. package/dist/src/planner/building/update.d.ts.map +1 -1
  217. package/dist/src/planner/building/update.js +27 -13
  218. package/dist/src/planner/building/update.js.map +1 -1
  219. package/dist/src/planner/building/view-mutation-builder.d.ts +1 -1
  220. package/dist/src/planner/building/view-mutation-builder.d.ts.map +1 -1
  221. package/dist/src/planner/building/view-mutation-builder.js +102 -8
  222. package/dist/src/planner/building/view-mutation-builder.js.map +1 -1
  223. package/dist/src/planner/building/with.d.ts.map +1 -1
  224. package/dist/src/planner/building/with.js +34 -4
  225. package/dist/src/planner/building/with.js.map +1 -1
  226. package/dist/src/planner/cache/correlation-detector.d.ts +15 -0
  227. package/dist/src/planner/cache/correlation-detector.d.ts.map +1 -1
  228. package/dist/src/planner/cache/correlation-detector.js +26 -0
  229. package/dist/src/planner/cache/correlation-detector.js.map +1 -1
  230. package/dist/src/planner/cache/materialization-advisory.d.ts +7 -0
  231. package/dist/src/planner/cache/materialization-advisory.d.ts.map +1 -1
  232. package/dist/src/planner/cache/materialization-advisory.js +12 -3
  233. package/dist/src/planner/cache/materialization-advisory.js.map +1 -1
  234. package/dist/src/planner/cost/conjunct-cost.d.ts +40 -0
  235. package/dist/src/planner/cost/conjunct-cost.d.ts.map +1 -1
  236. package/dist/src/planner/cost/conjunct-cost.js +45 -0
  237. package/dist/src/planner/cost/conjunct-cost.js.map +1 -1
  238. package/dist/src/planner/cost/index.d.ts +10 -0
  239. package/dist/src/planner/cost/index.d.ts.map +1 -1
  240. package/dist/src/planner/cost/index.js +15 -0
  241. package/dist/src/planner/cost/index.js.map +1 -1
  242. package/dist/src/planner/framework/characteristics.d.ts +9 -0
  243. package/dist/src/planner/framework/characteristics.d.ts.map +1 -1
  244. package/dist/src/planner/framework/characteristics.js.map +1 -1
  245. package/dist/src/planner/framework/pass.d.ts +2 -0
  246. package/dist/src/planner/framework/pass.d.ts.map +1 -1
  247. package/dist/src/planner/framework/pass.js +15 -0
  248. package/dist/src/planner/framework/pass.js.map +1 -1
  249. package/dist/src/planner/mutation/backward-body.d.ts.map +1 -1
  250. package/dist/src/planner/mutation/backward-body.js +4 -1
  251. package/dist/src/planner/mutation/backward-body.js.map +1 -1
  252. package/dist/src/planner/mutation/body-context.d.ts +23 -0
  253. package/dist/src/planner/mutation/body-context.d.ts.map +1 -0
  254. package/dist/src/planner/mutation/body-context.js +26 -0
  255. package/dist/src/planner/mutation/body-context.js.map +1 -0
  256. package/dist/src/planner/mutation/cte-flatten.js +15 -2
  257. package/dist/src/planner/mutation/cte-flatten.js.map +1 -1
  258. package/dist/src/planner/mutation/decomposition.d.ts +8 -0
  259. package/dist/src/planner/mutation/decomposition.d.ts.map +1 -1
  260. package/dist/src/planner/mutation/decomposition.js +8 -3
  261. package/dist/src/planner/mutation/decomposition.js.map +1 -1
  262. package/dist/src/planner/mutation/lens-enforcement.js +1 -1
  263. package/dist/src/planner/mutation/multi-source.d.ts +7 -0
  264. package/dist/src/planner/mutation/multi-source.d.ts.map +1 -1
  265. package/dist/src/planner/mutation/multi-source.js +5 -0
  266. package/dist/src/planner/mutation/multi-source.js.map +1 -1
  267. package/dist/src/planner/mutation/mutation-diagnostic.d.ts +1 -1
  268. package/dist/src/planner/mutation/mutation-diagnostic.d.ts.map +1 -1
  269. package/dist/src/planner/mutation/mutation-diagnostic.js.map +1 -1
  270. package/dist/src/planner/mutation/scope-transform.d.ts +32 -0
  271. package/dist/src/planner/mutation/scope-transform.d.ts.map +1 -1
  272. package/dist/src/planner/mutation/scope-transform.js +181 -33
  273. package/dist/src/planner/mutation/scope-transform.js.map +1 -1
  274. package/dist/src/planner/mutation/set-op.d.ts.map +1 -1
  275. package/dist/src/planner/mutation/set-op.js +66 -16
  276. package/dist/src/planner/mutation/set-op.js.map +1 -1
  277. package/dist/src/planner/mutation/single-source.d.ts.map +1 -1
  278. package/dist/src/planner/mutation/single-source.js +100 -24
  279. package/dist/src/planner/mutation/single-source.js.map +1 -1
  280. package/dist/src/planner/nodes/add-constraint-node.d.ts +15 -1
  281. package/dist/src/planner/nodes/add-constraint-node.d.ts.map +1 -1
  282. package/dist/src/planner/nodes/add-constraint-node.js +10 -1
  283. package/dist/src/planner/nodes/add-constraint-node.js.map +1 -1
  284. package/dist/src/planner/nodes/aggregate-node.d.ts +15 -0
  285. package/dist/src/planner/nodes/aggregate-node.d.ts.map +1 -1
  286. package/dist/src/planner/nodes/aggregate-node.js +32 -17
  287. package/dist/src/planner/nodes/aggregate-node.js.map +1 -1
  288. package/dist/src/planner/nodes/alias-node.d.ts.map +1 -1
  289. package/dist/src/planner/nodes/alias-node.js +2 -1
  290. package/dist/src/planner/nodes/alias-node.js.map +1 -1
  291. package/dist/src/planner/nodes/alter-table-node.d.ts +51 -10
  292. package/dist/src/planner/nodes/alter-table-node.d.ts.map +1 -1
  293. package/dist/src/planner/nodes/alter-table-node.js +49 -2
  294. package/dist/src/planner/nodes/alter-table-node.js.map +1 -1
  295. package/dist/src/planner/nodes/asof-scan-node.d.ts.map +1 -1
  296. package/dist/src/planner/nodes/asof-scan-node.js +4 -1
  297. package/dist/src/planner/nodes/asof-scan-node.js.map +1 -1
  298. package/dist/src/planner/nodes/asserted-keys-node.d.ts.map +1 -1
  299. package/dist/src/planner/nodes/asserted-keys-node.js +2 -1
  300. package/dist/src/planner/nodes/asserted-keys-node.js.map +1 -1
  301. package/dist/src/planner/nodes/bloom-join-node.d.ts.map +1 -1
  302. package/dist/src/planner/nodes/bloom-join-node.js +8 -3
  303. package/dist/src/planner/nodes/bloom-join-node.js.map +1 -1
  304. package/dist/src/planner/nodes/cache-node.d.ts.map +1 -1
  305. package/dist/src/planner/nodes/cache-node.js +2 -1
  306. package/dist/src/planner/nodes/cache-node.js.map +1 -1
  307. package/dist/src/planner/nodes/constraint-check-node.d.ts.map +1 -1
  308. package/dist/src/planner/nodes/constraint-check-node.js +17 -19
  309. package/dist/src/planner/nodes/constraint-check-node.js.map +1 -1
  310. package/dist/src/planner/nodes/create-assertion-node.d.ts +2 -1
  311. package/dist/src/planner/nodes/create-assertion-node.d.ts.map +1 -1
  312. package/dist/src/planner/nodes/create-assertion-node.js +5 -2
  313. package/dist/src/planner/nodes/create-assertion-node.js.map +1 -1
  314. package/dist/src/planner/nodes/cte-node.d.ts +19 -9
  315. package/dist/src/planner/nodes/cte-node.d.ts.map +1 -1
  316. package/dist/src/planner/nodes/cte-node.js +25 -9
  317. package/dist/src/planner/nodes/cte-node.js.map +1 -1
  318. package/dist/src/planner/nodes/delete-node.d.ts +20 -2
  319. package/dist/src/planner/nodes/delete-node.d.ts.map +1 -1
  320. package/dist/src/planner/nodes/delete-node.js +11 -2
  321. package/dist/src/planner/nodes/delete-node.js.map +1 -1
  322. package/dist/src/planner/nodes/distinct-node.d.ts +6 -0
  323. package/dist/src/planner/nodes/distinct-node.d.ts.map +1 -1
  324. package/dist/src/planner/nodes/distinct-node.js +10 -2
  325. package/dist/src/planner/nodes/distinct-node.js.map +1 -1
  326. package/dist/src/planner/nodes/dml-executor-node.d.ts +58 -1
  327. package/dist/src/planner/nodes/dml-executor-node.d.ts.map +1 -1
  328. package/dist/src/planner/nodes/dml-executor-node.js +107 -15
  329. package/dist/src/planner/nodes/dml-executor-node.js.map +1 -1
  330. package/dist/src/planner/nodes/drop-assertion-node.d.ts +2 -1
  331. package/dist/src/planner/nodes/drop-assertion-node.d.ts.map +1 -1
  332. package/dist/src/planner/nodes/drop-assertion-node.js +5 -2
  333. package/dist/src/planner/nodes/drop-assertion-node.js.map +1 -1
  334. package/dist/src/planner/nodes/eager-prefetch-node.d.ts.map +1 -1
  335. package/dist/src/planner/nodes/eager-prefetch-node.js +2 -1
  336. package/dist/src/planner/nodes/eager-prefetch-node.js.map +1 -1
  337. package/dist/src/planner/nodes/fanout-lookup-join-node.d.ts +5 -0
  338. package/dist/src/planner/nodes/fanout-lookup-join-node.d.ts.map +1 -1
  339. package/dist/src/planner/nodes/fanout-lookup-join-node.js +13 -6
  340. package/dist/src/planner/nodes/fanout-lookup-join-node.js.map +1 -1
  341. package/dist/src/planner/nodes/filter.d.ts.map +1 -1
  342. package/dist/src/planner/nodes/filter.js +18 -5
  343. package/dist/src/planner/nodes/filter.js.map +1 -1
  344. package/dist/src/planner/nodes/hash-aggregate.d.ts +1 -0
  345. package/dist/src/planner/nodes/hash-aggregate.d.ts.map +1 -1
  346. package/dist/src/planner/nodes/hash-aggregate.js +21 -16
  347. package/dist/src/planner/nodes/hash-aggregate.js.map +1 -1
  348. package/dist/src/planner/nodes/insert-node.d.ts +19 -2
  349. package/dist/src/planner/nodes/insert-node.d.ts.map +1 -1
  350. package/dist/src/planner/nodes/insert-node.js +10 -2
  351. package/dist/src/planner/nodes/insert-node.js.map +1 -1
  352. package/dist/src/planner/nodes/join-node.d.ts +20 -1
  353. package/dist/src/planner/nodes/join-node.d.ts.map +1 -1
  354. package/dist/src/planner/nodes/join-node.js +30 -9
  355. package/dist/src/planner/nodes/join-node.js.map +1 -1
  356. package/dist/src/planner/nodes/join-utils.d.ts +21 -0
  357. package/dist/src/planner/nodes/join-utils.d.ts.map +1 -1
  358. package/dist/src/planner/nodes/join-utils.js +26 -0
  359. package/dist/src/planner/nodes/join-utils.js.map +1 -1
  360. package/dist/src/planner/nodes/key-set-semi-join-node.d.ts +42 -10
  361. package/dist/src/planner/nodes/key-set-semi-join-node.d.ts.map +1 -1
  362. package/dist/src/planner/nodes/key-set-semi-join-node.js +90 -17
  363. package/dist/src/planner/nodes/key-set-semi-join-node.js.map +1 -1
  364. package/dist/src/planner/nodes/lens-auxiliary-access-node.d.ts +5 -0
  365. package/dist/src/planner/nodes/lens-auxiliary-access-node.d.ts.map +1 -1
  366. package/dist/src/planner/nodes/lens-auxiliary-access-node.js +2 -1
  367. package/dist/src/planner/nodes/lens-auxiliary-access-node.js.map +1 -1
  368. package/dist/src/planner/nodes/limit-offset.d.ts +6 -0
  369. package/dist/src/planner/nodes/limit-offset.d.ts.map +1 -1
  370. package/dist/src/planner/nodes/limit-offset.js +10 -2
  371. package/dist/src/planner/nodes/limit-offset.js.map +1 -1
  372. package/dist/src/planner/nodes/merge-join-node.d.ts.map +1 -1
  373. package/dist/src/planner/nodes/merge-join-node.js +8 -3
  374. package/dist/src/planner/nodes/merge-join-node.js.map +1 -1
  375. package/dist/src/planner/nodes/ordinal-slice-node.d.ts +5 -0
  376. package/dist/src/planner/nodes/ordinal-slice-node.d.ts.map +1 -1
  377. package/dist/src/planner/nodes/ordinal-slice-node.js +9 -2
  378. package/dist/src/planner/nodes/ordinal-slice-node.js.map +1 -1
  379. package/dist/src/planner/nodes/plan-node.d.ts +29 -0
  380. package/dist/src/planner/nodes/plan-node.d.ts.map +1 -1
  381. package/dist/src/planner/nodes/plan-node.js +12 -0
  382. package/dist/src/planner/nodes/plan-node.js.map +1 -1
  383. package/dist/src/planner/nodes/project-node.d.ts.map +1 -1
  384. package/dist/src/planner/nodes/project-node.js +18 -36
  385. package/dist/src/planner/nodes/project-node.js.map +1 -1
  386. package/dist/src/planner/nodes/reference.d.ts.map +1 -1
  387. package/dist/src/planner/nodes/reference.js +3 -2
  388. package/dist/src/planner/nodes/reference.js.map +1 -1
  389. package/dist/src/planner/nodes/retrieve-node.d.ts +16 -2
  390. package/dist/src/planner/nodes/retrieve-node.d.ts.map +1 -1
  391. package/dist/src/planner/nodes/retrieve-node.js +10 -2
  392. package/dist/src/planner/nodes/retrieve-node.js.map +1 -1
  393. package/dist/src/planner/nodes/returning-node.d.ts.map +1 -1
  394. package/dist/src/planner/nodes/returning-node.js +13 -32
  395. package/dist/src/planner/nodes/returning-node.js.map +1 -1
  396. package/dist/src/planner/nodes/scalar.d.ts.map +1 -1
  397. package/dist/src/planner/nodes/scalar.js +5 -18
  398. package/dist/src/planner/nodes/scalar.js.map +1 -1
  399. package/dist/src/planner/nodes/sort.d.ts.map +1 -1
  400. package/dist/src/planner/nodes/sort.js +3 -1
  401. package/dist/src/planner/nodes/sort.js.map +1 -1
  402. package/dist/src/planner/nodes/stream-aggregate.d.ts +1 -0
  403. package/dist/src/planner/nodes/stream-aggregate.d.ts.map +1 -1
  404. package/dist/src/planner/nodes/stream-aggregate.js +22 -20
  405. package/dist/src/planner/nodes/stream-aggregate.js.map +1 -1
  406. package/dist/src/planner/nodes/table-access-nodes.d.ts +89 -1
  407. package/dist/src/planner/nodes/table-access-nodes.d.ts.map +1 -1
  408. package/dist/src/planner/nodes/table-access-nodes.js +69 -2
  409. package/dist/src/planner/nodes/table-access-nodes.js.map +1 -1
  410. package/dist/src/planner/nodes/update-node.d.ts +19 -2
  411. package/dist/src/planner/nodes/update-node.d.ts.map +1 -1
  412. package/dist/src/planner/nodes/update-node.js +10 -2
  413. package/dist/src/planner/nodes/update-node.js.map +1 -1
  414. package/dist/src/planner/nodes/window-function.d.ts.map +1 -1
  415. package/dist/src/planner/nodes/window-function.js +8 -0
  416. package/dist/src/planner/nodes/window-function.js.map +1 -1
  417. package/dist/src/planner/nodes/window-node.d.ts +1 -1
  418. package/dist/src/planner/nodes/window-node.d.ts.map +1 -1
  419. package/dist/src/planner/nodes/window-node.js +3 -1
  420. package/dist/src/planner/nodes/window-node.js.map +1 -1
  421. package/dist/src/planner/optimizer.d.ts +27 -1
  422. package/dist/src/planner/optimizer.d.ts.map +1 -1
  423. package/dist/src/planner/optimizer.js +130 -10
  424. package/dist/src/planner/optimizer.js.map +1 -1
  425. package/dist/src/planner/planning-context.d.ts +24 -0
  426. package/dist/src/planner/planning-context.d.ts.map +1 -1
  427. package/dist/src/planner/planning-context.js.map +1 -1
  428. package/dist/src/planner/rules/access/rule-key-set-seek.d.ts +78 -20
  429. package/dist/src/planner/rules/access/rule-key-set-seek.d.ts.map +1 -1
  430. package/dist/src/planner/rules/access/rule-key-set-seek.js +296 -135
  431. package/dist/src/planner/rules/access/rule-key-set-seek.js.map +1 -1
  432. package/dist/src/planner/rules/access/rule-monotonic-range-access.d.ts.map +1 -1
  433. package/dist/src/planner/rules/access/rule-monotonic-range-access.js +2 -2
  434. package/dist/src/planner/rules/access/rule-monotonic-range-access.js.map +1 -1
  435. package/dist/src/planner/rules/access/rule-select-access-path.d.ts +30 -1
  436. package/dist/src/planner/rules/access/rule-select-access-path.d.ts.map +1 -1
  437. package/dist/src/planner/rules/access/rule-select-access-path.js +70 -5
  438. package/dist/src/planner/rules/access/rule-select-access-path.js.map +1 -1
  439. package/dist/src/planner/rules/aggregate/rule-groupby-fd-simplification.d.ts +7 -4
  440. package/dist/src/planner/rules/aggregate/rule-groupby-fd-simplification.d.ts.map +1 -1
  441. package/dist/src/planner/rules/aggregate/rule-groupby-fd-simplification.js +39 -5
  442. package/dist/src/planner/rules/aggregate/rule-groupby-fd-simplification.js.map +1 -1
  443. package/dist/src/planner/rules/cache/rule-cte-optimization.d.ts.map +1 -1
  444. package/dist/src/planner/rules/cache/rule-cte-optimization.js +15 -2
  445. package/dist/src/planner/rules/cache/rule-cte-optimization.js.map +1 -1
  446. package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.js +10 -3
  447. package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.js.map +1 -1
  448. package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.d.ts.map +1 -1
  449. package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.js +6 -4
  450. package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.js.map +1 -1
  451. package/dist/src/planner/rules/join/equi-pair-extractor.d.ts +5 -31
  452. package/dist/src/planner/rules/join/equi-pair-extractor.d.ts.map +1 -1
  453. package/dist/src/planner/rules/join/equi-pair-extractor.js +4 -44
  454. package/dist/src/planner/rules/join/equi-pair-extractor.js.map +1 -1
  455. package/dist/src/planner/rules/join/index-nested-loop.d.ts +49 -0
  456. package/dist/src/planner/rules/join/index-nested-loop.d.ts.map +1 -0
  457. package/dist/src/planner/rules/join/index-nested-loop.js +291 -0
  458. package/dist/src/planner/rules/join/index-nested-loop.js.map +1 -0
  459. package/dist/src/planner/rules/join/rule-fanout-batched-outer.js +8 -8
  460. package/dist/src/planner/rules/join/rule-fanout-lookup-join.d.ts +4 -0
  461. package/dist/src/planner/rules/join/rule-fanout-lookup-join.d.ts.map +1 -1
  462. package/dist/src/planner/rules/join/rule-fanout-lookup-join.js +50 -15
  463. package/dist/src/planner/rules/join/rule-fanout-lookup-join.js.map +1 -1
  464. package/dist/src/planner/rules/join/rule-join-elimination.d.ts +6 -0
  465. package/dist/src/planner/rules/join/rule-join-elimination.d.ts.map +1 -1
  466. package/dist/src/planner/rules/join/rule-join-elimination.js +25 -9
  467. package/dist/src/planner/rules/join/rule-join-elimination.js.map +1 -1
  468. package/dist/src/planner/rules/join/rule-join-key-inference.d.ts +7 -0
  469. package/dist/src/planner/rules/join/rule-join-key-inference.d.ts.map +1 -1
  470. package/dist/src/planner/rules/join/rule-join-key-inference.js +23 -11
  471. package/dist/src/planner/rules/join/rule-join-key-inference.js.map +1 -1
  472. package/dist/src/planner/rules/join/rule-join-physical-selection.d.ts +10 -4
  473. package/dist/src/planner/rules/join/rule-join-physical-selection.d.ts.map +1 -1
  474. package/dist/src/planner/rules/join/rule-join-physical-selection.js +115 -29
  475. package/dist/src/planner/rules/join/rule-join-physical-selection.js.map +1 -1
  476. package/dist/src/planner/rules/join/rule-monotonic-merge-join.d.ts +2 -0
  477. package/dist/src/planner/rules/join/rule-monotonic-merge-join.d.ts.map +1 -1
  478. package/dist/src/planner/rules/join/rule-monotonic-merge-join.js +18 -4
  479. package/dist/src/planner/rules/join/rule-monotonic-merge-join.js.map +1 -1
  480. package/dist/src/planner/rules/predicate/rule-aggregate-predicate-pushdown.d.ts +2 -2
  481. package/dist/src/planner/rules/predicate/rule-aggregate-predicate-pushdown.d.ts.map +1 -1
  482. package/dist/src/planner/rules/predicate/rule-aggregate-predicate-pushdown.js +19 -22
  483. package/dist/src/planner/rules/predicate/rule-aggregate-predicate-pushdown.js.map +1 -1
  484. package/dist/src/planner/rules/predicate/rule-filter-conjunct-ordering.d.ts +21 -8
  485. package/dist/src/planner/rules/predicate/rule-filter-conjunct-ordering.d.ts.map +1 -1
  486. package/dist/src/planner/rules/predicate/rule-filter-conjunct-ordering.js +70 -14
  487. package/dist/src/planner/rules/predicate/rule-filter-conjunct-ordering.js.map +1 -1
  488. package/dist/src/planner/rules/predicate/rule-filter-selectivity.d.ts +56 -17
  489. package/dist/src/planner/rules/predicate/rule-filter-selectivity.d.ts.map +1 -1
  490. package/dist/src/planner/rules/predicate/rule-filter-selectivity.js +103 -154
  491. package/dist/src/planner/rules/predicate/rule-filter-selectivity.js.map +1 -1
  492. package/dist/src/planner/rules/predicate/rule-join-predicate-pushdown.d.ts +76 -0
  493. package/dist/src/planner/rules/predicate/rule-join-predicate-pushdown.d.ts.map +1 -0
  494. package/dist/src/planner/rules/predicate/rule-join-predicate-pushdown.js +208 -0
  495. package/dist/src/planner/rules/predicate/rule-join-predicate-pushdown.js.map +1 -0
  496. package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.d.ts +14 -11
  497. package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.d.ts.map +1 -1
  498. package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.js +21 -85
  499. package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.js.map +1 -1
  500. package/dist/src/planner/rules/predicate/rule-predicate-pushdown.d.ts +7 -1
  501. package/dist/src/planner/rules/predicate/rule-predicate-pushdown.d.ts.map +1 -1
  502. package/dist/src/planner/rules/predicate/rule-predicate-pushdown.js +18 -22
  503. package/dist/src/planner/rules/predicate/rule-predicate-pushdown.js.map +1 -1
  504. package/dist/src/planner/rules/shared/access-leaf.d.ts +52 -0
  505. package/dist/src/planner/rules/shared/access-leaf.d.ts.map +1 -0
  506. package/dist/src/planner/rules/shared/access-leaf.js +95 -0
  507. package/dist/src/planner/rules/shared/access-leaf.js.map +1 -0
  508. package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.d.ts.map +1 -1
  509. package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.js +17 -7
  510. package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.js.map +1 -1
  511. package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.d.ts +3 -1
  512. package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.d.ts.map +1 -1
  513. package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.js +26 -9
  514. package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.js.map +1 -1
  515. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.d.ts.map +1 -1
  516. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js +69 -11
  517. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js.map +1 -1
  518. package/dist/src/planner/rules/window/rule-monotonic-window.d.ts +17 -7
  519. package/dist/src/planner/rules/window/rule-monotonic-window.d.ts.map +1 -1
  520. package/dist/src/planner/rules/window/rule-monotonic-window.js +124 -87
  521. package/dist/src/planner/rules/window/rule-monotonic-window.js.map +1 -1
  522. package/dist/src/planner/scopes/aliased.d.ts.map +1 -1
  523. package/dist/src/planner/scopes/aliased.js +6 -0
  524. package/dist/src/planner/scopes/aliased.js.map +1 -1
  525. package/dist/src/planner/stats/catalog-stats.d.ts +44 -13
  526. package/dist/src/planner/stats/catalog-stats.d.ts.map +1 -1
  527. package/dist/src/planner/stats/catalog-stats.js +137 -61
  528. package/dist/src/planner/stats/catalog-stats.js.map +1 -1
  529. package/dist/src/planner/stats/conjunct-selectivity.d.ts +48 -0
  530. package/dist/src/planner/stats/conjunct-selectivity.d.ts.map +1 -0
  531. package/dist/src/planner/stats/conjunct-selectivity.js +168 -0
  532. package/dist/src/planner/stats/conjunct-selectivity.js.map +1 -0
  533. package/dist/src/planner/stats/index.d.ts +22 -3
  534. package/dist/src/planner/stats/index.d.ts.map +1 -1
  535. package/dist/src/planner/stats/index.js.map +1 -1
  536. package/dist/src/planner/stats/table-cardinality.d.ts +28 -0
  537. package/dist/src/planner/stats/table-cardinality.d.ts.map +1 -0
  538. package/dist/src/planner/stats/table-cardinality.js +29 -0
  539. package/dist/src/planner/stats/table-cardinality.js.map +1 -0
  540. package/dist/src/planner/stored-body-context.d.ts +57 -0
  541. package/dist/src/planner/stored-body-context.d.ts.map +1 -0
  542. package/dist/src/planner/stored-body-context.js +64 -0
  543. package/dist/src/planner/stored-body-context.js.map +1 -0
  544. package/dist/src/planner/util/column-origins.d.ts +29 -8
  545. package/dist/src/planner/util/column-origins.d.ts.map +1 -1
  546. package/dist/src/planner/util/column-origins.js +74 -14
  547. package/dist/src/planner/util/column-origins.js.map +1 -1
  548. package/dist/src/planner/util/fd-utils.d.ts +32 -8
  549. package/dist/src/planner/util/fd-utils.d.ts.map +1 -1
  550. package/dist/src/planner/util/fd-utils.js +46 -9
  551. package/dist/src/planner/util/fd-utils.js.map +1 -1
  552. package/dist/src/planner/util/ind-utils.d.ts +66 -19
  553. package/dist/src/planner/util/ind-utils.d.ts.map +1 -1
  554. package/dist/src/planner/util/ind-utils.js +91 -21
  555. package/dist/src/planner/util/ind-utils.js.map +1 -1
  556. package/dist/src/planner/util/key-utils.d.ts +36 -3
  557. package/dist/src/planner/util/key-utils.d.ts.map +1 -1
  558. package/dist/src/planner/util/key-utils.js +57 -7
  559. package/dist/src/planner/util/key-utils.js.map +1 -1
  560. package/dist/src/planner/util/output-names.d.ts +12 -0
  561. package/dist/src/planner/util/output-names.d.ts.map +1 -0
  562. package/dist/src/planner/util/output-names.js +20 -0
  563. package/dist/src/planner/util/output-names.js.map +1 -0
  564. package/dist/src/planner/util/row-estimates.d.ts +39 -0
  565. package/dist/src/planner/util/row-estimates.d.ts.map +1 -0
  566. package/dist/src/planner/util/row-estimates.js +68 -0
  567. package/dist/src/planner/util/row-estimates.js.map +1 -0
  568. package/dist/src/planner/util/row-population.d.ts +42 -0
  569. package/dist/src/planner/util/row-population.d.ts.map +1 -0
  570. package/dist/src/planner/util/row-population.js +71 -0
  571. package/dist/src/planner/util/row-population.js.map +1 -0
  572. package/dist/src/runtime/deferred-constraint-queue.d.ts.map +1 -1
  573. package/dist/src/runtime/deferred-constraint-queue.js +3 -2
  574. package/dist/src/runtime/deferred-constraint-queue.js.map +1 -1
  575. package/dist/src/runtime/emit/add-constraint.d.ts.map +1 -1
  576. package/dist/src/runtime/emit/add-constraint.js +60 -6
  577. package/dist/src/runtime/emit/add-constraint.js.map +1 -1
  578. package/dist/src/runtime/emit/aggregate.d.ts.map +1 -1
  579. package/dist/src/runtime/emit/aggregate.js +4 -4
  580. package/dist/src/runtime/emit/aggregate.js.map +1 -1
  581. package/dist/src/runtime/emit/alter-schema-event.d.ts +97 -0
  582. package/dist/src/runtime/emit/alter-schema-event.d.ts.map +1 -0
  583. package/dist/src/runtime/emit/alter-schema-event.js +87 -0
  584. package/dist/src/runtime/emit/alter-schema-event.js.map +1 -0
  585. package/dist/src/runtime/emit/alter-table.d.ts.map +1 -1
  586. package/dist/src/runtime/emit/alter-table.js +582 -236
  587. package/dist/src/runtime/emit/alter-table.js.map +1 -1
  588. package/dist/src/runtime/emit/analyze.d.ts.map +1 -1
  589. package/dist/src/runtime/emit/analyze.js +50 -7
  590. package/dist/src/runtime/emit/analyze.js.map +1 -1
  591. package/dist/src/runtime/emit/assertion-drop-guard.d.ts +37 -0
  592. package/dist/src/runtime/emit/assertion-drop-guard.d.ts.map +1 -0
  593. package/dist/src/runtime/emit/assertion-drop-guard.js +59 -0
  594. package/dist/src/runtime/emit/assertion-drop-guard.js.map +1 -0
  595. package/dist/src/runtime/emit/assertion-rename-helpers.d.ts +33 -0
  596. package/dist/src/runtime/emit/assertion-rename-helpers.d.ts.map +1 -0
  597. package/dist/src/runtime/emit/assertion-rename-helpers.js +124 -0
  598. package/dist/src/runtime/emit/assertion-rename-helpers.js.map +1 -0
  599. package/dist/src/runtime/emit/cast.d.ts.map +1 -1
  600. package/dist/src/runtime/emit/cast.js +4 -19
  601. package/dist/src/runtime/emit/cast.js.map +1 -1
  602. package/dist/src/runtime/emit/constraint-check.d.ts.map +1 -1
  603. package/dist/src/runtime/emit/constraint-check.js +10 -227
  604. package/dist/src/runtime/emit/constraint-check.js.map +1 -1
  605. package/dist/src/runtime/emit/create-assertion.d.ts.map +1 -1
  606. package/dist/src/runtime/emit/create-assertion.js +31 -14
  607. package/dist/src/runtime/emit/create-assertion.js.map +1 -1
  608. package/dist/src/runtime/emit/cte.d.ts.map +1 -1
  609. package/dist/src/runtime/emit/cte.js +11 -6
  610. package/dist/src/runtime/emit/cte.js.map +1 -1
  611. package/dist/src/runtime/emit/dml-executor.d.ts.map +1 -1
  612. package/dist/src/runtime/emit/dml-executor.js +233 -28
  613. package/dist/src/runtime/emit/dml-executor.js.map +1 -1
  614. package/dist/src/runtime/emit/drop-assertion.js +8 -8
  615. package/dist/src/runtime/emit/drop-assertion.js.map +1 -1
  616. package/dist/src/runtime/emit/drop-column-guards.d.ts +151 -0
  617. package/dist/src/runtime/emit/drop-column-guards.d.ts.map +1 -0
  618. package/dist/src/runtime/emit/drop-column-guards.js +230 -0
  619. package/dist/src/runtime/emit/drop-column-guards.js.map +1 -0
  620. package/dist/src/runtime/emit/drop-index.d.ts.map +1 -1
  621. package/dist/src/runtime/emit/drop-index.js +4 -3
  622. package/dist/src/runtime/emit/drop-index.js.map +1 -1
  623. package/dist/src/runtime/emit/drop-table.d.ts.map +1 -1
  624. package/dist/src/runtime/emit/drop-table.js +6 -0
  625. package/dist/src/runtime/emit/drop-table.js.map +1 -1
  626. package/dist/src/runtime/emit/drop-view.d.ts.map +1 -1
  627. package/dist/src/runtime/emit/drop-view.js +4 -0
  628. package/dist/src/runtime/emit/drop-view.js.map +1 -1
  629. package/dist/src/runtime/emit/hash-aggregate.d.ts.map +1 -1
  630. package/dist/src/runtime/emit/hash-aggregate.js +2 -2
  631. package/dist/src/runtime/emit/hash-aggregate.js.map +1 -1
  632. package/dist/src/runtime/emit/join.d.ts.map +1 -1
  633. package/dist/src/runtime/emit/join.js +8 -67
  634. package/dist/src/runtime/emit/join.js.map +1 -1
  635. package/dist/src/runtime/emit/key-set-semi-join.d.ts.map +1 -1
  636. package/dist/src/runtime/emit/key-set-semi-join.js +11 -3
  637. package/dist/src/runtime/emit/key-set-semi-join.js.map +1 -1
  638. package/dist/src/runtime/emit/materialized-view-helpers.d.ts +4 -4
  639. package/dist/src/runtime/emit/materialized-view-helpers.d.ts.map +1 -1
  640. package/dist/src/runtime/emit/materialized-view-helpers.js +34 -22
  641. package/dist/src/runtime/emit/materialized-view-helpers.js.map +1 -1
  642. package/dist/src/runtime/emit/materialized-view.d.ts.map +1 -1
  643. package/dist/src/runtime/emit/materialized-view.js +7 -2
  644. package/dist/src/runtime/emit/materialized-view.js.map +1 -1
  645. package/dist/src/runtime/emit/operand-comparator.d.ts +30 -0
  646. package/dist/src/runtime/emit/operand-comparator.d.ts.map +1 -1
  647. package/dist/src/runtime/emit/operand-comparator.js +34 -0
  648. package/dist/src/runtime/emit/operand-comparator.js.map +1 -1
  649. package/dist/src/runtime/emit/recursive-cte.d.ts.map +1 -1
  650. package/dist/src/runtime/emit/recursive-cte.js +4 -5
  651. package/dist/src/runtime/emit/recursive-cte.js.map +1 -1
  652. package/dist/src/runtime/emit/schema-declarative.d.ts.map +1 -1
  653. package/dist/src/runtime/emit/schema-declarative.js +30 -0
  654. package/dist/src/runtime/emit/schema-declarative.js.map +1 -1
  655. package/dist/src/runtime/emit/subquery.d.ts.map +1 -1
  656. package/dist/src/runtime/emit/subquery.js +153 -52
  657. package/dist/src/runtime/emit/subquery.js.map +1 -1
  658. package/dist/src/runtime/emit/update.d.ts.map +1 -1
  659. package/dist/src/runtime/emit/update.js +18 -6
  660. package/dist/src/runtime/emit/update.js.map +1 -1
  661. package/dist/src/runtime/emit/window.js +36 -23
  662. package/dist/src/runtime/emit/window.js.map +1 -1
  663. package/dist/src/runtime/row-constraints.d.ts +85 -0
  664. package/dist/src/runtime/row-constraints.d.ts.map +1 -0
  665. package/dist/src/runtime/row-constraints.js +239 -0
  666. package/dist/src/runtime/row-constraints.js.map +1 -0
  667. package/dist/src/runtime/types.d.ts +8 -11
  668. package/dist/src/runtime/types.d.ts.map +1 -1
  669. package/dist/src/runtime/types.js.map +1 -1
  670. package/dist/src/schema/assertion.d.ts +14 -1
  671. package/dist/src/schema/assertion.d.ts.map +1 -1
  672. package/dist/src/schema/assertion.js +14 -1
  673. package/dist/src/schema/assertion.js.map +1 -1
  674. package/dist/src/schema/catalog-persistability.d.ts +19 -16
  675. package/dist/src/schema/catalog-persistability.d.ts.map +1 -1
  676. package/dist/src/schema/catalog-persistability.js +92 -20
  677. package/dist/src/schema/catalog-persistability.js.map +1 -1
  678. package/dist/src/schema/catalog.d.ts +73 -2
  679. package/dist/src/schema/catalog.d.ts.map +1 -1
  680. package/dist/src/schema/catalog.js +220 -39
  681. package/dist/src/schema/catalog.js.map +1 -1
  682. package/dist/src/schema/column-source-resolver.d.ts +18 -0
  683. package/dist/src/schema/column-source-resolver.d.ts.map +1 -0
  684. package/dist/src/schema/column-source-resolver.js +22 -0
  685. package/dist/src/schema/column-source-resolver.js.map +1 -0
  686. package/dist/src/schema/column.d.ts +26 -3
  687. package/dist/src/schema/column.d.ts.map +1 -1
  688. package/dist/src/schema/column.js.map +1 -1
  689. package/dist/src/schema/constraint-builder.d.ts.map +1 -1
  690. package/dist/src/schema/constraint-builder.js +7 -1
  691. package/dist/src/schema/constraint-builder.js.map +1 -1
  692. package/dist/src/schema/ddl-generator.d.ts.map +1 -1
  693. package/dist/src/schema/ddl-generator.js +27 -6
  694. package/dist/src/schema/ddl-generator.js.map +1 -1
  695. package/dist/src/schema/function.d.ts +32 -1
  696. package/dist/src/schema/function.d.ts.map +1 -1
  697. package/dist/src/schema/function.js +10 -2
  698. package/dist/src/schema/function.js.map +1 -1
  699. package/dist/src/schema/lens-compiler.d.ts.map +1 -1
  700. package/dist/src/schema/lens-compiler.js +203 -51
  701. package/dist/src/schema/lens-compiler.js.map +1 -1
  702. package/dist/src/schema/lens-prover.d.ts +2 -3
  703. package/dist/src/schema/lens-prover.d.ts.map +1 -1
  704. package/dist/src/schema/lens-prover.js +19 -11
  705. package/dist/src/schema/lens-prover.js.map +1 -1
  706. package/dist/src/schema/manager.d.ts +115 -20
  707. package/dist/src/schema/manager.d.ts.map +1 -1
  708. package/dist/src/schema/manager.js +202 -70
  709. package/dist/src/schema/manager.js.map +1 -1
  710. package/dist/src/schema/rename-rewriter.d.ts +142 -0
  711. package/dist/src/schema/rename-rewriter.d.ts.map +1 -1
  712. package/dist/src/schema/rename-rewriter.js +254 -9
  713. package/dist/src/schema/rename-rewriter.js.map +1 -1
  714. package/dist/src/schema/reserved-tags.d.ts +1 -1
  715. package/dist/src/schema/reserved-tags.d.ts.map +1 -1
  716. package/dist/src/schema/reserved-tags.js +4 -3
  717. package/dist/src/schema/reserved-tags.js.map +1 -1
  718. package/dist/src/schema/schema-differ.d.ts +16 -0
  719. package/dist/src/schema/schema-differ.d.ts.map +1 -1
  720. package/dist/src/schema/schema-differ.js +225 -38
  721. package/dist/src/schema/schema-differ.js.map +1 -1
  722. package/dist/src/schema/table.d.ts +149 -1
  723. package/dist/src/schema/table.d.ts.map +1 -1
  724. package/dist/src/schema/table.js +248 -1
  725. package/dist/src/schema/table.js.map +1 -1
  726. package/dist/src/schema/unique-enforcement.d.ts +5 -3
  727. package/dist/src/schema/unique-enforcement.d.ts.map +1 -1
  728. package/dist/src/schema/unique-enforcement.js +5 -3
  729. package/dist/src/schema/unique-enforcement.js.map +1 -1
  730. package/dist/src/schema/view.d.ts +11 -0
  731. package/dist/src/schema/view.d.ts.map +1 -1
  732. package/dist/src/schema/view.js +12 -0
  733. package/dist/src/schema/view.js.map +1 -1
  734. package/dist/src/types/builtin-types.d.ts +54 -0
  735. package/dist/src/types/builtin-types.d.ts.map +1 -1
  736. package/dist/src/types/builtin-types.js +123 -34
  737. package/dist/src/types/builtin-types.js.map +1 -1
  738. package/dist/src/types/cast-semantics.d.ts +42 -0
  739. package/dist/src/types/cast-semantics.d.ts.map +1 -1
  740. package/dist/src/types/cast-semantics.js +64 -0
  741. package/dist/src/types/cast-semantics.js.map +1 -1
  742. package/dist/src/types/comparison-coercion.d.ts +101 -0
  743. package/dist/src/types/comparison-coercion.d.ts.map +1 -0
  744. package/dist/src/types/comparison-coercion.js +162 -0
  745. package/dist/src/types/comparison-coercion.js.map +1 -0
  746. package/dist/src/types/index.d.ts +2 -2
  747. package/dist/src/types/index.d.ts.map +1 -1
  748. package/dist/src/types/index.js +2 -2
  749. package/dist/src/types/index.js.map +1 -1
  750. package/dist/src/types/logical-type.d.ts +7 -0
  751. package/dist/src/types/logical-type.d.ts.map +1 -1
  752. package/dist/src/types/logical-type.js.map +1 -1
  753. package/dist/src/types/validation.d.ts +56 -0
  754. package/dist/src/types/validation.d.ts.map +1 -1
  755. package/dist/src/types/validation.js +68 -0
  756. package/dist/src/types/validation.js.map +1 -1
  757. package/dist/src/util/{working-table-iterable.d.ts → array-row-iterable.d.ts} +6 -6
  758. package/dist/src/util/array-row-iterable.d.ts.map +1 -0
  759. package/dist/src/util/{working-table-iterable.js → array-row-iterable.js} +6 -6
  760. package/dist/src/util/array-row-iterable.js.map +1 -0
  761. package/dist/src/util/coercion.d.ts +8 -0
  762. package/dist/src/util/coercion.d.ts.map +1 -1
  763. package/dist/src/util/coercion.js +8 -0
  764. package/dist/src/util/coercion.js.map +1 -1
  765. package/dist/src/util/comparison.d.ts +16 -3
  766. package/dist/src/util/comparison.d.ts.map +1 -1
  767. package/dist/src/util/comparison.js +21 -5
  768. package/dist/src/util/comparison.js.map +1 -1
  769. package/dist/src/util/key-serializer.d.ts +46 -0
  770. package/dist/src/util/key-serializer.d.ts.map +1 -1
  771. package/dist/src/util/key-serializer.js +47 -0
  772. package/dist/src/util/key-serializer.js.map +1 -1
  773. package/dist/src/util/value-set.d.ts +21 -0
  774. package/dist/src/util/value-set.d.ts.map +1 -0
  775. package/dist/src/util/value-set.js +22 -0
  776. package/dist/src/util/value-set.js.map +1 -0
  777. package/dist/src/vtab/capabilities.d.ts +1 -1
  778. package/dist/src/vtab/events.d.ts +8 -1
  779. package/dist/src/vtab/events.d.ts.map +1 -1
  780. package/dist/src/vtab/events.js.map +1 -1
  781. package/dist/src/vtab/manifest.d.ts +15 -0
  782. package/dist/src/vtab/manifest.d.ts.map +1 -1
  783. package/dist/src/vtab/memory/layer/alter-column.d.ts +147 -0
  784. package/dist/src/vtab/memory/layer/alter-column.d.ts.map +1 -0
  785. package/dist/src/vtab/memory/layer/alter-column.js +214 -0
  786. package/dist/src/vtab/memory/layer/alter-column.js.map +1 -0
  787. package/dist/src/vtab/memory/layer/base.d.ts.map +1 -1
  788. package/dist/src/vtab/memory/layer/base.js +4 -3
  789. package/dist/src/vtab/memory/layer/base.js.map +1 -1
  790. package/dist/src/vtab/memory/layer/interface.d.ts +2 -2
  791. package/dist/src/vtab/memory/layer/interface.d.ts.map +1 -1
  792. package/dist/src/vtab/memory/layer/manager.d.ts +176 -25
  793. package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
  794. package/dist/src/vtab/memory/layer/manager.js +569 -558
  795. package/dist/src/vtab/memory/layer/manager.js.map +1 -1
  796. package/dist/src/vtab/memory/layer/scan-layer.d.ts.map +1 -1
  797. package/dist/src/vtab/memory/layer/scan-layer.js +32 -5
  798. package/dist/src/vtab/memory/layer/scan-layer.js.map +1 -1
  799. package/dist/src/vtab/memory/layer/transaction.d.ts +101 -15
  800. package/dist/src/vtab/memory/layer/transaction.d.ts.map +1 -1
  801. package/dist/src/vtab/memory/layer/transaction.js +133 -45
  802. package/dist/src/vtab/memory/layer/transaction.js.map +1 -1
  803. package/dist/src/vtab/memory/module.d.ts +16 -1
  804. package/dist/src/vtab/memory/module.d.ts.map +1 -1
  805. package/dist/src/vtab/memory/module.js +64 -3
  806. package/dist/src/vtab/memory/module.js.map +1 -1
  807. package/dist/src/vtab/memory/table.d.ts.map +1 -1
  808. package/dist/src/vtab/memory/table.js +11 -6
  809. package/dist/src/vtab/memory/table.js.map +1 -1
  810. package/dist/src/vtab/module.d.ts +77 -23
  811. package/dist/src/vtab/module.d.ts.map +1 -1
  812. package/dist/src/vtab/table.d.ts +9 -2
  813. package/dist/src/vtab/table.d.ts.map +1 -1
  814. package/dist/src/vtab/table.js +1 -1
  815. package/dist/src/vtab/table.js.map +1 -1
  816. package/package.json +3 -3
  817. package/dist/src/util/working-table-iterable.d.ts.map +0 -1
  818. package/dist/src/util/working-table-iterable.js.map +0 -1
@@ -1,6 +1,7 @@
1
- import { buildColumnIndexMap, columnDefToSchema, resolvePkDefaultConflict, resolveNamedConstraintClass, validateCollationForType } from '../../../schema/table.js';
1
+ import { buildColumnIndexMap, columnDefToSchema, resolvePkDefaultConflict, resolveNamedConstraintClass, shiftSchemaIndicesForDrop, rekeySchemaPrimaryKey } from '../../../schema/table.js';
2
2
  import { keyParts } from '../types.js';
3
3
  import { BTree } from 'inheritree';
4
+ import { createValueSet } from '../../../util/value-set.js';
4
5
  import { StatusCode } from '../../../common/types.js';
5
6
  import { BaseLayer, iteratePrimaryRows, populateIndexFromRows, populateIndexFromRowsAsync } from './base.js';
6
7
  import { TransactionLayer } from './transaction.js';
@@ -11,19 +12,32 @@ import { ConflictResolution } from '../../../common/constants.js';
11
12
  import { buildUniqueConstraintSchema, buildForeignKeyConstraintSchema, buildCheckConstraintSchema, validateForeignKeyOverExistingRows, maintainedTableUniqueViolationError, formatKeyValue } from '../../../schema/constraint-builder.js';
12
13
  import { indexEnforcesUnique, uniqueEnforcementCollations, uniqueEnforcementComparators } from '../../../schema/unique-enforcement.js';
13
14
  import { generateIndexDDL, generateDropIndexDDL } from '../../../schema/ddl-generator.js';
14
- import { compareSqlValues, rowsValueIdentical, normalizeCollationName, comparisonSemanticsDiffer } from '../../../util/comparison.js';
15
+ import { compareSqlValues, rowsValueIdentical, normalizeCollationName } from '../../../util/comparison.js';
15
16
  import { scanLayer as scanLayerImpl } from './scan-layer.js';
16
17
  import { createPrimaryKeyFunctions, buildPrimaryKeyFromValues, primaryKeyArity } from '../utils/primary-key.js';
17
18
  import { createMemoryTableLoggers } from '../utils/logging.js';
18
- import { tryFoldLiteral } from '../../../parser/utils.js';
19
- import { validateAndParse, coerceRowToSchema } from '../../../types/validation.js';
20
- import { inferType } from '../../../types/registry.js';
19
+ import { coerceRowToSchema, foldDefaultToType } from '../../../types/validation.js';
21
20
  import { compilePredicate } from '../utils/predicate.js';
22
21
  import { renameColumnInIndexPredicates } from '../../../schema/rename-rewriter.js';
23
22
  import { MemoryIndex } from '../index.js';
24
23
  import { convertRowAtIndex, mapRows, mapRowsAsync } from './row-convert.js';
24
+ import { buildAlterColumnPlan, planColumnAttributeChange } from './alter-column.js';
25
25
  let tableManagerCounter = 0;
26
26
  const logger = createMemoryTableLoggers('layer:manager');
27
+ /**
28
+ * The `_uc_<cols>` auto-name of the implicit covering structure realizing an UNNAMED
29
+ * UNIQUE constraint, resolved over an EXPLICIT column list rather than the manager's
30
+ * live one — `renameColumn` needs the name under the POST-rename columns, which
31
+ * `this.tableSchema` does not carry yet.
32
+ *
33
+ * The name is derived, never recorded, so it MOVES when a covered column is renamed.
34
+ * Every consumer re-derives it (see the catalog's `implicitIndexNameForColumns`, which
35
+ * this mirrors and must stay equal to, and `quereus-store`'s `implicitUniqueIndexName`);
36
+ * keep this the only spelling of the rule inside this file.
37
+ */
38
+ function implicitIndexNameOver(uc, columns) {
39
+ return `_uc_${uc.columns.map(i => columns[i]?.name ?? String(i)).join('_')}`;
40
+ }
27
41
  /** A copy of `items` with `value` inserted at `at` (`at === items.length` ⇒ append). */
28
42
  function insertValueAt(items, at, value) {
29
43
  const out = items.slice();
@@ -178,16 +192,36 @@ export class MemoryTableManager {
178
192
  // it would enforce this non-derived UC under the index's collation rather
179
193
  // than the declared one. A collation-mismatched index falls through to a
180
194
  // distinct `_uc_*` covering index and coexists as its own constraint.
181
- const matchingIndex = existingIndexes.find(idx => idx.columns.length === uc.columns.length &&
195
+ // A filtered (partial) index only covers rows matching its own predicate, so
196
+ // it's never valid backing for an unfiltered UNIQUE — and a filtered UNIQUE
197
+ // already owns its index, so it isn't part of this search either (mirrors
198
+ // `findReusableIndexForUnique` in quereus-store's implicit-unique-index.ts).
199
+ const matchingIndex = uc.predicate ? undefined : existingIndexes.find(idx => !idx.predicate &&
200
+ idx.columns.length === uc.columns.length &&
182
201
  idx.columns.every((col, i) => col.index === uc.columns[i]) &&
183
202
  this.indexCollationsMatchDeclared(idx, uc));
203
+ // The name this constraint's own structure would take, and whoever already holds
204
+ // it in `newIndexes` — a pre-existing index, or the structure an EARLIER
205
+ // constraint in this same loop just pushed. A held name is ADOPTED, never pushed
206
+ // a second time: two entries under one name is the state `importDDL` warns about
207
+ // (see `SchemaManager.importCatalog`) — `index_info()` then reports neither,
208
+ // `DROP INDEX` answers `no such index`, and a predicate over the covered column
209
+ // stops filtering. No write path can produce a duplicate unnamed UNIQUE any more
210
+ // (`assertNoDuplicateUniqueConstraints` / `assertUniqueConstraintNotDuplicated`
211
+ // refuse it at every declaration site), so this arm is defence in depth for a
212
+ // catalog written before those guards: it degrades to one shared structure and
213
+ // double enforcement rather than to a corrupt index list.
214
+ const wantedName = uc.name ?? this.implicitIndexNameFor(uc);
215
+ const claimedIndex = newIndexes.find(idx => idx.name.toLowerCase() === wantedName.toLowerCase());
184
216
  let indexName;
185
217
  if (matchingIndex) {
186
218
  indexName = matchingIndex.name;
187
219
  }
220
+ else if (claimedIndex) {
221
+ indexName = claimedIndex.name;
222
+ }
188
223
  else {
189
- const colNames = uc.columns.map(i => this.tableSchema.columns[i]?.name ?? String(i));
190
- indexName = uc.name ?? `_uc_${colNames.join('_')}`;
224
+ indexName = wantedName;
191
225
  newIndexes.push({
192
226
  name: indexName,
193
227
  // Carry each column's declared collation so the auto-index — and the
@@ -220,10 +254,70 @@ export class MemoryTableManager {
220
254
  const indexName = uc.name ?? this.implicitIndexNameFor(uc);
221
255
  return this.implicitCoveringStructures.get(indexName);
222
256
  }
223
- /** Conventional auto-index name for an unnamed UNIQUE constraint (mirrors {@link ensureUniqueConstraintIndexes}). */
257
+ /** Conventional auto-index name for an unnamed UNIQUE constraint, over the LIVE columns. */
224
258
  implicitIndexNameFor(uc) {
225
- const colNames = uc.columns.map(i => this.tableSchema.columns[i]?.name ?? String(i));
226
- return `_uc_${colNames.join('_')}`;
259
+ return implicitIndexNameOver(uc, this.tableSchema.columns);
260
+ }
261
+ /**
262
+ * The materialized covering-index renames a column rename forces: one per UNNAMED
263
+ * UNIQUE constraint covering the renamed column, from its `_uc_<old cols>` name to
264
+ * its `_uc_<new cols>` one.
265
+ *
266
+ * The auto-name is derived from the live column names and recomputed by every
267
+ * consumer ({@link implicitIndexNameFor} here, the catalog's exposure map behind
268
+ * `schema()` / `index_info()`), so leaving the entry under its pre-rename name
269
+ * severs the constraint↔structure link: the structure stops being recognized as
270
+ * hidden (it surfaces as a user index and becomes droppable, taking the
271
+ * constraint's enforcement structure with it) and
272
+ * {@link getImplicitCoveringStructure} falls through to its column-set fallback.
273
+ *
274
+ * Skipped for constraints that do not move: a NAMED one's structure takes the
275
+ * constraint's name, a `derivedFromIndex` one IS the user's index, and one realized
276
+ * by a REUSED user index has no `_uc_*` entry to rename (that index keeps its own
277
+ * name).
278
+ *
279
+ * A case-only column rename DOES produce a rename here, even though every name
280
+ * comparison folds case: the covering-structure map is keyed by the exact derived
281
+ * string, so leaving `_uc_a` in place while consumers derive `_uc_A` would break
282
+ * {@link getImplicitCoveringStructure} the same way. It cannot collide — an index
283
+ * named `_uc_A` could never have been created alongside `_uc_a` in the first place.
284
+ *
285
+ * Pure — the caller applies the result to the new index list and, once the schema
286
+ * swap has succeeded, to {@link implicitCoveringStructures}.
287
+ */
288
+ planImplicitCoveringIndexRenames(updatedCols, renamedColIndex) {
289
+ const renames = [];
290
+ const indexes = this.tableSchema.indexes ?? [];
291
+ for (const uc of this.tableSchema.uniqueConstraints ?? []) {
292
+ if (uc.name !== undefined || uc.derivedFromIndex !== undefined)
293
+ continue;
294
+ if (!uc.columns.includes(renamedColIndex))
295
+ continue;
296
+ const oldName = implicitIndexNameOver(uc, this.tableSchema.columns);
297
+ const newName = implicitIndexNameOver(uc, updatedCols);
298
+ if (oldName === newName)
299
+ continue;
300
+ if (!indexes.some(idx => idx.name.toLowerCase() === oldName.toLowerCase()))
301
+ continue;
302
+ renames.push({ oldName, newName });
303
+ }
304
+ return renames;
305
+ }
306
+ /**
307
+ * Re-keys {@link implicitCoveringStructures} for the renames
308
+ * {@link planImplicitCoveringIndexRenames} produced — the map is keyed by
309
+ * constraint identity, which for an unnamed constraint IS the derived index name.
310
+ * Runs only after the schema swap succeeded, so a failed rename leaves the map
311
+ * agreeing with the restored schema.
312
+ */
313
+ applyImplicitCoveringStructureRenames(renames) {
314
+ for (const { oldName, newName } of renames) {
315
+ const rec = this.implicitCoveringStructures.get(oldName);
316
+ if (!rec)
317
+ continue;
318
+ this.implicitCoveringStructures.delete(oldName);
319
+ this.implicitCoveringStructures.set(newName, { ...rec, indexName: newName });
320
+ }
227
321
  }
228
322
  /**
229
323
  * True when a same-column-set index's per-column collations are
@@ -504,21 +598,23 @@ export class MemoryTableManager {
504
598
  connection.clearSavepoints();
505
599
  // Emit data change events after successful commit
506
600
  if (changes.length > 0 && this.eventEmitter?.emitDataChange) {
507
- // The event contract carries the PK as a component array. Derive the stored
508
- // key's shape from the PK arity, never from `Array.isArray` — a JSON PK whose
509
- // value is a document like `[1]` is a SCALAR key that happens to be a JS
510
- // array, and sniffing it would emit `[1]` where the contract wants `[[1]]`.
511
- // NOTE: on the tuple path this hands listeners the STORED key array itself
512
- // (`VTableDataChangeEvent.key` is mutable `SqlValue[]`, as it always was).
513
- // If a listener is ever seen mutating `event.key`, copy here — an in-place
514
- // edit would re-order the primary tree under the comparator.
515
- const eventKeyIsTuple = primaryKeyArity(this.tableSchema) !== 1;
601
+ // The contract's `key` is the primary key projected out of the event's OWN row
602
+ // image — `newRow` for an insert or an update, `oldRow` for a delete — under the
603
+ // schema current at DELIVERY (docs/usage.md § Subscribing to Data Changes).
604
+ // Projecting here rather than replaying the key each write recorded is what
605
+ // makes an in-place rewrite that changes the key's VALUE but not the row's
606
+ // identity (a NOCASE 'apple' → 'APPLE', which `recordUpsert` files under the
607
+ // pre-image key) hand listeners the post-image the table actually holds. It also
608
+ // re-derives the key across a mid-transaction ALTER PRIMARY KEY for free: the
609
+ // pending-change images are already reshaped to the delivered schema, so
610
+ // projecting them through THAT schema's key is the re-key.
611
+ const pkIndices = this.tableSchema.primaryKeyDefinition.map(def => def.index);
516
612
  for (const change of changes) {
517
613
  const event = {
518
614
  type: change.type,
519
615
  schemaName: this.schemaName,
520
616
  tableName: this._tableName,
521
- key: keyParts(change.pk, eventKeyIsTuple),
617
+ key: this.eventKeyFromImage(change, pkIndices),
522
618
  oldRow: change.oldRow,
523
619
  newRow: change.newRow,
524
620
  };
@@ -535,6 +631,25 @@ export class MemoryTableManager {
535
631
  logger.debugLog(`[Commit ${connection.connectionId}] Released lock for ${this._tableName}`);
536
632
  }
537
633
  }
634
+ /**
635
+ * The delivered `key` of one pending change: the primary key projected out of the change's
636
+ * own row image (`newRow` for an insert or an update, `oldRow` for a delete) through
637
+ * `pkIndices`, the key columns of the schema current at delivery.
638
+ *
639
+ * Best-effort, exactly like the pending-change image reshape it consumes: an image the
640
+ * reshape had to leave at the retired arity cannot be projected, so the event ships with no
641
+ * key and logs rather than emitting an `undefined` key slot a listener would file a row
642
+ * under. (A `PendingChange` always carries at least one image — `recordUpsert` sets
643
+ * `newRow`, `recordDelete` sets `oldRow` — so a missing image means only that.)
644
+ */
645
+ eventKeyFromImage(change, pkIndices) {
646
+ const image = change.newRow ?? change.oldRow;
647
+ if (image && pkIndices.every(i => i >= 0 && i < image.length)) {
648
+ return pkIndices.map(i => image[i]);
649
+ }
650
+ logger.warn('Commit Transaction', this._tableName, `${change.type} event has no image the delivered primary key can be projected from; delivering it with no key`);
651
+ return undefined;
652
+ }
538
653
  /** All layers in `layer`'s parent chain, including `layer` itself. */
539
654
  layerChainSet(layer) {
540
655
  const chain = new Set();
@@ -1057,8 +1172,8 @@ export class MemoryTableManager {
1057
1172
  // finer index (e.g. BINARY over a NOCASE column) no longer collapses onto
1058
1173
  // the constraint; resolving by name is robust to `schema.indexes` order
1059
1174
  // (the finer index may be listed earlier, having been created first).
1060
- // Both fall through to the column-set scan only when the name does not
1061
- // resolve (defensive).
1175
+ // Both fall through to the column-set scan below when the name does not
1176
+ // resolve — see there for when that actually happens.
1062
1177
  if (uc.derivedFromIndex) {
1063
1178
  const index = targetLayer.getSecondaryIndex?.(uc.derivedFromIndex);
1064
1179
  if (index)
@@ -1072,14 +1187,40 @@ export class MemoryTableManager {
1072
1187
  return { kind: 'memory-index', index };
1073
1188
  }
1074
1189
  }
1075
- // Defensive fallback: match the auto-built `_uc_*` covering index by
1076
- // column-set when the by-name resolution above did not land.
1190
+ // Fallback: match the covering index by column-set when the by-name
1191
+ // resolution above did not land. Reached more often than "defensive"
1192
+ // suggests — the reuse arms of `ensureUniqueConstraintIndexes` /
1193
+ // `addUniqueConstraint` register an UNNAMED constraint's structure under the
1194
+ // REUSED index's name, which `getImplicitCoveringStructure` (keyed
1195
+ // `_uc_<cols>`) then cannot find; and a reused index that is later dropped
1196
+ // leaves the recorded name unresolvable.
1197
+ //
1198
+ // So this scan must apply the SAME admissibility rule as those two reuse
1199
+ // searches, or it re-opens the hole they close: a FILTERED index holds only
1200
+ // the rows its predicate admits, and `checkSingleUniqueConstraint` skips the
1201
+ // check outright for a row outside the covering index's predicate — adopting
1202
+ // one for an unfiltered UNIQUE silently narrows enforcement to the
1203
+ // predicate's scope. A collation-mismatched index enforces under ITS
1204
+ // collation rather than the declared one, the same way.
1205
+ //
1206
+ // Returning undefined is always SAFE: the caller falls back to the
1207
+ // predicate- and collation-aware full scan, which is slower but exact. So a
1208
+ // filtered constraint does not guess here at all — its own structure is
1209
+ // resolved by name above.
1210
+ if (uc.predicate)
1211
+ return undefined;
1077
1212
  for (const idx of schema.indexes) {
1078
- if (idx.columns.length === uc.columns.length &&
1079
- idx.columns.every((col, i) => col.index === uc.columns[i])) {
1080
- const index = targetLayer.getSecondaryIndex?.(idx.name);
1081
- return index ? { kind: 'memory-index', index } : undefined;
1082
- }
1213
+ if (idx.predicate)
1214
+ continue;
1215
+ if (idx.columns.length !== uc.columns.length)
1216
+ continue;
1217
+ if (!idx.columns.every((col, i) => col.index === uc.columns[i]))
1218
+ continue;
1219
+ if (!this.indexCollationsMatchDeclared(idx, uc))
1220
+ continue;
1221
+ const index = targetLayer.getSecondaryIndex?.(idx.name);
1222
+ if (index)
1223
+ return { kind: 'memory-index', index };
1083
1224
  }
1084
1225
  return undefined;
1085
1226
  }
@@ -1307,34 +1448,9 @@ export class MemoryTableManager {
1307
1448
  // (`readLayer.getSchema() === this.tableSchema`) and drops the transaction's staged
1308
1449
  // rows at COMMIT.
1309
1450
  this.adoptSchemaOnOpenLayers(renamed);
1310
- // Emit schema change event
1311
- this.eventEmitter?.emitSchemaChange?.({
1312
- type: 'alter',
1313
- objectType: 'table',
1314
- schemaName: this.schemaName,
1315
- objectName: newName,
1316
- });
1317
- }
1318
- /** Iterates all committed rows from the current committed layer (for rebuild). */
1319
- scanAllRows() {
1320
- const tree = this._currentCommittedLayer.getModificationTree('primary');
1321
- if (!tree)
1322
- return [];
1323
- const rows = [];
1324
- for (const path of tree.ascending(tree.first())) {
1325
- rows.push(tree.at(path));
1326
- }
1327
- return rows;
1328
- }
1329
- /** Inserts a row directly into the base layer (for rebuild, bypasses transaction).
1330
- * Throws on duplicate primary key. */
1331
- insertRow(row) {
1332
- const key = this.primaryKeyFunctions.extractFromRow(row);
1333
- const path = this.baseLayer.primaryTree.find(key);
1334
- if (path.on) {
1335
- throw new QuereusError(`UNIQUE constraint failed: ${this._tableName} PK.`, StatusCode.CONSTRAINT);
1336
- }
1337
- this.baseLayer.primaryTree.insert(row);
1451
+ // No emit here (or in any other ALTER-arm manager method): the module-level
1452
+ // `alterTable`/`renameTable` raises the statement's ONE schema event, gated on the
1453
+ // engine-set `change.ddl` — so a wrapper-driven manager call announces nothing.
1338
1454
  }
1339
1455
  /**
1340
1456
  * Atomically replaces the entire committed contents with `rows` by building a
@@ -1504,7 +1620,9 @@ export class MemoryTableManager {
1504
1620
  oldByKey.insert({ key: this.primaryKeyFunctions.extractFromRow(row), row });
1505
1621
  }
1506
1622
  // New-row keys (same PK comparator) for the delete pass's membership test.
1507
- const newKeys = new BTree(k => k, this.comparePrimaryKeys);
1623
+ // Entry is the bare PK value, so it must be a non-freezing set: a
1624
+ // single-column BLOB PK is a `Uint8Array`, which `Object.freeze` rejects.
1625
+ const newKeys = createValueSet(this.comparePrimaryKeys);
1508
1626
  // Insert/update/skip-identical pass, in new-row order.
1509
1627
  for (const newRow of op.rows) {
1510
1628
  const key = this.primaryKeyFunctions.extractFromRow(newRow);
@@ -1594,7 +1712,7 @@ export class MemoryTableManager {
1594
1712
  const result = await this.checkSingleUniqueConstraint(layer, schema, uc, change.newRow, newPrimaryKey, ConflictResolution.ABORT, noEvict, /*allowMvCovering*/ false);
1595
1713
  if (result) {
1596
1714
  const colNames = uc.columns.map(i => schema.columns[i]?.name ?? String(i));
1597
- throw maintainedTableUniqueViolationError(this.schemaName, this._tableName, uc.name ?? `_uc_${colNames.join('_')}`, colNames, uc.columns.map(i => change.newRow[i]));
1715
+ throw maintainedTableUniqueViolationError(this.schemaName, this._tableName, uc.name ?? implicitIndexNameOver(uc, schema.columns), colNames, uc.columns.map(i => change.newRow[i]));
1598
1716
  }
1599
1717
  }
1600
1718
  }
@@ -1628,13 +1746,14 @@ export class MemoryTableManager {
1628
1746
  throw new QuereusError(`Duplicate column name: ${newColumnSchema.name}`, StatusCode.ERROR);
1629
1747
  }
1630
1748
  let defaultValue = null;
1631
- let defaultIsLiteral = false;
1632
1749
  const defaultConstraint = columnDefAst.constraints.find(c => c.type === 'default');
1633
1750
  if (defaultConstraint && defaultConstraint.expr) {
1634
- const folded = tryFoldLiteral(defaultConstraint.expr);
1751
+ // Fold AND convert to the new column's declared type, so the backfilled cell
1752
+ // is the value a fresh INSERT under the same DEFAULT would store. An
1753
+ // unconvertible literal (`integer default 'abc'`) throws MISMATCH here.
1754
+ const folded = foldDefaultToType(defaultConstraint.expr, newColumnSchema.logicalType, newColumnSchema.name);
1635
1755
  if (folded !== undefined) {
1636
1756
  defaultValue = folded;
1637
- defaultIsLiteral = true;
1638
1757
  }
1639
1758
  else {
1640
1759
  // A non-literal expression default (e.g. `new.<col>`) is written as NULL
@@ -1643,13 +1762,27 @@ export class MemoryTableManager {
1643
1762
  }
1644
1763
  }
1645
1764
  // Check for NOT NULL constraint (could be explicit or from default behavior).
1646
- // Allow NOT NULL without DEFAULT if the table is empty (SQLite-compatible).
1647
- // A non-literal *expression* default (e.g. `new.<col>`) is backfilled per-row by
1648
- // the engine right after this returns, which then enforces NOT NULL on the
1649
- // backfilled values — so don't reject it here as "without a DEFAULT".
1765
+ // Allow NOT NULL without a value source if the table is empty (SQLite-compatible).
1766
+ //
1767
+ // `!backfillEvaluator` is the load-bearing clause, and mirrors
1768
+ // `StoreModuleBase.alterAddColumn`: an engine-supplied evaluator — a non-foldable
1769
+ // expression default (`new.<col>`) OR a `generated always as` expression — fills
1770
+ // each existing row right after this returns, and NOT NULL is then enforced on the
1771
+ // computed values (`BaseLayer.recreatePrimaryTreeWithNewColumn`, plus the
1772
+ // pending-row pass below). Asking only which KIND of DEFAULT was written used to
1773
+ // reject a NOT NULL generated column on a non-empty table the evaluator could fill,
1774
+ // and (in the other direction) to admit `default null` on a column that is NOT NULL
1775
+ // only by the session `default_column_nullability`. The gate is value-based now, so
1776
+ // it matches `StoreModuleBase.alterAddColumn` word for word.
1777
+ //
1778
+ // NOTE: that agreement — here, in the store module, and in the engine's own
1779
+ // pre-check in `runAddColumn` — is held together only by section 8 of
1780
+ // `test/logic/41.4-alter-add-column-constraints.sqllogic` running under both
1781
+ // `yarn test` and `yarn test:store`. Nothing enforces it mechanically. If a
1782
+ // fourth site ever needs the same rule, hoist it to one shared predicate
1783
+ // rather than adding another copy.
1650
1784
  const tableHasRows = this.baseLayer.primaryTree.at(this.baseLayer.primaryTree.first()) !== undefined;
1651
- const hasDefaultExpr = !!(defaultConstraint && defaultConstraint.expr);
1652
- if (newColumnSchema.notNull && defaultValue === null && !defaultIsLiteral && !hasDefaultExpr && tableHasRows) {
1785
+ if (newColumnSchema.notNull && defaultValue === null && !backfillEvaluator && tableHasRows) {
1653
1786
  throw new QuereusError(`Cannot add NOT NULL column '${newColumnSchema.name}' to non-empty table `
1654
1787
  + `'${this.schemaName}.${this._tableName}' without a DEFAULT value`, StatusCode.CONSTRAINT);
1655
1788
  }
@@ -1709,27 +1842,14 @@ export class MemoryTableManager {
1709
1842
  return insertValueAt(row, targetIndex, value);
1710
1843
  });
1711
1844
  this.baseLayer.updateSchema(finalNewTableSchema);
1712
- // A non-foldable DEFAULT (e.g. `new.<col>`) backfills each existing row from
1713
- // its own value via the engine-supplied evaluator; a literal/NULL default
1714
- // uses the single folded `defaultValue` for every row.
1845
+ // A per-row value source — a non-foldable DEFAULT (e.g. `new.<col>`) or a
1846
+ // `generated always as` expression — backfills each existing row from its own
1847
+ // value via the engine-supplied evaluator; a literal/NULL default uses the
1848
+ // single folded `defaultValue` for every row.
1715
1849
  await this.baseLayer.addColumnToBase(newColumnSchema, defaultValue, backfillEvaluator, targetIndex);
1716
1850
  this.tableSchema = finalNewTableSchema;
1717
1851
  this.initializePrimaryKeyFunctions();
1718
1852
  this.installReshapeOnOpenLayers(finalNewTableSchema, reshapePlans);
1719
- // Emit schema change event.
1720
- // NOTE: the event names the added column but not its position, which is fine while
1721
- // the only non-append caller is an in-process wrapper that rebuilds its view from the
1722
- // post-change schema. An append never invalidates an existing column index; an insert
1723
- // does. If a position ever becomes SQL-reachable, anything that caches a column index
1724
- // across this swap (planner caches, prepared statements, a wrapper's own schema
1725
- // snapshot) needs to learn the insert point — so the event would have to carry it.
1726
- this.eventEmitter?.emitSchemaChange?.({
1727
- type: 'alter',
1728
- objectType: 'column',
1729
- schemaName: this.schemaName,
1730
- objectName: this._tableName,
1731
- columnName: newColumnSchema.name,
1732
- });
1733
1853
  logger.operation('Add Column', this._tableName, { columnName: newColumnSchema.name });
1734
1854
  }
1735
1855
  catch (e) {
@@ -1758,57 +1878,23 @@ export class MemoryTableManager {
1758
1878
  if (this.tableSchema.primaryKeyDefinition.some(def => def.index === colIndex)) {
1759
1879
  throw new QuereusError(`Cannot drop PK column "${columnName}".`, StatusCode.CONSTRAINT);
1760
1880
  }
1761
- const updatedColumnsSchema = this.tableSchema.columns.filter((_, idx) => idx !== colIndex);
1762
- const updatedPkDefinition = this.tableSchema.primaryKeyDefinition.map(def => ({
1763
- ...def, index: def.index > colIndex ? def.index - 1 : def.index
1764
- }));
1765
- const updatedPrimaryKeyNames = updatedPkDefinition.map(def => updatedColumnsSchema[def.index]?.name).filter(Boolean);
1766
- // Prune any UNIQUE constraint over the dropped column. A UNIQUE that includes the
1767
- // dropped column is removed outright (a UNIQUE missing one of its columns is a
1768
- // different, stronger constraint, not a silently-narrowed one); the auto-built
1769
- // covering index it backed is torn down with it (see the index exclusion below).
1770
- // Remaining constraints have their column indices shifted to track the removed slot.
1771
- // Without this, dropping a uniquely-constrained column (including the ADD COLUMN +
1772
- // inline-UNIQUE revert path) would strand a constraint whose column index dangles
1773
- // past the end of the column array.
1774
- const oldUniqueConstraints = this.tableSchema.uniqueConstraints ?? [];
1775
- const droppedUcKeys = oldUniqueConstraints
1776
- .filter(uc => uc.columns.includes(colIndex))
1777
- .map(uc => uc.name ?? this.implicitIndexNameFor(uc));
1778
- const remainingUniqueConstraints = oldUniqueConstraints
1779
- .filter(uc => !uc.columns.includes(colIndex))
1780
- .map(uc => ({ ...uc, columns: Object.freeze(uc.columns.map(i => i > colIndex ? i - 1 : i)) }));
1881
+ // Renumber every position-bearing field over the removed slot — shared with the
1882
+ // store module's `alterDropColumn`, the mirror of `shiftSchemaIndicesForInsert`.
1883
+ const shifted = shiftSchemaIndicesForDrop(this.tableSchema, colIndex);
1884
+ const updatedPrimaryKeyNames = shifted.primaryKeyDefinition.map(def => shifted.columns[def.index]?.name).filter(Boolean);
1781
1885
  // Drop the implicit covering index of each removed constraint outright (matched by
1782
1886
  // the same `uc.name ?? '_uc_<cols>'` convention DROP CONSTRAINT uses, so a user
1783
- // index that merely shares columns is left untouched), then shift/prune the rest
1784
- // over the removed slot. A *single*-column covering index collapses to empty and is
1785
- // filtered by the trailing `length > 0` regardless; the explicit name exclusion is
1786
- // what tears down a *multi*-column covering index, which would otherwise survive
1787
- // orphaned — narrowed to its surviving columns — in `index_info` and on every write.
1887
+ // index that merely shares columns is left untouched). Only this backend needs the
1888
+ // pass: the covering index deliberately carries no `unique: true` flag (enforcement
1889
+ // routes through `uniqueConstraints`), so `shiftSchemaIndicesForDrop`'s own
1890
+ // drop-unique-indexes-outright rule does not see it. A *single*-column covering index
1891
+ // collapses to empty and is dropped by the helper's `length > 0` filter regardless;
1892
+ // this exclusion is what tears down a *multi*-column one, which would otherwise
1893
+ // survive orphaned — narrowed to its surviving columns — in `index_info` and on every
1894
+ // write.
1895
+ const droppedUcKeys = shifted.removedUniqueConstraints.map(uc => uc.name ?? this.implicitIndexNameFor(uc));
1788
1896
  const droppedCoveringIndexNames = new Set(droppedUcKeys.map(k => k.toLowerCase()));
1789
- const updatedIndexes = (this.tableSchema.indexes || [])
1790
- .filter(idx => !droppedCoveringIndexNames.has(idx.name.toLowerCase()))
1791
- .map(idx => ({
1792
- ...idx,
1793
- columns: idx.columns
1794
- .filter(ic => ic.index !== colIndex)
1795
- .map(ic => ({ ...ic, index: ic.index > colIndex ? ic.index - 1 : ic.index }))
1796
- })).filter(idx => idx.columns.length > 0);
1797
- // Shift or prune the table's own foreign keys. `foreignKeys[].columns` are indices
1798
- // into THIS table, so they renumber over the removed slot exactly as the PK and the
1799
- // UNIQUE constraints above do. A foreign key that loses ANY of its child columns is
1800
- // removed outright, the same call the UNIQUE pruning makes: a key missing one of its
1801
- // child columns is a different constraint against the parent's key, not a narrowed
1802
- // one. Both halves matter — left unshifted, a surviving key's index either dangles
1803
- // past the end of the column array or, worse, silently slides onto an unrelated
1804
- // column and starts enforcing against the parent there.
1805
- //
1806
- // `referencedColumns` is not touched: enforcement resolves the parent indices on
1807
- // demand from `referencedColumnNames` against the parent's current schema. See
1808
- // `shiftSchemaIndicesForInsert`, the ADD-COLUMN-at-a-position mirror of this block.
1809
- const remainingForeignKeys = (this.tableSchema.foreignKeys ?? [])
1810
- .filter(fk => !fk.columns.includes(colIndex))
1811
- .map(fk => ({ ...fk, columns: Object.freeze(fk.columns.map(i => i > colIndex ? i - 1 : i)) }));
1897
+ const updatedIndexes = shifted.indexes.filter(idx => !droppedCoveringIndexNames.has(idx.name.toLowerCase()));
1812
1898
  // NOTE: the generated-column bookkeeping (`generatedColumnDependencies` /
1813
1899
  // `generatedColumnTopoOrder`, also index-keyed) is likewise unshifted, but the
1814
1900
  // engine recomputes it from column names right after this returns
@@ -1818,17 +1904,13 @@ export class MemoryTableManager {
1818
1904
  // `primaryKey` below is not a TableSchema field at all — nothing reads it.
1819
1905
  const finalNewTableSchema = Object.freeze({
1820
1906
  ...this.tableSchema,
1821
- columns: Object.freeze(updatedColumnsSchema),
1822
- columnIndexMap: buildColumnIndexMap(updatedColumnsSchema),
1823
- primaryKeyDefinition: Object.freeze(updatedPkDefinition),
1907
+ columns: shifted.columns,
1908
+ columnIndexMap: buildColumnIndexMap(shifted.columns),
1909
+ primaryKeyDefinition: shifted.primaryKeyDefinition,
1824
1910
  primaryKey: Object.freeze(updatedPrimaryKeyNames),
1825
1911
  indexes: Object.freeze(updatedIndexes),
1826
- uniqueConstraints: remainingUniqueConstraints.length > 0
1827
- ? Object.freeze(remainingUniqueConstraints)
1828
- : undefined,
1829
- foreignKeys: remainingForeignKeys.length > 0
1830
- ? Object.freeze(remainingForeignKeys)
1831
- : undefined,
1912
+ uniqueConstraints: shifted.uniqueConstraints,
1913
+ foreignKeys: shifted.foreignKeys,
1832
1914
  });
1833
1915
  // Phase 1 of reaching the open transaction's own pending rows. The rewrite here is
1834
1916
  // a pure filter and cannot throw — the split exists for ADD COLUMN's fallible
@@ -1845,14 +1927,6 @@ export class MemoryTableManager {
1845
1927
  this.implicitCoveringStructures.delete(key);
1846
1928
  this.initializePrimaryKeyFunctions();
1847
1929
  this.installReshapeOnOpenLayers(finalNewTableSchema, reshapePlans);
1848
- // Emit schema change event
1849
- this.eventEmitter?.emitSchemaChange?.({
1850
- type: 'drop',
1851
- objectType: 'column',
1852
- schemaName: this.schemaName,
1853
- objectName: this._tableName,
1854
- columnName,
1855
- });
1856
1930
  logger.operation('Drop Column', this._tableName, { columnName });
1857
1931
  }
1858
1932
  catch (e) {
@@ -1891,8 +1965,17 @@ export class MemoryTableManager {
1891
1965
  const defaultNotNull = defaultNullability === 'not_null';
1892
1966
  const newColumnSchemaAtIndex = columnDefToSchema(newColumnDefAst, defaultNotNull, 'BINARY', (n) => this.db.isCollationRegistered(n));
1893
1967
  const updatedCols = this.tableSchema.columns.map((c, i) => i === colIndex ? newColumnSchemaAtIndex : c);
1968
+ // An unnamed UNIQUE's covering index is named `_uc_<column names>`, so renaming a
1969
+ // covered column moves that name — rewrite the materialized ENTRY, not just its
1970
+ // column references, or the structure is orphaned under the old name (see
1971
+ // {@link planImplicitCoveringIndexRenames}). The engine refuses the statement up
1972
+ // front when the post-rename name is already an index here, so no rename below can
1973
+ // collide with a sibling entry.
1974
+ const coveringRenames = this.planImplicitCoveringIndexRenames(updatedCols, colIndex);
1975
+ const renamedTo = new Map(coveringRenames.map(r => [r.oldName.toLowerCase(), r.newName]));
1894
1976
  const updatedIndexes = (this.tableSchema.indexes || []).map(idx => ({
1895
1977
  ...idx,
1978
+ name: renamedTo.get(idx.name.toLowerCase()) ?? idx.name,
1896
1979
  columns: idx.columns.map(ic => ic.index === colIndex ? { ...ic, name: newColumnName } : ic)
1897
1980
  }));
1898
1981
  const finalNewTableSchema = Object.freeze({
@@ -1925,8 +2008,13 @@ export class MemoryTableManager {
1925
2008
  predicatesRewritten = true;
1926
2009
  renameColumnInIndexPredicates(finalNewTableSchema.indexes, this._tableName, oldName, newColumnName, this.schemaName, resolveColumnInSource);
1927
2010
  this.baseLayer.updateSchema(finalNewTableSchema);
2011
+ // Rebuilds every secondary index from the new schema, so a renamed covering index
2012
+ // lands under its new key in the base's index map with no extra rebuild here.
1928
2013
  await this.baseLayer.handleColumnRename();
1929
2014
  this.tableSchema = finalNewTableSchema;
2015
+ // Only now that the swap has succeeded — the catch below restores the old schema
2016
+ // and the map must keep agreeing with it.
2017
+ this.applyImplicitCoveringStructureRenames(coveringRenames);
1930
2018
  this.initializePrimaryKeyFunctions();
1931
2019
  // The DDL transaction's own layers froze their schema at creation; hand them the
1932
2020
  // renamed one, mirroring `handleColumnRename`'s base-side secondary rebuild —
@@ -1942,15 +2030,6 @@ export class MemoryTableManager {
1942
2030
  // silently dropped at COMMIT. Covered by
1943
2031
  // `test/logic/41.8-alter-savepoint-staged-rows.sqllogic`.
1944
2032
  this.adoptSchemaOnOpenLayers(finalNewTableSchema);
1945
- // Emit schema change event
1946
- this.eventEmitter?.emitSchemaChange?.({
1947
- type: 'alter',
1948
- objectType: 'column',
1949
- schemaName: this.schemaName,
1950
- objectName: this._tableName,
1951
- columnName: newColumnName,
1952
- oldColumnName: oldName,
1953
- });
1954
2033
  logger.operation('Rename Column', this._tableName, { oldName, newName: newColumnName });
1955
2034
  }
1956
2035
  catch (e) {
@@ -1971,10 +2050,17 @@ export class MemoryTableManager {
1971
2050
  }
1972
2051
  }
1973
2052
  /**
1974
- * Apply a single-attribute ALTER COLUMN change (NOT NULL, DEFAULT, DATA TYPE).
2053
+ * Apply a single-attribute ALTER COLUMN change (NOT NULL, DEFAULT, DATA TYPE, COLLATE).
1975
2054
  * The caller supplies exactly one populated change; multi-attribute combinations
1976
2055
  * are rejected by the runtime before reaching this method.
1977
2056
  *
2057
+ * The body is the ordering contract, and only that: resolve the column → decide the change
2058
+ * and pre-validate it (`alter-column.ts`, which mutates nothing) → probe the re-keyed
2059
+ * structures ({@link validateAlterColumnPlan}) → rebuild the base
2060
+ * ({@link applyAlterColumnToBase}, the first write) → swap this manager's schema →
2061
+ * propagate to open layers ({@link propagateAlterColumnToOpenLayers}) → emit. Each step's
2062
+ * own reasoning lives on the step.
2063
+ *
1978
2064
  * `validateOnly` runs everything up to (and including) the pre-mutation validation
1979
2065
  * passes — the effective-row NULL / conversion scans, the re-keyed UNIQUE probe, and
1980
2066
  * the primary-key re-key legality/representability passes — and returns before the
@@ -1988,8 +2074,7 @@ export class MemoryTableManager {
1988
2074
  const lockKey = `MemoryTable.SchemaChange:${this.schemaName}.${this._tableName}`;
1989
2075
  const release = await this.db.latches.acquire(lockKey);
1990
2076
  const originalManagerSchema = this.tableSchema;
1991
- /** The base primary tree `rebuildPrimaryTreeStrict` replaced, for the catch's rollback. */
1992
- let basePrimaryTreeBeforeRekey = null;
2077
+ const undo = { basePrimaryTree: null };
1993
2078
  try {
1994
2079
  await this.ensureSchemaChangeSafety();
1995
2080
  const colNameLower = change.columnName.toLowerCase();
@@ -1997,382 +2082,50 @@ export class MemoryTableManager {
1997
2082
  if (colIndex === -1) {
1998
2083
  throw new QuereusError(`Column '${change.columnName}' not found.`, StatusCode.ERROR);
1999
2084
  }
2000
- const oldCol = this.tableSchema.columns[colIndex];
2001
- let newCol = oldCol;
2002
- // A collation change re-keys any PK / UNIQUE / index that orders by this
2003
- // column, so it needs the structure re-sort + uniqueness re-validation below.
2004
- let collationChanged = false;
2005
- // Set when a SET DATA TYPE moves to a type that ORDERS values differently
2006
- // (comparisonSemanticsDiffer). Same consequence as a collation change — every
2007
- // structure keyed by the column has to be re-sorted and its uniqueness re-judged —
2008
- // but a separate flag, because the index-column collation propagation and the
2009
- // `pkColumnRekeyed` primary-tree path below belong to SET COLLATE alone. Usually
2010
- // coincides with `valueConvert` (every non-alias retype sets that); the rebuild
2011
- // chains below test `valueConvert` FIRST, whose full-rebuild path subsumes the
2012
- // comparator-only re-sort.
2013
- let comparatorChanged = false;
2014
- // Set to the per-value conversion function when a physical value rewrite is needed:
2015
- // SET DATA TYPE (every non-alias retype — values normalize to the new type's
2016
- // canonical spelling even when the storage class is unchanged) or SET NOT NULL
2017
- // backfill (map null → DEFAULT). Both REPLACE the base primary tree with a
2018
- // freshly-built one (never an in-place mutation, which inheritree forbids while the
2019
- // open transaction's layers derive from it) and convert the transaction's
2020
- // own-written rows in every open layer, after `updateSchema` (see the rebuild
2021
- // section and convertColumnOnOpenLayers).
2022
- let valueConvert = null;
2023
- // SET NOT NULL backfill also routes NULL values through `valueConvert`; SET DATA TYPE
2024
- // leaves nulls untouched. Selects the null-including path in convertBaseRows/convertColumn.
2025
- let convertNulls = false;
2026
- if (change.setCollation !== undefined) {
2027
- const normalized = validateCollationForType(change.setCollation, oldCol.logicalType, change.columnName, (n) => this.db.isCollationRegistered(n));
2028
- const nameMatches = normalized === (oldCol.collation || 'BINARY');
2029
- if (nameMatches && oldCol.collationExplicit) {
2030
- return; // already explicit in the desired collation — nothing to do
2031
- }
2032
- // SET COLLATE is a user declaration with the same standing as a
2033
- // CREATE-time COLLATE clause, so mark the collation explicit (rank 2 in
2034
- // the comparison lattice) regardless of the column's creation history —
2035
- // including SET COLLATE binary. When only the name matches but the column
2036
- // was not yet explicit (a defaulted collation, or one inherited from
2037
- // session default_collation), flip the flag as a METADATA-ONLY change:
2038
- // the collation bytes are unchanged, so keep collationChanged false and
2039
- // skip the physical re-sort / re-key / UNIQUE re-validation below. A
2040
- // different name takes the full path AND sets the flag.
2041
- newCol = { ...oldCol, collation: normalized, collationExplicit: true };
2042
- collationChanged = !nameMatches;
2043
- }
2044
- else if (change.setNotNull !== undefined) {
2045
- if (change.setNotNull === true && !oldCol.notNull) {
2046
- // Tightening: scan the DDL transaction's EFFECTIVE rows for NULLs — committed rows
2047
- // overlaid with this transaction's own pending writes — exactly as the setDataType
2048
- // arm does. A pending NULL the transaction can SEE rejects the ALTER; one only in a
2049
- // row it has DELETED does not block it. `rows` is the wrapper-supplied effective set
2050
- // (the isolation overlay); when absent, effectiveDdlRows() is the layered view.
2051
- const defaultExpr = oldCol.defaultValue;
2052
- const defaultLiteral = defaultExpr ? tryFoldLiteral(defaultExpr) : undefined;
2053
- let anyNull = false;
2054
- if (rows) {
2055
- for await (const row of rows()) {
2056
- if (row[colIndex] === null) {
2057
- anyNull = true;
2058
- break;
2059
- }
2060
- }
2061
- }
2062
- else {
2063
- for (const row of this.effectiveDdlRows()) {
2064
- if (row[colIndex] === null) {
2065
- anyNull = true;
2066
- break;
2067
- }
2068
- }
2069
- }
2070
- if (anyNull) {
2071
- if (defaultLiteral === undefined || defaultLiteral === null) {
2072
- throw new QuereusError(`column ${change.columnName} contains NULL values`, StatusCode.CONSTRAINT);
2073
- }
2074
- // Backfill: map null → the folded DEFAULT literal, routed through the SAME
2075
- // base-replacement + open-layer conversion machinery setDataType uses — no
2076
- // logical-type change, no PK re-key, no in-place base mutation. The old in-place
2077
- // `tree.upsert` backfill could not fill the transaction's pending rows (they live
2078
- // in the pending layer, not the base) and mutated a base the open layers derive
2079
- // from — both fixed by the unified path.
2080
- const literal = defaultLiteral;
2081
- valueConvert = (v) => (v === null ? literal : v);
2082
- convertNulls = true;
2083
- }
2084
- newCol = { ...oldCol, notNull: true };
2085
- }
2086
- else if (change.setNotNull === false && oldCol.notNull) {
2087
- if (this.tableSchema.primaryKeyDefinition.some(def => def.index === colIndex)) {
2088
- throw new QuereusError(`Cannot DROP NOT NULL on PRIMARY KEY column '${change.columnName}'`, StatusCode.CONSTRAINT);
2089
- }
2090
- newCol = { ...oldCol, notNull: false };
2091
- }
2092
- else {
2093
- // No-op (already in desired state).
2094
- return;
2095
- }
2096
- }
2097
- else if (change.setDataType !== undefined) {
2098
- const newLogicalType = inferType(change.setDataType);
2099
- // Gate on logical-type IDENTITY, not the physical storage class: `inferType`
2100
- // flattens aliases to the shared type object (`varchar(50)` IS `TEXT_TYPE`,
2101
- // `bigint` IS `INTEGER_TYPE`), so an alias retype is schema-only — no scan, no
2102
- // rewrite, no re-key. Every OTHER retype validates AND normalizes every value,
2103
- // whether or not the storage class changes: a same-class move (text → date)
2104
- // must reject values the new type refuses ('hello') and rewrite the rest to
2105
- // the new type's canonical spelling ('2024-06-05T00:00:00Z' → '2024-06-05'),
2106
- // or the column holds values no INSERT could have produced — unfindable by
2107
- // equality (DATE compares BINARY over the stored text) and invisible to UNIQUE.
2108
- // NOTE: the rewrite is unconditional once the types differ, even when every
2109
- // converted value comes back byte-identical (already-canonical ISO durations on a
2110
- // text → timespan). That costs a full base-tree + secondary-index rebuild here, and
2111
- // a physical rewrite of every row on the store leg. If ALTER on large tables ever
2112
- // shows up as slow, have the convert pre-pass record whether any value actually
2113
- // moved and, when none did, fall through to the comparator-only re-key.
2114
- if (newLogicalType !== oldCol.logicalType) {
2115
- // Retyping a PRIMARY KEY column moves the key bytes (a class change), the
2116
- // tree's ordering (a comparator move), or at minimum the key values'
2117
- // canonical spelling — and neither the base rewrite below nor the
2118
- // transaction-layer conversion re-keys the primary tree. The engine already
2119
- // refuses SET DATA TYPE on any PK column (runtime/emit/alter-table.ts);
2120
- // this guards direct module calls. Reject rather than corrupt — the
2121
- // type-change analogue of the SET COLLATE primary-key carve-out
2122
- // (`alter-collate-pk-in-transaction`).
2123
- if (this.tableSchema.primaryKeyDefinition.some(def => def.index === colIndex)) {
2124
- throw new QuereusError(`Cannot change the data type of primary key column '${change.columnName}' of table '${this._tableName}'.`, StatusCode.CONSTRAINT);
2125
- }
2126
- // Every MemoryIndex builds its comparator from the column's LOGICAL type
2127
- // (`createTypedComparator(columnSchema.logicalType, …)` in vtab/memory/index.ts),
2128
- // so a move to a differently-ordering type (text ↔ timespan: 'PT1H' ≡ 'PT60M';
2129
- // text ↔ date/time/datetime: binary, ignoring the column's collation) re-sorts
2130
- // every structure keyed by the column. Tracked separately from the value rewrite
2131
- // because SET COLLATE shares the re-key machinery without rewriting values.
2132
- comparatorChanged = comparisonSemanticsDiffer(oldCol.logicalType, newLogicalType);
2133
- const convert = (v) => {
2134
- try {
2135
- return validateAndParse(v, newLogicalType, change.columnName);
2136
- }
2137
- catch {
2138
- throw new QuereusError(`Cannot convert value in '${change.columnName}' to ${change.setDataType}`, StatusCode.MISMATCH);
2139
- }
2140
- };
2141
- // Validate BEFORE any mutation, over the DDL transaction's EFFECTIVE rows
2142
- // (committed rows overlaid with this transaction's own pending writes): an
2143
- // unconvertible value the transaction can SEE rejects the ALTER, and one only in
2144
- // a row it has DELETED does not block it. A throw here leaves the schema, the base
2145
- // and the transaction untouched. `rows` is the wrapper-supplied effective set (the
2146
- // isolation overlay); when absent, `effectiveDdlRows()` is the layered view.
2147
- if (rows) {
2148
- for await (const row of rows()) {
2149
- const val = row[colIndex];
2150
- if (val !== null)
2151
- convert(val);
2152
- }
2153
- }
2154
- else {
2155
- for (const row of this.effectiveDdlRows()) {
2156
- const val = row[colIndex];
2157
- if (val !== null)
2158
- convert(val);
2159
- }
2160
- }
2161
- // The base rows are converted below, AFTER `updateSchema`, by REPLACING the base
2162
- // primary tree with a fresh one (see the `valueConvert` branch) — never by an
2163
- // in-place mutation, which inheritree forbids while the open transaction's layers
2164
- // derive from that tree (`MutatedBaseError`). `valueConvert` drives both the base
2165
- // replacement and the transaction-layer conversion.
2166
- valueConvert = convert;
2167
- }
2168
- newCol = { ...oldCol, logicalType: newLogicalType };
2169
- }
2170
- else if (change.setDefault !== undefined) {
2171
- newCol = { ...oldCol, defaultValue: change.setDefault };
2172
- }
2173
- else {
2174
- throw new QuereusError('ALTER COLUMN requires an attribute to change', StatusCode.INTERNAL);
2175
- }
2176
- const updatedCols = this.tableSchema.columns.map((c, i) => i === colIndex ? newCol : c);
2177
- // The changes that move the COMPARATOR the structures are keyed by: SET COLLATE
2178
- // (values untouched) and a retype into a differently-ordering type (which, unless it
2179
- // is an alias retype, ALSO rewrites values — `valueConvert` — and its full-rebuild
2180
- // path below subsumes the comparator-only re-sort). Both need fresh IndexSchema
2181
- // objects and, when no rewrite runs, the re-validate / re-sort / adopt sequence.
2182
- const structuresRekeyed = collationChanged || comparatorChanged;
2183
- // Propagate a collation change into every PK-definition entry and index
2184
- // column that orders by this column, so their comparators re-key under it.
2185
- const updatedPkDef = collationChanged
2186
- ? this.tableSchema.primaryKeyDefinition.map(def => def.index === colIndex ? { ...def, collation: newCol.collation } : def)
2187
- : this.tableSchema.primaryKeyDefinition;
2188
- // Every re-keying change also REBUILDS the IndexSchema objects, because their identity is
2189
- // the discriminator `TransactionLayer.adoptSchema` uses to decide an open layer's
2190
- // MemoryIndex must be replaced rather than kept (an index it holds under an object the new
2191
- // schema still carries is left alone). SET COLLATE has a field to write — the index
2192
- // column's own collation. A comparator-only retype has none: an index column carries no
2193
- // logical type, it reads the column's from `newSchema.columns`, so the fresh object IS the
2194
- // whole signal. Without it the base rebuilt its trees under the new comparator while the
2195
- // DDL transaction's own layers went on comparing the old way — and shadowed the base's
2196
- // rebuilt trees once the pending layer became the committed head.
2197
- const updatedIndexes = (structuresRekeyed && this.tableSchema.indexes)
2198
- ? this.tableSchema.indexes.map(idx => ({
2199
- ...idx,
2200
- columns: idx.columns.map(ic => (ic.index === colIndex && collationChanged) ? { ...ic, collation: newCol.collation } : ic),
2201
- }))
2202
- : this.tableSchema.indexes;
2203
- const finalNewTableSchema = Object.freeze({
2204
- ...this.tableSchema,
2205
- columns: Object.freeze(updatedCols),
2206
- columnIndexMap: buildColumnIndexMap(updatedCols),
2207
- primaryKeyDefinition: Object.freeze(updatedPkDef),
2208
- indexes: updatedIndexes ? Object.freeze(updatedIndexes) : updatedIndexes,
2209
- });
2210
- const pkColumnRekeyed = collationChanged && updatedPkDef.some(def => def.index === colIndex);
2211
- // Validate BEFORE any mutation, over the DDL transaction's EFFECTIVE rows: a pair
2212
- // the transaction inserted that collides under the NEW schema must reject the
2213
- // change, and one it has deleted must not block it. A throw here leaves the schema,
2214
- // the base layer and the index map exactly as they were.
2215
- //
2216
- // A value-REWRITING change (`valueConvert`: SET DATA TYPE, or a SET NOT NULL null →
2217
- // DEFAULT backfill) probes the CONVERTED rows — the same per-row conversion the base
2218
- // rewrite below applies — under the NEW schema's comparators, so one call covers both
2219
- // ways an ALTER can collapse two previously-distinct rows: the VALUES converge
2220
- // (`'1'`/`'01'` → 1; two NULLs → one DEFAULT; '2024-06-05T00:00:00Z' → '2024-06-05')
2221
- // and/or the COMPARATOR moves (text → timespan makes 'PT1H'/'PT60M' one value). A
2222
- // same-storage-class retype sets `valueConvert` AND `structuresRekeyed`, so the
2223
- // rewrite arm is tested FIRST — its converted-row probe subsumes the comparator-only
2224
- // one. The rebuild that follows is deliberately non-enforcing, so this is the only
2225
- // guard.
2226
- //
2227
- // The comparator-MOVING arm without a rewrite has one trigger left: SET COLLATE. The
2228
- // values are untouched — hence no `mapRow` — and only the comparator the structures
2229
- // are keyed by moves. `newSchema` carries the new collations, so the probe indexes
2230
- // compare as the rebuilt ones will.
2231
- //
2232
- // The primary key: SET COLLATE on a PK member gets a stricter pre-pass
2233
- // (`validateRekeyedPrimaryKey`): no layer in the chain, base included, may hold a
2234
- // collision. That is what lets every step below succeed unconditionally, and what
2235
- // `TransactionLayer.rekeyPrimaryKey` relies on. The rewrite arm needs no PK pre-pass
2236
- // and cannot shadow one: a retype of a PK column is rejected upstream, the backfill
2237
- // only fires on a column holding NULLs (which a PK member cannot — the engine
2238
- // enforces NOT NULL on every PK member regardless of the declared nullability), and
2239
- // `pkColumnRekeyed` is set only by SET COLLATE, which never sets `valueConvert` — so
2240
- // whenever `pkColumnRekeyed` is true, the `structuresRekeyed` arm still runs.
2241
- // NOTE: if PK members ever become genuinely nullable, the backfill arm gains a PK
2242
- // collision path (two NULL keys → one DEFAULT) and needs `validateRekeyedPrimaryKey`
2243
- // plus a primary-tree re-key of its own.
2244
- if (valueConvert) {
2245
- const convert = valueConvert;
2246
- const nulls = convertNulls;
2247
- await this.validateRekeyedUniqueStructures(finalNewTableSchema, colIndex, rows,
2248
- // Unlike `convertBaseRows`, a conversion failure here is NOT swallowed. Every row
2249
- // the probe sees is visible to the transaction, and the setDataType pre-pass above
2250
- // already proved each one convertible, so a throw is unreachable; surfacing it as
2251
- // MISMATCH still beats probing a stale value that could mask a collision.
2252
- row => convertRowAtIndex(row, colIndex, convert, nulls));
2253
- }
2254
- else if (structuresRekeyed) {
2255
- await this.validateRekeyedUniqueStructures(finalNewTableSchema, colIndex, rows);
2256
- // Unlike the secondary-structure pass above — which only ever judges the effective
2257
- // rows — the PK pass judges TWO row sets: the effective rows (`rows` when a wrapper
2258
- // supplies them) decide whether the change is LEGAL, and this manager's own layer
2259
- // chain decides whether the re-keyed trees can PHYSICALLY carry it. See
2260
- // `validateRekeyedPrimaryKey` for why the sets differ and which status each raises.
2261
- if (pkColumnRekeyed)
2262
- await this.validateRekeyedPrimaryKey(finalNewTableSchema, rows);
2263
- }
2085
+ // Decide + validate, in that order and both before any mutation: `planColumnAttributeChange`
2086
+ // runs the attribute's own pre-validation (the NULL scan, the convertibility scan, the
2087
+ // primary-key carve-outs) over the effective rows, and `validateAlterColumnPlan` runs the
2088
+ // re-keyed UNIQUE / primary-key probes over the schema it produced. Nothing above
2089
+ // `applyAlterColumnToBase` writes, so a throw from either leaves the table as it was.
2090
+ const attributeChange = await planColumnAttributeChange({
2091
+ schema: this.tableSchema,
2092
+ tableName: this._tableName,
2093
+ columnName: change.columnName,
2094
+ colIndex,
2095
+ effectiveRows: this.effectiveRowSource(rows),
2096
+ isCollationRegistered: (n) => this.db.isCollationRegistered(n),
2097
+ }, change);
2098
+ if (attributeChange === null)
2099
+ return; // already in the requested state — nothing to do
2100
+ const plan = buildAlterColumnPlan(this.tableSchema, colIndex, attributeChange);
2101
+ await this.validateAlterColumnPlan(plan, rows);
2264
2102
  // Dry run ends here: everything above validates without mutating (the one earlier
2265
2103
  // side effect, ensureSchemaChangeSafety's committed-layer drain, is semantically
2266
2104
  // neutral bookkeeping), and everything below mutates. See the method doc.
2267
2105
  if (validateOnly)
2268
2106
  return;
2269
- this.baseLayer.updateSchema(finalNewTableSchema);
2270
- // Both arms rebuild the base's structures under the schema `updateSchema` above just
2271
- // swapped in — each MemoryIndex rebuilds its comparator from the CURRENT schema's
2272
- // collation and logical type. The secondary rebuilds are NON-enforcing (the pre-pass
2273
- // above owns uniqueness, and the base's rows are not a subset of the effective rows);
2274
- // the SET COLLATE PK rebuild is strict, since a PK collision cannot be represented at
2275
- // all — the pre-pass has already proved the base collision-free, so the strict
2276
- // rebuild is a live invariant check, not the enforcement path. It runs LAST so its
2277
- // throw leaves the live tree intact for the catch's rollback.
2278
- if (valueConvert) {
2279
- // SET DATA TYPE / SET NOT NULL backfill: convert the committed base rows and REPLACE
2280
- // the primary tree with a fresh one holding them (not an in-place upsert — inheritree
2281
- // forbids mutating a base while the open transaction's layers derive from it).
2282
- // `rebuildPrimaryTreeFromRows` also rebuilds every secondary index from the converted
2283
- // rows under the new comparators, so index-backed lookups see the new values — which
2284
- // is why this arm runs first and subsumes `rebuildAllSecondaryIndexes` when a
2285
- // same-storage-class retype sets `structuresRekeyed` too. The old tree is saved for
2286
- // the catch's rollback, exactly as the PK-rekey path does.
2287
- // NOTE: rebuilds EVERY secondary index, not only those covering the altered column;
2288
- // if a wide-index table ever shows this as slow, filter to indexes whose columns
2289
- // include colIndex. Mirrors the collationChanged path's unconditional rebuild.
2290
- //
2291
- // SET DATA TYPE: a base value that fails to convert is kept as-is — validation over
2292
- // the effective view already rejected any unconvertible value the transaction can SEE,
2293
- // so a surviving one is shadowed by a pending delete/overwrite and is never read back
2294
- // (a ROLLBACK re-exposes it under the new type — DDL is not undone by rollback, the
2295
- // known behavior of `feat-ddl-transaction-capability`).
2296
- // SET NOT NULL (`convertNulls`): null base values are mapped to the DEFAULT literal.
2297
- const convertedBaseRows = this.convertBaseRows(colIndex, valueConvert, convertNulls);
2298
- basePrimaryTreeBeforeRekey = this.baseLayer.primaryTree;
2299
- this.baseLayer.rebuildPrimaryTreeFromRows(convertedBaseRows);
2300
- }
2301
- else if (structuresRekeyed) {
2302
- this.baseLayer.rebuildAllSecondaryIndexes();
2303
- if (pkColumnRekeyed) {
2304
- basePrimaryTreeBeforeRekey = this.baseLayer.primaryTree;
2305
- this.baseLayer.rebuildPrimaryTreeStrict();
2306
- }
2307
- }
2308
- this.tableSchema = finalNewTableSchema;
2107
+ this.applyAlterColumnToBase(plan, undo);
2108
+ this.tableSchema = plan.newSchema;
2309
2109
  this.initializePrimaryKeyFunctions();
2310
- // The base rebuild handed every secondary index a fresh tree under the new
2311
- // comparator; the DDL transaction's own layers still inherit the old ones and froze
2312
- // the old schema at construction. Re-key them, or the rest of the transaction — and
2313
- // everything after the pending layer becomes the committed head at commit — keeps
2314
- // comparing under the old collation / old logical type.
2315
- //
2316
- // When the altered column is part of the primary key, `rebuildPrimaryTreeStrict` also
2317
- // swapped the base primary tree object out from under those layers' copy-on-write
2318
- // bases and invalidated their `pkFunctions`; `rekeyPrimaryKey` rebuilds both, plus
2319
- // every secondary index (each derives its PK comparator/encoder from the PK
2320
- // definition). Outside a transaction there are no open layers and both are no-ops.
2321
- if (valueConvert) {
2322
- // SET DATA TYPE / SET NOT NULL backfill converted the base above; the DDL
2323
- // transaction's own open layers still froze the old schema and hold their own-written
2324
- // rows unconverted. Swap the schema and convert those values so the rest of the
2325
- // transaction — and the committed head at commit — read the new value. For SET NOT
2326
- // NULL this fills the transaction's OWN pending NULL rows (which live in the pending
2327
- // layer, never reached by the old in-place base upsert). `convertColumn` installs the
2328
- // new schema and rebuilds every one of the layer's secondary indexes from it, so it
2329
- // subsumes `adoptSchema` when a same-storage-class retype moved the comparators too.
2330
- // No-op in autocommit.
2331
- this.convertColumnOnOpenLayers(finalNewTableSchema, colIndex, valueConvert, convertNulls);
2332
- }
2333
- else if (structuresRekeyed) {
2334
- this.adoptSchemaOnOpenLayers(finalNewTableSchema, pkColumnRekeyed);
2335
- }
2336
- else {
2337
- // The remaining changes (SET DEFAULT, DROP NOT NULL, a SET NOT NULL that needed no
2338
- // backfill, a retype between aliases of one logical type) touch nothing a layer
2339
- // DERIVES — its index set, its `uniqueConstraints` enforcement and its MemoryIndex
2340
- // comparators all stay put, and DEFAULT application / NOT NULL enforcement happen
2341
- // above the module, off the catalog schema. But the frozen schema OBJECT is itself
2342
- // observable: `commitTransaction` only wraps a swapped-in savepoint snapshot back
2343
- // into the committed chain when `readLayer.getSchema() === this.tableSchema`. Left
2344
- // stale, a `rollback to savepoint` taken across one of these ALTERs restores a
2345
- // snapshot the wrap then skips, and the transaction's staged rows are silently
2346
- // dropped at COMMIT. Adoption is cheap here — every IndexSchema object is carried
2347
- // over unchanged, so `adoptSchema` keeps each layer's MemoryIndex and only swaps
2348
- // the schema reference.
2349
- this.adoptSchemaOnOpenLayers(finalNewTableSchema);
2350
- }
2351
- this.eventEmitter?.emitSchemaChange?.({
2352
- type: 'alter',
2353
- objectType: 'column',
2354
- schemaName: this.schemaName,
2355
- objectName: this._tableName,
2356
- columnName: change.columnName,
2357
- });
2110
+ this.propagateAlterColumnToOpenLayers(plan);
2358
2111
  logger.operation('Alter Column', this._tableName, { columnName: change.columnName });
2359
2112
  }
2360
2113
  catch (e) {
2361
2114
  // Restore the prior schema and primary tree, then re-key the secondary indexes back
2362
- // to it. Both pre-passes now run before any mutation, so nothing below `updateSchema`
2363
- // is expected to throw; the restores are the safety net for an unexpected one (and
2364
- // for `rebuildPrimaryTreeStrict`'s invariant check, whose precondition
2365
- // `validateRekeyedPrimaryKey` has already established).
2115
+ // to it. Both pre-passes run before any mutation, so nothing inside
2116
+ // `applyAlterColumnToBase` is expected to throw; the restores are the safety net for
2117
+ // an unexpected one (and for `rebuildPrimaryTreeStrict`'s invariant check, whose
2118
+ // precondition `validateRekeyedPrimaryKey` has already established).
2366
2119
  //
2367
- // NOTE: a throw from a pre-pass (or from `setNotNull`'s NULL scan) mutated nothing,
2120
+ // NOTE: a throw from a pre-pass (or from `set not null`'s NULL scan) mutated nothing,
2368
2121
  // so this rebuild only swaps the base's index trees for fresh, content-identical
2369
2122
  // ones — an O(rows) cost on a pure rejection. Harmless (a pending layer keeps
2370
2123
  // reading its orphaned but content-correct copy-on-write base), but if a rejected
2371
2124
  // ALTER on a large table ever shows up as slow, gate the rebuild on a "mutation
2372
- // started" flag set just before `updateSchema`.
2125
+ // started" flag set just before `applyAlterColumnToBase`.
2373
2126
  this.baseLayer.updateSchema(originalManagerSchema);
2374
- if (basePrimaryTreeBeforeRekey)
2375
- this.baseLayer.primaryTree = basePrimaryTreeBeforeRekey;
2127
+ if (undo.basePrimaryTree)
2128
+ this.baseLayer.primaryTree = undo.basePrimaryTree;
2376
2129
  this.baseLayer.rebuildAllSecondaryIndexes();
2377
2130
  this.tableSchema = originalManagerSchema;
2378
2131
  this.initializePrimaryKeyFunctions();
@@ -2383,6 +2136,272 @@ export class MemoryTableManager {
2383
2136
  release();
2384
2137
  }
2385
2138
  }
2139
+ /**
2140
+ * Apply `alter table … alter primary key` in place — the table's rows, the open
2141
+ * transaction's pending writes, and its pending change events all survive under the new
2142
+ * key. Follows {@link alterColumn}'s ordering contract: resolve and pre-validate the new
2143
+ * definition (mutating nothing) → probe the re-keyed primary structures
2144
+ * ({@link validateRekeyedPrimaryKey}, the same pass the `set collate` re-key runs) →
2145
+ * rebuild the base → swap this manager's schema → propagate to the open transaction's
2146
+ * layers → emit. What differs from the `set collate` re-key is WHAT moves: the key's
2147
+ * columns rather than its comparator, so each open layer's net deletions and its pending
2148
+ * event log must be re-derived from row images — a two-phase prepare/install pair
2149
+ * ({@link TransactionLayer.prepareRekeyedPrimaryKeyColumns}), with every prepare running
2150
+ * BEFORE the first mutation because a deletion's image resolves only through the intact
2151
+ * old layer chain.
2152
+ *
2153
+ * `validateOnly` runs everything up to (and including) the pre-mutation validation and
2154
+ * returns before the first mutation, throwing exactly what the real application would
2155
+ * throw — the same dry-run contract as {@link alterColumn}'s, for a wrapper (the
2156
+ * isolation layer) that must pre-flight before a shared underlying mutates irreversibly.
2157
+ */
2158
+ async alterPrimaryKey(newPkColumns, rows, validateOnly = false) {
2159
+ if (this.isReadOnly)
2160
+ throw new QuereusError(`Table '${this._tableName}' is read-only`, StatusCode.READONLY);
2161
+ const lockKey = `MemoryTable.SchemaChange:${this.schemaName}.${this._tableName}`;
2162
+ const release = await this.db.latches.acquire(lockKey);
2163
+ const originalManagerSchema = this.tableSchema;
2164
+ const undo = { basePrimaryTree: null };
2165
+ try {
2166
+ await this.ensureSchemaChangeSafety();
2167
+ // NOTE: no early return for a definition equal to the current one (unlike
2168
+ // `alterColumn`'s already-in-the-requested-state exit) — the statement is rare and
2169
+ // its only producer, the declarative differ, emits it solely on a genuine change.
2170
+ // If a caller ever re-issues an unchanged key, add the comparison here: the work
2171
+ // below is a full O(rows × layers) rebuild.
2172
+ const newSchema = this.buildRekeyedPrimaryKeySchema(newPkColumns);
2173
+ // Pre-validate before any mutation: the effective rows decide whether the change
2174
+ // is LEGAL (CONSTRAINT on a visible collision), the manager's own layer chain
2175
+ // whether the re-keyed trees can PHYSICALLY carry it (BUSY when only rows a
2176
+ // rollback must restore collide). A throw leaves everything as it was.
2177
+ await this.validateRekeyedPrimaryKey(newSchema, rows);
2178
+ // Dry run ends here: everything above validates without mutating, everything
2179
+ // below mutates. See the method doc.
2180
+ if (validateOnly)
2181
+ return;
2182
+ // Compute every open layer's re-derived net writes and event log BEFORE the
2183
+ // first mutation: a net deletion's new key comes from the parent's row image at
2184
+ // the old key, which only the intact old chain can still resolve.
2185
+ const newPkFunctions = createPrimaryKeyFunctions(newSchema, this.collationResolver);
2186
+ const plans = this.openTransactionLayersOldestFirst().map(layer => ({
2187
+ layer,
2188
+ prepared: layer.prepareRekeyedPrimaryKeyColumns(newPkFunctions),
2189
+ }));
2190
+ // Base rebuild, mirroring alterColumn's `set collate` arm: secondary indexes
2191
+ // first (each entry's key encoding embeds the primary key), then the strict
2192
+ // primary rebuild LAST so its throw — a live invariant check; the pre-pass has
2193
+ // already proven the base collision-free — leaves the live tree intact for the
2194
+ // rollback below.
2195
+ this.baseLayer.updateSchema(newSchema);
2196
+ this.baseLayer.rebuildAllSecondaryIndexes();
2197
+ undo.basePrimaryTree = this.baseLayer.primaryTree;
2198
+ this.baseLayer.rebuildPrimaryTreeStrict();
2199
+ this.tableSchema = newSchema;
2200
+ this.initializePrimaryKeyFunctions();
2201
+ // Oldest-first (the plans were gathered in that order): each layer's rebuilt tree
2202
+ // inherits copy-on-write from its parent's NEW one. Synchronous and mutation-only.
2203
+ for (const { layer, prepared } of plans) {
2204
+ layer.installRekeyedPrimaryKeyColumns(newSchema, prepared);
2205
+ }
2206
+ logger.operation('Alter Primary Key', this._tableName, {
2207
+ columns: newSchema.primaryKeyDefinition.map(def => def.index),
2208
+ });
2209
+ }
2210
+ catch (e) {
2211
+ // Restore the prior schema and primary tree, then re-key the secondary indexes
2212
+ // back to it — the same safety net as alterColumn's catch: both pre-passes run
2213
+ // before any mutation, so nothing in the apply steps is expected to throw.
2214
+ this.baseLayer.updateSchema(originalManagerSchema);
2215
+ if (undo.basePrimaryTree)
2216
+ this.baseLayer.primaryTree = undo.basePrimaryTree;
2217
+ this.baseLayer.rebuildAllSecondaryIndexes();
2218
+ this.tableSchema = originalManagerSchema;
2219
+ this.initializePrimaryKeyFunctions();
2220
+ logger.error('Alter Primary Key', this._tableName, e);
2221
+ throw e;
2222
+ }
2223
+ finally {
2224
+ release();
2225
+ }
2226
+ }
2227
+ /**
2228
+ * Resolve `alter primary key`'s column list against the current schema — bounds, no
2229
+ * duplicates, every member NOT NULL — and return the re-keyed schema. The engine's
2230
+ * emitter validates the same three by column NAME before dispatch; re-checking by index
2231
+ * here keeps a wrapper driving the module API directly (the isolation layer) from
2232
+ * installing an unkeyable definition. The schema construction itself (definition +
2233
+ * per-column flag rebuild, member collations carried) is delegated to the shared
2234
+ * {@link rekeySchemaPrimaryKey}, which the store's native arm uses too.
2235
+ */
2236
+ buildRekeyedPrimaryKeySchema(newPkColumns) {
2237
+ const columns = this.tableSchema.columns;
2238
+ const seen = new Set();
2239
+ for (const pk of newPkColumns) {
2240
+ if (pk.index < 0 || pk.index >= columns.length) {
2241
+ throw new QuereusError(`Primary key column index ${pk.index} is out of bounds for table '${this._tableName}'.`, StatusCode.ERROR);
2242
+ }
2243
+ if (seen.has(pk.index)) {
2244
+ throw new QuereusError(`Duplicate column '${columns[pk.index].name}' in PRIMARY KEY definition`, StatusCode.ERROR);
2245
+ }
2246
+ seen.add(pk.index);
2247
+ if (!columns[pk.index].notNull) {
2248
+ throw new QuereusError(`Column '${columns[pk.index].name}' must be NOT NULL to participate in PRIMARY KEY`, StatusCode.CONSTRAINT);
2249
+ }
2250
+ }
2251
+ return rekeySchemaPrimaryKey(this.tableSchema, newPkColumns);
2252
+ }
2253
+ /**
2254
+ * The re-keyed-structure pre-pass for {@link alterColumn}, over the DDL transaction's EFFECTIVE
2255
+ * rows: a pair the transaction inserted that collides under the NEW schema must reject the
2256
+ * change, and one it has deleted must not block it. Runs before any mutation, so a throw leaves
2257
+ * the schema, the base layer and the index map exactly as they were.
2258
+ *
2259
+ * A value-REWRITING change (`set data type`, or a `set not null` null → DEFAULT backfill) probes
2260
+ * the CONVERTED rows — the same per-row conversion the base rewrite applies — under the NEW
2261
+ * schema's comparators, so one call covers both ways an ALTER can collapse two previously-distinct
2262
+ * rows: the VALUES converge (`'1'`/`'01'` → 1; two NULLs → one DEFAULT;
2263
+ * '2024-06-05T00:00:00Z' → '2024-06-05') and/or the COMPARATOR moves (text → timespan makes
2264
+ * 'PT1H'/'PT60M' one value). A same-storage-class retype sets both `rewrite` and
2265
+ * `structuresRekeyed`, so the rewrite arm is tested FIRST — its converted-row probe subsumes the
2266
+ * comparator-only one. The rebuild that follows is deliberately non-enforcing, so this is the
2267
+ * only guard.
2268
+ *
2269
+ * The comparator-MOVING arm without a rewrite has one trigger left: `set collate`. The values are
2270
+ * untouched — hence no `mapRow` — and only the comparator the structures are keyed by moves.
2271
+ * `newSchema` carries the new collations, so the probe indexes compare as the rebuilt ones will.
2272
+ *
2273
+ * The primary key: `set collate` on a PK member gets a stricter pre-pass
2274
+ * ({@link validateRekeyedPrimaryKey}): no layer in the chain, base included, may hold a collision.
2275
+ * That is what lets every apply step succeed unconditionally, and what
2276
+ * `TransactionLayer.rekeyPrimaryKey` relies on. The rewrite arm needs no PK pre-pass and cannot
2277
+ * shadow one: a retype of a PK column is rejected upstream, the backfill only fires on a column
2278
+ * holding NULLs (which a PK member cannot — the engine enforces NOT NULL on every PK member
2279
+ * regardless of the declared nullability), and `pkColumnRekeyed` is set only by `set collate`,
2280
+ * which never sets `rewrite` — so whenever `pkColumnRekeyed` is true, the `structuresRekeyed` arm
2281
+ * still runs.
2282
+ * NOTE: if PK members ever become genuinely nullable, the backfill arm gains a PK collision path
2283
+ * (two NULL keys → one DEFAULT) and needs `validateRekeyedPrimaryKey` plus a primary-tree re-key
2284
+ * of its own.
2285
+ */
2286
+ async validateAlterColumnPlan(plan, rows) {
2287
+ if (plan.rewrite) {
2288
+ const { convert, convertNulls } = plan.rewrite;
2289
+ await this.validateRekeyedUniqueStructures(plan.newSchema, plan.colIndex, rows,
2290
+ // Unlike `convertBaseRows`, a conversion failure here is NOT swallowed. Every row
2291
+ // the probe sees is visible to the transaction, and the `set data type` pre-pass
2292
+ // already proved each one convertible, so a throw is unreachable; surfacing it as
2293
+ // MISMATCH still beats probing a stale value that could mask a collision.
2294
+ row => convertRowAtIndex(row, plan.colIndex, convert, convertNulls));
2295
+ }
2296
+ else if (plan.structuresRekeyed) {
2297
+ await this.validateRekeyedUniqueStructures(plan.newSchema, plan.colIndex, rows);
2298
+ // Unlike the secondary-structure pass above — which only ever judges the effective
2299
+ // rows — the PK pass judges TWO row sets: the effective rows (`rows` when a wrapper
2300
+ // supplies them) decide whether the change is LEGAL, and this manager's own layer
2301
+ // chain decides whether the re-keyed trees can PHYSICALLY carry it. See
2302
+ // `validateRekeyedPrimaryKey` for why the sets differ and which status each raises.
2303
+ if (plan.pkColumnRekeyed)
2304
+ await this.validateRekeyedPrimaryKey(plan.newSchema, rows);
2305
+ }
2306
+ }
2307
+ /**
2308
+ * First mutation of {@link alterColumn}: install the new schema on the base layer and rebuild its
2309
+ * structures under it — each MemoryIndex rebuilds its comparator from the CURRENT schema's
2310
+ * collation and logical type. The secondary rebuilds are NON-enforcing ({@link validateAlterColumnPlan}
2311
+ * owns uniqueness, and the base's rows are not a subset of the effective rows); the `set collate`
2312
+ * PK rebuild is strict, since a PK collision cannot be represented at all — the pre-pass has
2313
+ * already proved the base collision-free, so the strict rebuild is a live invariant check, not
2314
+ * the enforcement path. It runs LAST so its throw leaves the live tree intact for the rollback.
2315
+ *
2316
+ * Records the primary tree it is about to REPLACE in `undo` *before* replacing it, so a throw
2317
+ * from either rebuild still leaves the caller's `catch` a tree to restore.
2318
+ */
2319
+ applyAlterColumnToBase(plan, undo) {
2320
+ this.baseLayer.updateSchema(plan.newSchema);
2321
+ if (plan.rewrite) {
2322
+ // `set data type` / `set not null` backfill: convert the committed base rows and REPLACE
2323
+ // the primary tree with a fresh one holding them (not an in-place upsert — inheritree
2324
+ // forbids mutating a base while the open transaction's layers derive from it).
2325
+ // `rebuildPrimaryTreeFromRows` also rebuilds every secondary index from the converted
2326
+ // rows under the new comparators, so index-backed lookups see the new values — which
2327
+ // is why this arm runs first and subsumes `rebuildAllSecondaryIndexes` when a
2328
+ // same-storage-class retype sets `structuresRekeyed` too.
2329
+ // NOTE: rebuilds EVERY secondary index, not only those covering the altered column;
2330
+ // if a wide-index table ever shows this as slow, filter to indexes whose columns
2331
+ // include colIndex. Mirrors the `set collate` path's unconditional rebuild.
2332
+ //
2333
+ // `set data type`: a base value that fails to convert is kept as-is — validation over
2334
+ // the effective view already rejected any unconvertible value the transaction can SEE,
2335
+ // so a surviving one is shadowed by a pending delete/overwrite and is never read back
2336
+ // (a ROLLBACK re-exposes it under the new type — DDL is not undone by rollback, the
2337
+ // known behavior of `feat-ddl-transaction-capability`).
2338
+ // `set not null` (`convertNulls`): null base values are mapped to the DEFAULT literal.
2339
+ const convertedBaseRows = this.convertBaseRows(plan.colIndex, plan.rewrite.convert, plan.rewrite.convertNulls);
2340
+ undo.basePrimaryTree = this.baseLayer.primaryTree;
2341
+ this.baseLayer.rebuildPrimaryTreeFromRows(convertedBaseRows);
2342
+ }
2343
+ else if (plan.structuresRekeyed) {
2344
+ this.baseLayer.rebuildAllSecondaryIndexes();
2345
+ if (plan.pkColumnRekeyed) {
2346
+ undo.basePrimaryTree = this.baseLayer.primaryTree;
2347
+ this.baseLayer.rebuildPrimaryTreeStrict();
2348
+ }
2349
+ }
2350
+ }
2351
+ /**
2352
+ * Hand the post-{@link alterColumn} schema to the DDL transaction's own open layers.
2353
+ *
2354
+ * The base rebuild handed every secondary index a fresh tree under the new comparator; those
2355
+ * layers still inherit the old ones and froze the old schema at construction. Re-key them, or
2356
+ * the rest of the transaction — and everything after the pending layer becomes the committed
2357
+ * head at commit — keeps comparing under the old collation / old logical type.
2358
+ *
2359
+ * When the altered column is part of the primary key, `rebuildPrimaryTreeStrict` also swapped the
2360
+ * base primary tree object out from under those layers' copy-on-write bases and invalidated their
2361
+ * `pkFunctions`; `rekeyPrimaryKey` rebuilds both, plus every secondary index (each derives its PK
2362
+ * comparator/encoder from the PK definition). Outside a transaction there are no open layers and
2363
+ * every arm is a no-op.
2364
+ */
2365
+ propagateAlterColumnToOpenLayers(plan) {
2366
+ if (plan.rewrite) {
2367
+ // `set data type` / `set not null` backfill converted the base; the open layers still hold
2368
+ // their own-written rows unconverted. Swap the schema and convert those values so the rest
2369
+ // of the transaction — and the committed head at commit — read the new value. For
2370
+ // `set not null` this fills the transaction's OWN pending NULL rows (which live in the
2371
+ // pending layer, never reached by an in-place base upsert). `convertColumn` installs the
2372
+ // new schema and rebuilds every one of the layer's secondary indexes from it, so it
2373
+ // subsumes `adoptSchema` when a same-storage-class retype moved the comparators too.
2374
+ this.convertColumnOnOpenLayers(plan.newSchema, plan.colIndex, plan.rewrite.convert, plan.rewrite.convertNulls);
2375
+ }
2376
+ else if (plan.structuresRekeyed) {
2377
+ this.adoptSchemaOnOpenLayers(plan.newSchema, plan.pkColumnRekeyed);
2378
+ }
2379
+ else {
2380
+ // The remaining changes (`set default`, `drop not null`, a `set not null` that needed no
2381
+ // backfill, a retype between aliases of one logical type) touch nothing a layer
2382
+ // DERIVES — its index set, its `uniqueConstraints` enforcement and its MemoryIndex
2383
+ // comparators all stay put, and DEFAULT application / NOT NULL enforcement happen
2384
+ // above the module, off the catalog schema. But the frozen schema OBJECT is itself
2385
+ // observable: `commitTransaction` only wraps a swapped-in savepoint snapshot back
2386
+ // into the committed chain when `readLayer.getSchema() === this.tableSchema`. Left
2387
+ // stale, a `rollback to savepoint` taken across one of these ALTERs restores a
2388
+ // snapshot the wrap then skips, and the transaction's staged rows are silently
2389
+ // dropped at COMMIT. Adoption is cheap here — every IndexSchema object is carried
2390
+ // over unchanged, so `adoptSchema` keeps each layer's MemoryIndex and only swaps
2391
+ // the schema reference.
2392
+ this.adoptSchemaOnOpenLayers(plan.newSchema);
2393
+ }
2394
+ }
2395
+ /**
2396
+ * The rows the `alter column` pre-validation scans judge: `rows` when a wrapper module supplies
2397
+ * them (the isolation overlay holds the transaction's pending rows outside this manager, so only
2398
+ * it can name the rows the issuing connection actually sees), else this manager's own layered
2399
+ * view ({@link effectiveDdlRows}) — which stays a SYNC iterable on purpose, so a scan over it
2400
+ * cannot be interleaved with another connection's write. See `scanEffectiveRows`.
2401
+ */
2402
+ effectiveRowSource(rows) {
2403
+ return rows ?? (() => this.effectiveDdlRows());
2404
+ }
2386
2405
  async createIndex(newIndexSchemaEntry, ifNotExistsFromAst, rows) {
2387
2406
  if (this.isReadOnly)
2388
2407
  throw new QuereusError(`Table '${this._tableName}' is read-only`, StatusCode.READONLY);
@@ -2580,12 +2599,6 @@ export class MemoryTableManager {
2580
2599
  // stops enforcing for the rest of it; harmless for CHECK/FK (they re-freeze an
2581
2600
  // equivalent schema, holding no per-layer structure).
2582
2601
  this.adoptSchemaOnOpenLayers(newSchema);
2583
- this.eventEmitter?.emitSchemaChange?.({
2584
- type: 'alter',
2585
- objectType: 'table',
2586
- schemaName: this.schemaName,
2587
- objectName: this._tableName,
2588
- });
2589
2602
  logger.operation('Drop Constraint', this._tableName, { constraintName });
2590
2603
  }
2591
2604
  catch (e) {
@@ -2666,12 +2679,6 @@ export class MemoryTableManager {
2666
2679
  // check (`readLayer.getSchema() === this.tableSchema`) skips a savepoint snapshot
2667
2680
  // restored across this ALTER and drops the transaction's staged rows at COMMIT.
2668
2681
  this.adoptSchemaOnOpenLayers(newSchema);
2669
- this.eventEmitter?.emitSchemaChange?.({
2670
- type: 'alter',
2671
- objectType: 'table',
2672
- schemaName: this.schemaName,
2673
- objectName: this._tableName,
2674
- });
2675
2682
  logger.operation('Rename Constraint', this._tableName, { oldName, newName });
2676
2683
  }
2677
2684
  catch (e) {
@@ -2724,12 +2731,6 @@ export class MemoryTableManager {
2724
2731
  else {
2725
2732
  throw new QuereusError(`MemoryTable ADD CONSTRAINT does not support constraint type '${constraint.type}'`, StatusCode.UNSUPPORTED);
2726
2733
  }
2727
- this.eventEmitter?.emitSchemaChange?.({
2728
- type: 'alter',
2729
- objectType: 'table',
2730
- schemaName: this.schemaName,
2731
- objectName: this._tableName,
2732
- });
2733
2734
  logger.operation('Add Constraint', this._tableName, { type: constraint.type, name: constraint.name });
2734
2735
  }
2735
2736
  catch (e) {
@@ -2783,7 +2784,11 @@ export class MemoryTableManager {
2783
2784
  // would under-enforce this non-derived UNIQUE. A collation mismatch falls
2784
2785
  // through to build the distinct `_uc_*` covering index; the user index keeps
2785
2786
  // enforcing its own (stricter) uniqueness independently (matches SQLite).
2786
- const matchingUniqueIndex = existingIndexes.find(idx => idx.unique &&
2787
+ // A FILTERED (partial) unique index only guarantees uniqueness among the rows
2788
+ // its own predicate admits, so it can't back a full (unfiltered) UNIQUE either —
2789
+ // same reasoning as `ensureUniqueConstraintIndexes` above.
2790
+ const matchingUniqueIndex = uc.predicate ? undefined : existingIndexes.find(idx => idx.unique &&
2791
+ !idx.predicate &&
2787
2792
  idx.columns.length === uc.columns.length &&
2788
2793
  idx.columns.every((col, i) => col.index === uc.columns[i]) &&
2789
2794
  this.indexCollationsMatchDeclared(idx, uc));
@@ -2803,8 +2808,7 @@ export class MemoryTableManager {
2803
2808
  this.adoptSchemaOnOpenLayers(newSchema);
2804
2809
  return;
2805
2810
  }
2806
- const colNames = uc.columns.map(i => columns[i]?.name ?? String(i));
2807
- const indexName = uc.name ?? `_uc_${colNames.join('_')}`;
2811
+ const indexName = uc.name ?? implicitIndexNameOver(uc, columns);
2808
2812
  const indexSchema = {
2809
2813
  name: indexName,
2810
2814
  // Carry per-column collation so enforcement honors e.g. NOCASE (mirrors
@@ -3122,8 +3126,11 @@ export class MemoryTableManager {
3122
3126
  }
3123
3127
  }
3124
3128
  /**
3125
- * PRIMARY KEY arm of the `alter column … set collate` pre-pass. Runs before anything is
3126
- * mutated, so a rejection leaves the table, the schema and the transaction untouched.
3129
+ * The primary-key re-key pre-pass, shared by both statements that move the key:
3130
+ * `alter column … set collate` on a PK member (the comparator moves) and
3131
+ * `alter table … alter primary key` (the key columns move — {@link alterPrimaryKey}).
3132
+ * Runs before anything is mutated, so a rejection leaves the table, the schema and the
3133
+ * transaction untouched.
3127
3134
  *
3128
3135
  * Asks two questions, in order, over two DIFFERENT row sets:
3129
3136
  *
@@ -3141,11 +3148,11 @@ export class MemoryTableManager {
3141
3148
  * necessity, not because the data is invalid: the base must keep both rows for a
3142
3149
  * rollback, and a base re-keyed under the new collation could not represent the pair
3143
3150
  * at all → `BUSY` with the same "commit/rollback and retry" posture as
3144
- * {@link ensureSchemaChangeSafety}. The persistent store backend refuses the same
3145
- * shape for the same reason (its committed rows equally survive a rollback — see
3146
- * `backlog/bug-store-pk-collate-rejects-deleted-row-collision`); accepting it would
3147
- * take transaction-scoped DDL (`backlog/feat-transactional-ddl-native-backends`),
3148
- * which Quereus does not have.
3151
+ * {@link ensureSchemaChangeSafety}. The persistent store backend asks the same two
3152
+ * questions with the same statuses (`StoreTable.validateRekeyedPrimaryKey` in
3153
+ * quereus-store — its committed rows equally survive a rollback); accepting the
3154
+ * deleted-collider shape instead would take transaction-scoped DDL
3155
+ * (`backlog/feat-transactional-ddl-native-backends`), which Quereus does not have.
3149
3156
  *
3150
3157
  * The passes judge different sets because a wrapper's effective stream and this manager's
3151
3158
  * layers genuinely diverge: staged inserts exist only in the stream, deleted committed
@@ -3161,9 +3168,10 @@ export class MemoryTableManager {
3161
3168
  * rebase that savepoint snapshots exist to avoid. The tradeoff is a rare false BUSY on a
3162
3169
  * statement sequence the user can retry after committing, versus losing a row on rollback.
3163
3170
  *
3164
- * This precondition is also what makes `TransactionLayer.rekeyPrimaryKey`'s replay sound:
3165
- * with no collisions anywhere in the chain, every primary key resolves to at most one row
3166
- * in each layer under the new comparator.
3171
+ * This precondition is also what makes the open-layer replays sound — both
3172
+ * `TransactionLayer.rekeyPrimaryKey`'s and `installRekeyedPrimaryKeyColumns`'s: with no
3173
+ * collisions anywhere in the chain, every primary key resolves to at most one row in
3174
+ * each layer under the new definition.
3167
3175
  */
3168
3176
  async validateRekeyedPrimaryKey(newSchema, rows) {
3169
3177
  const newPkFunctions = createPrimaryKeyFunctions(newSchema, this.collationResolver);
@@ -3211,8 +3219,11 @@ export class MemoryTableManager {
3211
3219
  const key = seen(row);
3212
3220
  if (key === undefined)
3213
3221
  continue;
3214
- const keyDesc = keyParts(key, keyIsTuple).map(formatKeyValue).join(', ');
3215
- throw new QuereusError(`UNIQUE constraint failed: ${this._tableName} primary key collides under new collation (key: ${keyDesc})`, StatusCode.CONSTRAINT);
3222
+ // An empty new key (`alter primary key ()`, the singleton table) has no components
3223
+ // to name: every row IS the one key, so say that rather than render "(key: )".
3224
+ const parts = keyParts(key, keyIsTuple).map(formatKeyValue);
3225
+ const keyDesc = parts.length > 0 ? `(key: ${parts.join(', ')})` : '(the empty key admits one row)';
3226
+ throw new QuereusError(`UNIQUE constraint failed: ${this._tableName} primary key collides under the new key definition ${keyDesc}`, StatusCode.CONSTRAINT);
3216
3227
  }
3217
3228
  }
3218
3229
  /**
@@ -3233,8 +3244,8 @@ export class MemoryTableManager {
3233
3244
  const seen = this.makePrimaryKeyProbe(pkFunctions);
3234
3245
  for (const row of iteratePrimaryRows(tree)) {
3235
3246
  if (seen(row) !== undefined) {
3236
- throw new QuereusError(`Cannot change the collation of a primary key column of table ${this._tableName}: `
3237
- + `rows this transaction has removed still collide under the new collation and must survive a rollback. `
3247
+ throw new QuereusError(`Cannot re-key the primary key of table ${this._tableName}: `
3248
+ + `rows this transaction has removed still collide under the new key definition and must survive a rollback. `
3238
3249
  + `Commit/rollback and retry.`, StatusCode.BUSY);
3239
3250
  }
3240
3251
  }