@quereus/quereus 4.3.2 → 4.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (396) hide show
  1. package/README.md +5 -0
  2. package/dist/src/common/types.d.ts +9 -0
  3. package/dist/src/common/types.d.ts.map +1 -1
  4. package/dist/src/common/types.js.map +1 -1
  5. package/dist/src/core/database-events.d.ts +49 -0
  6. package/dist/src/core/database-events.d.ts.map +1 -1
  7. package/dist/src/core/database-events.js +148 -0
  8. package/dist/src/core/database-events.js.map +1 -1
  9. package/dist/src/core/database-external-changes.d.ts +2 -2
  10. package/dist/src/core/database-external-changes.d.ts.map +1 -1
  11. package/dist/src/core/database-external-changes.js +12 -9
  12. package/dist/src/core/database-external-changes.js.map +1 -1
  13. package/dist/src/core/database-materialized-views-apply.d.ts +156 -14
  14. package/dist/src/core/database-materialized-views-apply.d.ts.map +1 -1
  15. package/dist/src/core/database-materialized-views-apply.js +370 -65
  16. package/dist/src/core/database-materialized-views-apply.js.map +1 -1
  17. package/dist/src/core/database-materialized-views-plan-builders.d.ts +66 -1
  18. package/dist/src/core/database-materialized-views-plan-builders.d.ts.map +1 -1
  19. package/dist/src/core/database-materialized-views-plan-builders.js +368 -8
  20. package/dist/src/core/database-materialized-views-plan-builders.js.map +1 -1
  21. package/dist/src/core/database-materialized-views-plans.d.ts +257 -30
  22. package/dist/src/core/database-materialized-views-plans.d.ts.map +1 -1
  23. package/dist/src/core/database-materialized-views.d.ts +99 -42
  24. package/dist/src/core/database-materialized-views.d.ts.map +1 -1
  25. package/dist/src/core/database-materialized-views.js +198 -121
  26. package/dist/src/core/database-materialized-views.js.map +1 -1
  27. package/dist/src/core/database.d.ts +5 -0
  28. package/dist/src/core/database.d.ts.map +1 -1
  29. package/dist/src/core/database.js +41 -18
  30. package/dist/src/core/database.js.map +1 -1
  31. package/dist/src/core/internal-statement-cache.d.ts +18 -0
  32. package/dist/src/core/internal-statement-cache.d.ts.map +1 -0
  33. package/dist/src/core/internal-statement-cache.js +211 -0
  34. package/dist/src/core/internal-statement-cache.js.map +1 -0
  35. package/dist/src/func/builtins/aggregate.d.ts +13 -12
  36. package/dist/src/func/builtins/aggregate.d.ts.map +1 -1
  37. package/dist/src/func/builtins/aggregate.js +146 -62
  38. package/dist/src/func/builtins/aggregate.js.map +1 -1
  39. package/dist/src/func/builtins/builtin-window-functions.d.ts.map +1 -1
  40. package/dist/src/func/builtins/builtin-window-functions.js +63 -48
  41. package/dist/src/func/builtins/builtin-window-functions.js.map +1 -1
  42. package/dist/src/func/registration.d.ts +19 -1
  43. package/dist/src/func/registration.d.ts.map +1 -1
  44. package/dist/src/func/registration.js +41 -0
  45. package/dist/src/func/registration.js.map +1 -1
  46. package/dist/src/index.d.ts +8 -8
  47. package/dist/src/index.d.ts.map +1 -1
  48. package/dist/src/index.js +12 -11
  49. package/dist/src/index.js.map +1 -1
  50. package/dist/src/parser/parser.d.ts +6 -0
  51. package/dist/src/parser/parser.d.ts.map +1 -1
  52. package/dist/src/parser/parser.js +45 -34
  53. package/dist/src/parser/parser.js.map +1 -1
  54. package/dist/src/planner/analysis/comparison-collation.d.ts +2 -0
  55. package/dist/src/planner/analysis/comparison-collation.d.ts.map +1 -1
  56. package/dist/src/planner/analysis/comparison-collation.js +1 -1
  57. package/dist/src/planner/analysis/comparison-collation.js.map +1 -1
  58. package/dist/src/planner/analysis/equi-correlation.d.ts +26 -0
  59. package/dist/src/planner/analysis/equi-correlation.d.ts.map +1 -0
  60. package/dist/src/planner/analysis/equi-correlation.js +62 -0
  61. package/dist/src/planner/analysis/equi-correlation.js.map +1 -0
  62. package/dist/src/planner/analysis/expression-fingerprint.d.ts.map +1 -1
  63. package/dist/src/planner/analysis/expression-fingerprint.js +29 -0
  64. package/dist/src/planner/analysis/expression-fingerprint.js.map +1 -1
  65. package/dist/src/planner/analysis/query-rewrite-matcher.d.ts +60 -18
  66. package/dist/src/planner/analysis/query-rewrite-matcher.d.ts.map +1 -1
  67. package/dist/src/planner/analysis/query-rewrite-matcher.js +95 -42
  68. package/dist/src/planner/analysis/query-rewrite-matcher.js.map +1 -1
  69. package/dist/src/planner/analysis/sat-checker.d.ts.map +1 -1
  70. package/dist/src/planner/analysis/sat-checker.js +43 -4
  71. package/dist/src/planner/analysis/sat-checker.js.map +1 -1
  72. package/dist/src/planner/analysis/scalar-subqueries.d.ts +28 -0
  73. package/dist/src/planner/analysis/scalar-subqueries.d.ts.map +1 -0
  74. package/dist/src/planner/analysis/scalar-subqueries.js +60 -0
  75. package/dist/src/planner/analysis/scalar-subqueries.js.map +1 -0
  76. package/dist/src/planner/building/delete.d.ts.map +1 -1
  77. package/dist/src/planner/building/delete.js +10 -3
  78. package/dist/src/planner/building/delete.js.map +1 -1
  79. package/dist/src/planner/building/expression.d.ts.map +1 -1
  80. package/dist/src/planner/building/expression.js +87 -6
  81. package/dist/src/planner/building/expression.js.map +1 -1
  82. package/dist/src/planner/building/foreign-key-builder.d.ts +44 -1
  83. package/dist/src/planner/building/foreign-key-builder.d.ts.map +1 -1
  84. package/dist/src/planner/building/foreign-key-builder.js +54 -0
  85. package/dist/src/planner/building/foreign-key-builder.js.map +1 -1
  86. package/dist/src/planner/building/insert.d.ts.map +1 -1
  87. package/dist/src/planner/building/insert.js +9 -12
  88. package/dist/src/planner/building/insert.js.map +1 -1
  89. package/dist/src/planner/building/select.d.ts.map +1 -1
  90. package/dist/src/planner/building/select.js +15 -1
  91. package/dist/src/planner/building/select.js.map +1 -1
  92. package/dist/src/planner/building/update.d.ts.map +1 -1
  93. package/dist/src/planner/building/update.js +13 -4
  94. package/dist/src/planner/building/update.js.map +1 -1
  95. package/dist/src/planner/building/with.d.ts.map +1 -1
  96. package/dist/src/planner/building/with.js +5 -8
  97. package/dist/src/planner/building/with.js.map +1 -1
  98. package/dist/src/planner/cache/materialization-advisory.d.ts +33 -0
  99. package/dist/src/planner/cache/materialization-advisory.d.ts.map +1 -1
  100. package/dist/src/planner/cache/materialization-advisory.js +164 -28
  101. package/dist/src/planner/cache/materialization-advisory.js.map +1 -1
  102. package/dist/src/planner/cache/reference-graph.d.ts +0 -4
  103. package/dist/src/planner/cache/reference-graph.d.ts.map +1 -1
  104. package/dist/src/planner/cache/reference-graph.js +5 -13
  105. package/dist/src/planner/cache/reference-graph.js.map +1 -1
  106. package/dist/src/planner/cost/index.d.ts +28 -7
  107. package/dist/src/planner/cost/index.d.ts.map +1 -1
  108. package/dist/src/planner/cost/index.js +26 -0
  109. package/dist/src/planner/cost/index.js.map +1 -1
  110. package/dist/src/planner/framework/pass.js +3 -3
  111. package/dist/src/planner/nodes/cache-node.d.ts +18 -2
  112. package/dist/src/planner/nodes/cache-node.d.ts.map +1 -1
  113. package/dist/src/planner/nodes/cache-node.js +42 -3
  114. package/dist/src/planner/nodes/cache-node.js.map +1 -1
  115. package/dist/src/planner/nodes/cte-node.d.ts +15 -1
  116. package/dist/src/planner/nodes/cte-node.d.ts.map +1 -1
  117. package/dist/src/planner/nodes/cte-node.js +12 -2
  118. package/dist/src/planner/nodes/cte-node.js.map +1 -1
  119. package/dist/src/planner/nodes/dml-executor-node.d.ts +0 -9
  120. package/dist/src/planner/nodes/dml-executor-node.d.ts.map +1 -1
  121. package/dist/src/planner/nodes/dml-executor-node.js.map +1 -1
  122. package/dist/src/planner/nodes/recursive-cte-node.d.ts +30 -1
  123. package/dist/src/planner/nodes/recursive-cte-node.d.ts.map +1 -1
  124. package/dist/src/planner/nodes/recursive-cte-node.js +30 -3
  125. package/dist/src/planner/nodes/recursive-cte-node.js.map +1 -1
  126. package/dist/src/planner/nodes/scalar.d.ts.map +1 -1
  127. package/dist/src/planner/nodes/scalar.js +26 -3
  128. package/dist/src/planner/nodes/scalar.js.map +1 -1
  129. package/dist/src/planner/optimizer.d.ts.map +1 -1
  130. package/dist/src/planner/optimizer.js +129 -8
  131. package/dist/src/planner/optimizer.js.map +1 -1
  132. package/dist/src/planner/rules/access/rule-select-access-path.d.ts.map +1 -1
  133. package/dist/src/planner/rules/access/rule-select-access-path.js +43 -18
  134. package/dist/src/planner/rules/access/rule-select-access-path.js.map +1 -1
  135. package/dist/src/planner/rules/cache/rule-cte-optimization.d.ts.map +1 -1
  136. package/dist/src/planner/rules/cache/rule-cte-optimization.js +8 -1
  137. package/dist/src/planner/rules/cache/rule-cte-optimization.js.map +1 -1
  138. package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.d.ts.map +1 -1
  139. package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.js +72 -54
  140. package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.js.map +1 -1
  141. package/dist/src/planner/rules/cache/rule-mutating-subquery-cache.d.ts.map +1 -1
  142. package/dist/src/planner/rules/cache/rule-mutating-subquery-cache.js +6 -0
  143. package/dist/src/planner/rules/cache/rule-mutating-subquery-cache.js.map +1 -1
  144. package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.d.ts +25 -0
  145. package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.d.ts.map +1 -0
  146. package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.js +176 -0
  147. package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.js.map +1 -0
  148. package/dist/src/planner/rules/cache/rule-scalar-subquery-cache.d.ts +31 -0
  149. package/dist/src/planner/rules/cache/rule-scalar-subquery-cache.d.ts.map +1 -0
  150. package/dist/src/planner/rules/cache/rule-scalar-subquery-cache.js +68 -0
  151. package/dist/src/planner/rules/cache/rule-scalar-subquery-cache.js.map +1 -0
  152. package/dist/src/planner/rules/join/rule-fanout-lookup-join.d.ts.map +1 -1
  153. package/dist/src/planner/rules/join/rule-fanout-lookup-join.js +1 -54
  154. package/dist/src/planner/rules/join/rule-fanout-lookup-join.js.map +1 -1
  155. package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.js +8 -1
  156. package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.js.map +1 -1
  157. package/dist/src/planner/rules/subquery/rule-scalar-agg-decorrelation.d.ts +191 -0
  158. package/dist/src/planner/rules/subquery/rule-scalar-agg-decorrelation.d.ts.map +1 -0
  159. package/dist/src/planner/rules/subquery/rule-scalar-agg-decorrelation.js +627 -0
  160. package/dist/src/planner/rules/subquery/rule-scalar-agg-decorrelation.js.map +1 -0
  161. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.d.ts +10 -1
  162. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.d.ts.map +1 -1
  163. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js +242 -51
  164. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js.map +1 -1
  165. package/dist/src/runtime/cache/shared-cache.d.ts +7 -0
  166. package/dist/src/runtime/cache/shared-cache.d.ts.map +1 -1
  167. package/dist/src/runtime/cache/shared-cache.js +34 -1
  168. package/dist/src/runtime/cache/shared-cache.js.map +1 -1
  169. package/dist/src/runtime/deferred-constraint-queue.d.ts.map +1 -1
  170. package/dist/src/runtime/deferred-constraint-queue.js +10 -0
  171. package/dist/src/runtime/deferred-constraint-queue.js.map +1 -1
  172. package/dist/src/runtime/emit/aggregate-setup.d.ts +49 -0
  173. package/dist/src/runtime/emit/aggregate-setup.d.ts.map +1 -0
  174. package/dist/src/runtime/emit/aggregate-setup.js +99 -0
  175. package/dist/src/runtime/emit/aggregate-setup.js.map +1 -0
  176. package/dist/src/runtime/emit/aggregate.d.ts +2 -3
  177. package/dist/src/runtime/emit/aggregate.d.ts.map +1 -1
  178. package/dist/src/runtime/emit/aggregate.js +10 -84
  179. package/dist/src/runtime/emit/aggregate.js.map +1 -1
  180. package/dist/src/runtime/emit/alter-table.d.ts.map +1 -1
  181. package/dist/src/runtime/emit/alter-table.js +348 -165
  182. package/dist/src/runtime/emit/alter-table.js.map +1 -1
  183. package/dist/src/runtime/emit/asof-scan.d.ts.map +1 -1
  184. package/dist/src/runtime/emit/asof-scan.js +6 -0
  185. package/dist/src/runtime/emit/asof-scan.js.map +1 -1
  186. package/dist/src/runtime/emit/between.d.ts.map +1 -1
  187. package/dist/src/runtime/emit/between.js +32 -3
  188. package/dist/src/runtime/emit/between.js.map +1 -1
  189. package/dist/src/runtime/emit/binary.d.ts.map +1 -1
  190. package/dist/src/runtime/emit/binary.js +22 -2
  191. package/dist/src/runtime/emit/binary.js.map +1 -1
  192. package/dist/src/runtime/emit/bloom-join.d.ts.map +1 -1
  193. package/dist/src/runtime/emit/bloom-join.js +24 -3
  194. package/dist/src/runtime/emit/bloom-join.js.map +1 -1
  195. package/dist/src/runtime/emit/cache.d.ts +7 -3
  196. package/dist/src/runtime/emit/cache.d.ts.map +1 -1
  197. package/dist/src/runtime/emit/cache.js +23 -6
  198. package/dist/src/runtime/emit/cache.js.map +1 -1
  199. package/dist/src/runtime/emit/cast.d.ts.map +1 -1
  200. package/dist/src/runtime/emit/cast.js +10 -23
  201. package/dist/src/runtime/emit/cast.js.map +1 -1
  202. package/dist/src/runtime/emit/constraint-check.d.ts.map +1 -1
  203. package/dist/src/runtime/emit/constraint-check.js +41 -44
  204. package/dist/src/runtime/emit/constraint-check.js.map +1 -1
  205. package/dist/src/runtime/emit/create-view.d.ts.map +1 -1
  206. package/dist/src/runtime/emit/create-view.js +6 -0
  207. package/dist/src/runtime/emit/create-view.js.map +1 -1
  208. package/dist/src/runtime/emit/cte.d.ts.map +1 -1
  209. package/dist/src/runtime/emit/cte.js +43 -20
  210. package/dist/src/runtime/emit/cte.js.map +1 -1
  211. package/dist/src/runtime/emit/distinct.d.ts.map +1 -1
  212. package/dist/src/runtime/emit/distinct.js +6 -3
  213. package/dist/src/runtime/emit/distinct.js.map +1 -1
  214. package/dist/src/runtime/emit/dml-executor.d.ts.map +1 -1
  215. package/dist/src/runtime/emit/dml-executor.js +241 -115
  216. package/dist/src/runtime/emit/dml-executor.js.map +1 -1
  217. package/dist/src/runtime/emit/hash-aggregate.d.ts.map +1 -1
  218. package/dist/src/runtime/emit/hash-aggregate.js +16 -65
  219. package/dist/src/runtime/emit/hash-aggregate.js.map +1 -1
  220. package/dist/src/runtime/emit/insert.d.ts.map +1 -1
  221. package/dist/src/runtime/emit/insert.js +18 -7
  222. package/dist/src/runtime/emit/insert.js.map +1 -1
  223. package/dist/src/runtime/emit/join.js +5 -0
  224. package/dist/src/runtime/emit/join.js.map +1 -1
  225. package/dist/src/runtime/emit/materialized-view-helpers.d.ts +14 -1
  226. package/dist/src/runtime/emit/materialized-view-helpers.d.ts.map +1 -1
  227. package/dist/src/runtime/emit/materialized-view-helpers.js +38 -7
  228. package/dist/src/runtime/emit/materialized-view-helpers.js.map +1 -1
  229. package/dist/src/runtime/emit/materialized-view.d.ts.map +1 -1
  230. package/dist/src/runtime/emit/materialized-view.js +47 -6
  231. package/dist/src/runtime/emit/materialized-view.js.map +1 -1
  232. package/dist/src/runtime/emit/merge-join.d.ts.map +1 -1
  233. package/dist/src/runtime/emit/merge-join.js +18 -8
  234. package/dist/src/runtime/emit/merge-join.js.map +1 -1
  235. package/dist/src/runtime/emit/recursive-cte.d.ts.map +1 -1
  236. package/dist/src/runtime/emit/recursive-cte.js +59 -1
  237. package/dist/src/runtime/emit/recursive-cte.js.map +1 -1
  238. package/dist/src/runtime/emit/set-object-tags.d.ts +8 -0
  239. package/dist/src/runtime/emit/set-object-tags.d.ts.map +1 -1
  240. package/dist/src/runtime/emit/set-object-tags.js +8 -0
  241. package/dist/src/runtime/emit/set-object-tags.js.map +1 -1
  242. package/dist/src/runtime/emit/set-operation.d.ts.map +1 -1
  243. package/dist/src/runtime/emit/set-operation.js +7 -4
  244. package/dist/src/runtime/emit/set-operation.js.map +1 -1
  245. package/dist/src/runtime/emit/sort.d.ts.map +1 -1
  246. package/dist/src/runtime/emit/sort.js +5 -2
  247. package/dist/src/runtime/emit/sort.js.map +1 -1
  248. package/dist/src/runtime/emit/subquery.d.ts.map +1 -1
  249. package/dist/src/runtime/emit/subquery.js +113 -13
  250. package/dist/src/runtime/emit/subquery.js.map +1 -1
  251. package/dist/src/runtime/emit/temporal-arithmetic.d.ts +7 -0
  252. package/dist/src/runtime/emit/temporal-arithmetic.d.ts.map +1 -1
  253. package/dist/src/runtime/emit/temporal-arithmetic.js +15 -7
  254. package/dist/src/runtime/emit/temporal-arithmetic.js.map +1 -1
  255. package/dist/src/runtime/emit/update.d.ts.map +1 -1
  256. package/dist/src/runtime/emit/update.js +44 -3
  257. package/dist/src/runtime/emit/update.js.map +1 -1
  258. package/dist/src/runtime/emit/window.d.ts.map +1 -1
  259. package/dist/src/runtime/emit/window.js +72 -55
  260. package/dist/src/runtime/emit/window.js.map +1 -1
  261. package/dist/src/runtime/foreign-key-actions.d.ts +36 -1
  262. package/dist/src/runtime/foreign-key-actions.d.ts.map +1 -1
  263. package/dist/src/runtime/foreign-key-actions.js +238 -116
  264. package/dist/src/runtime/foreign-key-actions.js.map +1 -1
  265. package/dist/src/runtime/parallel-driver.d.ts +20 -1
  266. package/dist/src/runtime/parallel-driver.d.ts.map +1 -1
  267. package/dist/src/runtime/parallel-driver.js +23 -1
  268. package/dist/src/runtime/parallel-driver.js.map +1 -1
  269. package/dist/src/runtime/types.d.ts +54 -0
  270. package/dist/src/runtime/types.d.ts.map +1 -1
  271. package/dist/src/runtime/types.js.map +1 -1
  272. package/dist/src/schema/catalog-persistability.d.ts +58 -0
  273. package/dist/src/schema/catalog-persistability.d.ts.map +1 -0
  274. package/dist/src/schema/catalog-persistability.js +87 -0
  275. package/dist/src/schema/catalog-persistability.js.map +1 -0
  276. package/dist/src/schema/catalog.d.ts +17 -1
  277. package/dist/src/schema/catalog.d.ts.map +1 -1
  278. package/dist/src/schema/catalog.js +25 -3
  279. package/dist/src/schema/catalog.js.map +1 -1
  280. package/dist/src/schema/constraint-builder.d.ts +20 -22
  281. package/dist/src/schema/constraint-builder.d.ts.map +1 -1
  282. package/dist/src/schema/constraint-builder.js +43 -36
  283. package/dist/src/schema/constraint-builder.js.map +1 -1
  284. package/dist/src/schema/ddl-generator.d.ts +23 -0
  285. package/dist/src/schema/ddl-generator.d.ts.map +1 -1
  286. package/dist/src/schema/ddl-generator.js +27 -0
  287. package/dist/src/schema/ddl-generator.js.map +1 -1
  288. package/dist/src/schema/function.d.ts +109 -1
  289. package/dist/src/schema/function.d.ts.map +1 -1
  290. package/dist/src/schema/function.js.map +1 -1
  291. package/dist/src/schema/manager.d.ts +28 -0
  292. package/dist/src/schema/manager.d.ts.map +1 -1
  293. package/dist/src/schema/manager.js +82 -14
  294. package/dist/src/schema/manager.js.map +1 -1
  295. package/dist/src/schema/schema-differ.d.ts.map +1 -1
  296. package/dist/src/schema/schema-differ.js +51 -12
  297. package/dist/src/schema/schema-differ.js.map +1 -1
  298. package/dist/src/schema/unique-enforcement.d.ts +31 -0
  299. package/dist/src/schema/unique-enforcement.d.ts.map +1 -1
  300. package/dist/src/schema/unique-enforcement.js +37 -1
  301. package/dist/src/schema/unique-enforcement.js.map +1 -1
  302. package/dist/src/schema/window-function.d.ts +30 -10
  303. package/dist/src/schema/window-function.d.ts.map +1 -1
  304. package/dist/src/schema/window-function.js +20 -16
  305. package/dist/src/schema/window-function.js.map +1 -1
  306. package/dist/src/types/cast-semantics.d.ts +43 -0
  307. package/dist/src/types/cast-semantics.d.ts.map +1 -0
  308. package/dist/src/types/cast-semantics.js +59 -0
  309. package/dist/src/types/cast-semantics.js.map +1 -0
  310. package/dist/src/types/index.d.ts +1 -1
  311. package/dist/src/types/index.d.ts.map +1 -1
  312. package/dist/src/types/index.js +1 -1
  313. package/dist/src/types/index.js.map +1 -1
  314. package/dist/src/types/json-type.d.ts.map +1 -1
  315. package/dist/src/types/json-type.js +31 -10
  316. package/dist/src/types/json-type.js.map +1 -1
  317. package/dist/src/types/logical-type.d.ts +22 -0
  318. package/dist/src/types/logical-type.d.ts.map +1 -1
  319. package/dist/src/types/logical-type.js.map +1 -1
  320. package/dist/src/types/temporal-types.d.ts.map +1 -1
  321. package/dist/src/types/temporal-types.js +33 -11
  322. package/dist/src/types/temporal-types.js.map +1 -1
  323. package/dist/src/types/validation.d.ts +39 -1
  324. package/dist/src/types/validation.d.ts.map +1 -1
  325. package/dist/src/types/validation.js +60 -0
  326. package/dist/src/types/validation.js.map +1 -1
  327. package/dist/src/util/ast-spine-clone.d.ts +23 -0
  328. package/dist/src/util/ast-spine-clone.d.ts.map +1 -0
  329. package/dist/src/util/ast-spine-clone.js +41 -0
  330. package/dist/src/util/ast-spine-clone.js.map +1 -0
  331. package/dist/src/util/coercion.d.ts +13 -0
  332. package/dist/src/util/coercion.d.ts.map +1 -1
  333. package/dist/src/util/coercion.js +10 -1
  334. package/dist/src/util/coercion.js.map +1 -1
  335. package/dist/src/util/comparison.d.ts +89 -0
  336. package/dist/src/util/comparison.d.ts.map +1 -1
  337. package/dist/src/util/comparison.js +156 -27
  338. package/dist/src/util/comparison.js.map +1 -1
  339. package/dist/src/vtab/manifest.d.ts +7 -0
  340. package/dist/src/vtab/manifest.d.ts.map +1 -1
  341. package/dist/src/vtab/memory/connection.d.ts +14 -1
  342. package/dist/src/vtab/memory/connection.d.ts.map +1 -1
  343. package/dist/src/vtab/memory/connection.js +20 -2
  344. package/dist/src/vtab/memory/connection.js.map +1 -1
  345. package/dist/src/vtab/memory/layer/base.d.ts +6 -1
  346. package/dist/src/vtab/memory/layer/base.d.ts.map +1 -1
  347. package/dist/src/vtab/memory/layer/base.js +14 -5
  348. package/dist/src/vtab/memory/layer/base.js.map +1 -1
  349. package/dist/src/vtab/memory/layer/connection.d.ts +17 -0
  350. package/dist/src/vtab/memory/layer/connection.d.ts.map +1 -1
  351. package/dist/src/vtab/memory/layer/connection.js +26 -0
  352. package/dist/src/vtab/memory/layer/connection.js.map +1 -1
  353. package/dist/src/vtab/memory/layer/manager.d.ts +96 -13
  354. package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
  355. package/dist/src/vtab/memory/layer/manager.js +595 -119
  356. package/dist/src/vtab/memory/layer/manager.js.map +1 -1
  357. package/dist/src/vtab/memory/layer/plan-filter.d.ts +41 -20
  358. package/dist/src/vtab/memory/layer/plan-filter.d.ts.map +1 -1
  359. package/dist/src/vtab/memory/layer/plan-filter.js +57 -27
  360. package/dist/src/vtab/memory/layer/plan-filter.js.map +1 -1
  361. package/dist/src/vtab/memory/layer/row-convert.d.ts +21 -0
  362. package/dist/src/vtab/memory/layer/row-convert.d.ts.map +1 -0
  363. package/dist/src/vtab/memory/layer/row-convert.js +30 -0
  364. package/dist/src/vtab/memory/layer/row-convert.js.map +1 -0
  365. package/dist/src/vtab/memory/layer/scan-layer.d.ts +6 -3
  366. package/dist/src/vtab/memory/layer/scan-layer.d.ts.map +1 -1
  367. package/dist/src/vtab/memory/layer/scan-layer.js +69 -36
  368. package/dist/src/vtab/memory/layer/scan-layer.js.map +1 -1
  369. package/dist/src/vtab/memory/layer/transaction.d.ts +127 -13
  370. package/dist/src/vtab/memory/layer/transaction.d.ts.map +1 -1
  371. package/dist/src/vtab/memory/layer/transaction.js +214 -65
  372. package/dist/src/vtab/memory/layer/transaction.js.map +1 -1
  373. package/dist/src/vtab/memory/module.d.ts.map +1 -1
  374. package/dist/src/vtab/memory/module.js +9 -2
  375. package/dist/src/vtab/memory/module.js.map +1 -1
  376. package/dist/src/vtab/memory/table.d.ts.map +1 -1
  377. package/dist/src/vtab/memory/table.js +3 -2
  378. package/dist/src/vtab/memory/table.js.map +1 -1
  379. package/dist/src/vtab/memory/types.d.ts +27 -1
  380. package/dist/src/vtab/memory/types.d.ts.map +1 -1
  381. package/dist/src/vtab/memory/types.js +16 -1
  382. package/dist/src/vtab/memory/types.js.map +1 -1
  383. package/dist/src/vtab/memory/utils/primary-key.d.ts +9 -0
  384. package/dist/src/vtab/memory/utils/primary-key.d.ts.map +1 -1
  385. package/dist/src/vtab/memory/utils/primary-key.js +11 -0
  386. package/dist/src/vtab/memory/utils/primary-key.js.map +1 -1
  387. package/dist/src/vtab/module.d.ts +63 -0
  388. package/dist/src/vtab/module.d.ts.map +1 -1
  389. package/dist/src/vtab/table.d.ts +24 -6
  390. package/dist/src/vtab/table.d.ts.map +1 -1
  391. package/dist/src/vtab/table.js.map +1 -1
  392. package/package.json +3 -3
  393. package/dist/src/planner/rules/cache/rule-in-subquery-cache.d.ts +0 -19
  394. package/dist/src/planner/rules/cache/rule-in-subquery-cache.d.ts.map +0 -1
  395. package/dist/src/planner/rules/cache/rule-in-subquery-cache.js +0 -53
  396. package/dist/src/planner/rules/cache/rule-in-subquery-cache.js.map +0 -1
