@quereus/quereus 4.3.1 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (788) hide show
  1. package/README.md +25 -7
  2. package/dist/src/common/types.d.ts +9 -59
  3. package/dist/src/common/types.d.ts.map +1 -1
  4. package/dist/src/common/types.js.map +1 -1
  5. package/dist/src/core/database-assertions.d.ts +2 -2
  6. package/dist/src/core/database-assertions.d.ts.map +1 -1
  7. package/dist/src/core/database-assertions.js +4 -3
  8. package/dist/src/core/database-assertions.js.map +1 -1
  9. package/dist/src/core/database-external-changes.d.ts +3 -3
  10. package/dist/src/core/database-external-changes.d.ts.map +1 -1
  11. package/dist/src/core/database-external-changes.js +13 -10
  12. package/dist/src/core/database-external-changes.js.map +1 -1
  13. package/dist/src/core/database-internal.d.ts.map +1 -1
  14. package/dist/src/core/database-materialized-views-analysis.d.ts +199 -0
  15. package/dist/src/core/database-materialized-views-analysis.d.ts.map +1 -0
  16. package/dist/src/core/database-materialized-views-analysis.js +502 -0
  17. package/dist/src/core/database-materialized-views-analysis.js.map +1 -0
  18. package/dist/src/core/database-materialized-views-apply.d.ts +422 -0
  19. package/dist/src/core/database-materialized-views-apply.d.ts.map +1 -0
  20. package/dist/src/core/database-materialized-views-apply.js +929 -0
  21. package/dist/src/core/database-materialized-views-apply.js.map +1 -0
  22. package/dist/src/core/database-materialized-views-plan-builders.d.ts +267 -0
  23. package/dist/src/core/database-materialized-views-plan-builders.d.ts.map +1 -0
  24. package/dist/src/core/database-materialized-views-plan-builders.js +1423 -0
  25. package/dist/src/core/database-materialized-views-plan-builders.js.map +1 -0
  26. package/dist/src/core/database-materialized-views-plans.d.ts +641 -0
  27. package/dist/src/core/database-materialized-views-plans.d.ts.map +1 -0
  28. package/dist/src/core/database-materialized-views-plans.js +13 -0
  29. package/dist/src/core/database-materialized-views-plans.js.map +1 -0
  30. package/dist/src/core/database-materialized-views.d.ts +108 -860
  31. package/dist/src/core/database-materialized-views.d.ts.map +1 -1
  32. package/dist/src/core/database-materialized-views.js +212 -2165
  33. package/dist/src/core/database-materialized-views.js.map +1 -1
  34. package/dist/src/core/database-transaction.d.ts +10 -1
  35. package/dist/src/core/database-transaction.d.ts.map +1 -1
  36. package/dist/src/core/database-transaction.js +16 -4
  37. package/dist/src/core/database-transaction.js.map +1 -1
  38. package/dist/src/core/database-watchers.d.ts.map +1 -1
  39. package/dist/src/core/database-watchers.js +2 -1
  40. package/dist/src/core/database-watchers.js.map +1 -1
  41. package/dist/src/core/database.d.ts +99 -13
  42. package/dist/src/core/database.d.ts.map +1 -1
  43. package/dist/src/core/database.js +270 -50
  44. package/dist/src/core/database.js.map +1 -1
  45. package/dist/src/core/derived-row-validator.d.ts +1 -1
  46. package/dist/src/core/derived-row-validator.d.ts.map +1 -1
  47. package/dist/src/core/derived-row-validator.js +5 -3
  48. package/dist/src/core/derived-row-validator.js.map +1 -1
  49. package/dist/src/core/statement.d.ts +8 -0
  50. package/dist/src/core/statement.d.ts.map +1 -1
  51. package/dist/src/core/statement.js +98 -18
  52. package/dist/src/core/statement.js.map +1 -1
  53. package/dist/src/emit/ast-stringify.d.ts.map +1 -1
  54. package/dist/src/emit/ast-stringify.js +24 -13
  55. package/dist/src/emit/ast-stringify.js.map +1 -1
  56. package/dist/src/func/builtins/aggregate.d.ts.map +1 -1
  57. package/dist/src/func/builtins/aggregate.js +127 -21
  58. package/dist/src/func/builtins/aggregate.js.map +1 -1
  59. package/dist/src/func/builtins/explain.d.ts.map +1 -1
  60. package/dist/src/func/builtins/explain.js +2 -1
  61. package/dist/src/func/builtins/explain.js.map +1 -1
  62. package/dist/src/func/builtins/json.d.ts.map +1 -1
  63. package/dist/src/func/builtins/json.js +2 -1
  64. package/dist/src/func/builtins/json.js.map +1 -1
  65. package/dist/src/func/builtins/mutation.d.ts.map +1 -1
  66. package/dist/src/func/builtins/mutation.js +3 -2
  67. package/dist/src/func/builtins/mutation.js.map +1 -1
  68. package/dist/src/func/registration.d.ts +6 -1
  69. package/dist/src/func/registration.d.ts.map +1 -1
  70. package/dist/src/func/registration.js +16 -0
  71. package/dist/src/func/registration.js.map +1 -1
  72. package/dist/src/index.d.ts +16 -6
  73. package/dist/src/index.d.ts.map +1 -1
  74. package/dist/src/index.js +33 -7
  75. package/dist/src/index.js.map +1 -1
  76. package/dist/src/parser/ast.d.ts +2 -2
  77. package/dist/src/parser/lexer.d.ts +11 -1
  78. package/dist/src/parser/lexer.d.ts.map +1 -1
  79. package/dist/src/parser/lexer.js +40 -34
  80. package/dist/src/parser/lexer.js.map +1 -1
  81. package/dist/src/parser/parser.d.ts.map +1 -1
  82. package/dist/src/parser/parser.js +16 -9
  83. package/dist/src/parser/parser.js.map +1 -1
  84. package/dist/src/planner/analysis/authored-inverse.js +1 -1
  85. package/dist/src/planner/analysis/comparison-collation.d.ts +52 -0
  86. package/dist/src/planner/analysis/comparison-collation.d.ts.map +1 -1
  87. package/dist/src/planner/analysis/comparison-collation.js +84 -7
  88. package/dist/src/planner/analysis/comparison-collation.js.map +1 -1
  89. package/dist/src/planner/analysis/constraint-extractor.d.ts.map +1 -1
  90. package/dist/src/planner/analysis/constraint-extractor.js +64 -17
  91. package/dist/src/planner/analysis/constraint-extractor.js.map +1 -1
  92. package/dist/src/planner/analysis/coverage-prover.d.ts +1 -1
  93. package/dist/src/planner/analysis/coverage-prover.js +1 -1
  94. package/dist/src/planner/analysis/equi-correlation.d.ts +26 -0
  95. package/dist/src/planner/analysis/equi-correlation.d.ts.map +1 -0
  96. package/dist/src/planner/analysis/equi-correlation.js +62 -0
  97. package/dist/src/planner/analysis/equi-correlation.js.map +1 -0
  98. package/dist/src/planner/analysis/query-rewrite-matcher.d.ts +54 -18
  99. package/dist/src/planner/analysis/query-rewrite-matcher.d.ts.map +1 -1
  100. package/dist/src/planner/analysis/query-rewrite-matcher.js +86 -42
  101. package/dist/src/planner/analysis/query-rewrite-matcher.js.map +1 -1
  102. package/dist/src/planner/analysis/sat-checker.d.ts +8 -1
  103. package/dist/src/planner/analysis/sat-checker.d.ts.map +1 -1
  104. package/dist/src/planner/analysis/sat-checker.js +117 -22
  105. package/dist/src/planner/analysis/sat-checker.js.map +1 -1
  106. package/dist/src/planner/analysis/scalar-invertibility.d.ts +13 -4
  107. package/dist/src/planner/analysis/scalar-invertibility.d.ts.map +1 -1
  108. package/dist/src/planner/analysis/scalar-invertibility.js +12 -3
  109. package/dist/src/planner/analysis/scalar-invertibility.js.map +1 -1
  110. package/dist/src/planner/analysis/scalar-subqueries.d.ts +28 -0
  111. package/dist/src/planner/analysis/scalar-subqueries.d.ts.map +1 -0
  112. package/dist/src/planner/analysis/scalar-subqueries.js +60 -0
  113. package/dist/src/planner/analysis/scalar-subqueries.js.map +1 -0
  114. package/dist/src/planner/analysis/update-lineage.d.ts +1 -1
  115. package/dist/src/planner/analysis/update-lineage.js +1 -1
  116. package/dist/src/planner/analysis/update-lineage.js.map +1 -1
  117. package/dist/src/planner/analysis/view-complement.d.ts +2 -2
  118. package/dist/src/planner/building/delete.js +2 -2
  119. package/dist/src/planner/building/delete.js.map +1 -1
  120. package/dist/src/planner/building/dml-target.d.ts +2 -2
  121. package/dist/src/planner/building/dml-target.js +2 -2
  122. package/dist/src/planner/building/insert.d.ts.map +1 -1
  123. package/dist/src/planner/building/insert.js +53 -2
  124. package/dist/src/planner/building/insert.js.map +1 -1
  125. package/dist/src/planner/building/schema-resolution.d.ts +3 -0
  126. package/dist/src/planner/building/schema-resolution.d.ts.map +1 -1
  127. package/dist/src/planner/building/schema-resolution.js +4 -5
  128. package/dist/src/planner/building/schema-resolution.js.map +1 -1
  129. package/dist/src/planner/building/select.d.ts.map +1 -1
  130. package/dist/src/planner/building/select.js +18 -4
  131. package/dist/src/planner/building/select.js.map +1 -1
  132. package/dist/src/planner/building/update.js +2 -2
  133. package/dist/src/planner/building/update.js.map +1 -1
  134. package/dist/src/planner/building/view-mutation-builder.js +7 -7
  135. package/dist/src/planner/building/view-mutation-builder.js.map +1 -1
  136. package/dist/src/planner/building/with.d.ts.map +1 -1
  137. package/dist/src/planner/building/with.js +5 -8
  138. package/dist/src/planner/building/with.js.map +1 -1
  139. package/dist/src/planner/cache/materialization-advisory.d.ts +34 -2
  140. package/dist/src/planner/cache/materialization-advisory.d.ts.map +1 -1
  141. package/dist/src/planner/cache/materialization-advisory.js +185 -42
  142. package/dist/src/planner/cache/materialization-advisory.js.map +1 -1
  143. package/dist/src/planner/cache/reference-graph.d.ts +14 -5
  144. package/dist/src/planner/cache/reference-graph.d.ts.map +1 -1
  145. package/dist/src/planner/cache/reference-graph.js +31 -39
  146. package/dist/src/planner/cache/reference-graph.js.map +1 -1
  147. package/dist/src/planner/cost/index.d.ts +30 -5
  148. package/dist/src/planner/cost/index.d.ts.map +1 -1
  149. package/dist/src/planner/cost/index.js +26 -0
  150. package/dist/src/planner/cost/index.js.map +1 -1
  151. package/dist/src/planner/debug.d.ts +3 -2
  152. package/dist/src/planner/debug.d.ts.map +1 -1
  153. package/dist/src/planner/debug.js +9 -3
  154. package/dist/src/planner/debug.js.map +1 -1
  155. package/dist/src/planner/framework/characteristics.d.ts +46 -19
  156. package/dist/src/planner/framework/characteristics.d.ts.map +1 -1
  157. package/dist/src/planner/framework/characteristics.js +50 -134
  158. package/dist/src/planner/framework/characteristics.js.map +1 -1
  159. package/dist/src/planner/framework/context.d.ts +8 -44
  160. package/dist/src/planner/framework/context.d.ts.map +1 -1
  161. package/dist/src/planner/framework/context.js +0 -91
  162. package/dist/src/planner/framework/context.js.map +1 -1
  163. package/dist/src/planner/framework/pass.d.ts +7 -0
  164. package/dist/src/planner/framework/pass.d.ts.map +1 -1
  165. package/dist/src/planner/framework/pass.js +84 -0
  166. package/dist/src/planner/framework/pass.js.map +1 -1
  167. package/dist/src/planner/framework/registry.d.ts +13 -42
  168. package/dist/src/planner/framework/registry.d.ts.map +1 -1
  169. package/dist/src/planner/framework/registry.js +14 -182
  170. package/dist/src/planner/framework/registry.js.map +1 -1
  171. package/dist/src/planner/mutation/backward-body.d.ts +2 -2
  172. package/dist/src/planner/mutation/cte-flatten.js +1 -1
  173. package/dist/src/planner/mutation/decomposition.d.ts +2 -2
  174. package/dist/src/planner/mutation/decomposition.js +1 -1
  175. package/dist/src/planner/mutation/lens-enforcement.d.ts.map +1 -1
  176. package/dist/src/planner/mutation/lens-enforcement.js +2 -1
  177. package/dist/src/planner/mutation/lens-enforcement.js.map +1 -1
  178. package/dist/src/planner/mutation/multi-source.d.ts +8 -8
  179. package/dist/src/planner/mutation/multi-source.js +11 -11
  180. package/dist/src/planner/mutation/multi-source.js.map +1 -1
  181. package/dist/src/planner/mutation/propagate.d.ts +1 -1
  182. package/dist/src/planner/mutation/propagate.js +1 -1
  183. package/dist/src/planner/mutation/scope-transform.d.ts +2 -2
  184. package/dist/src/planner/mutation/scope-transform.js +3 -3
  185. package/dist/src/planner/mutation/scope-transform.js.map +1 -1
  186. package/dist/src/planner/mutation/set-op.d.ts +1 -1
  187. package/dist/src/planner/mutation/set-op.d.ts.map +1 -1
  188. package/dist/src/planner/mutation/set-op.js +3 -2
  189. package/dist/src/planner/mutation/set-op.js.map +1 -1
  190. package/dist/src/planner/mutation/single-source.d.ts +3 -3
  191. package/dist/src/planner/mutation/single-source.js +9 -9
  192. package/dist/src/planner/mutation/single-source.js.map +1 -1
  193. package/dist/src/planner/nodes/aggregate-function.d.ts +3 -1
  194. package/dist/src/planner/nodes/aggregate-function.d.ts.map +1 -1
  195. package/dist/src/planner/nodes/aggregate-function.js +1 -0
  196. package/dist/src/planner/nodes/aggregate-function.js.map +1 -1
  197. package/dist/src/planner/nodes/aggregate-node.d.ts +1 -0
  198. package/dist/src/planner/nodes/aggregate-node.d.ts.map +1 -1
  199. package/dist/src/planner/nodes/aggregate-node.js +8 -1
  200. package/dist/src/planner/nodes/aggregate-node.js.map +1 -1
  201. package/dist/src/planner/nodes/alias-node.d.ts.map +1 -1
  202. package/dist/src/planner/nodes/alias-node.js +3 -1
  203. package/dist/src/planner/nodes/alias-node.js.map +1 -1
  204. package/dist/src/planner/nodes/asof-scan-node.d.ts.map +1 -1
  205. package/dist/src/planner/nodes/asof-scan-node.js +3 -2
  206. package/dist/src/planner/nodes/asof-scan-node.js.map +1 -1
  207. package/dist/src/planner/nodes/asserted-keys-node.d.ts +1 -1
  208. package/dist/src/planner/nodes/asserted-keys-node.d.ts.map +1 -1
  209. package/dist/src/planner/nodes/asserted-keys-node.js +5 -2
  210. package/dist/src/planner/nodes/asserted-keys-node.js.map +1 -1
  211. package/dist/src/planner/nodes/async-gather-node.d.ts.map +1 -1
  212. package/dist/src/planner/nodes/async-gather-node.js +3 -1
  213. package/dist/src/planner/nodes/async-gather-node.js.map +1 -1
  214. package/dist/src/planner/nodes/block.js +3 -3
  215. package/dist/src/planner/nodes/block.js.map +1 -1
  216. package/dist/src/planner/nodes/bloom-join-node.d.ts +2 -0
  217. package/dist/src/planner/nodes/bloom-join-node.d.ts.map +1 -1
  218. package/dist/src/planner/nodes/bloom-join-node.js +5 -1
  219. package/dist/src/planner/nodes/bloom-join-node.js.map +1 -1
  220. package/dist/src/planner/nodes/cache-node.d.ts +19 -2
  221. package/dist/src/planner/nodes/cache-node.d.ts.map +1 -1
  222. package/dist/src/planner/nodes/cache-node.js +43 -3
  223. package/dist/src/planner/nodes/cache-node.js.map +1 -1
  224. package/dist/src/planner/nodes/cte-node.d.ts +16 -1
  225. package/dist/src/planner/nodes/cte-node.d.ts.map +1 -1
  226. package/dist/src/planner/nodes/cte-node.js +16 -3
  227. package/dist/src/planner/nodes/cte-node.js.map +1 -1
  228. package/dist/src/planner/nodes/distinct-node.js +3 -3
  229. package/dist/src/planner/nodes/distinct-node.js.map +1 -1
  230. package/dist/src/planner/nodes/dml-executor-node.d.ts +21 -0
  231. package/dist/src/planner/nodes/dml-executor-node.d.ts.map +1 -1
  232. package/dist/src/planner/nodes/dml-executor-node.js.map +1 -1
  233. package/dist/src/planner/nodes/envelope-scan-node.d.ts +1 -1
  234. package/dist/src/planner/nodes/envelope-scan-node.js +1 -1
  235. package/dist/src/planner/nodes/fanout-lookup-join-node.d.ts.map +1 -1
  236. package/dist/src/planner/nodes/fanout-lookup-join-node.js +4 -2
  237. package/dist/src/planner/nodes/fanout-lookup-join-node.js.map +1 -1
  238. package/dist/src/planner/nodes/filter.d.ts +10 -2
  239. package/dist/src/planner/nodes/filter.d.ts.map +1 -1
  240. package/dist/src/planner/nodes/filter.js +81 -14
  241. package/dist/src/planner/nodes/filter.js.map +1 -1
  242. package/dist/src/planner/nodes/hash-aggregate.d.ts +12 -1
  243. package/dist/src/planner/nodes/hash-aggregate.d.ts.map +1 -1
  244. package/dist/src/planner/nodes/hash-aggregate.js +28 -1
  245. package/dist/src/planner/nodes/hash-aggregate.js.map +1 -1
  246. package/dist/src/planner/nodes/internal-recursive-cte-ref-node.d.ts +3 -1
  247. package/dist/src/planner/nodes/internal-recursive-cte-ref-node.d.ts.map +1 -1
  248. package/dist/src/planner/nodes/internal-recursive-cte-ref-node.js +1 -0
  249. package/dist/src/planner/nodes/internal-recursive-cte-ref-node.js.map +1 -1
  250. package/dist/src/planner/nodes/join-node.d.ts +3 -1
  251. package/dist/src/planner/nodes/join-node.d.ts.map +1 -1
  252. package/dist/src/planner/nodes/join-node.js +5 -5
  253. package/dist/src/planner/nodes/join-node.js.map +1 -1
  254. package/dist/src/planner/nodes/lens-auxiliary-access-node.d.ts.map +1 -1
  255. package/dist/src/planner/nodes/lens-auxiliary-access-node.js +4 -1
  256. package/dist/src/planner/nodes/lens-auxiliary-access-node.js.map +1 -1
  257. package/dist/src/planner/nodes/limit-offset.d.ts +1 -0
  258. package/dist/src/planner/nodes/limit-offset.d.ts.map +1 -1
  259. package/dist/src/planner/nodes/limit-offset.js +4 -3
  260. package/dist/src/planner/nodes/limit-offset.js.map +1 -1
  261. package/dist/src/planner/nodes/merge-join-node.d.ts +2 -0
  262. package/dist/src/planner/nodes/merge-join-node.d.ts.map +1 -1
  263. package/dist/src/planner/nodes/merge-join-node.js +6 -1
  264. package/dist/src/planner/nodes/merge-join-node.js.map +1 -1
  265. package/dist/src/planner/nodes/ordinal-slice-node.d.ts.map +1 -1
  266. package/dist/src/planner/nodes/ordinal-slice-node.js +3 -1
  267. package/dist/src/planner/nodes/ordinal-slice-node.js.map +1 -1
  268. package/dist/src/planner/nodes/plan-node.d.ts +68 -5
  269. package/dist/src/planner/nodes/plan-node.d.ts.map +1 -1
  270. package/dist/src/planner/nodes/plan-node.js +137 -24
  271. package/dist/src/planner/nodes/plan-node.js.map +1 -1
  272. package/dist/src/planner/nodes/project-node.d.ts +3 -2
  273. package/dist/src/planner/nodes/project-node.d.ts.map +1 -1
  274. package/dist/src/planner/nodes/project-node.js +1 -0
  275. package/dist/src/planner/nodes/project-node.js.map +1 -1
  276. package/dist/src/planner/nodes/recursive-cte-node.d.ts +30 -1
  277. package/dist/src/planner/nodes/recursive-cte-node.d.ts.map +1 -1
  278. package/dist/src/planner/nodes/recursive-cte-node.js +38 -5
  279. package/dist/src/planner/nodes/recursive-cte-node.js.map +1 -1
  280. package/dist/src/planner/nodes/reference.d.ts +5 -1
  281. package/dist/src/planner/nodes/reference.d.ts.map +1 -1
  282. package/dist/src/planner/nodes/reference.js +3 -0
  283. package/dist/src/planner/nodes/reference.js.map +1 -1
  284. package/dist/src/planner/nodes/remote-query-node.d.ts.map +1 -1
  285. package/dist/src/planner/nodes/remote-query-node.js +3 -1
  286. package/dist/src/planner/nodes/remote-query-node.js.map +1 -1
  287. package/dist/src/planner/nodes/retrieve-node.d.ts.map +1 -1
  288. package/dist/src/planner/nodes/retrieve-node.js +3 -1
  289. package/dist/src/planner/nodes/retrieve-node.js.map +1 -1
  290. package/dist/src/planner/nodes/set-operation-node.d.ts.map +1 -1
  291. package/dist/src/planner/nodes/set-operation-node.js +3 -1
  292. package/dist/src/planner/nodes/set-operation-node.js.map +1 -1
  293. package/dist/src/planner/nodes/sink-node.d.ts.map +1 -1
  294. package/dist/src/planner/nodes/sink-node.js +3 -1
  295. package/dist/src/planner/nodes/sink-node.js.map +1 -1
  296. package/dist/src/planner/nodes/sort.d.ts +2 -1
  297. package/dist/src/planner/nodes/sort.d.ts.map +1 -1
  298. package/dist/src/planner/nodes/sort.js +9 -5
  299. package/dist/src/planner/nodes/sort.js.map +1 -1
  300. package/dist/src/planner/nodes/stream-aggregate.d.ts +12 -1
  301. package/dist/src/planner/nodes/stream-aggregate.d.ts.map +1 -1
  302. package/dist/src/planner/nodes/stream-aggregate.js +32 -3
  303. package/dist/src/planner/nodes/stream-aggregate.js.map +1 -1
  304. package/dist/src/planner/nodes/table-access-nodes.d.ts +2 -1
  305. package/dist/src/planner/nodes/table-access-nodes.d.ts.map +1 -1
  306. package/dist/src/planner/nodes/table-access-nodes.js +2 -0
  307. package/dist/src/planner/nodes/table-access-nodes.js.map +1 -1
  308. package/dist/src/planner/nodes/view-mutation-node.d.ts +2 -2
  309. package/dist/src/planner/nodes/view-mutation-node.d.ts.map +1 -1
  310. package/dist/src/planner/nodes/view-mutation-node.js +5 -1
  311. package/dist/src/planner/nodes/view-mutation-node.js.map +1 -1
  312. package/dist/src/planner/nodes/window-function.d.ts +3 -1
  313. package/dist/src/planner/nodes/window-function.d.ts.map +1 -1
  314. package/dist/src/planner/nodes/window-function.js +1 -0
  315. package/dist/src/planner/nodes/window-function.js.map +1 -1
  316. package/dist/src/planner/optimizer.d.ts +52 -8
  317. package/dist/src/planner/optimizer.d.ts.map +1 -1
  318. package/dist/src/planner/optimizer.js +1014 -895
  319. package/dist/src/planner/optimizer.js.map +1 -1
  320. package/dist/src/planner/rules/access/rule-select-access-path.d.ts.map +1 -1
  321. package/dist/src/planner/rules/access/rule-select-access-path.js +235 -202
  322. package/dist/src/planner/rules/access/rule-select-access-path.js.map +1 -1
  323. package/dist/src/planner/rules/cache/rule-cte-optimization.d.ts.map +1 -1
  324. package/dist/src/planner/rules/cache/rule-cte-optimization.js +8 -1
  325. package/dist/src/planner/rules/cache/rule-cte-optimization.js.map +1 -1
  326. package/dist/src/planner/rules/cache/rule-in-subquery-cache.d.ts +7 -0
  327. package/dist/src/planner/rules/cache/rule-in-subquery-cache.d.ts.map +1 -1
  328. package/dist/src/planner/rules/cache/rule-in-subquery-cache.js +14 -1
  329. package/dist/src/planner/rules/cache/rule-in-subquery-cache.js.map +1 -1
  330. package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.d.ts +2 -2
  331. package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.d.ts.map +1 -1
  332. package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.js +55 -56
  333. package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.js.map +1 -1
  334. package/dist/src/planner/rules/cache/rule-mutating-subquery-cache.d.ts.map +1 -1
  335. package/dist/src/planner/rules/cache/rule-mutating-subquery-cache.js +6 -0
  336. package/dist/src/planner/rules/cache/rule-mutating-subquery-cache.js.map +1 -1
  337. package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.d.ts +25 -0
  338. package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.d.ts.map +1 -0
  339. package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.js +176 -0
  340. package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.js.map +1 -0
  341. package/dist/src/planner/rules/cache/rule-scalar-cse.d.ts +1 -1
  342. package/dist/src/planner/rules/cache/rule-scalar-cse.js +1 -1
  343. package/dist/src/planner/rules/cache/rule-scalar-subquery-cache.d.ts +29 -0
  344. package/dist/src/planner/rules/cache/rule-scalar-subquery-cache.d.ts.map +1 -0
  345. package/dist/src/planner/rules/cache/rule-scalar-subquery-cache.js +66 -0
  346. package/dist/src/planner/rules/cache/rule-scalar-subquery-cache.js.map +1 -0
  347. package/dist/src/planner/rules/join/rule-fanout-batched-outer.d.ts +1 -1
  348. package/dist/src/planner/rules/join/rule-fanout-batched-outer.js +1 -1
  349. package/dist/src/planner/rules/join/rule-fanout-lookup-join.d.ts.map +1 -1
  350. package/dist/src/planner/rules/join/rule-fanout-lookup-join.js +1 -54
  351. package/dist/src/planner/rules/join/rule-fanout-lookup-join.js.map +1 -1
  352. package/dist/src/planner/rules/join/rule-inner-join-existence-recovery.d.ts +1 -1
  353. package/dist/src/planner/rules/join/rule-inner-join-existence-recovery.js +1 -1
  354. package/dist/src/planner/rules/join/rule-join-elimination.d.ts +1 -1
  355. package/dist/src/planner/rules/join/rule-join-elimination.js +1 -1
  356. package/dist/src/planner/rules/parallel/rule-async-gather-zip-by-key.js +5 -6
  357. package/dist/src/planner/rules/parallel/rule-async-gather-zip-by-key.js.map +1 -1
  358. package/dist/src/planner/rules/predicate/rule-empty-relation-folding.d.ts +1 -1
  359. package/dist/src/planner/rules/predicate/rule-empty-relation-folding.js +1 -1
  360. package/dist/src/planner/rules/predicate/rule-filter-contradiction.d.ts +2 -2
  361. package/dist/src/planner/rules/predicate/rule-filter-contradiction.d.ts.map +1 -1
  362. package/dist/src/planner/rules/predicate/rule-filter-contradiction.js +4 -3
  363. package/dist/src/planner/rules/predicate/rule-filter-contradiction.js.map +1 -1
  364. package/dist/src/planner/rules/predicate/rule-filter-selectivity.d.ts +19 -0
  365. package/dist/src/planner/rules/predicate/rule-filter-selectivity.d.ts.map +1 -0
  366. package/dist/src/planner/rules/predicate/rule-filter-selectivity.js +48 -0
  367. package/dist/src/planner/rules/predicate/rule-filter-selectivity.js.map +1 -0
  368. package/dist/src/planner/rules/predicate/rule-sargable-range-rewrite.js +12 -1
  369. package/dist/src/planner/rules/predicate/rule-sargable-range-rewrite.js.map +1 -1
  370. package/dist/src/planner/rules/retrieve/rule-grow-retrieve.d.ts.map +1 -1
  371. package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js +22 -20
  372. package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js.map +1 -1
  373. package/dist/src/planner/rules/shared/index-style-context.d.ts +39 -0
  374. package/dist/src/planner/rules/shared/index-style-context.d.ts.map +1 -0
  375. package/dist/src/planner/rules/shared/index-style-context.js +26 -0
  376. package/dist/src/planner/rules/shared/index-style-context.js.map +1 -0
  377. package/dist/src/planner/rules/sort/rule-orderby-fd-pruning.d.ts +1 -1
  378. package/dist/src/planner/rules/sort/rule-orderby-fd-pruning.js +1 -1
  379. package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.d.ts +1 -1
  380. package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.js +1 -1
  381. package/dist/src/planner/rules/subquery/rule-scalar-agg-decorrelation.d.ts +191 -0
  382. package/dist/src/planner/rules/subquery/rule-scalar-agg-decorrelation.d.ts.map +1 -0
  383. package/dist/src/planner/rules/subquery/rule-scalar-agg-decorrelation.js +623 -0
  384. package/dist/src/planner/rules/subquery/rule-scalar-agg-decorrelation.js.map +1 -0
  385. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.d.ts +10 -1
  386. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.d.ts.map +1 -1
  387. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js +242 -51
  388. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js.map +1 -1
  389. package/dist/src/planner/stats/analyze.d.ts.map +1 -1
  390. package/dist/src/planner/stats/analyze.js +2 -20
  391. package/dist/src/planner/stats/analyze.js.map +1 -1
  392. package/dist/src/planner/stats/histogram.d.ts.map +1 -1
  393. package/dist/src/planner/stats/histogram.js +4 -0
  394. package/dist/src/planner/stats/histogram.js.map +1 -1
  395. package/dist/src/planner/util/fd-utils.d.ts +2 -3
  396. package/dist/src/planner/util/fd-utils.d.ts.map +1 -1
  397. package/dist/src/planner/util/fd-utils.js +2 -3
  398. package/dist/src/planner/util/fd-utils.js.map +1 -1
  399. package/dist/src/planner/validation/plan-validator.d.ts +16 -0
  400. package/dist/src/planner/validation/plan-validator.d.ts.map +1 -1
  401. package/dist/src/planner/validation/plan-validator.js +36 -0
  402. package/dist/src/planner/validation/plan-validator.js.map +1 -1
  403. package/dist/src/runtime/async-util.d.ts +26 -0
  404. package/dist/src/runtime/async-util.d.ts.map +1 -1
  405. package/dist/src/runtime/async-util.js +139 -55
  406. package/dist/src/runtime/async-util.js.map +1 -1
  407. package/dist/src/runtime/cache/shared-cache.d.ts +7 -0
  408. package/dist/src/runtime/cache/shared-cache.d.ts.map +1 -1
  409. package/dist/src/runtime/cache/shared-cache.js +34 -1
  410. package/dist/src/runtime/cache/shared-cache.js.map +1 -1
  411. package/dist/src/runtime/context-helpers.d.ts +32 -4
  412. package/dist/src/runtime/context-helpers.d.ts.map +1 -1
  413. package/dist/src/runtime/context-helpers.js +26 -9
  414. package/dist/src/runtime/context-helpers.js.map +1 -1
  415. package/dist/src/runtime/deferred-constraint-queue.d.ts.map +1 -1
  416. package/dist/src/runtime/deferred-constraint-queue.js +2 -1
  417. package/dist/src/runtime/deferred-constraint-queue.js.map +1 -1
  418. package/dist/src/runtime/emission-context.d.ts +27 -3
  419. package/dist/src/runtime/emission-context.d.ts.map +1 -1
  420. package/dist/src/runtime/emission-context.js +38 -7
  421. package/dist/src/runtime/emission-context.js.map +1 -1
  422. package/dist/src/runtime/emit/add-constraint.d.ts.map +1 -1
  423. package/dist/src/runtime/emit/add-constraint.js +7 -1
  424. package/dist/src/runtime/emit/add-constraint.js.map +1 -1
  425. package/dist/src/runtime/emit/aggregate.d.ts +2 -3
  426. package/dist/src/runtime/emit/aggregate.d.ts.map +1 -1
  427. package/dist/src/runtime/emit/aggregate.js +23 -28
  428. package/dist/src/runtime/emit/aggregate.js.map +1 -1
  429. package/dist/src/runtime/emit/alter-table.d.ts.map +1 -1
  430. package/dist/src/runtime/emit/alter-table.js +98 -9
  431. package/dist/src/runtime/emit/alter-table.js.map +1 -1
  432. package/dist/src/runtime/emit/analyze.d.ts.map +1 -1
  433. package/dist/src/runtime/emit/analyze.js +2 -1
  434. package/dist/src/runtime/emit/analyze.js.map +1 -1
  435. package/dist/src/runtime/emit/asof-scan.d.ts.map +1 -1
  436. package/dist/src/runtime/emit/asof-scan.js +13 -10
  437. package/dist/src/runtime/emit/asof-scan.js.map +1 -1
  438. package/dist/src/runtime/emit/async-gather.d.ts.map +1 -1
  439. package/dist/src/runtime/emit/async-gather.js +4 -3
  440. package/dist/src/runtime/emit/async-gather.js.map +1 -1
  441. package/dist/src/runtime/emit/between.d.ts.map +1 -1
  442. package/dist/src/runtime/emit/between.js +2 -1
  443. package/dist/src/runtime/emit/between.js.map +1 -1
  444. package/dist/src/runtime/emit/binary.d.ts.map +1 -1
  445. package/dist/src/runtime/emit/binary.js +122 -14
  446. package/dist/src/runtime/emit/binary.js.map +1 -1
  447. package/dist/src/runtime/emit/block.d.ts.map +1 -1
  448. package/dist/src/runtime/emit/block.js +2 -1
  449. package/dist/src/runtime/emit/block.js.map +1 -1
  450. package/dist/src/runtime/emit/bloom-join.d.ts.map +1 -1
  451. package/dist/src/runtime/emit/bloom-join.js +20 -8
  452. package/dist/src/runtime/emit/bloom-join.js.map +1 -1
  453. package/dist/src/runtime/emit/cache.d.ts +7 -3
  454. package/dist/src/runtime/emit/cache.d.ts.map +1 -1
  455. package/dist/src/runtime/emit/cache.js +25 -7
  456. package/dist/src/runtime/emit/cache.js.map +1 -1
  457. package/dist/src/runtime/emit/case.d.ts.map +1 -1
  458. package/dist/src/runtime/emit/case.js +66 -45
  459. package/dist/src/runtime/emit/case.js.map +1 -1
  460. package/dist/src/runtime/emit/cast.d.ts.map +1 -1
  461. package/dist/src/runtime/emit/cast.js +2 -1
  462. package/dist/src/runtime/emit/cast.js.map +1 -1
  463. package/dist/src/runtime/emit/constraint-check.d.ts.map +1 -1
  464. package/dist/src/runtime/emit/constraint-check.js +13 -7
  465. package/dist/src/runtime/emit/constraint-check.js.map +1 -1
  466. package/dist/src/runtime/emit/create-assertion.d.ts.map +1 -1
  467. package/dist/src/runtime/emit/create-assertion.js +2 -1
  468. package/dist/src/runtime/emit/create-assertion.js.map +1 -1
  469. package/dist/src/runtime/emit/create-index.d.ts.map +1 -1
  470. package/dist/src/runtime/emit/create-index.js +12 -1
  471. package/dist/src/runtime/emit/create-index.js.map +1 -1
  472. package/dist/src/runtime/emit/create-table.d.ts.map +1 -1
  473. package/dist/src/runtime/emit/create-table.js +12 -1
  474. package/dist/src/runtime/emit/create-table.js.map +1 -1
  475. package/dist/src/runtime/emit/cte-reference.d.ts.map +1 -1
  476. package/dist/src/runtime/emit/cte-reference.js +2 -1
  477. package/dist/src/runtime/emit/cte-reference.js.map +1 -1
  478. package/dist/src/runtime/emit/cte.d.ts.map +1 -1
  479. package/dist/src/runtime/emit/cte.js +45 -21
  480. package/dist/src/runtime/emit/cte.js.map +1 -1
  481. package/dist/src/runtime/emit/ddl-transaction-policy.d.ts +50 -0
  482. package/dist/src/runtime/emit/ddl-transaction-policy.d.ts.map +1 -0
  483. package/dist/src/runtime/emit/ddl-transaction-policy.js +69 -0
  484. package/dist/src/runtime/emit/ddl-transaction-policy.js.map +1 -0
  485. package/dist/src/runtime/emit/delete.d.ts.map +1 -1
  486. package/dist/src/runtime/emit/delete.js +2 -1
  487. package/dist/src/runtime/emit/delete.js.map +1 -1
  488. package/dist/src/runtime/emit/distinct.d.ts.map +1 -1
  489. package/dist/src/runtime/emit/distinct.js +2 -1
  490. package/dist/src/runtime/emit/distinct.js.map +1 -1
  491. package/dist/src/runtime/emit/dml-executor.d.ts.map +1 -1
  492. package/dist/src/runtime/emit/dml-executor.js +138 -74
  493. package/dist/src/runtime/emit/dml-executor.js.map +1 -1
  494. package/dist/src/runtime/emit/drop-assertion.d.ts.map +1 -1
  495. package/dist/src/runtime/emit/drop-assertion.js +2 -1
  496. package/dist/src/runtime/emit/drop-assertion.js.map +1 -1
  497. package/dist/src/runtime/emit/drop-index.d.ts.map +1 -1
  498. package/dist/src/runtime/emit/drop-index.js +17 -1
  499. package/dist/src/runtime/emit/drop-index.js.map +1 -1
  500. package/dist/src/runtime/emit/drop-table.d.ts.map +1 -1
  501. package/dist/src/runtime/emit/drop-table.js +11 -1
  502. package/dist/src/runtime/emit/drop-table.js.map +1 -1
  503. package/dist/src/runtime/emit/eager-prefetch.d.ts.map +1 -1
  504. package/dist/src/runtime/emit/eager-prefetch.js +2 -1
  505. package/dist/src/runtime/emit/eager-prefetch.js.map +1 -1
  506. package/dist/src/runtime/emit/envelope-scan.d.ts.map +1 -1
  507. package/dist/src/runtime/emit/envelope-scan.js +2 -1
  508. package/dist/src/runtime/emit/envelope-scan.js.map +1 -1
  509. package/dist/src/runtime/emit/fanout-lookup-join.d.ts.map +1 -1
  510. package/dist/src/runtime/emit/fanout-lookup-join.js +3 -2
  511. package/dist/src/runtime/emit/fanout-lookup-join.js.map +1 -1
  512. package/dist/src/runtime/emit/filter.d.ts.map +1 -1
  513. package/dist/src/runtime/emit/filter.js +8 -3
  514. package/dist/src/runtime/emit/filter.js.map +1 -1
  515. package/dist/src/runtime/emit/hash-aggregate.d.ts.map +1 -1
  516. package/dist/src/runtime/emit/hash-aggregate.js +16 -11
  517. package/dist/src/runtime/emit/hash-aggregate.js.map +1 -1
  518. package/dist/src/runtime/emit/insert.d.ts.map +1 -1
  519. package/dist/src/runtime/emit/insert.js +2 -1
  520. package/dist/src/runtime/emit/insert.js.map +1 -1
  521. package/dist/src/runtime/emit/join.d.ts.map +1 -1
  522. package/dist/src/runtime/emit/join.js +20 -6
  523. package/dist/src/runtime/emit/join.js.map +1 -1
  524. package/dist/src/runtime/emit/limit-offset.d.ts.map +1 -1
  525. package/dist/src/runtime/emit/limit-offset.js +2 -1
  526. package/dist/src/runtime/emit/limit-offset.js.map +1 -1
  527. package/dist/src/runtime/emit/literal.d.ts.map +1 -1
  528. package/dist/src/runtime/emit/literal.js +2 -1
  529. package/dist/src/runtime/emit/literal.js.map +1 -1
  530. package/dist/src/runtime/emit/materialized-view-helpers.d.ts +22 -0
  531. package/dist/src/runtime/emit/materialized-view-helpers.d.ts.map +1 -1
  532. package/dist/src/runtime/emit/materialized-view-helpers.js +128 -16
  533. package/dist/src/runtime/emit/materialized-view-helpers.js.map +1 -1
  534. package/dist/src/runtime/emit/materialized-view.d.ts.map +1 -1
  535. package/dist/src/runtime/emit/materialized-view.js +6 -0
  536. package/dist/src/runtime/emit/materialized-view.js.map +1 -1
  537. package/dist/src/runtime/emit/merge-join.d.ts.map +1 -1
  538. package/dist/src/runtime/emit/merge-join.js +14 -4
  539. package/dist/src/runtime/emit/merge-join.js.map +1 -1
  540. package/dist/src/runtime/emit/ordinal-slice.d.ts.map +1 -1
  541. package/dist/src/runtime/emit/ordinal-slice.js +2 -1
  542. package/dist/src/runtime/emit/ordinal-slice.js.map +1 -1
  543. package/dist/src/runtime/emit/pragma.d.ts.map +1 -1
  544. package/dist/src/runtime/emit/pragma.js +2 -1
  545. package/dist/src/runtime/emit/pragma.js.map +1 -1
  546. package/dist/src/runtime/emit/project.d.ts.map +1 -1
  547. package/dist/src/runtime/emit/project.js +7 -2
  548. package/dist/src/runtime/emit/project.js.map +1 -1
  549. package/dist/src/runtime/emit/recursive-cte.d.ts.map +1 -1
  550. package/dist/src/runtime/emit/recursive-cte.js +61 -2
  551. package/dist/src/runtime/emit/recursive-cte.js.map +1 -1
  552. package/dist/src/runtime/emit/returning.d.ts.map +1 -1
  553. package/dist/src/runtime/emit/returning.js +7 -2
  554. package/dist/src/runtime/emit/returning.js.map +1 -1
  555. package/dist/src/runtime/emit/scalar-function.d.ts.map +1 -1
  556. package/dist/src/runtime/emit/scalar-function.js +2 -1
  557. package/dist/src/runtime/emit/scalar-function.js.map +1 -1
  558. package/dist/src/runtime/emit/scan.d.ts.map +1 -1
  559. package/dist/src/runtime/emit/scan.js +55 -17
  560. package/dist/src/runtime/emit/scan.js.map +1 -1
  561. package/dist/src/runtime/emit/schema-declarative.d.ts.map +1 -1
  562. package/dist/src/runtime/emit/schema-declarative.js +6 -5
  563. package/dist/src/runtime/emit/schema-declarative.js.map +1 -1
  564. package/dist/src/runtime/emit/sequencing.d.ts.map +1 -1
  565. package/dist/src/runtime/emit/sequencing.js +2 -1
  566. package/dist/src/runtime/emit/sequencing.js.map +1 -1
  567. package/dist/src/runtime/emit/set-operation.d.ts.map +1 -1
  568. package/dist/src/runtime/emit/set-operation.js +6 -5
  569. package/dist/src/runtime/emit/set-operation.js.map +1 -1
  570. package/dist/src/runtime/emit/sink.d.ts.map +1 -1
  571. package/dist/src/runtime/emit/sink.js +2 -1
  572. package/dist/src/runtime/emit/sink.js.map +1 -1
  573. package/dist/src/runtime/emit/sort.d.ts.map +1 -1
  574. package/dist/src/runtime/emit/sort.js +2 -1
  575. package/dist/src/runtime/emit/sort.js.map +1 -1
  576. package/dist/src/runtime/emit/subquery.d.ts.map +1 -1
  577. package/dist/src/runtime/emit/subquery.js +42 -23
  578. package/dist/src/runtime/emit/subquery.js.map +1 -1
  579. package/dist/src/runtime/emit/table-valued-function.d.ts.map +1 -1
  580. package/dist/src/runtime/emit/table-valued-function.js +2 -1
  581. package/dist/src/runtime/emit/table-valued-function.js.map +1 -1
  582. package/dist/src/runtime/emit/temporal-arithmetic.d.ts.map +1 -1
  583. package/dist/src/runtime/emit/temporal-arithmetic.js +2 -1
  584. package/dist/src/runtime/emit/temporal-arithmetic.js.map +1 -1
  585. package/dist/src/runtime/emit/transaction.d.ts.map +1 -1
  586. package/dist/src/runtime/emit/transaction.js +2 -1
  587. package/dist/src/runtime/emit/transaction.js.map +1 -1
  588. package/dist/src/runtime/emit/unary.d.ts.map +1 -1
  589. package/dist/src/runtime/emit/unary.js +2 -1
  590. package/dist/src/runtime/emit/unary.js.map +1 -1
  591. package/dist/src/runtime/emit/update.d.ts.map +1 -1
  592. package/dist/src/runtime/emit/update.js +2 -1
  593. package/dist/src/runtime/emit/update.js.map +1 -1
  594. package/dist/src/runtime/emit/values.d.ts.map +1 -1
  595. package/dist/src/runtime/emit/values.js +2 -1
  596. package/dist/src/runtime/emit/values.js.map +1 -1
  597. package/dist/src/runtime/emit/view-mutation.d.ts +1 -1
  598. package/dist/src/runtime/emit/view-mutation.d.ts.map +1 -1
  599. package/dist/src/runtime/emit/view-mutation.js +6 -3
  600. package/dist/src/runtime/emit/view-mutation.js.map +1 -1
  601. package/dist/src/runtime/emit/window.d.ts.map +1 -1
  602. package/dist/src/runtime/emit/window.js +26 -9
  603. package/dist/src/runtime/emit/window.js.map +1 -1
  604. package/dist/src/runtime/emitters.d.ts +11 -3
  605. package/dist/src/runtime/emitters.d.ts.map +1 -1
  606. package/dist/src/runtime/emitters.js +13 -22
  607. package/dist/src/runtime/emitters.js.map +1 -1
  608. package/dist/src/runtime/foreign-key-actions.d.ts.map +1 -1
  609. package/dist/src/runtime/foreign-key-actions.js +39 -13
  610. package/dist/src/runtime/foreign-key-actions.js.map +1 -1
  611. package/dist/src/runtime/parallel-driver.d.ts +32 -4
  612. package/dist/src/runtime/parallel-driver.d.ts.map +1 -1
  613. package/dist/src/runtime/parallel-driver.js +88 -18
  614. package/dist/src/runtime/parallel-driver.js.map +1 -1
  615. package/dist/src/runtime/scheduler.d.ts +56 -7
  616. package/dist/src/runtime/scheduler.d.ts.map +1 -1
  617. package/dist/src/runtime/scheduler.js +223 -200
  618. package/dist/src/runtime/scheduler.js.map +1 -1
  619. package/dist/src/runtime/strict-flags.d.ts +22 -0
  620. package/dist/src/runtime/strict-flags.d.ts.map +1 -0
  621. package/dist/src/runtime/strict-flags.js +26 -0
  622. package/dist/src/runtime/strict-flags.js.map +1 -0
  623. package/dist/src/runtime/strict-fork.d.ts +4 -4
  624. package/dist/src/runtime/strict-fork.d.ts.map +1 -1
  625. package/dist/src/runtime/strict-fork.js +175 -31
  626. package/dist/src/runtime/strict-fork.js.map +1 -1
  627. package/dist/src/runtime/types.d.ts +102 -4
  628. package/dist/src/runtime/types.d.ts.map +1 -1
  629. package/dist/src/runtime/types.js +37 -0
  630. package/dist/src/runtime/types.js.map +1 -1
  631. package/dist/src/runtime/utils.d.ts.map +1 -1
  632. package/dist/src/runtime/utils.js +8 -17
  633. package/dist/src/runtime/utils.js.map +1 -1
  634. package/dist/src/schema/column.d.ts +8 -0
  635. package/dist/src/schema/column.d.ts.map +1 -1
  636. package/dist/src/schema/column.js.map +1 -1
  637. package/dist/src/schema/ddl-generator.js +5 -0
  638. package/dist/src/schema/ddl-generator.js.map +1 -1
  639. package/dist/src/schema/function.d.ts +79 -0
  640. package/dist/src/schema/function.d.ts.map +1 -1
  641. package/dist/src/schema/function.js.map +1 -1
  642. package/dist/src/schema/lens-compiler.js +2 -2
  643. package/dist/src/schema/lens-compiler.js.map +1 -1
  644. package/dist/src/schema/lens-prover.d.ts.map +1 -1
  645. package/dist/src/schema/lens-prover.js +2 -3
  646. package/dist/src/schema/lens-prover.js.map +1 -1
  647. package/dist/src/schema/lens.d.ts +1 -1
  648. package/dist/src/schema/manager.d.ts.map +1 -1
  649. package/dist/src/schema/manager.js +7 -2
  650. package/dist/src/schema/manager.js.map +1 -1
  651. package/dist/src/schema/rename-rewriter.d.ts +61 -0
  652. package/dist/src/schema/rename-rewriter.d.ts.map +1 -1
  653. package/dist/src/schema/rename-rewriter.js +77 -0
  654. package/dist/src/schema/rename-rewriter.js.map +1 -1
  655. package/dist/src/schema/table.d.ts +36 -8
  656. package/dist/src/schema/table.d.ts.map +1 -1
  657. package/dist/src/schema/table.js +61 -11
  658. package/dist/src/schema/table.js.map +1 -1
  659. package/dist/src/schema/unique-enforcement.d.ts +28 -5
  660. package/dist/src/schema/unique-enforcement.d.ts.map +1 -1
  661. package/dist/src/schema/unique-enforcement.js +37 -5
  662. package/dist/src/schema/unique-enforcement.js.map +1 -1
  663. package/dist/src/schema/view.d.ts +1 -1
  664. package/dist/src/schema/view.js +1 -1
  665. package/dist/src/types/json-type.d.ts.map +1 -1
  666. package/dist/src/types/json-type.js +18 -8
  667. package/dist/src/types/json-type.js.map +1 -1
  668. package/dist/src/types/logical-type.d.ts +26 -0
  669. package/dist/src/types/logical-type.d.ts.map +1 -1
  670. package/dist/src/types/logical-type.js.map +1 -1
  671. package/dist/src/util/comparison.d.ts +83 -59
  672. package/dist/src/util/comparison.d.ts.map +1 -1
  673. package/dist/src/util/comparison.js +191 -131
  674. package/dist/src/util/comparison.js.map +1 -1
  675. package/dist/src/util/json-canonical.d.ts +34 -0
  676. package/dist/src/util/json-canonical.d.ts.map +1 -0
  677. package/dist/src/util/json-canonical.js +32 -0
  678. package/dist/src/util/json-canonical.js.map +1 -0
  679. package/dist/src/util/key-serializer.d.ts +10 -3
  680. package/dist/src/util/key-serializer.d.ts.map +1 -1
  681. package/dist/src/util/key-serializer.js +43 -17
  682. package/dist/src/util/key-serializer.js.map +1 -1
  683. package/dist/src/util/key-tuple-codec.d.ts +37 -0
  684. package/dist/src/util/key-tuple-codec.d.ts.map +1 -0
  685. package/dist/src/util/key-tuple-codec.js +65 -0
  686. package/dist/src/util/key-tuple-codec.js.map +1 -0
  687. package/dist/src/util/latches.d.ts +29 -3
  688. package/dist/src/util/latches.d.ts.map +1 -1
  689. package/dist/src/util/latches.js +60 -6
  690. package/dist/src/util/latches.js.map +1 -1
  691. package/dist/src/util/patterns.d.ts +22 -8
  692. package/dist/src/util/patterns.d.ts.map +1 -1
  693. package/dist/src/util/patterns.js +87 -16
  694. package/dist/src/util/patterns.js.map +1 -1
  695. package/dist/src/util/qualified-name.d.ts +10 -0
  696. package/dist/src/util/qualified-name.d.ts.map +1 -0
  697. package/dist/src/util/qualified-name.js +15 -0
  698. package/dist/src/util/qualified-name.js.map +1 -0
  699. package/dist/src/vtab/backing-host.d.ts +8 -1
  700. package/dist/src/vtab/backing-host.d.ts.map +1 -1
  701. package/dist/src/vtab/backing-host.js +7 -0
  702. package/dist/src/vtab/backing-host.js.map +1 -1
  703. package/dist/src/vtab/best-access-plan.d.ts +18 -0
  704. package/dist/src/vtab/best-access-plan.d.ts.map +1 -1
  705. package/dist/src/vtab/best-access-plan.js +15 -0
  706. package/dist/src/vtab/best-access-plan.js.map +1 -1
  707. package/dist/src/vtab/capabilities.d.ts +44 -0
  708. package/dist/src/vtab/capabilities.d.ts.map +1 -1
  709. package/dist/src/vtab/filter-info.d.ts +42 -0
  710. package/dist/src/vtab/filter-info.d.ts.map +1 -1
  711. package/dist/src/vtab/filter-info.js +137 -1
  712. package/dist/src/vtab/filter-info.js.map +1 -1
  713. package/dist/src/vtab/idx-str.d.ts +62 -0
  714. package/dist/src/vtab/idx-str.d.ts.map +1 -0
  715. package/dist/src/vtab/idx-str.js +130 -0
  716. package/dist/src/vtab/idx-str.js.map +1 -0
  717. package/dist/src/vtab/index-descriptor.d.ts +122 -0
  718. package/dist/src/vtab/index-descriptor.d.ts.map +1 -0
  719. package/dist/src/vtab/index-descriptor.js +104 -0
  720. package/dist/src/vtab/index-descriptor.js.map +1 -0
  721. package/dist/src/vtab/mapping-advertisement.d.ts +1 -1
  722. package/dist/src/vtab/memory/index.d.ts +12 -4
  723. package/dist/src/vtab/memory/index.d.ts.map +1 -1
  724. package/dist/src/vtab/memory/index.js +17 -9
  725. package/dist/src/vtab/memory/index.js.map +1 -1
  726. package/dist/src/vtab/memory/layer/base.d.ts +85 -31
  727. package/dist/src/vtab/memory/layer/base.d.ts.map +1 -1
  728. package/dist/src/vtab/memory/layer/base.js +127 -86
  729. package/dist/src/vtab/memory/layer/base.js.map +1 -1
  730. package/dist/src/vtab/memory/layer/connection.d.ts +27 -0
  731. package/dist/src/vtab/memory/layer/connection.d.ts.map +1 -1
  732. package/dist/src/vtab/memory/layer/connection.js +36 -1
  733. package/dist/src/vtab/memory/layer/connection.js.map +1 -1
  734. package/dist/src/vtab/memory/layer/interface.d.ts +24 -4
  735. package/dist/src/vtab/memory/layer/interface.d.ts.map +1 -1
  736. package/dist/src/vtab/memory/layer/manager.d.ts +212 -16
  737. package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
  738. package/dist/src/vtab/memory/layer/manager.js +754 -170
  739. package/dist/src/vtab/memory/layer/manager.js.map +1 -1
  740. package/dist/src/vtab/memory/layer/plan-filter.d.ts +26 -1
  741. package/dist/src/vtab/memory/layer/plan-filter.d.ts.map +1 -1
  742. package/dist/src/vtab/memory/layer/plan-filter.js +29 -11
  743. package/dist/src/vtab/memory/layer/plan-filter.js.map +1 -1
  744. package/dist/src/vtab/memory/layer/safe-iterate.d.ts +2 -2
  745. package/dist/src/vtab/memory/layer/safe-iterate.d.ts.map +1 -1
  746. package/dist/src/vtab/memory/layer/safe-iterate.js +2 -2
  747. package/dist/src/vtab/memory/layer/safe-iterate.js.map +1 -1
  748. package/dist/src/vtab/memory/layer/scan-layer.d.ts +5 -1
  749. package/dist/src/vtab/memory/layer/scan-layer.d.ts.map +1 -1
  750. package/dist/src/vtab/memory/layer/scan-layer.js +59 -24
  751. package/dist/src/vtab/memory/layer/scan-layer.js.map +1 -1
  752. package/dist/src/vtab/memory/layer/scan-plan.d.ts.map +1 -1
  753. package/dist/src/vtab/memory/layer/scan-plan.js +13 -21
  754. package/dist/src/vtab/memory/layer/scan-plan.js.map +1 -1
  755. package/dist/src/vtab/memory/layer/transaction.d.ts +169 -7
  756. package/dist/src/vtab/memory/layer/transaction.d.ts.map +1 -1
  757. package/dist/src/vtab/memory/layer/transaction.js +334 -9
  758. package/dist/src/vtab/memory/layer/transaction.js.map +1 -1
  759. package/dist/src/vtab/memory/module.d.ts +11 -4
  760. package/dist/src/vtab/memory/module.d.ts.map +1 -1
  761. package/dist/src/vtab/memory/module.js +35 -16
  762. package/dist/src/vtab/memory/module.js.map +1 -1
  763. package/dist/src/vtab/memory/table.d.ts +30 -4
  764. package/dist/src/vtab/memory/table.d.ts.map +1 -1
  765. package/dist/src/vtab/memory/table.js +63 -15
  766. package/dist/src/vtab/memory/table.js.map +1 -1
  767. package/dist/src/vtab/memory/utils/predicate.d.ts +9 -1
  768. package/dist/src/vtab/memory/utils/predicate.d.ts.map +1 -1
  769. package/dist/src/vtab/memory/utils/predicate.js +35 -14
  770. package/dist/src/vtab/memory/utils/predicate.js.map +1 -1
  771. package/dist/src/vtab/memory/utils/primary-key-encode.d.ts.map +1 -1
  772. package/dist/src/vtab/memory/utils/primary-key-encode.js +12 -6
  773. package/dist/src/vtab/memory/utils/primary-key-encode.js.map +1 -1
  774. package/dist/src/vtab/memory/utils/primary-key.d.ts +6 -1
  775. package/dist/src/vtab/memory/utils/primary-key.d.ts.map +1 -1
  776. package/dist/src/vtab/memory/utils/primary-key.js +12 -8
  777. package/dist/src/vtab/memory/utils/primary-key.js.map +1 -1
  778. package/dist/src/vtab/module.d.ts +38 -14
  779. package/dist/src/vtab/module.d.ts.map +1 -1
  780. package/dist/src/vtab/table.d.ts +41 -2
  781. package/dist/src/vtab/table.d.ts.map +1 -1
  782. package/dist/src/vtab/table.js +19 -0
  783. package/dist/src/vtab/table.js.map +1 -1
  784. package/package.json +5 -4
  785. package/dist/src/planner/rules/cache/rule-materialization-advisory.d.ts +0 -18
  786. package/dist/src/planner/rules/cache/rule-materialization-advisory.d.ts.map +0 -1
  787. package/dist/src/planner/rules/cache/rule-materialization-advisory.js +0 -65
  788. package/dist/src/planner/rules/cache/rule-materialization-advisory.js.map +0 -1