@@ -5,15 +5,18 @@ import { QuereusError } from '../../common/errors.js';
5
5
  import { StatusCode } from '../../common/types.js';
6
6
  import { createLogger } from '../../common/logger.js';
7
7
  import { buildColumnIndexMap, withGeneratedColumnGraph, requireVtabModule, resolveNamedConstraintClass, validateCollationForType } from '../../schema/table.js';
8
- import { validateForeignKeyOverExistingRows, validateForeignKeyCollations, extractColumnLevelCheckConstraints, extractColumnLevelForeignKeys, extractColumnLevelUniqueConstraints } from '../../schema/constraint-builder.js';
8
+ import { validateForeignKeyCollations, buildForeignKeyConstraintSchema, extractColumnLevelCheckConstraints, extractColumnLevelForeignKeys, extractColumnLevelUniqueConstraints } from '../../schema/constraint-builder.js';
9
9
  import { MemoryTableModule } from '../../vtab/memory/module.js';
10
10
  import { quoteIdentifier, expressionToString, astToString } from '../../emit/ast-stringify.js';
11
11
  import { renameTableInAst, renameColumnInAst, renameColumnInCheckExpression } from '../../schema/rename-rewriter.js';
12
+ import { assertCatalogObjectPersistable, assertRenameDependentsPersistable } from '../../schema/catalog-persistability.js';
12
13
  import { tryFoldLiteral } from '../../parser/utils.js';
13
14
  import { isTruthy } from '../../util/comparison.js';
14
15
  import { assertDdlTransactionPolicy } from './ddl-transaction-policy.js';
16
+ import { validateAndParse } from '../../types/validation.js';
15
17
  import { snapshotStaleMaterializedViews, propagateTableRenameToMaterializedViews, propagateColumnRenameToMaterializedViews, restoreUnaffectedMaterializedViews, attachMaintainedDerivation, detachMaintainedDerivation, } from './materialized-view-helpers.js';
16
18
  import { isMaintainedTable } from '../../schema/derivation.js';
19
+ import { inferType } from '../../types/registry.js';
17
20
  const log = createLogger('runtime:emit:alter-table');
18
21
  /** A scheduled sub-program resolved to a callback the emitter invokes per row. */
19
22
  function qualifyTableName(schemaName, tableName) {
@@ -156,6 +159,20 @@ async function runRenameTable(rctx, tableSchema, schema, newName) {
156
159
  if (schema.getTable(newName)) {
157
160
  throw new QuereusError(`Table '${newName}' already exists`, StatusCode.ERROR);
158
161
  }
162
+ // Pre-flight, BEFORE the first side effect (`module.renameTable`): every catalog
163
+ // entry this rename would rewrite must still be persistable. Both the rename
164
+ // propagation and the store's catalog write are unfailable (notifier try/catch,
165
+ // then an async persist queue), so without this the statement reports success and
166
+ // the dependent silently diverges from — or vanishes from — the durable catalog.
167
+ if (isMaintainedTable(tableSchema)) {
168
+ // The renamed table is itself a materialized view: its own catalog entry moves
169
+ // (`materialized_view_removed` old → `materialized_view_added` new), so vet the
170
+ // prospective record's new KEY and DDL text. The self-reference rewrite
171
+ // `rewriteTableForTableRename` performs is not applied to the probe — it only
172
+ // substitutes `newName`, which is already under test as the record's own name.
173
+ assertCatalogObjectPersistable(rctx.db, 'materializedView', { ...tableSchema, name: newName });
174
+ }
175
+ assertRenameDependentsPersistable(rctx.db, schema, ast => renameTableInAst(ast, oldName, newName, tableSchema.schemaName));
159
176
  // Clone schema with new name
160
177
  const updatedTableSchema = {
161
178
  ...tableSchema,
@@ -169,6 +186,18 @@ async function runRenameTable(rctx, tableSchema, schema, newName) {
169
186
  if (module.renameTable) {
170
187
  await module.renameTable(rctx.db, tableSchema.schemaName, oldName, newName);
171
188
  }
189
+ // Events this transaction already recorded still carry the OLD name; relabel them so
190
+ // the commit delivers every event under the name the table has at delivery. AFTER the
191
+ // module call (a module failure must leave the batch as untouched as the catalog, and
192
+ // the store's `ddlCommitPendingOps` flushes its queued events into our batch DURING
193
+ // that call — those must be in the batch before we walk it), BEFORE the catalog swap,
194
+ // matching where the other ALTER arms call `remapBatchedDataEvents`.
195
+ //
196
+ // NOTE: batched SCHEMA events are deliberately out of scope here. A schema event
197
+ // records a DDL operation, not current state — relabelling `objectName` without
198
+ // rewriting its `ddl` text would produce an incoherent instruction. How a rename
199
+ // crosses the wire to a peer is `fix/sync-schema-migrations-replicate-empty-ddl`.
200
+ rctx.db._getEventEmitter().renameBatchedEvents(tableSchema.schemaName, oldName, newName);
172
201
  // The renamed table's own definition can name itself: a self-referencing FK's
173
202
  // `referencedTable`, a table-qualified CHECK expression, a table-qualified
174
203
  // partial-index predicate. Rewrite those BEFORE the catalog swap and the notify
@@ -238,6 +267,16 @@ async function runRenameColumn(rctx, tableSchema, schema, oldName, newName) {
238
267
  if (oldName.toLowerCase() !== newNameLower && tableSchema.columnIndexMap.has(newNameLower)) {
239
268
  throw new QuereusError(`Column '${newName}' already exists in table '${tableSchema.name}'`, StatusCode.ERROR);
240
269
  }
270
+ // Pre-flight, BEFORE the first side effect (`module.alterTable`): the rewritten
271
+ // body of every dependent view / materialized view must still be persistable —
272
+ // same unfailable-propagation reasoning as the table-rename arm above. Shares one
273
+ // resolver with `propagateColumnRename` so the two passes cannot drift apart in
274
+ // code; what makes them agree at RUNTIME (the resolver reads the LIVE catalog, and
275
+ // this probe runs pre-mutation while the propagation runs post-) is that
276
+ // `isTableInUnaliasedScope` skips the renamed table itself and probes only OTHER
277
+ // sources, whose column sets this rename does not touch.
278
+ const resolveColumnInSource = buildColumnSourceResolver(rctx.db);
279
+ assertRenameDependentsPersistable(rctx.db, schema, ast => renameColumnInAst(ast, tableSchema.name, oldName, newName, tableSchema.schemaName, resolveColumnInSource));
241
280
  const existingCol = tableSchema.columns[colIndex];
242
281
  // Build a ColumnDef AST for the renamed column (preserving type info)
243
282
  const newColumnDef = {
@@ -265,6 +304,12 @@ async function runRenameColumn(rctx, tableSchema, schema, oldName, newName) {
265
304
  columnIndexMap: buildColumnIndexMap(updatedCols),
266
305
  };
267
306
  }
307
+ // A rename moves no value and changes no arity, so the batched events' row images are
308
+ // already right — but their `changedColumns` still names the OLD column. Re-derive it
309
+ // against the new names with an identity row map, so no delivered event names a column
310
+ // the table no longer has. (Modules that emit at commit from their own queue read the
311
+ // current schema then, so they need nothing here.)
312
+ await rctx.db._getEventEmitter().remapBatchedDataEvents(tableSchema.schemaName, tableSchema.name, (row) => row, updatedTableSchema.columns.map(c => c.name));
268
313
  // Update the schema catalog
269
314
  schema.addTable(updatedTableSchema);
270
315
  // Snapshot pre-statement MV staleness BEFORE the notify below: the notify's
@@ -281,7 +326,7 @@ async function runRenameColumn(rctx, tableSchema, schema, oldName, newName) {
281
326
  });
282
327
  // Propagate the rename into dependent objects (CHECK / FK / partial-index
283
328
  // predicates in this and other tables, view and materialized-view bodies).
284
- await propagateColumnRename(rctx, tableSchema.schemaName, tableSchema.name, oldName, newName, preStaleMvs);
329
+ await propagateColumnRename(rctx, tableSchema.schemaName, tableSchema.name, oldName, newName, preStaleMvs, resolveColumnInSource);
285
330
  log('Renamed column %s.%s.%s to %s', tableSchema.schemaName, tableSchema.name, oldName, newName);
286
331
  return null;
287
332
  }
@@ -299,6 +344,10 @@ async function runAddColumn(rctx, tableSchema, schema, columnDef, backfill, back
299
344
  // and, when it does not fold to a literal, compiled into `backfill` — the default
300
345
  // evaluated against the existing row, so `new.<column>` reads that row's sibling.
301
346
  const defaultConstraint = columnDef.constraints?.find(c => c.type === 'default');
347
+ // Folded literal default; undefined when there is no default or it does not fold
348
+ // (the latter carries `backfill` instead). Used by the NOT NULL gate below and by
349
+ // the batched-event remap's backfill value.
350
+ const foldedDefault = defaultConstraint?.expr ? tryFoldLiteral(defaultConstraint.expr) : undefined;
302
351
  // Call module.alterTable for data + schema update
303
352
  const module = requireVtabModule(tableSchema);
304
353
  if (!module.alterTable) {
@@ -318,19 +367,28 @@ async function runAddColumn(rctx, tableSchema, schema, columnDef, backfill, back
318
367
  const delegatesBackfill = module.getCapabilities?.().delegatesNotNullBackfill === true;
319
368
  const hasNotNull = columnDef.constraints?.some(c => c.type === 'notNull') ?? false;
320
369
  if (hasNotNull && !delegatesBackfill && !backfill) {
321
- const folded = defaultConstraint?.expr ? tryFoldLiteral(defaultConstraint.expr) : undefined;
322
- const defaultIsNullish = !defaultConstraint?.expr || folded === null;
370
+ const defaultIsNullish = !defaultConstraint?.expr || foldedDefault === null;
323
371
  if (defaultIsNullish) {
324
372
  await validateNotNullBackfill(rctx, tableSchema, columnDef.name);
325
373
  }
326
374
  }
327
- // Extract column-level CHECK / FK constraints to merge into the engine-side schema below.
328
- // Column-level UNIQUE is handled separately, right after the column is materialized (see
329
- // the inline-UNIQUE block below): it routes through the module's `addConstraint` UNIQUE
330
- // path the same path `ALTER TABLE ADD CONSTRAINT UNIQUE` uses so it is materialized,
331
- // enforced, and (for store-backed modules) persisted, symmetric with CREATE TABLE.
332
- const newCheckConstraints = extractColumnLevelCheckConstraints(columnDef);
333
- const newForeignKeys = extractColumnLevelForeignKeys(columnDef, tableSchema.schemaName);
375
+ // Synthesize the table-level equivalent of every constraint declared inline on the new
376
+ // column. All three kinds go to the module via `addConstraint` below — the same path
377
+ // `ALTER TABLE ADD CONSTRAINT` uses so the module owns them exactly as it owns a
378
+ // constraint declared in CREATE TABLE, and they survive every later structural ALTER
379
+ // (which installs the module's returned schema in the catalog verbatim).
380
+ //
381
+ // Extracted BEFORE the column is materialized so a malformed declaration (e.g. a
382
+ // multi-parent-column FK on a single ADD COLUMN) throws while the table is still
383
+ // untouched. Install order within the loop is UNIQUE → CHECK → FK, so a column
384
+ // declaring several kinds reports the cheapest-to-explain violation first; the
385
+ // literal-default CHECK scan runs ahead of the whole loop (see below).
386
+ const inlineChecks = extractColumnLevelCheckConstraints(columnDef);
387
+ const inlineConstraints = [
388
+ ...extractColumnLevelUniqueConstraints(columnDef),
389
+ ...inlineChecks,
390
+ ...extractColumnLevelForeignKeys(columnDef),
391
+ ];
334
392
  // A non-foldable default backfills each existing row from its own value. Install a row
335
393
  // slot over the default's row descriptor; the evaluator the module calls per existing
336
394
  // row sets the slot to that row, so the default's `new.<col>` refs resolve to it.
@@ -369,185 +427,226 @@ async function runAddColumn(rctx, tableSchema, schema, columnDef, backfill, back
369
427
  // scan below re-reads the table — so the backfill's context does not shadow the
370
428
  // scan's own row context.
371
429
  let updatedTableSchema;
430
+ // Slot the module actually placed the new column at (the module API permits
431
+ // `insertAtIndex`; SQL always appends). Recorded so the revert paths below can apply
432
+ // the inverse event remap.
433
+ let addedColIndex;
372
434
  try {
373
435
  updatedTableSchema = await module.alterTable(rctx.db, tableSchema.schemaName, tableSchema.name, {
374
436
  type: 'addColumn',
375
437
  columnDef,
376
438
  backfillEvaluator,
377
439
  });
440
+ // Events this transaction already batched for the table still describe the
441
+ // pre-ADD column set; insert the backfilled value at the new slot so a listener
442
+ // at commit pairs value i with column i of the schema current at delivery.
443
+ // Covers the engine auto-event path and the store module (which flushed its
444
+ // queued events into the batch during the ALTER); the memory module's own
445
+ // pending-change log is reshaped inside its alterTable. Must run INSIDE this
446
+ // try: the backfill evaluator closes over rowSlot/checkSlot, which the finally
447
+ // below closes the moment the module returns.
448
+ addedColIndex = updatedTableSchema.columnIndexMap.get(columnDef.name.toLowerCase());
449
+ if (addedColIndex !== undefined) {
450
+ const insertAt = addedColIndex;
451
+ await rctx.db._getEventEmitter().remapBatchedDataEvents(tableSchema.schemaName, tableSchema.name, async (row) => {
452
+ // oldRow gets the SAME map as newRow: the literal default, or the backfill
453
+ // evaluator applied to the pre-image itself (the evaluator is a function of
454
+ // a row, and the pre-image is a row), falling back to NULL — the honest
455
+ // "column did not exist yet" placeholder, which errs toward REPORTING a
456
+ // change on the new column rather than suppressing one. Rejected: reusing
457
+ // the newRow result for oldRow (makes oldRow[new] === newRow[new] always,
458
+ // so a diffing consumer never syncs the added column); suppressing the
459
+ // pre-ALTER oldRow (silently turns updates into upserts).
460
+ let value = foldedDefault ?? null;
461
+ if (backfillEvaluator) {
462
+ try {
463
+ value = await backfillEvaluator(row);
464
+ }
465
+ catch {
466
+ // Best-effort: a historical image may fail the evaluator (or its
467
+ // CHECKs) where every live row backfilled cleanly. Never abort
468
+ // the ALTER for an event image.
469
+ value = null;
470
+ }
471
+ }
472
+ return [...row.slice(0, insertAt), value, ...row.slice(insertAt)];
473
+ }, updatedTableSchema.columns.map(c => c.name));
474
+ }
378
475
  }
379
476
  finally {
380
477
  rowSlot?.close();
381
478
  checkSlot?.close();
382
479
  }
383
- // Materialize + enforce any inline column-level UNIQUE(s) on the new column. CREATE TABLE
384
- // routes inline UNIQUE through `extractUniqueConstraints`; `ALTER TABLE ADD CONSTRAINT
385
- // UNIQUE` routes it through `module.alterTable({ addConstraint })`. The imperative ADD
386
- // COLUMN path reaches neither, so without this an inline UNIQUE would be silently dropped —
387
- // never materialized, enforced, or rejected. Convert each into the equivalent table-level
388
- // constraint over the just-added column and feed it to the same addConstraint path, so the
389
- // module builds/reuses its covering structure, validates the existing rows (throwing
390
- // CONSTRAINT on the first duplicate), and (store) persists. Each call returns a schema
391
- // carrying the new column + the unique constraint (+ memory covering index); thread the
392
- // latest forward so the CHECK/FK merge below layers naturally on top.
393
- //
394
- // Ordering: the column is already materialized (so it resolves in `columnIndexMap`), and the
395
- // engine catalog is untouched until the first `schema.addTable` below. So on a UNIQUE failure
396
- // (e.g. a literal DEFAULT that backfills the same value to ≥2 existing rows → immediate
397
- // duplicate) we only drop the just-added column from the module and rethrow no catalog
398
- // restore. The module's own addConstraint already rolled back its half-built covering
399
- // structure before throwing.
400
- const inlineUniqueConstraints = extractColumnLevelUniqueConstraints(columnDef);
401
- for (const uniqueConstraint of inlineUniqueConstraints) {
402
- try {
403
- updatedTableSchema = await module.alterTable(rctx.db, tableSchema.schemaName, tableSchema.name, {
404
- type: 'addConstraint',
405
- constraint: uniqueConstraint,
406
- });
407
- }
408
- catch (err) {
409
- try {
410
- await module.alterTable(rctx.db, tableSchema.schemaName, tableSchema.name, {
411
- type: 'dropColumn',
412
- columnName: columnDef.name,
413
- });
414
- }
415
- catch (revertErr) {
416
- log('Failed to revert ADD COLUMN after inline UNIQUE violation: %s', revertErr.message);
417
- }
418
- throw err;
419
- }
420
- }
421
- // Resolve the new child column index in the freshly returned schema for any FK constraints.
422
- const newColIdx = updatedTableSchema.columnIndexMap.get(columnDef.name.toLowerCase());
423
- const resolvedForeignKeys = newColIdx !== undefined
424
- ? newForeignKeys.map(fk => ({ ...fk, columns: Object.freeze([newColIdx]) }))
425
- : newForeignKeys;
426
- // Merge new column-level CHECK / FK into the table-level constraint sets so the
427
- // existing constraint-builder picks them up for INSERT/UPDATE enforcement.
428
- const mergedChecks = newCheckConstraints.length > 0
429
- ? Object.freeze([...updatedTableSchema.checkConstraints, ...newCheckConstraints])
430
- : updatedTableSchema.checkConstraints;
431
- const mergedForeignKeys = resolvedForeignKeys.length > 0
432
- ? Object.freeze([...(updatedTableSchema.foreignKeys ?? []), ...resolvedForeignKeys])
433
- : updatedTableSchema.foreignKeys;
434
- const enhancedBase = {
435
- ...updatedTableSchema,
436
- checkConstraints: mergedChecks,
437
- foreignKeys: mergedForeignKeys,
438
- };
439
- // Recompute the generated-column dependency graph. If the added column is
440
- // generated and its expression references an unknown column, or any new
441
- // generated-column edges form a cycle, this throws before we register the
442
- // new schema in the catalog.
443
- const enhancedTableSchema = withGeneratedColumnGraph(enhancedBase);
444
- // The optimizer trusts a DECLARED constraint as a proven invariant, which makes
445
- // the existing-row validators below fold away their own work if the new constraint
446
- // is already live:
447
- // - A new FK seeds an inclusion dependency `child.fk ⊆ parent.pk`; the FK
448
- // validator's `not exists` anti-join folds to EmptyRelation under
449
- // `ruleAntiJoinFkEmpty` (+ the INDs seeded at TableReferenceNode).
450
- // - A new CHECK `<p>` seeds a domain constraint on the scan; the CHECK post-scan's
451
- // own `where not (<p>)` folds to EmptyRelation under `ruleFilterContradiction`
452
- // (the domain `<p>` and the predicate `not <p>` are jointly unsatisfiable).
453
- // Either fold makes validation trust the very invariant it is checking and silently
454
- // admit a violating row. So register the new COLUMN with only the PRE-EXISTING
455
- // (already-proven) constraints for the validation pass, then register the full schema
456
- // — with the new FK(s) and CHECK(s) — only once validation passes. This mirrors the
457
- // ADD CONSTRAINT path, which validates before swapping the constraint into the live
458
- // schema. Pre-existing constraints are kept: they held before this ALTER, so folding
459
- // against them is sound and preserves the optimizer's reach.
460
- const hasNewForeignKeys = resolvedForeignKeys.length > 0;
461
- const hasNewChecks = newCheckConstraints.length > 0;
462
- const usesIntermediateSchema = hasNewForeignKeys || hasNewChecks;
463
- const validationSchema = usesIntermediateSchema
464
- ? withGeneratedColumnGraph({
465
- ...enhancedBase,
466
- checkConstraints: updatedTableSchema.checkConstraints,
467
- foreignKeys: updatedTableSchema.foreignKeys,
468
- })
469
- : enhancedTableSchema;
470
- schema.addTable(validationSchema);
471
- // Validate new CHECK constraints against the (already-backfilled) rows AND validate
472
- // existing rows against any new column-level FK, reverting (drop the column + restore
473
- // the original catalog entry) on a violation. Both run inside a single try/revert
474
- // region so that when both a new CHECK and a new FK exist and either fails, the same
475
- // revert path fires.
476
- //
477
- // CHECK is gated on `!backfill`: NOT NULL of a per-row default is enforced by the module
478
- // during backfill (it has the values in-hand and throws before the column is committed),
479
- // and the per-row (evaluator) default path already enforced each CHECK inside the backfill
480
- // hook above (against the freshly-computed value, not a stale snapshot). The CHECK post-scan
481
- // is therefore only correct for the literal-default path, whose values were bulk-written by
482
- // the module without a per-row hook.
483
- //
484
- // FK runs for ALL default kinds. It is a cross-table existence check, not a per-row
485
- // predicate, so it must be a post-`alterTable` scan: the scan sees both the bulk-written
486
- // (literal) and per-row-evaluated backfilled values, and for a self-referential FK it reads
487
- // a consistent post-alter table (a per-row hook would have to query the very table being
488
- // rebuilt). It reuses `validateForeignKeyOverExistingRows` — the same MATCH-SIMPLE,
489
- // pragma-gated validator the ADD CONSTRAINT path calls — so the two paths can never drift.
490
- const runCheckScan = !backfill && newCheckConstraints.length > 0;
491
- if (runCheckScan || hasNewForeignKeys) {
492
- try {
493
- // Reject any new FK whose child/parent column collations declare a same-rank
494
- // conflict (the conflict enforcement would raise at first DML). Pure schema
495
- // check — no row scan, pragma-independent — but kept inside this try/revert
496
- // region so a conflict drops the just-materialized column and restores the
497
- // original catalog, leaving the table untouched. `enhancedTableSchema` carries
498
- // the new column so the child FK column resolves.
499
- for (const fk of resolvedForeignKeys) {
500
- validateForeignKeyCollations(rctx.db, enhancedTableSchema, fk);
501
- }
502
- if (runCheckScan) {
503
- await validateBackfillAgainstChecks(rctx, validationSchema, newCheckConstraints);
504
- }
505
- for (const fk of resolvedForeignKeys) {
506
- // `enhancedTableSchema` supplies only column-name resolution here; the LIVE
507
- // schema the planner reads is `validationSchema`, which omits the new FK(s)
508
- // and CHECK(s), so the anti-join is not folded.
509
- await validateForeignKeyOverExistingRows(rctx.db, enhancedTableSchema, fk);
510
- }
480
+ // The column is materialized; now install the inline constraints. Names of the CHECK /
481
+ // FK ones the module has accepted so far, so a later failure can hand each back to
482
+ // `dropConstraint` before the column itself goes (see {@link revertAddColumn}).
483
+ const installedConstraintNames = [];
484
+ let finalTableSchema;
485
+ try {
486
+ // Recompute the generated-column dependency graph. If the added column is generated
487
+ // and its expression references an unknown column, or any new generated-column edges
488
+ // form a cycle, this throws and the revert below undoes the materialization.
489
+ const columnOnlySchema = withGeneratedColumnGraph(updatedTableSchema);
490
+ // Register the COLUMN-ONLY schema before installing any inline constraint. Two
491
+ // properties depend on this ordering, and both are easy to break:
492
+ //
493
+ // - The module's FK arm validates existing rows with SQL planned against the LIVE
494
+ // catalog, so the new column has to resolve there. Likewise the CHECK backfill
495
+ // scan below.
496
+ // - The new constraint must NOT be live while its own validation runs. The optimizer
497
+ // trusts a DECLARED constraint as a proven invariant: a declared FK seeds the
498
+ // inclusion dependency `child.fk parent.pk` and folds the validator's own
499
+ // `not exists` anti-join to EmptyRelation (`ruleAntiJoinFkEmpty`); a declared CHECK
500
+ // `<p>` seeds a domain constraint that folds the CHECK scan's `where not (<p>)`
501
+ // away (`ruleFilterContradiction`). Either fold makes validation trust the very
502
+ // thing it is checking and silently admit a violating row. The module holds each
503
+ // new constraint in its own cached schema until that constraint's validation
504
+ // passes, and the catalog only learns of them from `finalTableSchema` below.
505
+ //
506
+ // Pre-existing constraints stay live throughout: they held before this ALTER, so
507
+ // folding against them is sound and preserves the optimizer's reach.
508
+ schema.addTable(columnOnlySchema);
509
+ // Validate the backfilled values against each inline CHECK, for the literal-default
510
+ // path only. A per-row (evaluator) default already enforced its CHECKs inside the
511
+ // backfill hook above — against the freshly-computed value rather than this scan's
512
+ // stale pre-backfill snapshot — and the module enforces NOT NULL there too. Runs
513
+ // before the whole install loop below, so on a column declaring several kinds a
514
+ // CHECK violation is reported ahead of a UNIQUE or FK one.
515
+ if (!backfill && inlineChecks.length > 0) {
516
+ await validateBackfillAgainstChecks(rctx, columnOnlySchema, inlineChecks);
511
517
  }
512
- catch (err) {
513
- // Revert: drop the column and restore the original catalog entry.
514
- try {
515
- await module.alterTable(rctx.db, tableSchema.schemaName, tableSchema.name, {
516
- type: 'dropColumn',
517
- columnName: columnDef.name,
518
- });
518
+ // Starts as the column-only schema so a column with no inline constraint needs no
519
+ // further work; each accepted constraint replaces it with the module's answer.
520
+ //
521
+ // NOTE: one module round-trip per inline constraint — each takes the module's
522
+ // schema-change latch and, store-backed, writes the table's DDL again. Fine at the
523
+ // counts SQL produces (a column declares 0 or 1 of each kind); if a batched
524
+ // `addConstraint` arm ever appears, or ADD COLUMN becomes hot, hand the whole set
525
+ // over in one call instead.
526
+ let current = columnOnlySchema;
527
+ for (const constraint of inlineConstraints) {
528
+ // A CHECK / FK is dropped by NAME on the revert path, so resolve the name the
529
+ // module will store BEFORE handing the constraint over. UNIQUE needs no entry:
530
+ // an unnamed one has no name to drop by, and the module's own DROP COLUMN
531
+ // prunes a UNIQUE over the dropped column (which CHECK / FK are not).
532
+ let installedName;
533
+ if (constraint.type === 'foreignKey') {
534
+ // Reject a same-rank child/parent collation conflict (which enforcement would
535
+ // raise at the first DML) BEFORE `module.alterTable`, so a rejected ALTER never
536
+ // reaches the module's persistence side effects — mirroring
537
+ // `runAddConstraintViaModule`. Built with the same builder and columnIndexMap
538
+ // the module uses, so the name and column indices are identical to its own.
539
+ const fk = buildForeignKeyConstraintSchema(constraint, columnOnlySchema.columnIndexMap, tableSchema.name, tableSchema.schemaName);
540
+ validateForeignKeyCollations(rctx.db, columnOnlySchema, fk);
541
+ installedName = fk.name;
519
542
  }
520
- catch (revertErr) {
521
- log('Failed to revert ADD COLUMN after constraint violation: %s', revertErr.message);
543
+ else if (constraint.type === 'check') {
544
+ installedName = constraint.name; // always set by the extractor
522
545
  }
523
- schema.addTable(tableSchema);
524
- throw err;
546
+ // The module materializes (UNIQUE's covering structure), validates the existing
547
+ // rows as the kind requires (UNIQUE duplicates, pragma-gated MATCH SIMPLE FK
548
+ // orphans) and — store-backed — persists. Thread the returned schema forward so
549
+ // each constraint layers on the last. The module's answer carries no
550
+ // generated-column bookkeeping of its own, so re-derive it each round.
551
+ const withConstraint = await module.alterTable(rctx.db, tableSchema.schemaName, tableSchema.name, {
552
+ type: 'addConstraint',
553
+ constraint,
554
+ });
555
+ current = withGeneratedColumnGraph(withConstraint);
556
+ if (installedName !== undefined)
557
+ installedConstraintNames.push(installedName);
525
558
  }
559
+ finalTableSchema = current;
526
560
  }
527
- // Validation passed — commit the full schema (with the new FK(s)/CHECK(s)) into the
528
- // catalog. Skipped when no intermediate schema was used, in which case
529
- // `validationSchema === enhancedTableSchema` is already registered.
530
- if (usesIntermediateSchema) {
531
- schema.addTable(enhancedTableSchema);
561
+ catch (err) {
562
+ await revertAddColumn(rctx, tableSchema, schema, columnDef.name, addedColIndex, installedConstraintNames);
563
+ throw err;
532
564
  }
565
+ // Every constraint validated and installed — publish the module's final schema.
566
+ schema.addTable(finalTableSchema);
533
567
  rctx.db.schemaManager.getChangeNotifier().notifyChange({
534
568
  type: 'table_modified',
535
569
  schemaName: tableSchema.schemaName,
536
570
  objectName: tableSchema.name,
537
571
  oldObject: tableSchema,
538
- newObject: enhancedTableSchema,
572
+ newObject: finalTableSchema,
539
573
  });
540
574
  log('Added column %s to table %s.%s', columnDef.name, tableSchema.schemaName, tableSchema.name);
541
575
  return null;
542
576
  }
543
577
  /**
544
- * Runs each new CHECK against existing rows. We rely on the just-registered
545
- * enhanced schema so SQL can resolve the new column. Any row matching
578
+ * Undoes a partially-applied ADD COLUMN, leaving the table exactly as it was: hands each
579
+ * inline CHECK / FK the module already accepted back to `dropConstraint` (newest first),
580
+ * drops the column, un-remaps the batched events, and restores the original catalog entry.
581
+ *
582
+ * The constraints must go before the column: neither built-in module prunes a CHECK / FK
583
+ * over a dropped column, so a stranded one would keep naming a column the table no longer
584
+ * has. (An inline UNIQUE needs no explicit drop — both modules prune a UNIQUE over the
585
+ * dropped column, and an unnamed one has no name to drop by.)
586
+ *
587
+ * Best-effort on the module half: a revert failure is logged, never thrown, so it cannot
588
+ * mask the original violation. Restoring the catalog entry is a no-op when the ALTER failed
589
+ * before registering anything (the original schema is still the live one).
590
+ *
591
+ * NOTE: the hand-back is by NAME, so it assumes a name resolves to the constraint this
592
+ * ALTER installed. A pre-existing constraint can legitimately share an auto-name (nothing
593
+ * rejects `constraint _check_w check (…)` on a table that later gets `add column w …
594
+ * check (…)`; `create table` collides the same way), and today both modules' DROP
595
+ * CONSTRAINT removes every match, which lands on the right end state. If constraint-name
596
+ * resolution ever narrows to a single match, revert must instead identify the installed
597
+ * constraint by identity — otherwise it can drop the pre-existing one and leave ours.
598
+ */
599
+ async function revertAddColumn(rctx, tableSchema, schema, columnName, addedColIndex, installedConstraintNames) {
600
+ try {
601
+ const module = requireVtabModule(tableSchema);
602
+ // Unreachable: runAddColumn requires `alterTable` before materializing anything.
603
+ if (!module.alterTable)
604
+ return;
605
+ for (let i = installedConstraintNames.length - 1; i >= 0; i--) {
606
+ await module.alterTable(rctx.db, tableSchema.schemaName, tableSchema.name, {
607
+ type: 'dropConstraint',
608
+ constraintName: installedConstraintNames[i],
609
+ });
610
+ }
611
+ await module.alterTable(rctx.db, tableSchema.schemaName, tableSchema.name, {
612
+ type: 'dropColumn',
613
+ columnName,
614
+ });
615
+ await remapEventsForRevertedAddColumn(rctx, tableSchema, addedColIndex);
616
+ }
617
+ catch (revertErr) {
618
+ log('Failed to revert ADD COLUMN %s.%s.%s: %s', tableSchema.schemaName, tableSchema.name, columnName, revertErr.message);
619
+ }
620
+ schema.addTable(tableSchema);
621
+ }
622
+ /**
623
+ * Inverse of {@link runAddColumn}'s batched-event remap, for its revert paths: the
624
+ * just-added column has been dropped from the module again, so the batched events must
625
+ * drop the slot too or they keep describing a column the table no longer has. No-op when
626
+ * the forward remap never ran (`addedColIndex` undefined). Best-effort like the forward
627
+ * remap — never masks the original constraint error.
628
+ */
629
+ async function remapEventsForRevertedAddColumn(rctx, tableSchema, addedColIndex) {
630
+ if (addedColIndex === undefined)
631
+ return;
632
+ await rctx.db._getEventEmitter().remapBatchedDataEvents(tableSchema.schemaName, tableSchema.name, (row) => row.filter((_, i) => i !== addedColIndex), tableSchema.columns.map(c => c.name));
633
+ }
634
+ /**
635
+ * Runs each new CHECK against the (already-backfilled) existing rows. Relies on the
636
+ * just-registered column-only schema so SQL can resolve the new column while the CHECK
637
+ * itself is not yet declared — declaring it first would let `ruleFilterContradiction`
638
+ * fold this scan's own `not (<check_expr>)` to EmptyRelation. Any row matching
546
639
  * `not (<check_expr>)` is a violation and aborts the ALTER.
547
640
  */
548
- async function validateBackfillAgainstChecks(rctx, enhancedTableSchema, newCheckConstraints) {
549
- const qualifiedTable = qualifyTableName(enhancedTableSchema.schemaName, enhancedTableSchema.name);
641
+ async function validateBackfillAgainstChecks(rctx, columnOnlySchema, newCheckConstraints) {
642
+ const qualifiedTable = qualifyTableName(columnOnlySchema.schemaName, columnOnlySchema.name);
550
643
  for (const cc of newCheckConstraints) {
644
+ // `extractColumnLevelCheckConstraints` skips an expression-less CHECK, so this
645
+ // cannot fire — but silently skipping a constraint we were asked to validate
646
+ // would admit a violating row, so say so loudly rather than `continue`.
647
+ if (!cc.expr) {
648
+ throw new QuereusError(`CHECK constraint ${cc.name ? `'${cc.name}' ` : ''}on ALTER TABLE ADD COLUMN has no expression`, StatusCode.INTERNAL);
649
+ }
551
650
  const checkSql = expressionToString(cc.expr);
552
651
  const sql = `select 1 from ${qualifiedTable} where not (${checkSql}) limit 1`;
553
652
  const stmt = rctx.db.prepare(sql);
@@ -558,7 +657,7 @@ async function validateBackfillAgainstChecks(rctx, enhancedTableSchema, newCheck
558
657
  break;
559
658
  }
560
659
  if (violated) {
561
- throw new QuereusError(`CHECK constraint ${cc.name ? `'${cc.name}' ` : ''}violated by backfilled rows in ALTER TABLE ADD COLUMN on '${enhancedTableSchema.name}'`, StatusCode.CONSTRAINT);
660
+ throw new QuereusError(`CHECK constraint ${cc.name ? `'${cc.name}' ` : ''}violated by backfilled rows in ALTER TABLE ADD COLUMN on '${columnOnlySchema.name}'`, StatusCode.CONSTRAINT);
562
661
  }
563
662
  }
564
663
  finally {
@@ -668,6 +767,13 @@ async function runDropColumn(rctx, tableSchema, schema, columnName) {
668
767
  type: 'dropColumn',
669
768
  columnName,
670
769
  });
770
+ // Events this transaction already batched for the table still carry the pre-drop
771
+ // arity; drop the slot so a listener at commit pairs value i with column i of the
772
+ // schema current at delivery (and `changedColumns` never names the dropped column).
773
+ // Pure slot filter — no failure mode. Covers the engine auto-event path and the
774
+ // store module (which flushed its queued events into the batch during the ALTER);
775
+ // the memory module's own pending-change log is reshaped inside its alterTable.
776
+ await rctx.db._getEventEmitter().remapBatchedDataEvents(tableSchema.schemaName, tableSchema.name, (row) => row.filter((_, i) => i !== colIndex), updatedTableSchema.columns.map(c => c.name));
671
777
  // Recompute the generated-column dependency graph against the post-drop
672
778
  // column array — old indices in the previous map are invalid.
673
779
  const finalSchema = withGeneratedColumnGraph(updatedTableSchema);
@@ -803,6 +909,16 @@ async function runAlterColumn(rctx, tableSchema, schema, action) {
803
909
  if (action.setCollation !== undefined) {
804
910
  validateCollationForType(action.setCollation, tableSchema.columns[colIndex].logicalType, action.columnName, (n) => rctx.db.isCollationRegistered(n));
805
911
  }
912
+ // SET DATA TYPE: the column keeps its current collation, so the NEW type has to accept it —
913
+ // otherwise the ALTER mints a column shape CREATE TABLE would refuse and generateTableDDL
914
+ // cannot round-trip (a store-backed table with such a column is silently dropped on rehydrate).
915
+ // Same validator, same error text as CREATE TABLE / SET COLLATE. Rejects uniformly whether the
916
+ // collation was user-declared or inherited from `pragma default_collation`: `collationExplicit`
917
+ // is not persisted, so keying on it would coerce before a reopen and reject after one.
918
+ // Remedy: `SET COLLATE binary` first, then retype.
919
+ if (action.setDataType !== undefined) {
920
+ validateCollationForType(tableSchema.columns[colIndex].collation, inferType(action.setDataType), action.columnName, (n) => rctx.db.isCollationRegistered(n));
921
+ }
806
922
  // Route a SET DEFAULT through the same DDL validator CREATE TABLE uses, so the
807
923
  // stored default is consistent with what INSERT will accept: bind params / bare
808
924
  // columns / non-determinism rejected, `new.<column>` accepted (deferred to INSERT
@@ -823,6 +939,18 @@ async function runAlterColumn(rctx, tableSchema, schema, action) {
823
939
  setDefault: action.setDefault,
824
940
  setCollation: action.setCollation,
825
941
  });
942
+ // Events this transaction already batched still carry the PRE-conversion value at
943
+ // the altered column (`SET DATA TYPE`'s normalization, `SET NOT NULL`'s null →
944
+ // DEFAULT backfill); rewrite it so a listener at commit sees the value the
945
+ // committed row holds. The conversion is engine-derivable (the same
946
+ // `validateAndParse` the memory module's converter wraps), so no module-contract
947
+ // change. `SET COLLATE` / `SET DEFAULT` / `DROP NOT NULL` move no stored value and
948
+ // need no remap — in particular the primary-key `SET COLLATE` re-key leaves every
949
+ // event's key and row images valid as-is.
950
+ const eventValueRemap = alterColumnEventValueRemap(tableSchema, colIndex, action);
951
+ if (eventValueRemap) {
952
+ await rctx.db._getEventEmitter().remapBatchedDataEvents(tableSchema.schemaName, tableSchema.name, (row) => row.map((v, i) => i === colIndex ? eventValueRemap(v) : v), updatedTableSchema.columns.map(c => c.name));
953
+ }
826
954
  schema.addTable(updatedTableSchema);
827
955
  rctx.db.schemaManager.getChangeNotifier().notifyChange({
828
956
  type: 'table_modified',
@@ -834,6 +962,51 @@ async function runAlterColumn(rctx, tableSchema, schema, action) {
834
962
  log('Altered column %s.%s.%s', tableSchema.schemaName, tableSchema.name, action.columnName);
835
963
  return null;
836
964
  }
965
+ /**
966
+ * The per-value map {@link runAlterColumn}'s batched-event remap applies at the altered
967
+ * column, or undefined when the ALTER moves no stored value (SET COLLATE, SET DEFAULT,
968
+ * DROP NOT NULL, an alias retype). The returned function is TOTAL — an unconvertible
969
+ * historical event image keeps its raw value rather than aborting the ALTER; the module
970
+ * already validated every value the transaction can actually SEE, so a failure here is
971
+ * confined to a superseded intermediate image.
972
+ */
973
+ function alterColumnEventValueRemap(tableSchema, colIndex, action) {
974
+ if (action.setDataType !== undefined) {
975
+ const newLogicalType = inferType(action.setDataType);
976
+ // Alias retype (`varchar(50)` IS TEXT): schema-only, values untouched.
977
+ if (newLogicalType === tableSchema.columns[colIndex].logicalType)
978
+ return undefined;
979
+ const columnName = tableSchema.columns[colIndex].name;
980
+ return (v) => {
981
+ if (v === null)
982
+ return v; // retype leaves NULLs untouched, matching the module's conversion
983
+ try {
984
+ return validateAndParse(v, newLogicalType, columnName);
985
+ }
986
+ catch {
987
+ // NOTE: the surviving raw value is honest about what the row held, but its
988
+ // JS type no longer matches the column's logical type — the delivered
989
+ // contract is positional (value i belongs to column i), not typed. Only
990
+ // reachable for a superseded intermediate image (e.g. insert 'zzz' →
991
+ // update to '42' → retype to integer delivers oldRow ['zzz']). If a
992
+ // consumer ever type-validates delivered images, revisit: the options are
993
+ // NULL (loses the value) or dropping the image (loses the event).
994
+ return v;
995
+ }
996
+ };
997
+ }
998
+ if (action.setNotNull === true) {
999
+ // SET NOT NULL backfill: null → the folded literal DEFAULT, the same map the
1000
+ // module applies. No usable literal default means the module either found no
1001
+ // NULLs (nothing to remap) or rejected the ALTER before reaching here.
1002
+ const defaultExpr = tableSchema.columns[colIndex].defaultValue;
1003
+ const folded = defaultExpr ? tryFoldLiteral(defaultExpr) : undefined;
1004
+ if (folded === undefined || folded === null)
1005
+ return undefined;
1006
+ return (v) => (v === null ? folded : v);
1007
+ }
1008
+ return undefined;
1009
+ }
837
1010
  /**
838
1011
  * Catalog-only metadata-tag mutations. Tags touch no stored row and no physical
839
1012
  * layout, so these never call `module.alterTable` — they delegate to the
@@ -1295,13 +1468,23 @@ function rewriteTableForTableRename(table, renamedSchemaLower, oldName, newName)
1295
1468
  indexes: table.indexes ? Object.freeze(newIndexes) : table.indexes,
1296
1469
  });
1297
1470
  }
1298
- async function propagateColumnRename(rctx, renamedSchemaName, tableName, oldCol, newCol, preStaleMvs) {
1299
- const schemaManager = rctx.db.schemaManager;
1300
- const resolveColumnInSource = (s, t, col) => {
1301
- const targetSchema = schemaManager.getSchema(s);
1471
+ /**
1472
+ * The catalog-backed {@link ResolveColumnInSource} the column-rename rewriters consult
1473
+ * to keep their unqualified-reference walk scope-aware. Built once per statement and
1474
+ * shared by the pre-flight probe in {@link runRenameColumn} and the real propagation
1475
+ * below, so the two cannot drift apart. Note it resolves against the LIVE catalog on
1476
+ * every call, so sharing it does not by itself freeze the answer between the two passes
1477
+ * — see the pre-flight's comment for why they agree anyway.
1478
+ */
1479
+ function buildColumnSourceResolver(db) {
1480
+ return (s, t, col) => {
1481
+ const targetSchema = db.schemaManager.getSchema(s);
1302
1482
  const targetTable = targetSchema?.getTable(t);
1303
1483
  return targetTable?.columnIndexMap.has(col.toLowerCase()) ?? false;
1304
1484
  };
1485
+ }
1486
+ async function propagateColumnRename(rctx, renamedSchemaName, tableName, oldCol, newCol, preStaleMvs, resolveColumnInSource) {
1487
+ const schemaManager = rctx.db.schemaManager;
1305
1488
  for (const schema of schemaManager._getAllSchemas()) {
1306
1489
  await propagateColumnRenameInSchema(rctx.db, schema, renamedSchemaName, tableName, oldCol, newCol, resolveColumnInSource, preStaleMvs);
1307
1490
  }