@@ -0,0 +1,929 @@
1
+ /**
2
+ * Materialized-view maintenance — **delta apply**. The per-row / per-flush appliers that
3
+ * take a compiled {@link MaintenancePlan} plus a source {@link BackingRowChange}, compute the
4
+ * bounded backing delta (or the full-rebuild diff), and write it through the backing table's
5
+ * coordinated transaction connection — plus the residual runners, backing-host / connection
6
+ * resolvers, derived-row and parent-side referential enforcement, and the small key-compare
7
+ * helpers they share. Extracted from database-materialized-views.ts as free functions over
8
+ * {@link MaterializedViewManagerContext}; the manager's orchestration methods
9
+ * (`maintainRowTime`, `flushDeferredMaintenance`, `lookupCoveringConflicts`) call in.
10
+ */
11
+ import { QuereusError } from '../common/errors.js';
12
+ import { StatusCode } from '../common/types.js';
13
+ import { createStrictRowContextMap, wrapTableContextsStrict } from '../runtime/strict-fork.js';
14
+ import { isAsyncIterable } from '../runtime/utils.js';
15
+ import { resolveBackingHost, nullInNotNullSeededPkError } from '../runtime/emit/materialized-view-helpers.js';
16
+ import { assertTransitiveRestrictsForParentMutation, executeForeignKeyActionsAndLens } from '../runtime/foreign-key-actions.js';
17
+ import { validateDerivedRowImage } from './derived-row-validator.js';
18
+ import { buildPrimaryKeyFromValues } from '../vtab/memory/utils/primary-key.js';
19
+ import { compareSqlValuesFast, rowsValueIdentical } from '../util/comparison.js';
20
+ import { canonKeyValues } from './database-materialized-views-analysis.js';
21
+ import { cloneInitialValue } from '../func/registration.js';
22
+ /**
23
+ * Resolve a plan's backing table to its {@link BackingHost} + coordinated
24
+ * {@link VirtualTableConnection} — the two handles every apply path writes through.
25
+ * Shared by the per-row appliers, the batched residual flush, and the full-rebuild
26
+ * `'replace-all'` diff; throws INTERNAL when the backing table has vanished (an MV in a
27
+ * broken state).
28
+ */
29
+ export async function resolveBackingApplyTarget(ctx,
30
+ // Structural (not the MaintenancePlan union) so the shared ForwardResidualPlan
31
+ // subset the join arm reuses resolves through it too.
32
+ plan, cache) {
33
+ const backing = ctx.schemaManager.getTable(plan.backingSchema, plan.backingTableName);
34
+ if (!backing) {
35
+ throw new QuereusError(`Internal error: backing table '${plan.backingTableName}' for materialized view '${plan.mv.name}' not found`, StatusCode.INTERNAL);
36
+ }
37
+ const host = backingHost(ctx, backing);
38
+ const connection = await getBackingConnection(ctx, host, `${plan.backingSchema}.${plan.backingTableName}`, cache);
39
+ return { host, connection };
40
+ }
41
+ /**
42
+ * Compute an `'inverse-projection'` plan's per-row backing delta, apply it, and
43
+ * return the **effective** {@link BackingRowChange}(s) the backing layer realized.
44
+ * An out-of-scope row (or a delete of an absent backing key) yields no change. This
45
+ * body is the shipped covering-index maintenance, lifted verbatim from the former
46
+ * `applyRowTimeChange`, plus the equal-image short-circuit: an UPDATE whose old and
47
+ * new projected images are value-identical (both in scope) projects to NO backing
48
+ * delta — the dominant no-op echo (a source update touching only unprojected columns,
49
+ * or rewriting a projected column to its existing value) is suppressed before any
50
+ * backing-connection work. Accurate by the maintenance invariant (the backing row IS
51
+ * the old image's projection), so nothing would have changed; the host's
52
+ * value-identical upsert skip (vtab/backing-host.ts) remains the effective-state
53
+ * backstop for the paths that do emit ops.
54
+ */
55
+ export async function applyInverseProjection(ctx, plan, change, cache) {
56
+ const inScope = (row) => plan.predicate === undefined || plan.predicate.evaluate(row) === true;
57
+ const project = (row) => plan.projectors.map(p => p.kind === 'passthrough' ? row[p.sourceCol] : p.eval(row));
58
+ const keyOf = (backingRow) => buildPrimaryKeyFromValues(plan.backingPkDefinition.map(d => backingRow[d.index]), plan.backingPkDefinition);
59
+ const ops = [];
60
+ if (change.op === 'insert') {
61
+ if (inScope(change.newRow))
62
+ ops.push({ kind: 'upsert', row: project(change.newRow) });
63
+ }
64
+ else if (change.op === 'delete') {
65
+ if (inScope(change.oldRow))
66
+ ops.push({ kind: 'delete-key', key: keyOf(project(change.oldRow)) });
67
+ }
68
+ else {
69
+ // UPDATE: a both-in-scope, same-backing-key change is one upsert (the host
70
+ // reports a single `update`); otherwise delete the old image if it was in
71
+ // scope and upsert the new image if it is — predicate-scope transitions and
72
+ // key-changing updates are genuinely two-sided. The scope check reads the
73
+ // SOURCE row (the predicate may reference unprojected columns), so both
74
+ // images must be in scope for the equal-image short-circuit.
75
+ const oldIn = inScope(change.oldRow);
76
+ const newIn = inScope(change.newRow);
77
+ if (oldIn && newIn) {
78
+ const oldImage = project(change.oldRow);
79
+ const newImage = project(change.newRow);
80
+ // Byte-faithful identity (rowsValueIdentical): subsumes key equality, and a
81
+ // collation-equal / byte-different image is NOT suppressed (it must re-key
82
+ // the stored bytes) — the same discipline as the host-level upsert skip.
83
+ if (rowsValueIdentical(oldImage, newImage))
84
+ return [];
85
+ if (backingPkEqual(plan.backingPkDefinition, oldImage, newImage)) {
86
+ // Same backing key (collation-aware — a collation-equal / byte-different
87
+ // key is the SAME btree identity, and the upsert re-keys the stored
88
+ // bytes): one upsert replaces the row wholesale, so the host reports
89
+ // a single `update` — matching the residual arms' post-suppression
90
+ // shape (one cascade dispatch, one change-log entry, no secondary-index
91
+ // churn from a delete+insert at an unchanged key).
92
+ ops.push({ kind: 'upsert', row: newImage });
93
+ }
94
+ else {
95
+ ops.push({ kind: 'delete-key', key: keyOf(oldImage) });
96
+ ops.push({ kind: 'upsert', row: newImage });
97
+ }
98
+ }
99
+ else {
100
+ if (oldIn)
101
+ ops.push({ kind: 'delete-key', key: keyOf(project(change.oldRow)) });
102
+ if (newIn)
103
+ ops.push({ kind: 'upsert', row: project(change.newRow) });
104
+ }
105
+ }
106
+ if (ops.length === 0)
107
+ return [];
108
+ const { host, connection } = await resolveBackingApplyTarget(ctx, plan, cache);
109
+ return host.applyMaintenance(connection, ops);
110
+ }
111
+ /**
112
+ * Validate the row images a maintenance apply WROTE (insert/update
113
+ * {@link BackingRowChange}s — a delete writes no image) against the plan's
114
+ * compiled {@link DerivedRowConstraintValidator}. Inline checks abort the
115
+ * writing statement with the maintained-table-attributed CONSTRAINT error;
116
+ * auto-deferred checks (subquery CHECK, every child-side FK) queue to the
117
+ * deferred-constraint queue and validate at commit. Deferred entries are
118
+ * pinned to the backing connection the maintenance write used (resolved from
119
+ * the per-statement cache, or re-resolved deterministically — the same
120
+ * connection either way) so commit-time evaluation reads the same pending
121
+ * state, mirroring the DML pipeline's active-connection capture.
122
+ */
123
+ export async function validateDerivedChanges(ctx, plan, validator, changes, cache) {
124
+ let connectionId;
125
+ if (validator.checks.some(c => c.needsDeferred)) {
126
+ const backing = ctx.schemaManager.getTable(plan.backingSchema, plan.backingTableName);
127
+ if (backing) {
128
+ const host = backingHost(ctx, backing);
129
+ const conn = await getBackingConnection(ctx, host, `${plan.backingSchema}.${plan.backingTableName}`, cache);
130
+ connectionId = conn.connectionId;
131
+ }
132
+ }
133
+ for (const change of changes) {
134
+ if (change.op === 'delete')
135
+ continue;
136
+ await validateDerivedRowImage(ctx, validator, change.newRow, connectionId);
137
+ }
138
+ }
139
+ /**
140
+ * Row-time guard: reject a maintenance write that would store a NULL into a backing column
141
+ * the schema declares NOT NULL *and* that is a physical-PK member whose re-derived body
142
+ * output turned nullable — the row-time analogue of the refresh-path
143
+ * `assertNoNullInNotNullSeededPk` (runtime/emit/materialized-view-helpers.ts). Row-time
144
+ * maintenance is the PRIMARY silent-corruption vector: it fires at the source
145
+ * insert/update, before any refresh, so without this guard a NULL lands in a
146
+ * declared-NOT-NULL PK column with no error.
147
+ *
148
+ * The offending skew (a NOT-NULL ordering-seeded PK column over a loosened source) is
149
+ * precomputed once at plan build into {@link MaintenancePlanCommon.nullGuardColumns}
150
+ * (`undefined` for nearly every MV — the zero-overhead gate), so the common path pays a
151
+ * single boolean check per maintained write and only the rare skewed MV scans its guarded
152
+ * columns per change. A `delete` writes no image and is skipped. The throw unwinds the source
153
+ * statement with nothing committed — the backing write rides the pending layer, discarded on
154
+ * a throw before commit, exactly like {@link validateDerivedChanges}. Called BEFORE the
155
+ * MV-over-MV cascade so a NULL row never reaches a consumer. See
156
+ * fix/bug-mv-rowtime-null-into-notnull-seeded-pk.
157
+ */
158
+ export function assertNoNullInNotNullSeededPkRowTime(plan, changes) {
159
+ const guard = plan.nullGuardColumns;
160
+ if (!guard)
161
+ return;
162
+ for (const change of changes) {
163
+ if (change.op === 'delete')
164
+ continue; // a delete writes no image
165
+ for (const g of guard) {
166
+ const v = change.newRow[g.index];
167
+ if (v === null || v === undefined) {
168
+ throw nullInNotNullSeededPkError(plan.mv.schemaName, plan.mv.name, g.name);
169
+ }
170
+ }
171
+ }
172
+ }
173
+ /**
174
+ * Fire **parent-side** referential enforcement over the backing rows a maintenance
175
+ * apply REMOVED or re-keyed (delete / key-update {@link BackingRowChange}s — an insert
176
+ * has no parent-side action). When the maintained table `M` is the PARENT (FK target)
177
+ * of an FK declared on an ordinary table `C` (`create table C (… references M(col) …)`),
178
+ * a maintenance-driven delete/key-update of the referenced `M` row would silently orphan
179
+ * `C`'s rows, bypassing the declared RESTRICT / referential action. This is the
180
+ * **dual** of {@link validateDerivedChanges} (constraints declared *on* `M`); the FK here
181
+ * lives on `C` and references `M`, so it is invisible to `M`'s own plan/validator.
182
+ *
183
+ * It reuses the SAME shared referential-action engine the DML executor and the
184
+ * external-change ingestion seam use — no third copy — applying its two functions over
185
+ * each backing change exactly as `database-external-changes.ts` does:
186
+ * - {@link assertTransitiveRestrictsForParentMutation} — pre-walk the transitive cascade
187
+ * closure and throw a CONSTRAINT error naming `M` on any surviving RESTRICT child;
188
+ * - {@link executeForeignKeyActionsAndLens} — run declared CASCADE / SET NULL / SET DEFAULT,
189
+ * re-entering the DML executor (the already-holding-the-mutex variant) for each cascaded
190
+ * child write, so `C`'s own constraints, watches, nested cascades, and (if `C` is itself
191
+ * an MV source) its own maintenance all fire.
192
+ *
193
+ * Ordering: called AFTER the backing delta has landed in the pending layer (the RESTRICT
194
+ * walk runs POST-application — the child rows it keys off still exist because the cascade
195
+ * has not run yet) and AFTER `M`'s own image is validated, matching the DML executor's
196
+ * per-change order (capture → MV maintenance → FK actions) and the external-changes seam.
197
+ * `lensRouted = false`: a maintenance backing write is a physical basis write (maintained
198
+ * tables are not lens basis spines). A surviving RESTRICT throws up through
199
+ * {@link maintainRowTime} → the DML executor → the statement, rolling back the source write
200
+ * attributed to `M`.
201
+ *
202
+ * Gate: a cheap `foreign_keys`-pragma early-return keeps the pragma-off path free (the
203
+ * engine also early-returns, but skipping the `getTable` + loop avoids all per-change work).
204
+ * NOT gated on `plan.derivedRowValidator` — that gate is child-side (constraints *on* `M`);
205
+ * an inbound FK lives on `C` and leaves `M`'s plan untouched. Beyond the gate it fires
206
+ * unconditionally per delete/update change, but the engine no longer pays an `O(catalog)`
207
+ * scan: both calls route through `SchemaManager.getReferencingForeignKeys`, the precomputed
208
+ * reverse-FK index, so an `M` that nothing references resolves to the shared empty bucket and
209
+ * each call early-returns in O(1) — a maintained table with no inbound FK (the common case)
210
+ * pays only the pragma check plus one map lookup per delete/key-update change.
211
+ */
212
+ export async function enforceParentSideReferentialActions(ctx, plan, changes) {
213
+ const db = ctx;
214
+ if (!db.options.getBooleanOption('foreign_keys'))
215
+ return; // cheap gate; engine early-returns too
216
+ // The backing `TableSchema` — same object validateDerivedChanges resolves; its `.name`
217
+ // equals `M`'s, so an FK on `C` (`references M`) matches the engine's referencing scan.
218
+ const parent = ctx.schemaManager.getTable(plan.backingSchema, plan.backingTableName);
219
+ if (!parent)
220
+ return; // backing gone ⇒ MV already broken
221
+ for (const change of changes) {
222
+ if (change.op === 'insert')
223
+ continue; // inserts have no parent-side actions
224
+ await assertTransitiveRestrictsForParentMutation(db, parent, change.op, change.oldRow, change.newRow);
225
+ await executeForeignKeyActionsAndLens(db, parent, change.op, change.oldRow, change.newRow);
226
+ }
227
+ }
228
+ /**
229
+ * Resolve the {@link BackingHost} capability surface for a backing table —
230
+ * see `vtab/backing-host.ts` for the contract. The host is resolved fresh per
231
+ * use (a map lookup on the owning module), so a drop+recreate of the backing
232
+ * always yields the new incarnation's host.
233
+ */
234
+ export function backingHost(ctx, backing) {
235
+ // The ctx IS the Database (same construction as buildMaintenancePlan's cast).
236
+ return resolveBackingHost(ctx, backing);
237
+ }
238
+ /**
239
+ * Obtain (lazily create + register) the backing table's
240
+ * {@link VirtualTableConnection} for the current transaction. Reuses the same
241
+ * connection a `select` from the MV resolves to (so reads-own-writes holds) —
242
+ * matched among the Database's registered connections by
243
+ * {@link BackingHost.ownsConnection}, which is pinned to the live backing
244
+ * incarnation; a freshly created connection is registered with the Database so
245
+ * the coordinated commit/rollback covers its pending state in lockstep with the
246
+ * source write.
247
+ *
248
+ * When an optional per-statement {@link BackingConnectionCache} is supplied, the
249
+ * scan over the Database's active connections (the dominant per-row cost on a bulk
250
+ * write) is paid once per (statement, backing): a hit returns the cached connection
251
+ * directly, and a miss caches whichever connection the scan resolves — or the one it
252
+ * lazily creates + registers. Caching the resolved/created connection is sound
253
+ * because the scan is deterministic within a statement (nothing interleaves between
254
+ * a statement's rows to change which connection a `select` from the MV picks), so the
255
+ * cache holds exactly what an uncached re-resolution would return.
256
+ */
257
+ export async function getBackingConnection(ctx, host, qualifiedName, cache) {
258
+ const cacheKey = qualifiedName.toLowerCase();
259
+ const cached = cache?.get(cacheKey);
260
+ if (cached)
261
+ return cached;
262
+ for (const c of ctx.getConnectionsForTable(qualifiedName)) {
263
+ if (host.ownsConnection(c)) {
264
+ cache?.set(cacheKey, c);
265
+ return c;
266
+ }
267
+ }
268
+ const conn = host.connect();
269
+ await ctx.registerConnection(conn);
270
+ cache?.set(cacheKey, conn);
271
+ return conn;
272
+ }
273
+ /**
274
+ * Execute a cached key-filtered residual for one affected key tuple, returning its
275
+ * result rows (0 or 1 for the aggregate shape; 0..N for the lateral-TVF fan-out shape).
276
+ * Bound through a fresh {@link RuntimeContext} on the live `db` so the residual's source
277
+ * scan reuses `T`'s transaction connection and reads this statement's pending writes
278
+ * (reads-own-writes) — the synchronous analogue of
279
+ * `database-assertions.ts:executeResidualPerTuple`. Shared by the residual-recompute
280
+ * (`'gk'`) and prefix-delete (`'pk'`) arms.
281
+ */
282
+ export async function runResidual(ctx, residualScheduler, bindParamPrefix, keyTuple) {
283
+ const params = {};
284
+ for (let i = 0; i < keyTuple.length; i++) {
285
+ params[`${bindParamPrefix}${i}`] = keyTuple[i];
286
+ }
287
+ return runScheduler(ctx, residualScheduler, params);
288
+ }
289
+ /**
290
+ * Run a cached maintenance scheduler to completion against **live mid-transaction source
291
+ * state** and collect its result rows. Bound through a fresh strict {@link RuntimeContext}
292
+ * on the live `db` so the scan reuses the source's transaction connection and reads this
293
+ * statement's pending writes (reads-own-writes). The no-`stmt`, fresh-context shape is the
294
+ * synchronous analogue of `database-assertions.ts:executeResidualPerTuple`. Shared by the
295
+ * key-filtered residual arms ({@link runResidual}, parameterized) and the whole-body
296
+ * full-rebuild arm ({@link applyFullRebuild}, no params).
297
+ */
298
+ export async function runScheduler(ctx, scheduler, params) {
299
+ const rctx = {
300
+ db: ctx,
301
+ stmt: undefined,
302
+ params,
303
+ context: createStrictRowContextMap(),
304
+ tableContexts: wrapTableContextsStrict(new Map()),
305
+ enableMetrics: false,
306
+ };
307
+ const result = await scheduler.run(rctx);
308
+ const rows = [];
309
+ if (isAsyncIterable(result)) {
310
+ for await (const r of result)
311
+ rows.push(r);
312
+ }
313
+ return rows;
314
+ }
315
+ /**
316
+ * Compute a **forward** key-filtered residual plan's per-row backing delta and apply it:
317
+ * derive the affected binding key(s) from the changed row (OLD ∪ NEW, deduped), re-run
318
+ * the key-filtered residual against live source state for each, and apply the **keyed
319
+ * diff**: a non-empty recomputed slice is upserted (the backing key IS the affected key,
320
+ * so the upsert replaces the old row wholesale — no delete-first — and the host's
321
+ * value-identical upsert skip turns a no-op recompute into ZERO effective changes
322
+ * instead of delete+insert churn); an emptied slice (residual returns nothing) emits the
323
+ * point delete, removing the stale backing row (nothing reported if it was already
324
+ * absent). Returns the effective {@link BackingRowChange}(s) the backing layer realized,
325
+ * for the MV-over-MV cascade — a real same-key change now reports one `update`.
326
+ *
327
+ * Shared by the single-source aggregate (`'residual-recompute'`, group key, ≤1 row per
328
+ * key) and the 1:1-join (`'join-residual'`, the driving table `T`'s PK, exactly the one
329
+ * joined row per key) arms — both bind on the forward driving source via
330
+ * {@link ForwardResidualPlan}; the only difference is the binding (group vs PK).
331
+ *
332
+ * This is the **cold** (no statement batch in scope) inline path. A statement-batched
333
+ * caller instead accumulates the same deduped keys via
334
+ * {@link collectForwardResidualKeys} and recomputes each distinct key once at the
335
+ * end-of-statement flush ({@link computeForwardResidualOps}) — sound for the same
336
+ * last-write-wins reason: every recompute reads live (reads-own-writes) state, so
337
+ * running it once at flush produces exactly what the last per-row run would have.
338
+ */
339
+ export async function applyForwardResidual(ctx, plan, change, cache) {
340
+ const affected = new Map();
341
+ collectForwardResidualKeys(plan, change, affected);
342
+ const ops = await computeForwardResidualOps(ctx, plan, affected.values());
343
+ if (ops.length === 0)
344
+ return [];
345
+ const { host, connection } = await resolveBackingApplyTarget(ctx, plan, cache);
346
+ return host.applyMaintenance(connection, ops);
347
+ }
348
+ /**
349
+ * Derive one changed source row's affected forward binding key(s) (OLD ∪ NEW) and add
350
+ * them to `into`, deduped on the canonical backing-key values: a non-key-changing update
351
+ * recomputes the group once; a key-changing update recomputes both the old and the new
352
+ * group. `into` may span a whole statement (the per-statement {@link ResidualKeyBatch})
353
+ * or a single change (the cold inline path) — the dedup is identical either way.
354
+ */
355
+ export function collectForwardResidualKeys(plan, change, into) {
356
+ const addFrom = (row) => {
357
+ const keyVals = plan.backingPkSourceCols.map(sc => row[sc]);
358
+ const dedupKey = canonKeyValues(keyVals);
359
+ if (into.has(dedupKey))
360
+ return;
361
+ into.set(dedupKey, {
362
+ keyTuple: plan.bindColumns.map(c => row[c]),
363
+ keyVals,
364
+ deleteKey: buildPrimaryKeyFromValues(keyVals, plan.backingPkDefinition),
365
+ });
366
+ };
367
+ if (change.op === 'insert')
368
+ addFrom(change.newRow);
369
+ else if (change.op === 'delete')
370
+ addFrom(change.oldRow);
371
+ else {
372
+ addFrom(change.oldRow);
373
+ addFrom(change.newRow);
374
+ }
375
+ }
376
+ /**
377
+ * Run the forward key-filtered residual once per affected key and build the keyed-diff
378
+ * ops: upsert the recomputed slice, or point-delete an emptied key. Pure op computation —
379
+ * the caller owns connection resolution and the single {@link BackingHost.applyMaintenance}
380
+ * call, so a statement flush can batch many keys' ops into one host call.
381
+ */
382
+ export async function computeForwardResidualOps(ctx, plan, keys) {
383
+ const ops = [];
384
+ for (const { keyTuple, keyVals, deleteKey } of keys) {
385
+ const recomputed = await runResidual(ctx, plan.residualScheduler, plan.bindParamPrefix, keyTuple);
386
+ // Keep only the recomputed rows whose backing key equals the affected key.
387
+ // The residual for key K must only contribute K's slice; any other row is
388
+ // spurious and is dropped. This is the soundness net for an emptied group: when
389
+ // no source row matches the key, a *correct* grouped residual returns zero rows,
390
+ // but a constant-pinned multi-column grouped aggregate is mis-collapsed by the
391
+ // optimizer into a *scalar* aggregate that emits one all-NULL `count=0` row over
392
+ // the empty input (a pre-existing optimizer bug, filed separately as
393
+ // `fix/optimizer-constant-group-aggregate-empty-input-spurious-row`). That row's
394
+ // key ≠ K, so it is filtered here and the delete-without-upsert correctly removes
395
+ // the emptied group's backing row.
396
+ const slice = recomputed.filter(row => residualRowMatchesKey(plan, row, keyVals));
397
+ if (slice.length === 0) {
398
+ // Emptied slice: delete-without-upsert removes the stale backing row (the
399
+ // host reports nothing if the key was already absent).
400
+ ops.push({ kind: 'delete-key', key: deleteKey });
401
+ }
402
+ else {
403
+ // The slice shares the affected backing key, so each upsert REPLACES the old
404
+ // backing row — no delete-first — and the host's value-identical skip
405
+ // (vtab/backing-host.ts) suppresses a recompute that changed nothing.
406
+ for (const row of slice)
407
+ ops.push({ kind: 'upsert', row });
408
+ }
409
+ }
410
+ return ops;
411
+ }
412
+ /**
413
+ * True iff `row`'s backing primary-key columns equal `keyVals` (the affected binding
414
+ * key, in `backingPkDefinition` order), under each column's collation. Used to keep
415
+ * only the residual row(s) belonging to the recomputed key — see
416
+ * {@link applyForwardResidual}.
417
+ */
418
+ export function residualRowMatchesKey(plan, row, keyVals) {
419
+ for (let i = 0; i < plan.backingPkDefinition.length; i++) {
420
+ const d = plan.backingPkDefinition[i];
421
+ if (compareSqlValuesFast(row[d.index], keyVals[i], d.collationFn) !== 0)
422
+ return false;
423
+ }
424
+ return true;
425
+ }
426
+ /**
427
+ * Dispatch a `'join-residual'` plan on **which source changed**. A write to the driving
428
+ * table `T` (`changedBase === plan.sourceBase`) is the forward case — recompute the one
429
+ * joined row keyed on `T`'s PK, identical to a size-1 `'row'`-binding residual — so it
430
+ * delegates straight to {@link applyForwardResidual} (delete old backing slice → run the
431
+ * `T`-keyed residual → upsert). A write to the lookup table `P` is the reverse case,
432
+ * handled by {@link applyLookupResidual}.
433
+ */
434
+ export async function applyJoinResidual(ctx, plan, change, changedBase, cache) {
435
+ if (changedBase === plan.sourceBase) {
436
+ return applyForwardResidual(ctx, plan, change, cache);
437
+ }
438
+ return applyLookupResidual(ctx, plan, change, cache);
439
+ }
440
+ /**
441
+ * Maintain a `'join-residual'` MV for a **lookup-side (`P`)** change: refresh the joined
442
+ * rows referencing each affected `P` key. Derive the affected `P` key(s) from the changed
443
+ * row (OLD ∪ NEW, deduped on `P`'s PK), and for each run the in-scope lookup-keyed residual
444
+ * (`… where P.pk = :pk0`, the body's WHERE retained) against live source state — returning
445
+ * every currently in-scope joined row, each carrying its `T.pk` backing key — and **upsert**
446
+ * each.
447
+ *
448
+ * **Upsert-only is sound for a no-WHERE / `T`-only-WHERE body.** For an inner/cross join with
449
+ * enforced RI and a predicate that cannot reference `P`, the *set* of backing rows referencing
450
+ * a given `P` row is `{ T : T.fk = P.pk }`, determined entirely by `T.fk` (a `T` column the
451
+ * `P` write cannot change), and the WHERE — over `T` only — cannot flip on a `P` write. So a
452
+ * `P` change can only re-derive the lookup-projected columns of those existing backing rows
453
+ * (an upsert at the unchanged `T.pk` key), never add or remove one: a `P` insert with no
454
+ * referencing `T` rows yields an empty residual (no-op); a `P` delete is only admissible (RI)
455
+ * when no `T` references it (empty residual); a `P` payload update upserts the affected rows
456
+ * with the new value.
457
+ *
458
+ * **A `P`-referencing WHERE needs the delete-capable pass.** When the body WHERE references
459
+ * `P`, a `P` write can flip a joined row's WHERE truth and so add or remove its backing row —
460
+ * which the in-scope upsert above (it returns *only* in-scope rows) could never delete. The
461
+ * builder then supplies `lookupMembershipResidualScheduler` (the body with the WHERE stripped,
462
+ * keyed on `P`). Per affected `P` key this runs both residuals against the same live state and
463
+ * applies the **keyed diff**: it **deletes** only the membership keys the in-scope recompute no
464
+ * longer produces (rows that left scope — the delete keys come from live `T` via the join, so
465
+ * they match existing backing keys and touch nothing belonging to another `P`; membership and
466
+ * in-scope rows read the same live state, so their key bytes match exactly), and **upserts**
467
+ * every in-scope row. A row leaving scope is deleted (removed); a row entering scope is
468
+ * upserted (added); an unchanged in-scope row's upsert is suppressed by the host's
469
+ * value-identical skip (vtab/backing-host.ts) — ZERO effective changes instead of the former
470
+ * delete+insert refresh churn; a changed in-scope row reports one `update`. The membership
471
+ * residual MUST ignore the WHERE — else a row leaving scope would never be deleted.
472
+ *
473
+ * A `T`-side membership change (insert/delete/FK-move) is the *forward* path's job and fires
474
+ * its own maintenance. Returns the effective {@link BackingRowChange}(s) for the MV-over-MV
475
+ * cascade. This is the cold inline path; a statement-batched caller accumulates via
476
+ * {@link collectLookupResidualKeys} and recomputes at flush ({@link computeLookupResidualOps})
477
+ * — sound for the same last-write-wins-against-live-state reason as
478
+ * {@link applyForwardResidual}.
479
+ */
480
+ export async function applyLookupResidual(ctx, plan, change, cache) {
481
+ const affected = new Map();
482
+ collectLookupResidualKeys(plan, change, affected);
483
+ const ops = await computeLookupResidualOps(ctx, plan, affected.values());
484
+ if (ops.length === 0)
485
+ return [];
486
+ const { host, connection } = await resolveBackingApplyTarget(ctx, plan, cache);
487
+ return host.applyMaintenance(connection, ops);
488
+ }
489
+ /**
490
+ * Derive one changed lookup-side (`P`) row's affected lookup key(s) (OLD ∪ NEW) and add
491
+ * them to `into`, deduped on `P`'s canonical PK values. The statement-batch counterpart
492
+ * of the derivation inside {@link applyLookupResidual}.
493
+ */
494
+ export function collectLookupResidualKeys(plan, change, into) {
495
+ const addFrom = (row) => {
496
+ const keyTuple = plan.lookupBindColumns.map(c => row[c]);
497
+ const dedupKey = canonKeyValues(keyTuple);
498
+ if (!into.has(dedupKey))
499
+ into.set(dedupKey, keyTuple);
500
+ };
501
+ if (change.op === 'insert')
502
+ addFrom(change.newRow);
503
+ else if (change.op === 'delete')
504
+ addFrom(change.oldRow);
505
+ else {
506
+ addFrom(change.oldRow);
507
+ addFrom(change.newRow);
508
+ }
509
+ }
510
+ /**
511
+ * Run the lookup-keyed residual variant once per affected `P` key and build the ops —
512
+ * the delete-capable membership diff when the plan carries
513
+ * `lookupMembershipResidualScheduler`, upsert-only otherwise (see
514
+ * {@link applyLookupResidual} for the soundness argument). Pure op computation; the
515
+ * caller owns connection resolution and the single applyMaintenance call.
516
+ */
517
+ export async function computeLookupResidualOps(ctx, plan, keys) {
518
+ const ops = [];
519
+ for (const keyTuple of keys) {
520
+ const recomputed = await runResidual(ctx, plan.lookupResidualScheduler, plan.lookupBindParamPrefix, keyTuple);
521
+ // Delete-capable (P-referencing WHERE): keyed diff of the membership residual
522
+ // (WHERE stripped) against the in-scope recompute — delete ONLY the membership
523
+ // keys the recompute no longer produces (rows that left the WHERE scope), not
524
+ // every member. Both residuals read the same live state, so a surviving row's
525
+ // key bytes match exactly (the byte-canonical set lookup is exact). Deletes
526
+ // precede upserts, preserving the prior arm's ordering discipline.
527
+ if (plan.lookupMembershipResidualScheduler) {
528
+ const produced = new Set(recomputed.map(row => canonKeyValues(plan.backingPkDefinition.map(d => row[d.index]))));
529
+ const members = await runResidual(ctx, plan.lookupMembershipResidualScheduler, plan.lookupBindParamPrefix, keyTuple);
530
+ for (const row of members) {
531
+ const keyVals = plan.backingPkDefinition.map(d => row[d.index]);
532
+ if (produced.has(canonKeyValues(keyVals)))
533
+ continue; // still in scope — upserted below
534
+ ops.push({ kind: 'delete-key', key: buildPrimaryKeyFromValues(keyVals, plan.backingPkDefinition) });
535
+ }
536
+ }
537
+ // Upsert every in-scope row; the host's value-identical skip suppresses the
538
+ // unchanged ones (an in-scope refresh that changed nothing reports nothing).
539
+ for (const row of recomputed)
540
+ ops.push({ kind: 'upsert', row });
541
+ }
542
+ return ops;
543
+ }
544
+ /**
545
+ * Compute a `'prefix-delete'` plan's per-row backing delta and apply it: derive the
546
+ * affected base key(s) from the changed row (OLD ∪ NEW, deduped on the base key), and
547
+ * for each — re-run the base-PK-keyed residual against live source state and apply the
548
+ * **keyed diff against the existing effective fan-out slice** (read via the host's
549
+ * `scanEffective` with the base prefix, pending over committed — the same contiguous
550
+ * range the former wholesale `'delete-by-prefix'` removed): delete ONLY the existing
551
+ * keys the recompute no longer produces, upsert every recomputed row (the host's
552
+ * value-identical skip suppresses the unchanged ones). A base-PK-changing UPDATE
553
+ * recomputes both the OLD base key (slice diffs to all-deletes; the residual returns
554
+ * nothing for the now-absent old PK) and the NEW base key (new fan-out upserted); a
555
+ * DELETE diffs the old slice to all-deletes; an INSERT diffs against an empty slice
556
+ * (all upserts). An emptied/shrunk fan-out keeps the delete-without-upsert exactly —
557
+ * a disappearance is never "skipped". Returns the effective
558
+ * {@link BackingRowChange}(s) the backing layer realized, for the MV-over-MV cascade.
559
+ *
560
+ * Prefix-scan soundness is unchanged from the wholesale arm: the diff's slice read
561
+ * uses the same binary `equalityPrefix` scan `'delete-by-prefix'` used, sound under
562
+ * the build-time collation gate (the backing base-PK prefix inherits the source PK
563
+ * collation, and source-PK uniqueness collapses each collation class to one binary
564
+ * value). The stored slice's prefix bytes always equal the OLD image's (the slice was
565
+ * projected from that very source row), and OLD ∪ NEW both iterate, so a case-only
566
+ * base-PK rewrite still converges: the OLD-prefix pass pairs the slice with the
567
+ * recomputed rows (key pairing is collation-aware — the btree's identity — so a
568
+ * collation-equal key is REPLACED by its upsert, never also deleted) and the byte
569
+ * change surfaces as `update`s that re-key the stored bytes.
570
+ *
571
+ * Structurally the same as {@link applyForwardResidual}, differing only in the
572
+ * **prefix-slice** diff (one base row owns N backing rows sharing the prefix) and the
573
+ * **N-row** residual. This is the cold inline path; a statement-batched caller
574
+ * accumulates the same deduped base keys via {@link collectPrefixDeleteKeys} and diffs
575
+ * each distinct key once at flush ({@link computePrefixDeleteOps}) — sound because the
576
+ * residual and the effective-slice read both see live (reads-own-writes) state, so the
577
+ * flush-time diff is exactly what the last per-row diff would have produced.
578
+ */
579
+ export async function applyPrefixDelete(ctx, plan, change, cache) {
580
+ const affected = new Map();
581
+ collectPrefixDeleteKeys(plan, change, affected);
582
+ // Resolved up front (unlike the point-op arms): the keyed diff reads the existing
583
+ // effective slice before any op exists. The former wholesale arm always emitted ops,
584
+ // so this resolves no more connections than it did.
585
+ const { host, connection } = await resolveBackingApplyTarget(ctx, plan, cache);
586
+ const ops = await computePrefixDeleteOps(ctx, plan, affected.values(), host, connection);
587
+ if (ops.length === 0)
588
+ return [];
589
+ return host.applyMaintenance(connection, ops);
590
+ }
591
+ /**
592
+ * Derive one changed base row's affected base key(s) (OLD ∪ NEW) and add them to
593
+ * `into`, deduped on the canonical base-PK values. `keyTuple` binds the residual
594
+ * (`pk{i}`); `prefix` is the slice's leading-PK equality key (the base-PK values in
595
+ * backing-PK order — identical here since the base PK leads the backing PK, but kept
596
+ * distinct for clarity). The statement-batch counterpart of the derivation inside
597
+ * {@link applyPrefixDelete}.
598
+ */
599
+ export function collectPrefixDeleteKeys(plan, change, into) {
600
+ const addFrom = (row) => {
601
+ const keyTuple = plan.bindColumns.map(c => row[c]);
602
+ const dedupKey = canonKeyValues(keyTuple);
603
+ if (into.has(dedupKey))
604
+ return;
605
+ into.set(dedupKey, { keyTuple, prefix: plan.backingPrefixSourceCols.map(sc => row[sc]) });
606
+ };
607
+ if (change.op === 'insert')
608
+ addFrom(change.newRow);
609
+ else if (change.op === 'delete')
610
+ addFrom(change.oldRow);
611
+ else {
612
+ addFrom(change.oldRow);
613
+ addFrom(change.newRow);
614
+ }
615
+ }
616
+ /**
617
+ * Per affected base key: run the fan-out residual, read the existing effective slice for
618
+ * the base prefix, and build the keyed-diff ops (delete disappeared keys, upsert the
619
+ * recomputed rows). Pure op computation over the supplied host/connection; the caller
620
+ * owns the single applyMaintenance call, so a statement flush batches many base keys'
621
+ * ops into one host call.
622
+ */
623
+ export async function computePrefixDeleteOps(ctx, plan, keys, host, connection) {
624
+ const ops = [];
625
+ for (const { keyTuple, prefix } of keys) {
626
+ const recomputed = await runResidual(ctx, plan.residualScheduler, plan.bindParamPrefix, keyTuple);
627
+ // The residual for base key K filters T to K, so every row it returns shares K's
628
+ // base-PK prefix; the prefix-match guard is a defensive soundness net (mirrors
629
+ // the aggregate arm's `residualRowMatchesKey`).
630
+ const slice = recomputed.filter(row => residualRowMatchesBasePrefix(plan, row, prefix));
631
+ // Existing effective fan-out rows for this base prefix (pending over committed).
632
+ const existing = [];
633
+ for await (const row of host.scanEffective(connection, { equalityPrefix: prefix })) {
634
+ existing.push(row);
635
+ }
636
+ // Keyed diff. Key pairing is collation-aware over the full backing PK (the btree's
637
+ // identity): a recomputed row whose key is collation-equal to an existing row
638
+ // REPLACES it via the upsert below, so it must not also be deleted. Deletes precede
639
+ // upserts (the wholesale arm's ordering discipline). The delete keys are built from
640
+ // the EXISTING rows' stored values, so the host's collation-aware point lookup
641
+ // always finds them.
642
+ for (const ex of existing) {
643
+ if (slice.some(row => backingPkEqual(plan.backingPkDefinition, row, ex)))
644
+ continue;
645
+ ops.push({
646
+ kind: 'delete-key',
647
+ key: buildPrimaryKeyFromValues(plan.backingPkDefinition.map(d => ex[d.index]), plan.backingPkDefinition),
648
+ });
649
+ }
650
+ for (const row of slice)
651
+ ops.push({ kind: 'upsert', row });
652
+ }
653
+ return ops;
654
+ }
655
+ /**
656
+ * True iff two backing rows agree on every backing-PK column under that column's
657
+ * collation — the btree's key identity. Pairs an existing slice row with the
658
+ * recomputed row that replaces it in {@link applyPrefixDelete}'s keyed diff.
659
+ */
660
+ export function backingPkEqual(pkDef, a, b) {
661
+ for (const d of pkDef) {
662
+ if (compareSqlValuesFast(a[d.index], b[d.index], d.collationFn) !== 0)
663
+ return false;
664
+ }
665
+ return true;
666
+ }
667
+ /**
668
+ * True iff `row`'s **leading** (base-prefix) backing-PK columns equal `prefixVals` (the
669
+ * affected base key, in backing-PK order), under each column's collation. Keeps only the
670
+ * residual fan-out row(s) belonging to the recomputed base key — see
671
+ * {@link applyPrefixDelete}.
672
+ */
673
+ export function residualRowMatchesBasePrefix(plan, row, prefixVals) {
674
+ for (let i = 0; i < plan.basePrefixLength; i++) {
675
+ const d = plan.backingPkDefinition[i];
676
+ if (compareSqlValuesFast(row[d.index], prefixVals[i], d.collationFn) !== 0)
677
+ return false;
678
+ }
679
+ return true;
680
+ }
681
+ /**
682
+ * Accumulate one source change's affected binding key(s) for a residual-arm plan into
683
+ * the per-statement {@link ResidualKeyBatch}, deduped across the whole statement —
684
+ * the deferred-accumulate counterpart of the cold per-row appliers above. Which
685
+ * variant map receives the keys follows the plan kind; a `'join-residual'` change
686
+ * routes on **which source changed** (forward for the driving `T`, lookup for `P`),
687
+ * exactly as {@link applyJoinResidual} dispatches. `planKey` is the MV key
688
+ * (lowercased `schema.name`) the manager indexes the plan under.
689
+ */
690
+ export function accumulateResidualKeys(plan, change, changedBase, batch, planKey) {
691
+ let entry = batch.get(planKey);
692
+ if (!entry) {
693
+ entry = { forward: new Map(), lookup: new Map(), prefix: new Map() };
694
+ batch.set(planKey, entry);
695
+ }
696
+ switch (plan.kind) {
697
+ case 'residual-recompute':
698
+ // Residual keys FIRST, always — they are the delta path's per-group fallback
699
+ // (retraction-unsafe groups, poisoned accumulations), so the delta map is
700
+ // strictly an optimization layered on top, never the only record.
701
+ collectForwardResidualKeys(plan, change, entry.forward);
702
+ if (plan.delta && !entry.deltaPoisoned) {
703
+ accumulateDeltaAggregates(plan, change, entry);
704
+ }
705
+ break;
706
+ case 'prefix-delete':
707
+ collectPrefixDeleteKeys(plan, change, entry.prefix);
708
+ break;
709
+ case 'join-residual': {
710
+ if (changedBase === plan.sourceBase)
711
+ collectForwardResidualKeys(plan, change, entry.forward);
712
+ else
713
+ collectLookupResidualKeys(plan, change, entry.lookup);
714
+ break;
715
+ }
716
+ }
717
+ }
718
+ /**
719
+ * Compute the flush-time ops for one residual-arm MV's accumulated statement keys: run
720
+ * the appropriate residual variant once per distinct key against live post-statement
721
+ * state and concatenate the keyed-diff ops. Distinct keys touch disjoint backing slices
722
+ * — except a `'join-residual'` statement that accumulated both forward and lookup keys,
723
+ * where an overlapping backing row is recomputed twice from the SAME live state, so the
724
+ * duplicate upsert is value-identical and the host suppresses it. The caller owns the
725
+ * single {@link BackingHost.applyMaintenance} call over the combined array — one host
726
+ * round-trip per (MV, flush round) instead of one per source row.
727
+ */
728
+ export async function computeResidualBatchOps(ctx, plan, entry, host, connection) {
729
+ if (plan.kind === 'prefix-delete') {
730
+ return computePrefixDeleteOps(ctx, plan, entry.prefix.values(), host, connection);
731
+ }
732
+ const ops = await computeForwardResidualOps(ctx, plan, entry.forward.values());
733
+ if (plan.kind === 'join-residual' && entry.lookup.size > 0) {
734
+ ops.push(...await computeLookupResidualOps(ctx, plan, entry.lookup.values()));
735
+ }
736
+ return ops;
737
+ }
738
+ /**
739
+ * Fold one source change's per-column aggregate contributions into the statement's
740
+ * delta accumulation ({@link ResidualKeyBatchEntry.delta}) — the delta-aggregate
741
+ * counterpart of {@link collectForwardResidualKeys}, called right after it (the
742
+ * residual keys remain the fallback record). Per contributing row image:
743
+ * `step(identity, row[arg])` (zero-arg → `step(identity)`) is the row's contribution;
744
+ * an insert `merge`s it in, a delete `merge`s its `negate`, an update retracts the OLD
745
+ * image into its group and inserts the NEW into its (possibly different) group. A row
746
+ * whose body-WHERE predicate is not unambiguously TRUE contributes nothing — but the
747
+ * raw column value (including NULL) IS fed to `step`, never pre-filtered: NULL-handling
748
+ * is the aggregate's own (law 2), and the row still counts toward the zero-arg
749
+ * multiplicity witness.
750
+ */
751
+ export function accumulateDeltaAggregates(plan, change, entry) {
752
+ const d = plan.delta;
753
+ if (!d)
754
+ return;
755
+ const delta = entry.delta ?? (entry.delta = new Map());
756
+ const contribute = (row, retract) => {
757
+ if (d.predicate && d.predicate.evaluate(row) !== true)
758
+ return; // out of body scope
759
+ const keyVals = plan.backingPkSourceCols.map(sc => row[sc]);
760
+ const dedupKey = canonKeyValues(keyVals);
761
+ let g = delta.get(dedupKey);
762
+ if (!g) {
763
+ g = {
764
+ keyVals,
765
+ deleteKey: buildPrimaryKeyFromValues(keyVals, plan.backingPkDefinition),
766
+ accs: d.aggColumns.map(c => cloneInitialValue(c.schema.initialValue)),
767
+ retracted: false,
768
+ };
769
+ delta.set(dedupKey, g);
770
+ }
771
+ if (retract)
772
+ g.retracted = true;
773
+ for (let i = 0; i < d.aggColumns.length; i++) {
774
+ const c = d.aggColumns[i];
775
+ // A tighten-only column (min/max — merge, no negate) cannot retract arithmetically.
776
+ // `g.retracted` was set above, so a retracted group with a tighten column re-derives
777
+ // wholesale from the residual at flush (descriptor.hasTighten) and this accumulator is
778
+ // discarded — so skip the retraction contribution entirely (there is no negate to
779
+ // apply). Its INSERT contributions still fold via merge on the non-retract path below.
780
+ if (retract && c.deltaClass === 'tighten')
781
+ continue;
782
+ let contrib = c.argSourceCol === undefined
783
+ ? c.schema.stepFunction(cloneInitialValue(c.schema.initialValue))
784
+ : c.schema.stepFunction(cloneInitialValue(c.schema.initialValue), row[c.argSourceCol]);
785
+ if (retract)
786
+ contrib = c.algebra.negate(contrib);
787
+ g.accs[i] = c.algebra.merge(g.accs[i], contrib);
788
+ }
789
+ };
790
+ if (change.op === 'insert')
791
+ contribute(change.newRow, false);
792
+ else if (change.op === 'delete')
793
+ contribute(change.oldRow, true);
794
+ else {
795
+ contribute(change.oldRow, true);
796
+ contribute(change.newRow, false);
797
+ }
798
+ }
799
+ /**
800
+ * Flush-time op computation for a delta-aggregate MV's accumulated statement deltas —
801
+ * the arithmetic read-modify-write that replaces the per-group residual re-execution.
802
+ * Per affected group:
803
+ * 1. read the group's current EFFECTIVE backing row by its full PK (the host's
804
+ * `scanEffective` equality-prefix point read — pending over committed, so a group
805
+ * written by an earlier statement of this transaction folds correctly);
806
+ * 2. per aggregate column: base = stored ? `decode(stored[col])` : a fresh identity
807
+ * accumulator; finalized = `finalize(merge(base, delta))`;
808
+ * 3. the multiplicity witness finalizing to 0 ⇔ the group emptied → `delete-key`
809
+ * (skipped when no row was stored); otherwise upsert the rebuilt row (group-key
810
+ * values + finalized aggregates) — the host's value-identical skip suppresses a
811
+ * net-identity delta (MV-016).
812
+ *
813
+ * **Retraction fallback.** A group that accumulated a retraction re-derives from its
814
+ * residual key (always accumulated alongside, same canonical map key) instead of the
815
+ * arithmetic, in two cases:
816
+ * - the descriptor has a **tighten** column (min/max — merge, no negate): a retraction
817
+ * cannot be undone by merge, so the whole group re-derives from live source state
818
+ * **whether or not a row is stored** (an intra-statement delete of the extreme poisons
819
+ * even a from-identity net-fold). The residual recomputes every column of the row
820
+ * (count/sum included), so a mixed group+tighten row is maintained by ONE path — no
821
+ * double-maintenance;
822
+ * - otherwise the descriptor is not retraction-safe (an abelian column whose decode is
823
+ * only an insert-observational witness — a nullable-argument sum) AND a stored row
824
+ * exists: the stored value cannot prove the true contribution count survives the
825
+ * retraction, so decoding it is unsound. A group with no stored row needs no fallback
826
+ * here — a pure abelian net-fold from identity is exact.
827
+ *
828
+ * Zero source reads, no residual execution on the arithmetic path — this is why the
829
+ * delta path also BYPASSES the per-statement degrade-to-rebuild crossover (it is
830
+ * already O(affected groups)).
831
+ */
832
+ export async function computeDeltaAggregateOps(ctx, plan, entry, host, connection) {
833
+ const d = plan.delta;
834
+ if (!d || !entry.delta)
835
+ return [];
836
+ const ops = [];
837
+ const residualFallbackKeys = [];
838
+ for (const [dedupKey, g] of entry.delta) {
839
+ // Effective point read: the full-PK equality prefix selects at most one row
840
+ // (BINARY collations on every PK column are a descriptor gate, so the binary
841
+ // prefix compare in the host's scan is exact).
842
+ let stored;
843
+ for await (const row of host.scanEffective(connection, { equalityPrefix: [...g.keyVals] })) {
844
+ stored = row;
845
+ break;
846
+ }
847
+ // Residual fallback for a group whose arithmetic cannot be trusted under retraction:
848
+ // - a **tighten** column (min/max) can never retract arithmetically — a retracted
849
+ // group re-derives from live state whether or not a row is stored (an intra-statement
850
+ // delete of the extreme cannot be undone by merge, even from a fresh identity);
851
+ // - otherwise a not-retraction-safe abelian column (a sum whose decode forgets the true
852
+ // contribution count) only needs the residual when a stored row must be decoded — its
853
+ // no-stored net-fold stays exact, so that case keeps the pure arithmetic path.
854
+ // NOTE: the tighten fallback is conservative — ANY retraction rescans the group, even a
855
+ // delete of a provably-non-extreme value. Correct, not minimal. If min/max MVs ever show
856
+ // this rescan as hot, a secondary-index "is this the current extreme?" probe could keep
857
+ // non-extreme deletes on the arithmetic path. Not built now (see docs/mv-maintenance.md
858
+ // § Tighten-only columns).
859
+ if (g.retracted && (d.hasTighten || (stored && !d.retractionSafe))) {
860
+ const fk = entry.forward.get(dedupKey);
861
+ if (!fk) {
862
+ // Impossible: accumulateResidualKeys collects the forward key for every
863
+ // change before the delta contribution, over the same canonical key.
864
+ throw new QuereusError(`Internal error: delta-aggregate group of materialized view '${plan.mv.name}' has no forward residual key`, StatusCode.INTERNAL);
865
+ }
866
+ residualFallbackKeys.push(fk);
867
+ continue;
868
+ }
869
+ const finals = new Array(d.aggColumns.length);
870
+ for (let i = 0; i < d.aggColumns.length; i++) {
871
+ const c = d.aggColumns[i];
872
+ const base = stored
873
+ ? c.algebra.decode(stored[c.backingCol])
874
+ : cloneInitialValue(c.schema.initialValue);
875
+ finals[i] = c.schema.finalizeFunction(c.algebra.merge(base, g.accs[i]));
876
+ }
877
+ const mult = finals[d.multiplicityIndex];
878
+ if (mult === 0 || mult === 0n) {
879
+ // Group emptied. The delete is emitted only when a row is stored (a group
880
+ // created and emptied within one statement writes nothing).
881
+ if (stored)
882
+ ops.push({ kind: 'delete-key', key: g.deleteKey });
883
+ continue;
884
+ }
885
+ const row = new Array(d.backingColumnCount).fill(null);
886
+ for (const gc of d.groupColumns)
887
+ row[gc.backingCol] = g.keyVals[gc.pkPos];
888
+ for (let i = 0; i < d.aggColumns.length; i++)
889
+ row[d.aggColumns[i].backingCol] = finals[i];
890
+ // Decomposition-maintained columns (the avg class): derived from the finalized
891
+ // partials, never accumulated. `combine` reproduces the aggregate's own finalize —
892
+ // incl. the empty-group / divide-by-zero case (avg → count 0/NULL ⇒ NULL). The group
893
+ // is non-empty here (multiplicity > 0), so a fully-emptied group is deleted above
894
+ // before combine could divide by zero; a non-empty all-NULL group finalizes count(x)
895
+ // = 0 and combine yields NULL, matching native avg.
896
+ // NOTE: byte-exactness vs a live re-fold holds while a group's integer sum stays
897
+ // ≤ 2^53. `avg`'s live finalize accumulates its own sum as a float, whereas this
898
+ // recombine reads the exact (bigint-capable) stored `sum` partial; the two round
899
+ // differently only once a group sum exceeds the double safe-integer range. If that
900
+ // regime ever becomes reachable, avg's finalize would need bigint accumulation (a
901
+ // change in aggregate.ts), not a change here.
902
+ for (const dc of d.decomposeColumns) {
903
+ row[dc.backingCol] = dc.combine(dc.partialIndices.map(pi => finals[pi]));
904
+ }
905
+ ops.push({ kind: 'upsert', row });
906
+ }
907
+ if (residualFallbackKeys.length > 0) {
908
+ ops.push(...await computeForwardResidualOps(ctx, plan, residualFallbackKeys));
909
+ }
910
+ return ops;
911
+ }
912
+ /**
913
+ * Invalidate every accumulated delta in the per-statement batch — called by the DML
914
+ * executor when an OR FAIL per-row savepoint ROLLS BACK: the savepoint undoes the
915
+ * failing row's source (and backing) writes, but the JS-side accumulation cannot be
916
+ * unwound, so the folded deltas may carry the reverted row's contribution. The residual
917
+ * keys are unaffected (a reverted key's recompute reads surviving live state and is
918
+ * value-identical → suppressed), so poisoning simply drops the fast path: the flush in
919
+ * the executor's catch routes those entries through the plain residual. One-way for the
920
+ * statement — `deltaPoisoned` also stops later (cascade-driven) delta re-accumulation
921
+ * into the same entry from mixing with an already-flushed-around state.
922
+ */
923
+ export function poisonResidualDeltaAccumulations(batch) {
924
+ for (const entry of batch.values()) {
925
+ entry.delta = undefined;
926
+ entry.deltaPoisoned = true;
927
+ }
928
+ }
929
+ //# sourceMappingURL=database-materialized-views-apply.js.map