@quereus/quereus 3.2.1 → 4.0.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 (935) hide show
  1. package/README.md +7 -0
  2. package/dist/src/common/datatype.d.ts +12 -0
  3. package/dist/src/common/datatype.d.ts.map +1 -1
  4. package/dist/src/common/datatype.js.map +1 -1
  5. package/dist/src/common/types.d.ts +24 -0
  6. package/dist/src/common/types.d.ts.map +1 -1
  7. package/dist/src/common/types.js.map +1 -1
  8. package/dist/src/core/database-assertions.d.ts +37 -9
  9. package/dist/src/core/database-assertions.d.ts.map +1 -1
  10. package/dist/src/core/database-assertions.js +62 -106
  11. package/dist/src/core/database-assertions.js.map +1 -1
  12. package/dist/src/core/database-events.d.ts +163 -0
  13. package/dist/src/core/database-events.d.ts.map +1 -1
  14. package/dist/src/core/database-events.js +235 -21
  15. package/dist/src/core/database-events.js.map +1 -1
  16. package/dist/src/core/database-external-changes.d.ts +28 -0
  17. package/dist/src/core/database-external-changes.d.ts.map +1 -0
  18. package/dist/src/core/database-external-changes.js +242 -0
  19. package/dist/src/core/database-external-changes.js.map +1 -0
  20. package/dist/src/core/database-internal.d.ts +50 -1
  21. package/dist/src/core/database-internal.d.ts.map +1 -1
  22. package/dist/src/core/database-materialized-views.d.ts +1253 -0
  23. package/dist/src/core/database-materialized-views.d.ts.map +1 -0
  24. package/dist/src/core/database-materialized-views.js +3064 -0
  25. package/dist/src/core/database-materialized-views.js.map +1 -0
  26. package/dist/src/core/database-options.d.ts +4 -0
  27. package/dist/src/core/database-options.d.ts.map +1 -1
  28. package/dist/src/core/database-options.js +10 -0
  29. package/dist/src/core/database-options.js.map +1 -1
  30. package/dist/src/core/database-transaction.d.ts +19 -3
  31. package/dist/src/core/database-transaction.d.ts.map +1 -1
  32. package/dist/src/core/database-transaction.js +30 -3
  33. package/dist/src/core/database-transaction.js.map +1 -1
  34. package/dist/src/core/database-watchers.d.ts +19 -0
  35. package/dist/src/core/database-watchers.d.ts.map +1 -1
  36. package/dist/src/core/database-watchers.js +63 -3
  37. package/dist/src/core/database-watchers.js.map +1 -1
  38. package/dist/src/core/database.d.ts +203 -11
  39. package/dist/src/core/database.d.ts.map +1 -1
  40. package/dist/src/core/database.js +493 -29
  41. package/dist/src/core/database.js.map +1 -1
  42. package/dist/src/core/derived-row-validator.d.ts +137 -0
  43. package/dist/src/core/derived-row-validator.d.ts.map +1 -0
  44. package/dist/src/core/derived-row-validator.js +314 -0
  45. package/dist/src/core/derived-row-validator.js.map +1 -0
  46. package/dist/src/core/statement.d.ts.map +1 -1
  47. package/dist/src/core/statement.js +30 -9
  48. package/dist/src/core/statement.js.map +1 -1
  49. package/dist/src/emit/ast-stringify.d.ts +135 -1
  50. package/dist/src/emit/ast-stringify.d.ts.map +1 -1
  51. package/dist/src/emit/ast-stringify.js +795 -120
  52. package/dist/src/emit/ast-stringify.js.map +1 -1
  53. package/dist/src/func/builtins/aggregate.d.ts.map +1 -1
  54. package/dist/src/func/builtins/aggregate.js +11 -10
  55. package/dist/src/func/builtins/aggregate.js.map +1 -1
  56. package/dist/src/func/builtins/builtin-window-functions.d.ts.map +1 -1
  57. package/dist/src/func/builtins/builtin-window-functions.js +32 -0
  58. package/dist/src/func/builtins/builtin-window-functions.js.map +1 -1
  59. package/dist/src/func/builtins/explain.d.ts +3 -0
  60. package/dist/src/func/builtins/explain.d.ts.map +1 -1
  61. package/dist/src/func/builtins/explain.js +229 -0
  62. package/dist/src/func/builtins/explain.js.map +1 -1
  63. package/dist/src/func/builtins/index.d.ts.map +1 -1
  64. package/dist/src/func/builtins/index.js +10 -2
  65. package/dist/src/func/builtins/index.js.map +1 -1
  66. package/dist/src/func/builtins/json.d.ts.map +1 -1
  67. package/dist/src/func/builtins/json.js +3 -2
  68. package/dist/src/func/builtins/json.js.map +1 -1
  69. package/dist/src/func/builtins/mutation.d.ts +2 -0
  70. package/dist/src/func/builtins/mutation.d.ts.map +1 -0
  71. package/dist/src/func/builtins/mutation.js +53 -0
  72. package/dist/src/func/builtins/mutation.js.map +1 -0
  73. package/dist/src/func/builtins/schema.d.ts +2 -0
  74. package/dist/src/func/builtins/schema.d.ts.map +1 -1
  75. package/dist/src/func/builtins/schema.js +713 -26
  76. package/dist/src/func/builtins/schema.js.map +1 -1
  77. package/dist/src/func/builtins/string.js +1 -1
  78. package/dist/src/func/builtins/string.js.map +1 -1
  79. package/dist/src/func/registration.d.ts +9 -0
  80. package/dist/src/func/registration.d.ts.map +1 -1
  81. package/dist/src/func/registration.js +4 -0
  82. package/dist/src/func/registration.js.map +1 -1
  83. package/dist/src/index.d.ts +25 -6
  84. package/dist/src/index.d.ts.map +1 -1
  85. package/dist/src/index.js +27 -3
  86. package/dist/src/index.js.map +1 -1
  87. package/dist/src/parser/ast.d.ts +353 -21
  88. package/dist/src/parser/ast.d.ts.map +1 -1
  89. package/dist/src/parser/index.d.ts +14 -1
  90. package/dist/src/parser/index.d.ts.map +1 -1
  91. package/dist/src/parser/index.js +19 -0
  92. package/dist/src/parser/index.js.map +1 -1
  93. package/dist/src/parser/lexer.d.ts +9 -0
  94. package/dist/src/parser/lexer.d.ts.map +1 -1
  95. package/dist/src/parser/lexer.js +9 -0
  96. package/dist/src/parser/lexer.js.map +1 -1
  97. package/dist/src/parser/parser.d.ts +277 -8
  98. package/dist/src/parser/parser.d.ts.map +1 -1
  99. package/dist/src/parser/parser.js +1393 -471
  100. package/dist/src/parser/parser.js.map +1 -1
  101. package/dist/src/parser/visitor.d.ts.map +1 -1
  102. package/dist/src/parser/visitor.js +12 -8
  103. package/dist/src/parser/visitor.js.map +1 -1
  104. package/dist/src/planner/analysis/assertion-classifier.d.ts.map +1 -1
  105. package/dist/src/planner/analysis/assertion-classifier.js +4 -0
  106. package/dist/src/planner/analysis/assertion-classifier.js.map +1 -1
  107. package/dist/src/planner/analysis/assertion-hoist-cache.d.ts.map +1 -1
  108. package/dist/src/planner/analysis/assertion-hoist-cache.js +8 -4
  109. package/dist/src/planner/analysis/assertion-hoist-cache.js.map +1 -1
  110. package/dist/src/planner/analysis/authored-inverse.d.ts +22 -0
  111. package/dist/src/planner/analysis/authored-inverse.d.ts.map +1 -0
  112. package/dist/src/planner/analysis/authored-inverse.js +267 -0
  113. package/dist/src/planner/analysis/authored-inverse.js.map +1 -0
  114. package/dist/src/planner/analysis/binding-extractor.d.ts.map +1 -1
  115. package/dist/src/planner/analysis/binding-extractor.js +9 -6
  116. package/dist/src/planner/analysis/binding-extractor.js.map +1 -1
  117. package/dist/src/planner/analysis/change-scope.d.ts +34 -4
  118. package/dist/src/planner/analysis/change-scope.d.ts.map +1 -1
  119. package/dist/src/planner/analysis/change-scope.js +115 -7
  120. package/dist/src/planner/analysis/change-scope.js.map +1 -1
  121. package/dist/src/planner/analysis/check-extraction.d.ts +36 -2
  122. package/dist/src/planner/analysis/check-extraction.d.ts.map +1 -1
  123. package/dist/src/planner/analysis/check-extraction.js +174 -46
  124. package/dist/src/planner/analysis/check-extraction.js.map +1 -1
  125. package/dist/src/planner/analysis/coarsened-key.d.ts +109 -0
  126. package/dist/src/planner/analysis/coarsened-key.d.ts.map +1 -0
  127. package/dist/src/planner/analysis/coarsened-key.js +228 -0
  128. package/dist/src/planner/analysis/coarsened-key.js.map +1 -0
  129. package/dist/src/planner/analysis/comparison-collation.d.ts +216 -0
  130. package/dist/src/planner/analysis/comparison-collation.d.ts.map +1 -0
  131. package/dist/src/planner/analysis/comparison-collation.js +341 -0
  132. package/dist/src/planner/analysis/comparison-collation.js.map +1 -0
  133. package/dist/src/planner/analysis/constraint-extractor.d.ts +13 -1
  134. package/dist/src/planner/analysis/constraint-extractor.d.ts.map +1 -1
  135. package/dist/src/planner/analysis/constraint-extractor.js +220 -21
  136. package/dist/src/planner/analysis/constraint-extractor.js.map +1 -1
  137. package/dist/src/planner/analysis/coverage-prover.d.ts +321 -0
  138. package/dist/src/planner/analysis/coverage-prover.d.ts.map +1 -0
  139. package/dist/src/planner/analysis/coverage-prover.js +1038 -0
  140. package/dist/src/planner/analysis/coverage-prover.js.map +1 -0
  141. package/dist/src/planner/analysis/key-filter.d.ts +22 -0
  142. package/dist/src/planner/analysis/key-filter.d.ts.map +1 -0
  143. package/dist/src/planner/analysis/key-filter.js +105 -0
  144. package/dist/src/planner/analysis/key-filter.js.map +1 -0
  145. package/dist/src/planner/analysis/partial-unique-extraction.d.ts +36 -1
  146. package/dist/src/planner/analysis/partial-unique-extraction.d.ts.map +1 -1
  147. package/dist/src/planner/analysis/partial-unique-extraction.js +148 -22
  148. package/dist/src/planner/analysis/partial-unique-extraction.js.map +1 -1
  149. package/dist/src/planner/analysis/predicate-normalizer.d.ts.map +1 -1
  150. package/dist/src/planner/analysis/predicate-normalizer.js +30 -1
  151. package/dist/src/planner/analysis/predicate-normalizer.js.map +1 -1
  152. package/dist/src/planner/analysis/predicate-shape.d.ts +36 -1
  153. package/dist/src/planner/analysis/predicate-shape.d.ts.map +1 -1
  154. package/dist/src/planner/analysis/predicate-shape.js +51 -13
  155. package/dist/src/planner/analysis/predicate-shape.js.map +1 -1
  156. package/dist/src/planner/analysis/query-rewrite-matcher.d.ts +314 -0
  157. package/dist/src/planner/analysis/query-rewrite-matcher.d.ts.map +1 -0
  158. package/dist/src/planner/analysis/query-rewrite-matcher.js +1081 -0
  159. package/dist/src/planner/analysis/query-rewrite-matcher.js.map +1 -0
  160. package/dist/src/planner/analysis/scalar-invertibility.d.ts +92 -0
  161. package/dist/src/planner/analysis/scalar-invertibility.d.ts.map +1 -0
  162. package/dist/src/planner/analysis/scalar-invertibility.js +129 -0
  163. package/dist/src/planner/analysis/scalar-invertibility.js.map +1 -0
  164. package/dist/src/planner/analysis/update-lineage.d.ts +196 -0
  165. package/dist/src/planner/analysis/update-lineage.d.ts.map +1 -0
  166. package/dist/src/planner/analysis/update-lineage.js +322 -0
  167. package/dist/src/planner/analysis/update-lineage.js.map +1 -0
  168. package/dist/src/planner/analysis/view-complement.d.ts +42 -0
  169. package/dist/src/planner/analysis/view-complement.d.ts.map +1 -0
  170. package/dist/src/planner/analysis/view-complement.js +54 -0
  171. package/dist/src/planner/analysis/view-complement.js.map +1 -0
  172. package/dist/src/planner/building/alter-table.d.ts +1 -1
  173. package/dist/src/planner/building/alter-table.d.ts.map +1 -1
  174. package/dist/src/planner/building/alter-table.js +211 -2
  175. package/dist/src/planner/building/alter-table.js.map +1 -1
  176. package/dist/src/planner/building/block.d.ts.map +1 -1
  177. package/dist/src/planner/building/block.js +18 -1
  178. package/dist/src/planner/building/block.js.map +1 -1
  179. package/dist/src/planner/building/constraint-builder.d.ts +33 -5
  180. package/dist/src/planner/building/constraint-builder.d.ts.map +1 -1
  181. package/dist/src/planner/building/constraint-builder.js +63 -28
  182. package/dist/src/planner/building/constraint-builder.js.map +1 -1
  183. package/dist/src/planner/building/create-view.d.ts +9 -0
  184. package/dist/src/planner/building/create-view.d.ts.map +1 -1
  185. package/dist/src/planner/building/create-view.js +41 -12
  186. package/dist/src/planner/building/create-view.js.map +1 -1
  187. package/dist/src/planner/building/ddl.d.ts.map +1 -1
  188. package/dist/src/planner/building/ddl.js +94 -0
  189. package/dist/src/planner/building/ddl.js.map +1 -1
  190. package/dist/src/planner/building/declare-schema.d.ts +1 -0
  191. package/dist/src/planner/building/declare-schema.d.ts.map +1 -1
  192. package/dist/src/planner/building/declare-schema.js +4 -1
  193. package/dist/src/planner/building/declare-schema.js.map +1 -1
  194. package/dist/src/planner/building/default-scope.d.ts +26 -0
  195. package/dist/src/planner/building/default-scope.d.ts.map +1 -0
  196. package/dist/src/planner/building/default-scope.js +41 -0
  197. package/dist/src/planner/building/default-scope.js.map +1 -0
  198. package/dist/src/planner/building/delete.d.ts +19 -1
  199. package/dist/src/planner/building/delete.d.ts.map +1 -1
  200. package/dist/src/planner/building/delete.js +116 -34
  201. package/dist/src/planner/building/delete.js.map +1 -1
  202. package/dist/src/planner/building/dml-target.d.ts +118 -0
  203. package/dist/src/planner/building/dml-target.d.ts.map +1 -0
  204. package/dist/src/planner/building/dml-target.js +282 -0
  205. package/dist/src/planner/building/dml-target.js.map +1 -0
  206. package/dist/src/planner/building/drop-index.d.ts.map +1 -1
  207. package/dist/src/planner/building/drop-index.js +4 -1
  208. package/dist/src/planner/building/drop-index.js.map +1 -1
  209. package/dist/src/planner/building/drop-view.d.ts.map +1 -1
  210. package/dist/src/planner/building/drop-view.js +4 -2
  211. package/dist/src/planner/building/drop-view.js.map +1 -1
  212. package/dist/src/planner/building/expression.d.ts.map +1 -1
  213. package/dist/src/planner/building/expression.js +60 -21
  214. package/dist/src/planner/building/expression.js.map +1 -1
  215. package/dist/src/planner/building/foreign-key-builder.d.ts +30 -0
  216. package/dist/src/planner/building/foreign-key-builder.d.ts.map +1 -1
  217. package/dist/src/planner/building/foreign-key-builder.js +160 -129
  218. package/dist/src/planner/building/foreign-key-builder.js.map +1 -1
  219. package/dist/src/planner/building/insert.d.ts +45 -2
  220. package/dist/src/planner/building/insert.d.ts.map +1 -1
  221. package/dist/src/planner/building/insert.js +257 -88
  222. package/dist/src/planner/building/insert.js.map +1 -1
  223. package/dist/src/planner/building/lens-auxiliary-access.d.ts +22 -0
  224. package/dist/src/planner/building/lens-auxiliary-access.d.ts.map +1 -0
  225. package/dist/src/planner/building/lens-auxiliary-access.js +132 -0
  226. package/dist/src/planner/building/lens-auxiliary-access.js.map +1 -0
  227. package/dist/src/planner/building/materialized-view.d.ts +16 -0
  228. package/dist/src/planner/building/materialized-view.d.ts.map +1 -0
  229. package/dist/src/planner/building/materialized-view.js +57 -0
  230. package/dist/src/planner/building/materialized-view.js.map +1 -0
  231. package/dist/src/planner/building/returning-star.d.ts +32 -0
  232. package/dist/src/planner/building/returning-star.d.ts.map +1 -0
  233. package/dist/src/planner/building/returning-star.js +45 -0
  234. package/dist/src/planner/building/returning-star.js.map +1 -0
  235. package/dist/src/planner/building/select-aggregates.d.ts.map +1 -1
  236. package/dist/src/planner/building/select-aggregates.js +51 -13
  237. package/dist/src/planner/building/select-aggregates.js.map +1 -1
  238. package/dist/src/planner/building/select-compound.d.ts.map +1 -1
  239. package/dist/src/planner/building/select-compound.js +84 -11
  240. package/dist/src/planner/building/select-compound.js.map +1 -1
  241. package/dist/src/planner/building/select-context.d.ts +10 -2
  242. package/dist/src/planner/building/select-context.d.ts.map +1 -1
  243. package/dist/src/planner/building/select-context.js +7 -1
  244. package/dist/src/planner/building/select-context.js.map +1 -1
  245. package/dist/src/planner/building/select-modifiers.js +6 -0
  246. package/dist/src/planner/building/select-modifiers.js.map +1 -1
  247. package/dist/src/planner/building/select-ordinal.d.ts +18 -0
  248. package/dist/src/planner/building/select-ordinal.d.ts.map +1 -1
  249. package/dist/src/planner/building/select-ordinal.js +30 -0
  250. package/dist/src/planner/building/select-ordinal.js.map +1 -1
  251. package/dist/src/planner/building/select-projections.d.ts +8 -2
  252. package/dist/src/planner/building/select-projections.d.ts.map +1 -1
  253. package/dist/src/planner/building/select-projections.js +26 -4
  254. package/dist/src/planner/building/select-projections.js.map +1 -1
  255. package/dist/src/planner/building/select-window.d.ts.map +1 -1
  256. package/dist/src/planner/building/select-window.js +8 -5
  257. package/dist/src/planner/building/select-window.js.map +1 -1
  258. package/dist/src/planner/building/select.d.ts.map +1 -1
  259. package/dist/src/planner/building/select.js +164 -59
  260. package/dist/src/planner/building/select.js.map +1 -1
  261. package/dist/src/planner/building/set-object-tags.d.ts +7 -0
  262. package/dist/src/planner/building/set-object-tags.d.ts.map +1 -0
  263. package/dist/src/planner/building/set-object-tags.js +38 -0
  264. package/dist/src/planner/building/set-object-tags.js.map +1 -0
  265. package/dist/src/planner/building/tag-diagnostics.d.ts +27 -0
  266. package/dist/src/planner/building/tag-diagnostics.d.ts.map +1 -0
  267. package/dist/src/planner/building/tag-diagnostics.js +37 -0
  268. package/dist/src/planner/building/tag-diagnostics.js.map +1 -0
  269. package/dist/src/planner/building/update.d.ts +18 -1
  270. package/dist/src/planner/building/update.d.ts.map +1 -1
  271. package/dist/src/planner/building/update.js +134 -58
  272. package/dist/src/planner/building/update.js.map +1 -1
  273. package/dist/src/planner/building/view-mutation-builder.d.ts +15 -0
  274. package/dist/src/planner/building/view-mutation-builder.d.ts.map +1 -0
  275. package/dist/src/planner/building/view-mutation-builder.js +1158 -0
  276. package/dist/src/planner/building/view-mutation-builder.js.map +1 -0
  277. package/dist/src/planner/building/with.d.ts +11 -0
  278. package/dist/src/planner/building/with.d.ts.map +1 -1
  279. package/dist/src/planner/building/with.js +48 -10
  280. package/dist/src/planner/building/with.js.map +1 -1
  281. package/dist/src/planner/cost/index.d.ts +83 -0
  282. package/dist/src/planner/cost/index.d.ts.map +1 -1
  283. package/dist/src/planner/cost/index.js +114 -0
  284. package/dist/src/planner/cost/index.js.map +1 -1
  285. package/dist/src/planner/framework/characteristics.d.ts +38 -4
  286. package/dist/src/planner/framework/characteristics.d.ts.map +1 -1
  287. package/dist/src/planner/framework/characteristics.js +50 -6
  288. package/dist/src/planner/framework/characteristics.js.map +1 -1
  289. package/dist/src/planner/framework/pass.d.ts.map +1 -1
  290. package/dist/src/planner/framework/pass.js +2 -1
  291. package/dist/src/planner/framework/pass.js.map +1 -1
  292. package/dist/src/planner/framework/physical-utils.d.ts.map +1 -1
  293. package/dist/src/planner/framework/physical-utils.js +7 -1
  294. package/dist/src/planner/framework/physical-utils.js.map +1 -1
  295. package/dist/src/planner/framework/registry.d.ts +39 -1
  296. package/dist/src/planner/framework/registry.d.ts.map +1 -1
  297. package/dist/src/planner/framework/registry.js +18 -2
  298. package/dist/src/planner/framework/registry.js.map +1 -1
  299. package/dist/src/planner/mutation/backward-body.d.ts +131 -0
  300. package/dist/src/planner/mutation/backward-body.d.ts.map +1 -0
  301. package/dist/src/planner/mutation/backward-body.js +135 -0
  302. package/dist/src/planner/mutation/backward-body.js.map +1 -0
  303. package/dist/src/planner/mutation/cte-flatten.d.ts +17 -0
  304. package/dist/src/planner/mutation/cte-flatten.d.ts.map +1 -0
  305. package/dist/src/planner/mutation/cte-flatten.js +364 -0
  306. package/dist/src/planner/mutation/cte-flatten.js.map +1 -0
  307. package/dist/src/planner/mutation/decomposition.d.ts +273 -0
  308. package/dist/src/planner/mutation/decomposition.d.ts.map +1 -0
  309. package/dist/src/planner/mutation/decomposition.js +1719 -0
  310. package/dist/src/planner/mutation/decomposition.js.map +1 -0
  311. package/dist/src/planner/mutation/lens-enforcement.d.ts +165 -0
  312. package/dist/src/planner/mutation/lens-enforcement.d.ts.map +1 -0
  313. package/dist/src/planner/mutation/lens-enforcement.js +745 -0
  314. package/dist/src/planner/mutation/lens-enforcement.js.map +1 -0
  315. package/dist/src/planner/mutation/multi-source.d.ts +568 -0
  316. package/dist/src/planner/mutation/multi-source.d.ts.map +1 -0
  317. package/dist/src/planner/mutation/multi-source.js +2915 -0
  318. package/dist/src/planner/mutation/multi-source.js.map +1 -0
  319. package/dist/src/planner/mutation/mutation-diagnostic.d.ts +37 -0
  320. package/dist/src/planner/mutation/mutation-diagnostic.d.ts.map +1 -0
  321. package/dist/src/planner/mutation/mutation-diagnostic.js +24 -0
  322. package/dist/src/planner/mutation/mutation-diagnostic.js.map +1 -0
  323. package/dist/src/planner/mutation/mutation-tags.d.ts +33 -0
  324. package/dist/src/planner/mutation/mutation-tags.d.ts.map +1 -0
  325. package/dist/src/planner/mutation/mutation-tags.js +31 -0
  326. package/dist/src/planner/mutation/mutation-tags.js.map +1 -0
  327. package/dist/src/planner/mutation/propagate.d.ts +97 -0
  328. package/dist/src/planner/mutation/propagate.d.ts.map +1 -0
  329. package/dist/src/planner/mutation/propagate.js +220 -0
  330. package/dist/src/planner/mutation/propagate.js.map +1 -0
  331. package/dist/src/planner/mutation/scope-transform.d.ts +181 -0
  332. package/dist/src/planner/mutation/scope-transform.d.ts.map +1 -0
  333. package/dist/src/planner/mutation/scope-transform.js +574 -0
  334. package/dist/src/planner/mutation/scope-transform.js.map +1 -0
  335. package/dist/src/planner/mutation/set-op.d.ts +242 -0
  336. package/dist/src/planner/mutation/set-op.d.ts.map +1 -0
  337. package/dist/src/planner/mutation/set-op.js +1687 -0
  338. package/dist/src/planner/mutation/set-op.js.map +1 -0
  339. package/dist/src/planner/mutation/single-source.d.ts +261 -0
  340. package/dist/src/planner/mutation/single-source.d.ts.map +1 -0
  341. package/dist/src/planner/mutation/single-source.js +1096 -0
  342. package/dist/src/planner/mutation/single-source.js.map +1 -0
  343. package/dist/src/planner/nodes/aggregate-node.d.ts +6 -4
  344. package/dist/src/planner/nodes/aggregate-node.d.ts.map +1 -1
  345. package/dist/src/planner/nodes/aggregate-node.js +11 -9
  346. package/dist/src/planner/nodes/aggregate-node.js.map +1 -1
  347. package/dist/src/planner/nodes/alias-node.d.ts.map +1 -1
  348. package/dist/src/planner/nodes/alias-node.js +5 -1
  349. package/dist/src/planner/nodes/alias-node.js.map +1 -1
  350. package/dist/src/planner/nodes/alter-table-node.d.ts +124 -1
  351. package/dist/src/planner/nodes/alter-table-node.d.ts.map +1 -1
  352. package/dist/src/planner/nodes/alter-table-node.js +27 -0
  353. package/dist/src/planner/nodes/alter-table-node.js.map +1 -1
  354. package/dist/src/planner/nodes/analyze-node.d.ts +2 -1
  355. package/dist/src/planner/nodes/analyze-node.d.ts.map +1 -1
  356. package/dist/src/planner/nodes/analyze-node.js +21 -1
  357. package/dist/src/planner/nodes/analyze-node.js.map +1 -1
  358. package/dist/src/planner/nodes/asserted-keys-node.d.ts +43 -0
  359. package/dist/src/planner/nodes/asserted-keys-node.d.ts.map +1 -0
  360. package/dist/src/planner/nodes/asserted-keys-node.js +99 -0
  361. package/dist/src/planner/nodes/asserted-keys-node.js.map +1 -0
  362. package/dist/src/planner/nodes/async-gather-node.d.ts.map +1 -1
  363. package/dist/src/planner/nodes/async-gather-node.js +33 -8
  364. package/dist/src/planner/nodes/async-gather-node.js.map +1 -1
  365. package/dist/src/planner/nodes/bloom-join-node.d.ts.map +1 -1
  366. package/dist/src/planner/nodes/bloom-join-node.js +2 -1
  367. package/dist/src/planner/nodes/bloom-join-node.js.map +1 -1
  368. package/dist/src/planner/nodes/create-view-node.d.ts +7 -2
  369. package/dist/src/planner/nodes/create-view-node.d.ts.map +1 -1
  370. package/dist/src/planner/nodes/create-view-node.js +4 -1
  371. package/dist/src/planner/nodes/create-view-node.js.map +1 -1
  372. package/dist/src/planner/nodes/declarative-schema.d.ts +13 -1
  373. package/dist/src/planner/nodes/declarative-schema.d.ts.map +1 -1
  374. package/dist/src/planner/nodes/declarative-schema.js +32 -0
  375. package/dist/src/planner/nodes/declarative-schema.js.map +1 -1
  376. package/dist/src/planner/nodes/distinct-node.d.ts.map +1 -1
  377. package/dist/src/planner/nodes/distinct-node.js +2 -0
  378. package/dist/src/planner/nodes/distinct-node.js.map +1 -1
  379. package/dist/src/planner/nodes/dml-executor-node.d.ts +29 -1
  380. package/dist/src/planner/nodes/dml-executor-node.d.ts.map +1 -1
  381. package/dist/src/planner/nodes/dml-executor-node.js +27 -3
  382. package/dist/src/planner/nodes/dml-executor-node.js.map +1 -1
  383. package/dist/src/planner/nodes/eager-prefetch-node.d.ts.map +1 -1
  384. package/dist/src/planner/nodes/eager-prefetch-node.js +2 -0
  385. package/dist/src/planner/nodes/eager-prefetch-node.js.map +1 -1
  386. package/dist/src/planner/nodes/envelope-scan-node.d.ts +42 -0
  387. package/dist/src/planner/nodes/envelope-scan-node.d.ts.map +1 -0
  388. package/dist/src/planner/nodes/envelope-scan-node.js +62 -0
  389. package/dist/src/planner/nodes/envelope-scan-node.js.map +1 -0
  390. package/dist/src/planner/nodes/fanout-lookup-join-node.d.ts.map +1 -1
  391. package/dist/src/planner/nodes/fanout-lookup-join-node.js +11 -1
  392. package/dist/src/planner/nodes/fanout-lookup-join-node.js.map +1 -1
  393. package/dist/src/planner/nodes/filter.d.ts.map +1 -1
  394. package/dist/src/planner/nodes/filter.js +63 -13
  395. package/dist/src/planner/nodes/filter.js.map +1 -1
  396. package/dist/src/planner/nodes/hash-aggregate.d.ts.map +1 -1
  397. package/dist/src/planner/nodes/hash-aggregate.js +6 -16
  398. package/dist/src/planner/nodes/hash-aggregate.js.map +1 -1
  399. package/dist/src/planner/nodes/join-node.d.ts +41 -1
  400. package/dist/src/planner/nodes/join-node.d.ts.map +1 -1
  401. package/dist/src/planner/nodes/join-node.js +78 -8
  402. package/dist/src/planner/nodes/join-node.js.map +1 -1
  403. package/dist/src/planner/nodes/join-utils.d.ts +33 -6
  404. package/dist/src/planner/nodes/join-utils.d.ts.map +1 -1
  405. package/dist/src/planner/nodes/join-utils.js +131 -10
  406. package/dist/src/planner/nodes/join-utils.js.map +1 -1
  407. package/dist/src/planner/nodes/lens-auxiliary-access-node.d.ts +104 -0
  408. package/dist/src/planner/nodes/lens-auxiliary-access-node.d.ts.map +1 -0
  409. package/dist/src/planner/nodes/lens-auxiliary-access-node.js +91 -0
  410. package/dist/src/planner/nodes/lens-auxiliary-access-node.js.map +1 -0
  411. package/dist/src/planner/nodes/limit-offset.d.ts +12 -0
  412. package/dist/src/planner/nodes/limit-offset.d.ts.map +1 -1
  413. package/dist/src/planner/nodes/limit-offset.js +52 -3
  414. package/dist/src/planner/nodes/limit-offset.js.map +1 -1
  415. package/dist/src/planner/nodes/materialized-view-nodes.d.ts +69 -0
  416. package/dist/src/planner/nodes/materialized-view-nodes.d.ts.map +1 -0
  417. package/dist/src/planner/nodes/materialized-view-nodes.js +111 -0
  418. package/dist/src/planner/nodes/materialized-view-nodes.js.map +1 -0
  419. package/dist/src/planner/nodes/merge-join-node.d.ts.map +1 -1
  420. package/dist/src/planner/nodes/merge-join-node.js +2 -1
  421. package/dist/src/planner/nodes/merge-join-node.js.map +1 -1
  422. package/dist/src/planner/nodes/ordinal-slice-node.d.ts.map +1 -1
  423. package/dist/src/planner/nodes/ordinal-slice-node.js +2 -0
  424. package/dist/src/planner/nodes/ordinal-slice-node.js.map +1 -1
  425. package/dist/src/planner/nodes/plan-node-type.d.ts +9 -0
  426. package/dist/src/planner/nodes/plan-node-type.d.ts.map +1 -1
  427. package/dist/src/planner/nodes/plan-node-type.js +9 -0
  428. package/dist/src/planner/nodes/plan-node-type.js.map +1 -1
  429. package/dist/src/planner/nodes/plan-node.d.ts +265 -5
  430. package/dist/src/planner/nodes/plan-node.d.ts.map +1 -1
  431. package/dist/src/planner/nodes/plan-node.js.map +1 -1
  432. package/dist/src/planner/nodes/pragma.d.ts +2 -1
  433. package/dist/src/planner/nodes/pragma.d.ts.map +1 -1
  434. package/dist/src/planner/nodes/pragma.js +12 -0
  435. package/dist/src/planner/nodes/pragma.js.map +1 -1
  436. package/dist/src/planner/nodes/project-node.d.ts +14 -1
  437. package/dist/src/planner/nodes/project-node.d.ts.map +1 -1
  438. package/dist/src/planner/nodes/project-node.js +103 -16
  439. package/dist/src/planner/nodes/project-node.js.map +1 -1
  440. package/dist/src/planner/nodes/reference.d.ts.map +1 -1
  441. package/dist/src/planner/nodes/reference.js +63 -30
  442. package/dist/src/planner/nodes/reference.js.map +1 -1
  443. package/dist/src/planner/nodes/retrieve-node.d.ts.map +1 -1
  444. package/dist/src/planner/nodes/retrieve-node.js +7 -0
  445. package/dist/src/planner/nodes/retrieve-node.js.map +1 -1
  446. package/dist/src/planner/nodes/returning-node.d.ts.map +1 -1
  447. package/dist/src/planner/nodes/returning-node.js +10 -3
  448. package/dist/src/planner/nodes/returning-node.js.map +1 -1
  449. package/dist/src/planner/nodes/scalar.d.ts +20 -0
  450. package/dist/src/planner/nodes/scalar.d.ts.map +1 -1
  451. package/dist/src/planner/nodes/scalar.js +71 -14
  452. package/dist/src/planner/nodes/scalar.js.map +1 -1
  453. package/dist/src/planner/nodes/set-object-tags-node.d.ts +39 -0
  454. package/dist/src/planner/nodes/set-object-tags-node.d.ts.map +1 -0
  455. package/dist/src/planner/nodes/set-object-tags-node.js +41 -0
  456. package/dist/src/planner/nodes/set-object-tags-node.js.map +1 -0
  457. package/dist/src/planner/nodes/set-operation-node.d.ts +123 -1
  458. package/dist/src/planner/nodes/set-operation-node.d.ts.map +1 -1
  459. package/dist/src/planner/nodes/set-operation-node.js +302 -18
  460. package/dist/src/planner/nodes/set-operation-node.js.map +1 -1
  461. package/dist/src/planner/nodes/single-row.d.ts.map +1 -1
  462. package/dist/src/planner/nodes/single-row.js +3 -0
  463. package/dist/src/planner/nodes/single-row.js.map +1 -1
  464. package/dist/src/planner/nodes/sort.d.ts.map +1 -1
  465. package/dist/src/planner/nodes/sort.js +8 -7
  466. package/dist/src/planner/nodes/sort.js.map +1 -1
  467. package/dist/src/planner/nodes/stream-aggregate.d.ts.map +1 -1
  468. package/dist/src/planner/nodes/stream-aggregate.js +8 -23
  469. package/dist/src/planner/nodes/stream-aggregate.js.map +1 -1
  470. package/dist/src/planner/nodes/subquery.d.ts +2 -0
  471. package/dist/src/planner/nodes/subquery.d.ts.map +1 -1
  472. package/dist/src/planner/nodes/subquery.js +18 -2
  473. package/dist/src/planner/nodes/subquery.js.map +1 -1
  474. package/dist/src/planner/nodes/table-access-nodes.d.ts.map +1 -1
  475. package/dist/src/planner/nodes/table-access-nodes.js +23 -3
  476. package/dist/src/planner/nodes/table-access-nodes.js.map +1 -1
  477. package/dist/src/planner/nodes/table-function-call.js +6 -0
  478. package/dist/src/planner/nodes/table-function-call.js.map +1 -1
  479. package/dist/src/planner/nodes/values-node.d.ts +3 -1
  480. package/dist/src/planner/nodes/values-node.d.ts.map +1 -1
  481. package/dist/src/planner/nodes/values-node.js +26 -0
  482. package/dist/src/planner/nodes/values-node.js.map +1 -1
  483. package/dist/src/planner/nodes/view-mutation-node.d.ts +259 -0
  484. package/dist/src/planner/nodes/view-mutation-node.d.ts.map +1 -0
  485. package/dist/src/planner/nodes/view-mutation-node.js +273 -0
  486. package/dist/src/planner/nodes/view-mutation-node.js.map +1 -0
  487. package/dist/src/planner/nodes/window-function.d.ts +17 -1
  488. package/dist/src/planner/nodes/window-function.d.ts.map +1 -1
  489. package/dist/src/planner/nodes/window-function.js +15 -1
  490. package/dist/src/planner/nodes/window-function.js.map +1 -1
  491. package/dist/src/planner/nodes/window-node.js +3 -3
  492. package/dist/src/planner/nodes/window-node.js.map +1 -1
  493. package/dist/src/planner/optimizer.d.ts.map +1 -1
  494. package/dist/src/planner/optimizer.js +372 -39
  495. package/dist/src/planner/optimizer.js.map +1 -1
  496. package/dist/src/planner/planning-context.d.ts +1 -1
  497. package/dist/src/planner/planning-context.d.ts.map +1 -1
  498. package/dist/src/planner/rules/access/lens-access-form-matcher.d.ts +70 -0
  499. package/dist/src/planner/rules/access/lens-access-form-matcher.d.ts.map +1 -0
  500. package/dist/src/planner/rules/access/lens-access-form-matcher.js +156 -0
  501. package/dist/src/planner/rules/access/lens-access-form-matcher.js.map +1 -0
  502. package/dist/src/planner/rules/access/rule-lens-auxiliary-access.d.ts +31 -0
  503. package/dist/src/planner/rules/access/rule-lens-auxiliary-access.d.ts.map +1 -0
  504. package/dist/src/planner/rules/access/rule-lens-auxiliary-access.js +176 -0
  505. package/dist/src/planner/rules/access/rule-lens-auxiliary-access.js.map +1 -0
  506. package/dist/src/planner/rules/access/rule-select-access-path.d.ts.map +1 -1
  507. package/dist/src/planner/rules/access/rule-select-access-path.js +435 -37
  508. package/dist/src/planner/rules/access/rule-select-access-path.js.map +1 -1
  509. package/dist/src/planner/rules/aggregate/rule-aggregate-streaming.d.ts.map +1 -1
  510. package/dist/src/planner/rules/aggregate/rule-aggregate-streaming.js +8 -27
  511. package/dist/src/planner/rules/aggregate/rule-aggregate-streaming.js.map +1 -1
  512. package/dist/src/planner/rules/aggregate/rule-groupby-fd-simplification.d.ts +9 -3
  513. package/dist/src/planner/rules/aggregate/rule-groupby-fd-simplification.d.ts.map +1 -1
  514. package/dist/src/planner/rules/aggregate/rule-groupby-fd-simplification.js +56 -5
  515. package/dist/src/planner/rules/aggregate/rule-groupby-fd-simplification.js.map +1 -1
  516. package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.d.ts +39 -0
  517. package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.d.ts.map +1 -0
  518. package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.js +616 -0
  519. package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.js.map +1 -0
  520. package/dist/src/planner/rules/cache/rule-scalar-cse.d.ts.map +1 -1
  521. package/dist/src/planner/rules/cache/rule-scalar-cse.js +8 -1
  522. package/dist/src/planner/rules/cache/rule-scalar-cse.js.map +1 -1
  523. package/dist/src/planner/rules/distinct/rule-distinct-elimination.d.ts +8 -7
  524. package/dist/src/planner/rules/distinct/rule-distinct-elimination.d.ts.map +1 -1
  525. package/dist/src/planner/rules/distinct/rule-distinct-elimination.js +14 -21
  526. package/dist/src/planner/rules/distinct/rule-distinct-elimination.js.map +1 -1
  527. package/dist/src/planner/rules/join/equi-pair-extractor.d.ts +36 -0
  528. package/dist/src/planner/rules/join/equi-pair-extractor.d.ts.map +1 -1
  529. package/dist/src/planner/rules/join/equi-pair-extractor.js +42 -5
  530. package/dist/src/planner/rules/join/equi-pair-extractor.js.map +1 -1
  531. package/dist/src/planner/rules/join/rule-fanout-batched-outer.d.ts.map +1 -1
  532. package/dist/src/planner/rules/join/rule-fanout-batched-outer.js +10 -0
  533. package/dist/src/planner/rules/join/rule-fanout-batched-outer.js.map +1 -1
  534. package/dist/src/planner/rules/join/rule-fanout-lookup-join.js +25 -9
  535. package/dist/src/planner/rules/join/rule-fanout-lookup-join.js.map +1 -1
  536. package/dist/src/planner/rules/join/rule-inner-join-existence-recovery.d.ts +130 -0
  537. package/dist/src/planner/rules/join/rule-inner-join-existence-recovery.d.ts.map +1 -0
  538. package/dist/src/planner/rules/join/rule-inner-join-existence-recovery.js +206 -0
  539. package/dist/src/planner/rules/join/rule-inner-join-existence-recovery.js.map +1 -0
  540. package/dist/src/planner/rules/join/rule-join-elimination.d.ts +67 -14
  541. package/dist/src/planner/rules/join/rule-join-elimination.d.ts.map +1 -1
  542. package/dist/src/planner/rules/join/rule-join-elimination.js +81 -25
  543. package/dist/src/planner/rules/join/rule-join-elimination.js.map +1 -1
  544. package/dist/src/planner/rules/join/rule-join-existence-pruning.d.ts +84 -0
  545. package/dist/src/planner/rules/join/rule-join-existence-pruning.d.ts.map +1 -0
  546. package/dist/src/planner/rules/join/rule-join-existence-pruning.js +138 -0
  547. package/dist/src/planner/rules/join/rule-join-existence-pruning.js.map +1 -0
  548. package/dist/src/planner/rules/join/rule-join-greedy-commute.d.ts.map +1 -1
  549. package/dist/src/planner/rules/join/rule-join-greedy-commute.js +19 -1
  550. package/dist/src/planner/rules/join/rule-join-greedy-commute.js.map +1 -1
  551. package/dist/src/planner/rules/join/rule-join-physical-selection.d.ts.map +1 -1
  552. package/dist/src/planner/rules/join/rule-join-physical-selection.js +14 -2
  553. package/dist/src/planner/rules/join/rule-join-physical-selection.js.map +1 -1
  554. package/dist/src/planner/rules/join/rule-lateral-top1-asof.d.ts.map +1 -1
  555. package/dist/src/planner/rules/join/rule-lateral-top1-asof.js +5 -2
  556. package/dist/src/planner/rules/join/rule-lateral-top1-asof.js.map +1 -1
  557. package/dist/src/planner/rules/join/rule-monotonic-merge-join.d.ts.map +1 -1
  558. package/dist/src/planner/rules/join/rule-monotonic-merge-join.js +4 -0
  559. package/dist/src/planner/rules/join/rule-monotonic-merge-join.js.map +1 -1
  560. package/dist/src/planner/rules/join/rule-quickpick-enumeration.d.ts.map +1 -1
  561. package/dist/src/planner/rules/join/rule-quickpick-enumeration.js +10 -0
  562. package/dist/src/planner/rules/join/rule-quickpick-enumeration.js.map +1 -1
  563. package/dist/src/planner/rules/join/rule-semijoin-existence-recovery.d.ts +286 -0
  564. package/dist/src/planner/rules/join/rule-semijoin-existence-recovery.d.ts.map +1 -0
  565. package/dist/src/planner/rules/join/rule-semijoin-existence-recovery.js +548 -0
  566. package/dist/src/planner/rules/join/rule-semijoin-existence-recovery.js.map +1 -0
  567. package/dist/src/planner/rules/parallel/rule-async-gather-union-all.d.ts.map +1 -1
  568. package/dist/src/planner/rules/parallel/rule-async-gather-union-all.js +9 -1
  569. package/dist/src/planner/rules/parallel/rule-async-gather-union-all.js.map +1 -1
  570. package/dist/src/planner/rules/parallel/rule-async-gather-zip-by-key.d.ts.map +1 -1
  571. package/dist/src/planner/rules/parallel/rule-async-gather-zip-by-key.js +7 -0
  572. package/dist/src/planner/rules/parallel/rule-async-gather-zip-by-key.js.map +1 -1
  573. package/dist/src/planner/rules/parallel/rule-eager-prefetch-probe.d.ts.map +1 -1
  574. package/dist/src/planner/rules/parallel/rule-eager-prefetch-probe.js +10 -1
  575. package/dist/src/planner/rules/parallel/rule-eager-prefetch-probe.js.map +1 -1
  576. package/dist/src/planner/rules/predicate/rule-aggregate-predicate-pushdown.d.ts.map +1 -1
  577. package/dist/src/planner/rules/predicate/rule-aggregate-predicate-pushdown.js +10 -1
  578. package/dist/src/planner/rules/predicate/rule-aggregate-predicate-pushdown.js.map +1 -1
  579. package/dist/src/planner/rules/predicate/rule-empty-relation-folding.d.ts.map +1 -1
  580. package/dist/src/planner/rules/predicate/rule-empty-relation-folding.js +18 -0
  581. package/dist/src/planner/rules/predicate/rule-empty-relation-folding.js.map +1 -1
  582. package/dist/src/planner/rules/predicate/rule-filter-contradiction.d.ts.map +1 -1
  583. package/dist/src/planner/rules/predicate/rule-filter-contradiction.js +7 -0
  584. package/dist/src/planner/rules/predicate/rule-filter-contradiction.js.map +1 -1
  585. package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.d.ts.map +1 -1
  586. package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.js +9 -0
  587. package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.js.map +1 -1
  588. package/dist/src/planner/rules/predicate/rule-predicate-pushdown.js +13 -3
  589. package/dist/src/planner/rules/predicate/rule-predicate-pushdown.js.map +1 -1
  590. package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js +2 -2
  591. package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js.map +1 -1
  592. package/dist/src/planner/rules/retrieve/rule-projection-pruning.d.ts.map +1 -1
  593. package/dist/src/planner/rules/retrieve/rule-projection-pruning.js +14 -0
  594. package/dist/src/planner/rules/retrieve/rule-projection-pruning.js.map +1 -1
  595. package/dist/src/planner/rules/sort/rule-orderby-fd-pruning.d.ts +16 -0
  596. package/dist/src/planner/rules/sort/rule-orderby-fd-pruning.d.ts.map +1 -1
  597. package/dist/src/planner/rules/sort/rule-orderby-fd-pruning.js +47 -4
  598. package/dist/src/planner/rules/sort/rule-orderby-fd-pruning.js.map +1 -1
  599. package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.d.ts.map +1 -1
  600. package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.js +8 -0
  601. package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.js.map +1 -1
  602. package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.d.ts.map +1 -1
  603. package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.js +7 -0
  604. package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.js.map +1 -1
  605. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.d.ts.map +1 -1
  606. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js +12 -0
  607. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js.map +1 -1
  608. package/dist/src/planner/rules/window/rule-monotonic-window.js +1 -1
  609. package/dist/src/planner/rules/window/rule-monotonic-window.js.map +1 -1
  610. package/dist/src/planner/type-utils.d.ts +14 -0
  611. package/dist/src/planner/type-utils.d.ts.map +1 -1
  612. package/dist/src/planner/type-utils.js +66 -21
  613. package/dist/src/planner/type-utils.js.map +1 -1
  614. package/dist/src/planner/util/fd-utils.d.ts +228 -36
  615. package/dist/src/planner/util/fd-utils.d.ts.map +1 -1
  616. package/dist/src/planner/util/fd-utils.js +501 -84
  617. package/dist/src/planner/util/fd-utils.js.map +1 -1
  618. package/dist/src/planner/util/ind-utils.d.ts +27 -1
  619. package/dist/src/planner/util/ind-utils.d.ts.map +1 -1
  620. package/dist/src/planner/util/ind-utils.js +80 -6
  621. package/dist/src/planner/util/ind-utils.js.map +1 -1
  622. package/dist/src/planner/util/key-utils.d.ts +26 -3
  623. package/dist/src/planner/util/key-utils.d.ts.map +1 -1
  624. package/dist/src/planner/util/key-utils.js +182 -33
  625. package/dist/src/planner/util/key-utils.js.map +1 -1
  626. package/dist/src/planner/util/set-op-wrapper.d.ts +37 -0
  627. package/dist/src/planner/util/set-op-wrapper.d.ts.map +1 -0
  628. package/dist/src/planner/util/set-op-wrapper.js +82 -0
  629. package/dist/src/planner/util/set-op-wrapper.js.map +1 -0
  630. package/dist/src/planner/validation/plan-validator.d.ts.map +1 -1
  631. package/dist/src/planner/validation/plan-validator.js +1 -0
  632. package/dist/src/planner/validation/plan-validator.js.map +1 -1
  633. package/dist/src/runtime/context-helpers.d.ts +13 -1
  634. package/dist/src/runtime/context-helpers.d.ts.map +1 -1
  635. package/dist/src/runtime/context-helpers.js +7 -1
  636. package/dist/src/runtime/context-helpers.js.map +1 -1
  637. package/dist/src/runtime/delta-executor.d.ts +30 -1
  638. package/dist/src/runtime/delta-executor.d.ts.map +1 -1
  639. package/dist/src/runtime/delta-executor.js +38 -4
  640. package/dist/src/runtime/delta-executor.js.map +1 -1
  641. package/dist/src/runtime/emit/add-constraint.d.ts.map +1 -1
  642. package/dist/src/runtime/emit/add-constraint.js +38 -5
  643. package/dist/src/runtime/emit/add-constraint.js.map +1 -1
  644. package/dist/src/runtime/emit/aggregate.d.ts.map +1 -1
  645. package/dist/src/runtime/emit/aggregate.js +10 -8
  646. package/dist/src/runtime/emit/aggregate.js.map +1 -1
  647. package/dist/src/runtime/emit/alter-table.d.ts +1 -1
  648. package/dist/src/runtime/emit/alter-table.d.ts.map +1 -1
  649. package/dist/src/runtime/emit/alter-table.js +664 -108
  650. package/dist/src/runtime/emit/alter-table.js.map +1 -1
  651. package/dist/src/runtime/emit/analyze.d.ts.map +1 -1
  652. package/dist/src/runtime/emit/analyze.js +2 -1
  653. package/dist/src/runtime/emit/analyze.js.map +1 -1
  654. package/dist/src/runtime/emit/asof-scan.d.ts.map +1 -1
  655. package/dist/src/runtime/emit/asof-scan.js +24 -9
  656. package/dist/src/runtime/emit/asof-scan.js.map +1 -1
  657. package/dist/src/runtime/emit/asserted-keys.d.ts +13 -0
  658. package/dist/src/runtime/emit/asserted-keys.d.ts.map +1 -0
  659. package/dist/src/runtime/emit/asserted-keys.js +13 -0
  660. package/dist/src/runtime/emit/asserted-keys.js.map +1 -0
  661. package/dist/src/runtime/emit/between.d.ts.map +1 -1
  662. package/dist/src/runtime/emit/between.js +24 -19
  663. package/dist/src/runtime/emit/between.js.map +1 -1
  664. package/dist/src/runtime/emit/binary.d.ts.map +1 -1
  665. package/dist/src/runtime/emit/binary.js +24 -36
  666. package/dist/src/runtime/emit/binary.js.map +1 -1
  667. package/dist/src/runtime/emit/block.d.ts.map +1 -1
  668. package/dist/src/runtime/emit/block.js +11 -2
  669. package/dist/src/runtime/emit/block.js.map +1 -1
  670. package/dist/src/runtime/emit/bloom-join.d.ts.map +1 -1
  671. package/dist/src/runtime/emit/bloom-join.js +12 -4
  672. package/dist/src/runtime/emit/bloom-join.js.map +1 -1
  673. package/dist/src/runtime/emit/constraint-check.d.ts.map +1 -1
  674. package/dist/src/runtime/emit/constraint-check.js +50 -1
  675. package/dist/src/runtime/emit/constraint-check.js.map +1 -1
  676. package/dist/src/runtime/emit/create-table.d.ts.map +1 -1
  677. package/dist/src/runtime/emit/create-table.js +8 -0
  678. package/dist/src/runtime/emit/create-table.js.map +1 -1
  679. package/dist/src/runtime/emit/create-view.d.ts.map +1 -1
  680. package/dist/src/runtime/emit/create-view.js +16 -1
  681. package/dist/src/runtime/emit/create-view.js.map +1 -1
  682. package/dist/src/runtime/emit/delete.d.ts.map +1 -1
  683. package/dist/src/runtime/emit/delete.js +15 -5
  684. package/dist/src/runtime/emit/delete.js.map +1 -1
  685. package/dist/src/runtime/emit/dml-executor.d.ts +27 -0
  686. package/dist/src/runtime/emit/dml-executor.d.ts.map +1 -1
  687. package/dist/src/runtime/emit/dml-executor.js +413 -193
  688. package/dist/src/runtime/emit/dml-executor.js.map +1 -1
  689. package/dist/src/runtime/emit/drop-table.d.ts.map +1 -1
  690. package/dist/src/runtime/emit/drop-table.js +10 -0
  691. package/dist/src/runtime/emit/drop-table.js.map +1 -1
  692. package/dist/src/runtime/emit/drop-view.d.ts.map +1 -1
  693. package/dist/src/runtime/emit/drop-view.js +17 -0
  694. package/dist/src/runtime/emit/drop-view.js.map +1 -1
  695. package/dist/src/runtime/emit/envelope-scan.d.ts +13 -0
  696. package/dist/src/runtime/emit/envelope-scan.d.ts.map +1 -0
  697. package/dist/src/runtime/emit/envelope-scan.js +22 -0
  698. package/dist/src/runtime/emit/envelope-scan.js.map +1 -0
  699. package/dist/src/runtime/emit/join.d.ts +10 -2
  700. package/dist/src/runtime/emit/join.d.ts.map +1 -1
  701. package/dist/src/runtime/emit/join.js +128 -38
  702. package/dist/src/runtime/emit/join.js.map +1 -1
  703. package/dist/src/runtime/emit/lens-auxiliary-access.d.ts +16 -0
  704. package/dist/src/runtime/emit/lens-auxiliary-access.d.ts.map +1 -0
  705. package/dist/src/runtime/emit/lens-auxiliary-access.js +16 -0
  706. package/dist/src/runtime/emit/lens-auxiliary-access.js.map +1 -0
  707. package/dist/src/runtime/emit/materialized-view-helpers.d.ts +640 -0
  708. package/dist/src/runtime/emit/materialized-view-helpers.d.ts.map +1 -0
  709. package/dist/src/runtime/emit/materialized-view-helpers.js +2576 -0
  710. package/dist/src/runtime/emit/materialized-view-helpers.js.map +1 -0
  711. package/dist/src/runtime/emit/materialized-view.d.ts +31 -0
  712. package/dist/src/runtime/emit/materialized-view.d.ts.map +1 -0
  713. package/dist/src/runtime/emit/materialized-view.js +187 -0
  714. package/dist/src/runtime/emit/materialized-view.js.map +1 -0
  715. package/dist/src/runtime/emit/merge-join.d.ts.map +1 -1
  716. package/dist/src/runtime/emit/merge-join.js +19 -5
  717. package/dist/src/runtime/emit/merge-join.js.map +1 -1
  718. package/dist/src/runtime/emit/project.d.ts.map +1 -1
  719. package/dist/src/runtime/emit/project.js +10 -5
  720. package/dist/src/runtime/emit/project.js.map +1 -1
  721. package/dist/src/runtime/emit/schema-declarative.d.ts +1 -0
  722. package/dist/src/runtime/emit/schema-declarative.d.ts.map +1 -1
  723. package/dist/src/runtime/emit/schema-declarative.js +101 -5
  724. package/dist/src/runtime/emit/schema-declarative.js.map +1 -1
  725. package/dist/src/runtime/emit/set-object-tags.d.ts +16 -0
  726. package/dist/src/runtime/emit/set-object-tags.d.ts.map +1 -0
  727. package/dist/src/runtime/emit/set-object-tags.js +57 -0
  728. package/dist/src/runtime/emit/set-object-tags.js.map +1 -0
  729. package/dist/src/runtime/emit/set-operation.d.ts.map +1 -1
  730. package/dist/src/runtime/emit/set-operation.js +140 -24
  731. package/dist/src/runtime/emit/set-operation.js.map +1 -1
  732. package/dist/src/runtime/emit/subquery.d.ts.map +1 -1
  733. package/dist/src/runtime/emit/subquery.js +110 -5
  734. package/dist/src/runtime/emit/subquery.js.map +1 -1
  735. package/dist/src/runtime/emit/unary.d.ts.map +1 -1
  736. package/dist/src/runtime/emit/unary.js +34 -6
  737. package/dist/src/runtime/emit/unary.js.map +1 -1
  738. package/dist/src/runtime/emit/view-mutation.d.ts +70 -0
  739. package/dist/src/runtime/emit/view-mutation.d.ts.map +1 -0
  740. package/dist/src/runtime/emit/view-mutation.js +299 -0
  741. package/dist/src/runtime/emit/view-mutation.js.map +1 -0
  742. package/dist/src/runtime/emit/window.js +29 -5
  743. package/dist/src/runtime/emit/window.js.map +1 -1
  744. package/dist/src/runtime/foreign-key-actions.d.ts +66 -3
  745. package/dist/src/runtime/foreign-key-actions.d.ts.map +1 -1
  746. package/dist/src/runtime/foreign-key-actions.js +580 -172
  747. package/dist/src/runtime/foreign-key-actions.js.map +1 -1
  748. package/dist/src/runtime/parallel-driver.d.ts +4 -1
  749. package/dist/src/runtime/parallel-driver.d.ts.map +1 -1
  750. package/dist/src/runtime/parallel-driver.js +5 -1
  751. package/dist/src/runtime/parallel-driver.js.map +1 -1
  752. package/dist/src/runtime/register.d.ts.map +1 -1
  753. package/dist/src/runtime/register.js +17 -1
  754. package/dist/src/runtime/register.js.map +1 -1
  755. package/dist/src/runtime/types.d.ts +10 -0
  756. package/dist/src/runtime/types.d.ts.map +1 -1
  757. package/dist/src/runtime/types.js.map +1 -1
  758. package/dist/src/schema/basis-backfill.d.ts +63 -0
  759. package/dist/src/schema/basis-backfill.d.ts.map +1 -0
  760. package/dist/src/schema/basis-backfill.js +161 -0
  761. package/dist/src/schema/basis-backfill.js.map +1 -0
  762. package/dist/src/schema/catalog.d.ts +115 -1
  763. package/dist/src/schema/catalog.d.ts.map +1 -1
  764. package/dist/src/schema/catalog.js +249 -22
  765. package/dist/src/schema/catalog.js.map +1 -1
  766. package/dist/src/schema/change-events.d.ts +42 -1
  767. package/dist/src/schema/change-events.d.ts.map +1 -1
  768. package/dist/src/schema/change-events.js.map +1 -1
  769. package/dist/src/schema/column.d.ts +16 -0
  770. package/dist/src/schema/column.d.ts.map +1 -1
  771. package/dist/src/schema/column.js.map +1 -1
  772. package/dist/src/schema/constraint-builder.d.ts +182 -0
  773. package/dist/src/schema/constraint-builder.d.ts.map +1 -0
  774. package/dist/src/schema/constraint-builder.js +424 -0
  775. package/dist/src/schema/constraint-builder.js.map +1 -0
  776. package/dist/src/schema/ddl-generator.d.ts +86 -1
  777. package/dist/src/schema/ddl-generator.d.ts.map +1 -1
  778. package/dist/src/schema/ddl-generator.js +316 -20
  779. package/dist/src/schema/ddl-generator.js.map +1 -1
  780. package/dist/src/schema/declared-schema-manager.d.ts +51 -0
  781. package/dist/src/schema/declared-schema-manager.d.ts.map +1 -1
  782. package/dist/src/schema/declared-schema-manager.js +61 -0
  783. package/dist/src/schema/declared-schema-manager.js.map +1 -1
  784. package/dist/src/schema/derivation.d.ts +106 -0
  785. package/dist/src/schema/derivation.d.ts.map +1 -0
  786. package/dist/src/schema/derivation.js +25 -0
  787. package/dist/src/schema/derivation.js.map +1 -0
  788. package/dist/src/schema/function.d.ts +13 -0
  789. package/dist/src/schema/function.d.ts.map +1 -1
  790. package/dist/src/schema/function.js.map +1 -1
  791. package/dist/src/schema/lens-ack.d.ts +90 -0
  792. package/dist/src/schema/lens-ack.d.ts.map +1 -0
  793. package/dist/src/schema/lens-ack.js +361 -0
  794. package/dist/src/schema/lens-ack.js.map +1 -0
  795. package/dist/src/schema/lens-compiler.d.ts +62 -0
  796. package/dist/src/schema/lens-compiler.d.ts.map +1 -0
  797. package/dist/src/schema/lens-compiler.js +1594 -0
  798. package/dist/src/schema/lens-compiler.js.map +1 -0
  799. package/dist/src/schema/lens-fk-discovery.d.ts +175 -0
  800. package/dist/src/schema/lens-fk-discovery.d.ts.map +1 -0
  801. package/dist/src/schema/lens-fk-discovery.js +336 -0
  802. package/dist/src/schema/lens-fk-discovery.js.map +1 -0
  803. package/dist/src/schema/lens-prover.d.ts +336 -0
  804. package/dist/src/schema/lens-prover.d.ts.map +1 -0
  805. package/dist/src/schema/lens-prover.js +1988 -0
  806. package/dist/src/schema/lens-prover.js.map +1 -0
  807. package/dist/src/schema/lens.d.ts +254 -0
  808. package/dist/src/schema/lens.d.ts.map +1 -0
  809. package/dist/src/schema/lens.js +21 -0
  810. package/dist/src/schema/lens.js.map +1 -0
  811. package/dist/src/schema/manager.d.ts +676 -18
  812. package/dist/src/schema/manager.d.ts.map +1 -1
  813. package/dist/src/schema/manager.js +1573 -238
  814. package/dist/src/schema/manager.js.map +1 -1
  815. package/dist/src/schema/mapping-advertisement-tags.d.ts +39 -0
  816. package/dist/src/schema/mapping-advertisement-tags.d.ts.map +1 -0
  817. package/dist/src/schema/mapping-advertisement-tags.js +216 -0
  818. package/dist/src/schema/mapping-advertisement-tags.js.map +1 -0
  819. package/dist/src/schema/rename-rewriter.d.ts +45 -4
  820. package/dist/src/schema/rename-rewriter.d.ts.map +1 -1
  821. package/dist/src/schema/rename-rewriter.js +412 -19
  822. package/dist/src/schema/rename-rewriter.js.map +1 -1
  823. package/dist/src/schema/reserved-tags-policy.d.ts +32 -0
  824. package/dist/src/schema/reserved-tags-policy.d.ts.map +1 -0
  825. package/dist/src/schema/reserved-tags-policy.js +34 -0
  826. package/dist/src/schema/reserved-tags-policy.js.map +1 -0
  827. package/dist/src/schema/reserved-tags.d.ts +170 -0
  828. package/dist/src/schema/reserved-tags.d.ts.map +1 -0
  829. package/dist/src/schema/reserved-tags.js +507 -0
  830. package/dist/src/schema/reserved-tags.js.map +1 -0
  831. package/dist/src/schema/schema-differ.d.ts +158 -2
  832. package/dist/src/schema/schema-differ.d.ts.map +1 -1
  833. package/dist/src/schema/schema-differ.js +1460 -78
  834. package/dist/src/schema/schema-differ.js.map +1 -1
  835. package/dist/src/schema/schema-hasher.d.ts +8 -3
  836. package/dist/src/schema/schema-hasher.d.ts.map +1 -1
  837. package/dist/src/schema/schema-hasher.js +22 -2
  838. package/dist/src/schema/schema-hasher.js.map +1 -1
  839. package/dist/src/schema/schema.d.ts +25 -1
  840. package/dist/src/schema/schema.d.ts.map +1 -1
  841. package/dist/src/schema/schema.js +36 -2
  842. package/dist/src/schema/schema.js.map +1 -1
  843. package/dist/src/schema/table.d.ts +259 -10
  844. package/dist/src/schema/table.d.ts.map +1 -1
  845. package/dist/src/schema/table.js +309 -26
  846. package/dist/src/schema/table.js.map +1 -1
  847. package/dist/src/schema/unique-enforcement.d.ts +78 -0
  848. package/dist/src/schema/unique-enforcement.d.ts.map +1 -0
  849. package/dist/src/schema/unique-enforcement.js +93 -0
  850. package/dist/src/schema/unique-enforcement.js.map +1 -0
  851. package/dist/src/schema/view.d.ts +83 -2
  852. package/dist/src/schema/view.d.ts.map +1 -1
  853. package/dist/src/schema/view.js +67 -1
  854. package/dist/src/schema/view.js.map +1 -1
  855. package/dist/src/schema/window-function.d.ts +9 -1
  856. package/dist/src/schema/window-function.d.ts.map +1 -1
  857. package/dist/src/schema/window-function.js.map +1 -1
  858. package/dist/src/types/temporal-types.d.ts.map +1 -1
  859. package/dist/src/types/temporal-types.js +71 -36
  860. package/dist/src/types/temporal-types.js.map +1 -1
  861. package/dist/src/util/comparison.d.ts +24 -0
  862. package/dist/src/util/comparison.d.ts.map +1 -1
  863. package/dist/src/util/comparison.js +34 -0
  864. package/dist/src/util/comparison.js.map +1 -1
  865. package/dist/src/util/mutation-statement.d.ts.map +1 -1
  866. package/dist/src/util/mutation-statement.js +4 -1
  867. package/dist/src/util/mutation-statement.js.map +1 -1
  868. package/dist/src/util/serialization.d.ts +9 -0
  869. package/dist/src/util/serialization.d.ts.map +1 -1
  870. package/dist/src/util/serialization.js +26 -0
  871. package/dist/src/util/serialization.js.map +1 -1
  872. package/dist/src/vtab/backing-host.d.ts +286 -0
  873. package/dist/src/vtab/backing-host.d.ts.map +1 -0
  874. package/dist/src/vtab/backing-host.js +118 -0
  875. package/dist/src/vtab/backing-host.js.map +1 -0
  876. package/dist/src/vtab/best-access-plan.d.ts +21 -0
  877. package/dist/src/vtab/best-access-plan.d.ts.map +1 -1
  878. package/dist/src/vtab/best-access-plan.js.map +1 -1
  879. package/dist/src/vtab/capabilities.d.ts +5 -5
  880. package/dist/src/vtab/capabilities.d.ts.map +1 -1
  881. package/dist/src/vtab/mapping-advertisement.d.ts +163 -0
  882. package/dist/src/vtab/mapping-advertisement.d.ts.map +1 -0
  883. package/dist/src/vtab/mapping-advertisement.js +2 -0
  884. package/dist/src/vtab/mapping-advertisement.js.map +1 -0
  885. package/dist/src/vtab/memory/index.d.ts +64 -4
  886. package/dist/src/vtab/memory/index.d.ts.map +1 -1
  887. package/dist/src/vtab/memory/index.js +119 -12
  888. package/dist/src/vtab/memory/index.js.map +1 -1
  889. package/dist/src/vtab/memory/layer/base.d.ts +38 -1
  890. package/dist/src/vtab/memory/layer/base.d.ts.map +1 -1
  891. package/dist/src/vtab/memory/layer/base.js +112 -24
  892. package/dist/src/vtab/memory/layer/base.js.map +1 -1
  893. package/dist/src/vtab/memory/layer/manager.d.ts +291 -4
  894. package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
  895. package/dist/src/vtab/memory/layer/manager.js +1050 -91
  896. package/dist/src/vtab/memory/layer/manager.js.map +1 -1
  897. package/dist/src/vtab/memory/layer/plan-filter.d.ts.map +1 -1
  898. package/dist/src/vtab/memory/layer/plan-filter.js +35 -6
  899. package/dist/src/vtab/memory/layer/plan-filter.js.map +1 -1
  900. package/dist/src/vtab/memory/layer/scan-layer.d.ts.map +1 -1
  901. package/dist/src/vtab/memory/layer/scan-layer.js +66 -14
  902. package/dist/src/vtab/memory/layer/scan-layer.js.map +1 -1
  903. package/dist/src/vtab/memory/layer/scan-plan.d.ts +14 -0
  904. package/dist/src/vtab/memory/layer/scan-plan.d.ts.map +1 -1
  905. package/dist/src/vtab/memory/layer/scan-plan.js +27 -4
  906. package/dist/src/vtab/memory/layer/scan-plan.js.map +1 -1
  907. package/dist/src/vtab/memory/layer/transaction.d.ts.map +1 -1
  908. package/dist/src/vtab/memory/layer/transaction.js +5 -1
  909. package/dist/src/vtab/memory/layer/transaction.js.map +1 -1
  910. package/dist/src/vtab/memory/module.d.ts +17 -0
  911. package/dist/src/vtab/memory/module.d.ts.map +1 -1
  912. package/dist/src/vtab/memory/module.js +82 -3
  913. package/dist/src/vtab/memory/module.js.map +1 -1
  914. package/dist/src/vtab/memory/table.d.ts.map +1 -1
  915. package/dist/src/vtab/memory/table.js +15 -5
  916. package/dist/src/vtab/memory/table.js.map +1 -1
  917. package/dist/src/vtab/memory/types.d.ts +20 -2
  918. package/dist/src/vtab/memory/types.d.ts.map +1 -1
  919. package/dist/src/vtab/memory/utils/predicate.d.ts.map +1 -1
  920. package/dist/src/vtab/memory/utils/predicate.js +46 -24
  921. package/dist/src/vtab/memory/utils/predicate.js.map +1 -1
  922. package/dist/src/vtab/memory/utils/primary-key-encode.d.ts +31 -0
  923. package/dist/src/vtab/memory/utils/primary-key-encode.d.ts.map +1 -0
  924. package/dist/src/vtab/memory/utils/primary-key-encode.js +101 -0
  925. package/dist/src/vtab/memory/utils/primary-key-encode.js.map +1 -0
  926. package/dist/src/vtab/memory/utils/primary-key.d.ts +8 -0
  927. package/dist/src/vtab/memory/utils/primary-key.d.ts.map +1 -1
  928. package/dist/src/vtab/memory/utils/primary-key.js +12 -5
  929. package/dist/src/vtab/memory/utils/primary-key.js.map +1 -1
  930. package/dist/src/vtab/module.d.ts +203 -4
  931. package/dist/src/vtab/module.d.ts.map +1 -1
  932. package/dist/src/vtab/table.d.ts +9 -0
  933. package/dist/src/vtab/table.d.ts.map +1 -1
  934. package/dist/src/vtab/table.js.map +1 -1
  935. package/package.json +6 -5
@@ -0,0 +1,1038 @@
1
+ /**
2
+ * Coverage prover — recognizes when an explicit materialized view *covers* a
3
+ * UNIQUE constraint, i.e. its materialized row set is observation-equivalent to
4
+ * the set of rows the constraint governs, keyed so a point lookup answers the
5
+ * uniqueness question. Pure analysis: it records a constraint↔structure link
6
+ * (see `runtime/emit/materialized-view.ts`); **nothing enforces through the MV's
7
+ * backing table in this ticket** (that needs row-time write-through maintenance
8
+ * — see `docs/materialized-views.md` § Covering structures, the soundness note).
9
+ *
10
+ * Shape — the body, after optimization, walks down to a single constrained base
11
+ * table `T` through a chain of:
12
+ *
13
+ * TableReference(T) → optional Filter(P) → Project(...) → optional Sort
14
+ *
15
+ * (physical access nodes such as IndexScan / SeqScan are transparent links in
16
+ * the chain). A binary **join** is admitted when `T` provably contributes
17
+ * *exactly one* MV row per governed `T` row — see the 1:1 decomposition below.
18
+ * Aggregation, DISTINCT, set operations, `FanOutLookupJoin`, and `AsofScan` are
19
+ * always `NotCovers('shape')`.
20
+ *
21
+ * Soundness is paramount: a false `Covers` would (once the lens layer routes
22
+ * enforcement through the structure) silently miss conflicts. Every check is
23
+ * conservative — a false `NotCovers` only forgoes an optimization.
24
+ *
25
+ * ---
26
+ *
27
+ * **The 1:1 join decomposition.** "Exactly one MV row per governed `T` row"
28
+ * splits into two independent obligations, each proven by a distinct surface:
29
+ *
30
+ * - **No row loss (≥1).** Proven one of two ways during the plan walk:
31
+ *
32
+ * 1. *Row preservation* — `T` sits on the row-*preserving* side of the join:
33
+ * a `left` join with `T` in the left subtree, or a `right` join with `T`
34
+ * in the right subtree.
35
+ * 2. *Referential integrity* — an `inner`/`cross` join whose equi-pairs are
36
+ * an inclusion dependency from the `T`-side relation to the lookup table's
37
+ * **primary key**, over a lookup side that exposes the parent's *full* row
38
+ * set (`innerJoinRetainsConstrainedTable`). Enforced RI then makes every
39
+ * `T` row match exactly one lookup row, so the inner join loses nothing.
40
+ * This obligation is now **IND-derived** (Wave 2): it first consults the
41
+ * propagated `PhysicalProperties.inds` surface on the `T`-side subtree
42
+ * (`indDerivedNoRowLoss`) and falls back to the original structural
43
+ * NOT-NULL-FK-on-`T` check (`lookupCoveringFK`, `!match.nullable`) when no
44
+ * IND discharges it. Both gate on the same preconditions, so they agree on
45
+ * every single-FK shape; the IND path additionally proves no-row-loss
46
+ * across multi-hop FK chains (`T → M → P`) whose threaded IND a single
47
+ * `lookupCoveringFK` call cannot see. Both lean on the engine treating
48
+ * declared FKs as inclusion dependencies — see the RI soundness note below.
49
+ *
50
+ * Every other join type/position (`inner`/`cross` *without* a covering FK/IND;
51
+ * `semi`/`anti` filter; `full` injects lookup-only rows; `T` on the dropping
52
+ * side) is rejected as `shape`. FDs encode uniqueness, not existence, so
53
+ * obligation (1) cannot be FD-derived; obligation (2) is discharged from the
54
+ * propagated IND surface (the Wave-1 over-claim-free guarantee licenses trusting
55
+ * it) with the structural FK-schema read as fallback.
56
+ *
57
+ * - **No fan-out (≤1).** `T`'s primary key must be a unique key of the
58
+ * **topmost join's output relation**, read through `isUnique`. The optimizer
59
+ * propagates join key-preservation into the join's `physical.fds`
60
+ * (`analyzeJoinKeyCoverage` → `propagateJoinFds`): for `T LEFT JOIN L on
61
+ * T.fk = L.ukey` it emits `T.pk → all_join_cols` *iff* the equi-pairs cover a
62
+ * unique key of `L`, i.e. iff each `T` row matches ≤1 `L` row. The moment the
63
+ * lookup side can multiply a `T` row, no preserved-key FD is emitted and
64
+ * `T.pk` is not a superkey of the join output ⇒ `NotCovers('fanout')`.
65
+ *
66
+ * **Why the join frame, not the projected `root`.** The check is deliberately
67
+ * against the topmost join node, where the lookup columns are still present.
68
+ * A fanning `left` join still carries `T`'s own PK FD `T.pk → T-cols` (from
69
+ * the left input's `physical.fds`); once the lookup columns are *projected
70
+ * away* in `root`, that FD would make `T.pk` a derived key of the narrowed
71
+ * relation and silently mask the fan-out (the duplicate `T` rows survive
72
+ * projection without `DISTINCT`). At the join frame the retained lookup
73
+ * columns witness the fan-out, so `isUnique` is faithful regardless of what
74
+ * the projection keeps.
75
+ *
76
+ * Both obligations are required and neither implies the other: a `left` join to
77
+ * a *non-unique* lookup key is row-preserving but fans out (caught by the fan-out
78
+ * gate); an `inner` join to a unique *non-FK* (or nullable-FK) lookup key does
79
+ * not fan out but can lose `T` rows (caught by the no-row-loss gate). A NOT-NULL
80
+ * FK→PK inner join satisfies both at once: the FK target is the PK, so it is
81
+ * unique (no fan-out) *and* every `T` row matches (no row loss).
82
+ *
83
+ * **Referential-integrity soundness (load-bearing).** Obligation (2) is sound
84
+ * only because Quereus *enforces* referential integrity: `pragma foreign_keys`
85
+ * defaults on, and the optimizer treats every declared FK as a hard inclusion
86
+ * dependency (`child.fk ⊆ parent.pk` — see `util/ind-utils.ts`). The INNER
87
+ * branch of `rule-join-elimination` already relies on exactly this invariant to
88
+ * drop an FK→PK join, so admitting the same shape here introduces no *new*
89
+ * assumption. If FKs were advisory — or RI is disabled and orphan child rows are
90
+ * inserted — both this admit path *and* inner join elimination would be unsound
91
+ * together; that is a global optimizer assumption, not one this prover owns.
92
+ *
93
+ * **NOT the `extractBindings` `'row'` classification.** A tempting-but-wrong
94
+ * signal is the binding extractor's `'row'` class (`binding-extractor.ts`,
95
+ * `analyzeRowSpecific`). That is *equality-pinned* — it fires only when equality
96
+ * constraints cover `T`'s key at the reference, and reports a bare join scan as
97
+ * `'global'`. The sound realization of "exactly one MV row per source row" is
98
+ * `T`'s primary key being preserved as a key of the join output — the FD-surface
99
+ * fact `isUnique` already consumes — so `binding-extractor.ts` needs no change.
100
+ *
101
+ * The v1 projection / ordering / predicate checks are frame-correct for a join
102
+ * body: the covering columns all belong to `T` (UC + PK), the lookup-side
103
+ * attributes simply are not in `baseAttrToCol` and are ignored, and the join `ON`
104
+ * lives in the AST `from` clause (not `WHERE`). The AST `ORDER BY` / `WHERE`
105
+ * column resolution is **qualifier-aware** (`makeBodyColumnResolver`): `alias.col`
106
+ * resolves to a `T` column only when `alias` denotes `T`'s reference, and a bare
107
+ * `col` only when unambiguous across the join's sources. A term on a lookup-side
108
+ * column therefore fails on its own terms (`ordering-mismatch` for an `ORDER BY`,
109
+ * `predicate-entailment` for a `WHERE`) rather than mis-mapping onto a same-named
110
+ * `T` column — so a 1:1 join whose lookup key shares a UC column name (e.g.
111
+ * `line_items ⋈ products on l.sku = p.sku`) now covers, instead of being rejected
112
+ * by the former bare-name collision guard.
113
+ *
114
+ * **Cross-schema qualifier resolution is (schema, table)-aware.** Qualifier
115
+ * matching keys on the reference's `(schema, table)` pair, not its table name
116
+ * alone: a `schema.table.col` ORDER BY / WHERE term whose *table* name equals
117
+ * `T`'s but whose *schema* denotes a different schema (e.g. a lookup `s2.t` joined
118
+ * against base `main.t`, both named `t`) resolves to `undefined` instead of
119
+ * collapsing onto base `T`'s same-named column and yielding a false `Covers`. This
120
+ * is **defense-in-depth**: the binder rejects *every* 3-part `schema.table.column`
121
+ * reference in expression context before the prover runs (see
122
+ * `AliasedScope.resolveSymbol` / `resolveColumn`), so a real materialized view can
123
+ * never carry such a term — the guard is reachable only by feeding `proveCoverage`
124
+ * a hand-built `selectAst` (which is what the dedicated unit test does). The two
125
+ * SQL-reachable orderings (`order by uc` bare, `order by t.uc` 2-part) both
126
+ * resolve to base `T`'s column, a genuine cover, and are unchanged.
127
+ *
128
+ * **Join elimination, not handled here.** When the optimizer eliminates a
129
+ * key-preserving lookup join (lookup columns unprojected + FK→PK alignment, see
130
+ * `rule-join-elimination.ts`) the body collapses to a single-source chain and the
131
+ * v1 path covers it with no join-specific code. This module handles the residual
132
+ * cases where the join survives the optimizer but is still provably 1:1.
133
+ *
134
+ * Inner/cross covering via enforced referential integrity is handled (obligation
135
+ * (2) above). Full-outer covering remains deferred (it injects lookup-only rows
136
+ * that have no governed `T` row).
137
+ *
138
+ * ---
139
+ *
140
+ * Two different "coverage" questions live in this module; keep them apart:
141
+ *
142
+ * 1. **Base-table covering** (`proveCoverage`, above) — does an explicit MV's
143
+ * materialized row set cover a `unique` constraint on a *base table* `T`,
144
+ * keyed so a point lookup answers the uniqueness question and the base PK is
145
+ * reconstructible so a conflicting row can be identified? Requires literal
146
+ * projection of every UC column + the source PK, an `order by` permutation of
147
+ * the UC columns, and predicate/NULL-skip alignment.
148
+ *
149
+ * 2. **Output-relation effective key** (`proveEffectiveKeyUnique`, below) — is
150
+ * the body's *own output relation* provably unique on the declared key
151
+ * columns, via its effective key (declared keys, FD-closure-derived keys, or
152
+ * the all-columns/set fallback, all read through the unified `isUnique`
153
+ * surface)? This is the obligation primitive the lens prover consumes for its
154
+ * `obligation: proved` class — e.g. a `group by x, y` body whose output is
155
+ * intrinsically one row per `(x, y)` vacuously satisfies a logical
156
+ * `unique(x, y)`, so no runtime enforcement structure is needed.
157
+ *
158
+ * **Why (2) is NOT folded into (1).** An FD-derived output key cannot prove a
159
+ * *base-table* constraint, and folding it in would be unsound. A `group by x`
160
+ * body's output is *always* unique on `x` — whether or not `T` satisfies
161
+ * `unique(x)` — because grouping collapses base-row duplicates: two base rows
162
+ * with `x = 5` (a base-constraint violation) still yield exactly one output row
163
+ * for `x = 5`. Output-key uniqueness is therefore silent about base duplicates;
164
+ * that masking is the whole problem. Aggregating bodies also drop the base PK, so
165
+ * the "identify the conflicting base row" half of the v1 covering contract (for
166
+ * REPLACE / IGNORE conflict resolution) is unrecoverable. (2) is thus a proof
167
+ * about the *derived (output) relation's own* constraint, deliberately kept out
168
+ * of `proveCoverage` to preserve the v1 soundness boundary and leave the
169
+ * eager-link path (`linkCoveredUniqueConstraints`) untouched. Whether a covering
170
+ * *enforcement* structure can ever be FD-derived (detection-only, ABORT) is a
171
+ * separate concern of the row-time-enforcement / lens tickets, not this one.
172
+ */
173
+ import { PlanNodeType } from '../nodes/plan-node-type.js';
174
+ import { TableReferenceNode, ColumnReferenceNode } from '../nodes/reference.js';
175
+ import { FilterNode } from '../nodes/filter.js';
176
+ import { JoinNode, extractEquiPairsFromCondition } from '../nodes/join-node.js';
177
+ import { BloomJoinNode } from '../nodes/bloom-join-node.js';
178
+ import { MergeJoinNode } from '../nodes/merge-join-node.js';
179
+ import { SeqScanNode, IndexScanNode } from '../nodes/table-access-nodes.js';
180
+ import { AliasNode } from '../nodes/alias-node.js';
181
+ import { SortNode } from '../nodes/sort.js';
182
+ import { RetrieveNode } from '../nodes/retrieve-node.js';
183
+ import { BinaryOpNode } from '../nodes/scalar.js';
184
+ import { CapabilityDetectors } from '../framework/characteristics.js';
185
+ import { recognizeConjunctiveClauses, guardClausesEntail } from './partial-unique-extraction.js';
186
+ import { normalizePredicate } from './predicate-normalizer.js';
187
+ import { isUnique } from '../util/fd-utils.js';
188
+ import { lookupCoveringFK } from '../util/ind-utils.js';
189
+ const COVERS = { covers: true };
190
+ function notCovers(reason) {
191
+ return { covers: false, reason };
192
+ }
193
+ /** Shared empty lookup-name set for single-source bodies (no join frame). */
194
+ const EMPTY_NAMES = new Set();
195
+ /**
196
+ * Row-preserving / single-source pass-through node types that may appear between
197
+ * the projection and the table reference after optimization. They neither change
198
+ * which base rows are present (Filter is handled separately — its predicate is
199
+ * captured) nor split into multiple sources.
200
+ *
201
+ * Row-*dropping* nodes are deliberately excluded — notably `OrdinalSlice` (a
202
+ * pushed-down LIMIT/OFFSET) and `LimitOffset` itself, which materialize only a
203
+ * prefix of the governed rows and so can never cover. A row cap is rejected up
204
+ * front from the AST (see `proveCoverage`); the exclusion here is the structural
205
+ * backstop should the cap ever reach the plan walk by another path.
206
+ */
207
+ const PASS_THROUGH = new Set([
208
+ PlanNodeType.Sort,
209
+ PlanNodeType.Project,
210
+ PlanNodeType.Retrieve,
211
+ PlanNodeType.Alias,
212
+ // A lens-boundary marker is a pure row-preserving single-source pass-through
213
+ // (it only contributes FDs); transparent to the coverage shape walk.
214
+ PlanNodeType.AssertedKeys,
215
+ PlanNodeType.SeqScan,
216
+ PlanNodeType.IndexScan,
217
+ PlanNodeType.IndexSeek,
218
+ PlanNodeType.TableSeek,
219
+ ]);
220
+ /**
221
+ * Binary (left/right/inner/cross/semi/anti) join node types the shape walk may
222
+ * descend through. These all implement `JoinCapable` (logical `JoinNode`,
223
+ * `BloomJoinNode` = `HashJoin`, `MergeJoinNode`), so `CapabilityDetectors.isJoin`
224
+ * exposes `getJoinType` / `getLeftSource` / `getRightSource`. `FanOutLookupJoin`
225
+ * and `AsofScan` are deliberately absent — they are not `JoinCapable` and fall
226
+ * through to the walk's `shape` rejection.
227
+ */
228
+ const BINARY_JOIN_TYPES = new Set([
229
+ PlanNodeType.Join,
230
+ PlanNodeType.NestedLoopJoin,
231
+ PlanNodeType.HashJoin,
232
+ PlanNodeType.MergeJoin,
233
+ ]);
234
+ /**
235
+ * Decides whether `mv` covers `uc` on `baseTable`. `root` is the optimized body
236
+ * relation (`db.getPlan(body).getRelations()[0]`); the body's declared `order by`
237
+ * comes from `mv.selectAst`. See the module doc for the recognition rules.
238
+ */
239
+ export function proveCoverage(root, mv, uc, baseTable, opts = {}) {
240
+ const bodyAst = mv.derivation.selectAst;
241
+ // ---- Row cap: a LIMIT/OFFSET body materializes only a prefix of the
242
+ // governed rows, so it can never be observation-equivalent. Read from the
243
+ // AST (the faithful source): the optimizer may push the cap into an
244
+ // `OrdinalSlice` over an ordinal-seek-capable leaf, which the shape walk
245
+ // would otherwise traverse as a transparent link. ----
246
+ if (bodyAst.type === 'select' && (bodyAst.limit !== undefined || bodyAst.offset !== undefined)) {
247
+ return notCovers('shape');
248
+ }
249
+ // ---- Shape: walk down to the constrained base table `T` via the shared
250
+ // descent (`walkToConstrainedBase`) — single-source pass-throughs are
251
+ // transparent links and a binary join is descended into `T`'s side iff
252
+ // it provably keeps every governed `T` row (the no-row-loss obligation).
253
+ // The topmost join (if any) is captured for the fan-out gate below. The
254
+ // *predicate* is taken from the AST further down (the optimizer may absorb
255
+ // a WHERE into an index range seek and drop the FilterNode). ----
256
+ const walk = walkToConstrainedBase(root, baseTable, opts);
257
+ if (!walk.ok)
258
+ return notCovers(walk.reason);
259
+ const tableRef = walk.tableRef;
260
+ const topJoin = walk.topJoin;
261
+ // ---- Projection coverage: map output attributes back to base columns via
262
+ // stable attribute IDs (a bare column reference preserves the source
263
+ // attribute's id through Project/Sort/scan nodes), keeping the first
264
+ // covering output index for the collation gate below. ----
265
+ const baseAttrToCol = new Map();
266
+ tableRef.getAttributes().forEach((attr, i) => baseAttrToCol.set(attr.id, i));
267
+ const coveredBaseCols = new Map();
268
+ root.getAttributes().forEach((attr, outIdx) => {
269
+ const col = baseAttrToCol.get(attr.id);
270
+ if (col !== undefined && !coveredBaseCols.has(col))
271
+ coveredBaseCols.set(col, outIdx);
272
+ });
273
+ // ---- Collation gate: the projected output column must carry the SAME collation
274
+ // as the constrained base column. The backing key inherits the OUTPUT
275
+ // collation (`buildBackingTableSchema`), so a mismatched link would let a
276
+ // coarser-keyed backing (e.g. NOCASE) answer a finer (BINARY) constraint's
277
+ // uniqueness question — collation-equal/byte-different rows would merge in
278
+ // the structure while the constraint must keep them distinct. Defense-in-depth
279
+ // today: a collation-changing projection mints a fresh attribute id and
280
+ // already fails the coverage maps above; this gate makes the requirement
281
+ // explicit so no future id-preserving surface can link across a mismatch. ----
282
+ const outputColumns = root.getType().columns;
283
+ const collationMatches = (baseCol) => {
284
+ const outIdx = coveredBaseCols.get(baseCol);
285
+ if (outIdx === undefined)
286
+ return true; // absence is the missing-*-column reject's job
287
+ const outColl = (outputColumns[outIdx]?.type.collationName ?? 'BINARY').toUpperCase();
288
+ const baseColl = (baseTable.columns[baseCol]?.collation ?? 'BINARY').toUpperCase();
289
+ return outColl === baseColl;
290
+ };
291
+ for (const col of uc.columns) {
292
+ if (!coveredBaseCols.has(col))
293
+ return notCovers('missing-uc-column');
294
+ if (!collationMatches(col))
295
+ return notCovers('collation-mismatch');
296
+ }
297
+ for (const pk of baseTable.primaryKeyDefinition) {
298
+ if (!coveredBaseCols.has(pk.index))
299
+ return notCovers('missing-pk-column');
300
+ if (!collationMatches(pk.index))
301
+ return notCovers('collation-mismatch');
302
+ }
303
+ // ---- Lookup-side column names in the join's output frame (a `T` attribute is
304
+ // one whose id is a key of `baseAttrToCol`); empty for a single-source
305
+ // body. Feeds the qualifier-aware AST resolver's unqualified-name
306
+ // ambiguity check below. ----
307
+ const lookupNames = topJoin !== undefined ? lookupColumnNames(topJoin, baseAttrToCol) : EMPTY_NAMES;
308
+ // ---- Multi-source (join body) no-fan-out gate: `T`'s primary key must remain
309
+ // a unique key of the topmost join's output. Vacuous — and v1 behavior
310
+ // unchanged — for a single-source chain (`topJoin` absent). ----
311
+ if (topJoin !== undefined) {
312
+ const noFanout = proveJoinNoFanout(topJoin, tableRef, baseTable);
313
+ if (!noFanout.covers)
314
+ return noFanout;
315
+ }
316
+ // ---- Qualifier-aware AST column resolution. An ORDER BY / WHERE term
317
+ // `alias.col` resolves to a base-table `T` column only when `alias`
318
+ // denotes `T`'s reference; an unqualified `col` only when `T` has it and
319
+ // no lookup-side column shares the name. A term resolving to a lookup
320
+ // column is then handled on its own terms below (ORDER BY ⇒
321
+ // `ordering-mismatch`, WHERE ⇒ `predicate-entailment`), never mis-mapped
322
+ // onto `T`. For a single-source body this is plain bare-name resolution. ----
323
+ const resolveBodyColumn = makeBodyColumnResolver(bodyAst, baseTable, lookupNames);
324
+ // ---- Ordering: the body's declared ORDER BY columns must be a permutation of
325
+ // the UC columns. The prover never invents an ordering — a missing one
326
+ // fails. Read from the body AST rather than `mv.ordering`: the optimizer
327
+ // drops the Sort (leaving `physical.ordering` empty) whenever an index
328
+ // scan already supplies the order, so the AST is the faithful source. ----
329
+ const orderingBaseCols = bodyOrderByColumns(bodyAst, resolveBodyColumn);
330
+ if (orderingBaseCols === undefined)
331
+ return notCovers('ordering-mismatch');
332
+ if (!isPermutation(orderingBaseCols, uc.columns))
333
+ return notCovers('ordering-mismatch');
334
+ // ---- Predicate alignment: the materialized set (rows where the body's WHERE
335
+ // holds) must equal the governed set (rows where uc.predicate holds,
336
+ // NULL-excluded). The WHERE is read from the AST (see shape note). ----
337
+ const bodyWhere = bodyAst.type === 'select' ? bodyAst.where : undefined;
338
+ return provePredicateAlignment(bodyWhere, uc, baseTable, resolveBodyColumn);
339
+ }
340
+ /**
341
+ * Walk `root` down to the constrained base table `T`, proving **no row loss**
342
+ * at every join descended through. Single-source pass-throughs (Filter + the
343
+ * physical access nodes in {@link PASS_THROUGH}) are transparent links; a binary
344
+ * join is descended into `T`'s side iff `T` provably keeps every governed row:
345
+ *
346
+ * - **row-preservation** — `T` on the preserving side of an outer join
347
+ * (`left`→left subtree, `right`→right subtree); or
348
+ * - **referential integrity** — an `inner`/`cross` join whose equi-pairs are a
349
+ * NOT-NULL FK / non-null IND from `T` to the lookup table's PK, so enforced RI
350
+ * makes every `T` row match exactly one lookup row
351
+ * (`innerJoinRetainsConstrainedTable`).
352
+ *
353
+ * Every other join type/position (a fanning lookup, `semi`/`anti`, `full`, `T`
354
+ * on the dropping side, a self-join, aggregation/DISTINCT/set-op) returns
355
+ * `{ ok: false, reason: 'shape' }`. The **no-fan-out** (≤1) obligation is NOT
356
+ * checked here — callers run {@link proveJoinNoFanout} on the returned `topJoin`
357
+ * (see {@link proveOneToOneJoin}); `proveCoverage` keeps its own fan-out gate so
358
+ * its diagnostic ordering is unchanged. Shared by `proveCoverage` and the
359
+ * materialized-view 1:1-join gate so the join soundness logic lives in one place.
360
+ */
361
+ export function walkToConstrainedBase(root, baseTable, opts = {}) {
362
+ let tableRef;
363
+ let topJoin;
364
+ let node = root;
365
+ while (node) {
366
+ if (node instanceof TableReferenceNode) {
367
+ tableRef = node;
368
+ break;
369
+ }
370
+ if (BINARY_JOIN_TYPES.has(node.nodeType) && CapabilityDetectors.isJoin(node)) {
371
+ const left = node.getLeftSource();
372
+ const right = node.getRightSource();
373
+ const joinType = node.getJoinType();
374
+ const leftHasT = subtreeContainsConstrainedTable(left, baseTable);
375
+ const rightHasT = subtreeContainsConstrainedTable(right, baseTable);
376
+ // `T` on both sides (self-join) or neither ⇒ ambiguous / not our table.
377
+ if (leftHasT === rightHasT)
378
+ return { ok: false, reason: 'shape' };
379
+ const tSide = leftHasT ? left : right;
380
+ const lookupSide = leftHasT ? right : left;
381
+ const rowPreserving = (leftHasT && joinType === 'left') || (rightHasT && joinType === 'right');
382
+ if (!rowPreserving) {
383
+ const fkRetained = (joinType === 'inner' || joinType === 'cross')
384
+ && innerJoinRetainsConstrainedTable(node, tSide, lookupSide, baseTable, opts.structuralOnly === true);
385
+ if (!fkRetained)
386
+ return { ok: false, reason: 'shape' };
387
+ }
388
+ if (topJoin === undefined)
389
+ topJoin = node;
390
+ node = tSide;
391
+ continue;
392
+ }
393
+ if (node instanceof FilterNode || PASS_THROUGH.has(node.nodeType)) {
394
+ const relations = node.getRelations();
395
+ if (relations.length !== 1)
396
+ return { ok: false, reason: 'shape' };
397
+ node = relations[0];
398
+ continue;
399
+ }
400
+ return { ok: false, reason: 'shape' };
401
+ }
402
+ if (!tableRef)
403
+ return { ok: false, reason: 'shape' };
404
+ if (tableRef.tableSchema.name.toLowerCase() !== baseTable.name.toLowerCase()
405
+ || tableRef.tableSchema.schemaName.toLowerCase() !== baseTable.schemaName.toLowerCase()) {
406
+ return { ok: false, reason: 'shape' };
407
+ }
408
+ return { ok: true, tableRef, topJoin };
409
+ }
410
+ /**
411
+ * Prove that `root`'s body is **provably 1:1 on `baseTable`** — exactly one
412
+ * output row per governed `T` row. Composes the two independent obligations the
413
+ * coverage prover splits a 1:1 join into: no-row-loss (≥1, via
414
+ * {@link walkToConstrainedBase}'s descent) and no-fan-out (≤1, via
415
+ * {@link proveJoinNoFanout} on the captured `topJoin`). For a single-source body
416
+ * (no join) the fan-out gate is vacuous and this succeeds iff the chain walks to
417
+ * `T`. The materialized-view 1:1-join gate calls this on the analyzed body to
418
+ * admit a join shape; `proveCoverage` reuses the same primitives directly so the
419
+ * join soundness logic is not duplicated.
420
+ */
421
+ export function proveOneToOneJoin(root, baseTable, opts = {}) {
422
+ const walk = walkToConstrainedBase(root, baseTable, opts);
423
+ if (!walk.ok)
424
+ return walk;
425
+ if (walk.topJoin !== undefined) {
426
+ const noFanout = proveJoinNoFanout(walk.topJoin, walk.tableRef, baseTable);
427
+ if (!noFanout.covers)
428
+ return { ok: false, reason: noFanout.reason };
429
+ }
430
+ return walk;
431
+ }
432
+ /**
433
+ * "Body proves it": true iff the body's output relation is provably unique on
434
+ * `keyColumns` (output-column indices) via its effective key — declared keys,
435
+ * FD-closure-derived keys, or the set/all-columns fallback, all read through the
436
+ * unified `isUnique` surface. This is the obligation primitive the lens prover
437
+ * consumes for its `obligation: proved` class (e.g. a `group by x, y` body
438
+ * proving a logical `unique(x, y)`).
439
+ *
440
+ * `root` MUST be the optimized body relation (the same node `proveCoverage`
441
+ * receives: `db.getPlan(body).getRelations()[0]`), so `physical.fds` is
442
+ * populated — the group-key FD (`propagateAggregateFds`) and projected
443
+ * source-key FDs live there.
444
+ *
445
+ * Soundness notes (why the v1 base-table covering checks do NOT apply here):
446
+ * - Ordering: irrelevant — a proof of intrinsic uniqueness needs no ordered
447
+ * point-lookup path, so the canonical `group by` body (no ORDER BY) qualifies.
448
+ * - PK reconstructibility / observation-equivalence: irrelevant — there is no
449
+ * enforcement and no base row to identify; the constraint is on the output.
450
+ * - NULL-skip: composes trivially by subsumption. `isUnique` proves *strict*
451
+ * key-uniqueness (NULL treated as a value); SQL `unique` is NULL-permissive
452
+ * (weaker), so strict-unique ⟹ `unique` holds. No extra NULL handling.
453
+ * - Superkey semantics are correct: if the body's real key is a subset of
454
+ * `keyColumns`, the (stronger) constraint on the smaller set still implies the
455
+ * declared one — `isUnique` already returns true for any superset of a key.
456
+ *
457
+ * `keyColumns` are **body-output** column indices; the lens prover owns the
458
+ * logical-column → output-column mapping (this primitive does no base-table
459
+ * attribute-id translation — that was a v1 mechanism for the base frame and does
460
+ * not apply to the output frame). Delegates uniqueness entirely to `isUnique`
461
+ * (DRY); the value this adds is the named obligation seam, the diagnostic result
462
+ * shape, and the load-bearing soundness documentation above.
463
+ */
464
+ export function proveEffectiveKeyUnique(root, keyColumns) {
465
+ const columnCount = root.getType().columns.length;
466
+ for (const c of keyColumns) {
467
+ if (c < 0 || c >= columnCount)
468
+ return { proved: false, reason: 'out-of-frame' };
469
+ }
470
+ return isUnique(keyColumns, root) ? { proved: true } : { proved: false, reason: 'not-a-key' };
471
+ }
472
+ /**
473
+ * Verifies the body predicate `P` is observation-equivalent (over the governed
474
+ * rows) to the constraint's scope:
475
+ *
476
+ * - soundness — `P` entails every required clause (`uc.predicate` clauses
477
+ * plus an `is not null` per nullable UC column), so the materialized set is
478
+ * contained in the governed set; and
479
+ * - completeness — `P` adds no restriction beyond those clauses (a NOT-NULL on
480
+ * any UC column is always allowed, since UNIQUE already ignores NULL rows),
481
+ * so the materialized set is not a strict subset that would miss conflicts.
482
+ *
483
+ * `resolveBodyColumn` resolves the body WHERE's column references (qualifier-aware
484
+ * for join bodies). `uc.predicate` is a constraint on `T`, so it always resolves
485
+ * by bare name against `baseTable` (the default).
486
+ */
487
+ function provePredicateAlignment(bodyWhere, uc, baseTable, resolveBodyColumn) {
488
+ // Required clauses (the governed scope).
489
+ const requiredClauses = [];
490
+ if (uc.predicate) {
491
+ const ucClauses = recognizeConjunctiveClauses(uc.predicate, baseTable);
492
+ if (ucClauses === undefined)
493
+ return notCovers('predicate-entailment');
494
+ requiredClauses.push(...ucClauses);
495
+ }
496
+ const nullableUcCols = uc.columns.filter(c => baseTable.columns[c]?.notNull !== true);
497
+ for (const c of nullableUcCols) {
498
+ requiredClauses.push({ kind: 'is-null', column: c, negated: true });
499
+ }
500
+ // Recognize P. An unrecognized conjunct makes the materialized set unbounded
501
+ // from the prover's view — reject (we can prove neither containment direction).
502
+ // A WHERE term on a lookup column resolves to `undefined` via the qualifier-
503
+ // aware resolver ⇒ unrecognized ⇒ this same rejection path (predicate-entailment).
504
+ let pClauses = [];
505
+ if (bodyWhere) {
506
+ const clauses = recognizeConjunctiveClauses(bodyWhere, baseTable, resolveBodyColumn);
507
+ if (clauses === undefined) {
508
+ return notCovers(uc.predicate || nullableUcCols.length === 0 ? 'predicate-entailment' : 'missing-null-skip');
509
+ }
510
+ pClauses = clauses;
511
+ }
512
+ // Soundness: P entails every required clause (per-clause for a precise reason).
513
+ for (const rc of requiredClauses) {
514
+ if (!guardClausesEntail(pClauses, [rc])) {
515
+ return notCovers(rc.kind === 'is-null' && rc.negated ? 'missing-null-skip' : 'predicate-entailment');
516
+ }
517
+ }
518
+ // Completeness: every clause of P is allowed (entailed by the required scope,
519
+ // widened by a permissible NOT-NULL on any UC column). A restriction beyond
520
+ // that would drop governed rows and miss conflicts.
521
+ const allowedForCompleteness = [...requiredClauses];
522
+ for (const c of uc.columns) {
523
+ allowedForCompleteness.push({ kind: 'is-null', column: c, negated: true });
524
+ }
525
+ if (!guardClausesEntail(allowedForCompleteness, pClauses)) {
526
+ return notCovers('predicate-entailment');
527
+ }
528
+ return COVERS;
529
+ }
530
+ /**
531
+ * True iff `node`'s subtree contains a `TableReferenceNode` over `baseTable`
532
+ * (matched by lowercased schema + name). Walks `getRelations()` recursively, so
533
+ * it descends through physical access / Retrieve wrappers and nested joins. A
534
+ * self-join of `T` makes *both* of a join's subtrees report true — the walk
535
+ * treats that as ambiguous (`shape`).
536
+ */
537
+ function subtreeContainsConstrainedTable(node, baseTable) {
538
+ if (node instanceof TableReferenceNode) {
539
+ return node.tableSchema.name.toLowerCase() === baseTable.name.toLowerCase()
540
+ && node.tableSchema.schemaName.toLowerCase() === baseTable.schemaName.toLowerCase();
541
+ }
542
+ for (const rel of node.getRelations()) {
543
+ if (subtreeContainsConstrainedTable(rel, baseTable))
544
+ return true;
545
+ }
546
+ return false;
547
+ }
548
+ /**
549
+ * The `TableReferenceNode` over `baseTable` somewhere in `node`'s subtree, or
550
+ * `undefined`. Like `subtreeContainsConstrainedTable` but returns the node so
551
+ * `T`'s stable attribute ids can be mapped to its base column indices. (A
552
+ * self-join is already rejected upstream, so the first match is unambiguous.)
553
+ */
554
+ function findConstrainedTableRef(node, baseTable) {
555
+ if (node instanceof TableReferenceNode) {
556
+ return node.tableSchema.name.toLowerCase() === baseTable.name.toLowerCase()
557
+ && node.tableSchema.schemaName.toLowerCase() === baseTable.schemaName.toLowerCase()
558
+ ? node : undefined;
559
+ }
560
+ for (const rel of node.getRelations()) {
561
+ const found = findConstrainedTableRef(rel, baseTable);
562
+ if (found)
563
+ return found;
564
+ }
565
+ return undefined;
566
+ }
567
+ /**
568
+ * The leaf `TableReferenceNode` of `node` **iff** the path down to it exposes the
569
+ * table's *full* row set — nothing filters, seeks, limits, or deduplicates rows.
570
+ * Returns `undefined` otherwise.
571
+ *
572
+ * This is the optimized-plan analogue of `ind-utils.ts`'s
573
+ * `isRowPreservingPathToTable` (which recognizes the *logical*-plan shape:
574
+ * bare TableReference / Retrieve-of-bare-table / Alias / Sort). After physical
575
+ * access selection a full scan is a `SeqScan`/`IndexScan` over the table — so we
576
+ * additionally admit those, but only when **not range-bounded** (`rangeBoundedOn`
577
+ * unset; a bounded scan drops rows). `IndexSeek`/`TableSeek` (row-reducing
578
+ * seeks), `Filter`, `LimitOffset`, `Distinct`, `Project`, joins, aggregates, …
579
+ * all disqualify by falling through to `undefined`.
580
+ *
581
+ * Required for the inner-join FK admit path: the lookup (parent) side must
582
+ * produce the parent's full row set, else a `T` row whose parent was filtered
583
+ * out would be dropped despite the FK guarantee — re-introducing row loss.
584
+ */
585
+ function resolveFullScanTableRef(node) {
586
+ let n = node;
587
+ for (;;) {
588
+ if (n instanceof TableReferenceNode)
589
+ return n;
590
+ if (n instanceof SeqScanNode || n instanceof IndexScanNode) {
591
+ if (n.rangeBoundedOn)
592
+ return undefined;
593
+ n = n.source;
594
+ continue;
595
+ }
596
+ if (n instanceof AliasNode || n instanceof SortNode || n instanceof RetrieveNode) {
597
+ const rels = n.getRelations();
598
+ if (rels.length !== 1)
599
+ return undefined;
600
+ n = rels[0];
601
+ continue;
602
+ }
603
+ return undefined;
604
+ }
605
+ }
606
+ /**
607
+ * The count of column-to-column equality conjuncts in `cond` (after
608
+ * normalization) when `cond` is a pure conjunction of them — `a.x = b.y AND …`
609
+ * with no other operator and no non-column operand — or `undefined` otherwise.
610
+ * The inner-join no-row-loss proof needs this: a residual non-equi conjunct (or
611
+ * an equality to a literal/expression) can drop `T` rows the FK→PK guarantee
612
+ * assumes survive, so any such condition disqualifies. The count lets the caller
613
+ * confirm every conjunct produced a cross-side equi-pair (see
614
+ * `pureJoinEquiAttrPairs`): a column equality whose operands sit on the *same*
615
+ * side is a single-relation filter that `extractEquiPairsFromCondition` silently
616
+ * drops yet still restricts the join's row set.
617
+ */
618
+ function pureColumnEquiConjunctCount(cond) {
619
+ const stack = [normalizePredicate(cond)];
620
+ let count = 0;
621
+ while (stack.length) {
622
+ const n = stack.pop();
623
+ if (n instanceof BinaryOpNode) {
624
+ const op = n.expression.operator;
625
+ if (op === 'AND') {
626
+ stack.push(n.left, n.right);
627
+ continue;
628
+ }
629
+ if (op === '=' && n.left instanceof ColumnReferenceNode && n.right instanceof ColumnReferenceNode) {
630
+ count++;
631
+ continue;
632
+ }
633
+ }
634
+ return undefined;
635
+ }
636
+ return count;
637
+ }
638
+ /**
639
+ * Equi-pairs of a binary join in attribute-id form, or `undefined` when the join
640
+ * carries anything beyond an equi-only condition (which could drop `T` rows and
641
+ * so breaks the no-row-loss proof). Physical joins (`BloomJoin`/`MergeJoin`)
642
+ * pre-extract their equi-pairs and stash any remainder in `residualCondition`; a
643
+ * logical `JoinNode` carries a single `condition` that must be a pure
644
+ * AND-of-column-equalities *every one of which crosses the two join sides*. A
645
+ * same-side column equality (e.g. `c.x = c.y`) passes the pure-equi shape but is
646
+ * a single-relation filter `extractEquiPairsFromCondition` drops — so we reject
647
+ * unless the extracted cross-side pair count matches the conjunct count, rather
648
+ * than leaning on predicate pushdown to have hoisted it below the join. A bare
649
+ * cross join (no condition / no equi-pairs) yields an empty list, which the
650
+ * caller treats as "no FK to align".
651
+ */
652
+ export function pureJoinEquiAttrPairs(join) {
653
+ if (join instanceof BloomJoinNode || join instanceof MergeJoinNode) {
654
+ return join.residualCondition === undefined ? join.equiPairs : undefined;
655
+ }
656
+ if (join instanceof JoinNode) {
657
+ if (!join.condition)
658
+ return [];
659
+ const conjunctCount = pureColumnEquiConjunctCount(join.condition);
660
+ if (conjunctCount === undefined)
661
+ return undefined;
662
+ const leftAttrs = join.left.getAttributes();
663
+ const rightAttrs = join.right.getAttributes();
664
+ const pairs = extractEquiPairsFromCondition(join.condition, leftAttrs, rightAttrs)
665
+ .map(p => ({ leftAttrId: leftAttrs[p.left].id, rightAttrId: rightAttrs[p.right].id }));
666
+ // A conjunct that produced no cross-side pair is a same-side filter that
667
+ // restricts rows without aligning `T` to the lookup — disqualify.
668
+ if (pairs.length !== conjunctCount)
669
+ return undefined;
670
+ return pairs;
671
+ }
672
+ return undefined;
673
+ }
674
+ /**
675
+ * No-row-loss proof for an `inner`/`cross` join: every governed `T` row is
676
+ * retained because the join's equi-pairs are an inclusion dependency from the
677
+ * `T`-side relation to the lookup table's primary key, and Quereus enforces
678
+ * referential integrity (declared FKs are treated as inclusion dependencies; see
679
+ * the module doc's soundness note).
680
+ *
681
+ * Two preconditions are shared by both proof paths and gate up front:
682
+ * - **equi-only join** (`pureJoinEquiAttrPairs`) — a residual/non-equi conjunct
683
+ * could fail for the matched lookup row and drop the `T` row.
684
+ * - **full parent row set** (`resolveFullScanTableRef` on the lookup side) — a
685
+ * filtered/seeked lookup side could omit the parent row a `T` row references,
686
+ * re-introducing row loss regardless of any inclusion guarantee.
687
+ *
688
+ * Two interchangeable derivations then discharge the inclusion obligation:
689
+ * 1. **IND-derived** (`indDerivedNoRowLoss`, Wave 2, tried first) — a propagated
690
+ * non-`nullRejecting` IND on the `T`-side subtree whose `(cols → targetCols)`
691
+ * pairing matches the join's equi-pairs and whose target is the lookup
692
+ * parent's key. This composes across multi-hop FK chains (`T → M → P`) where
693
+ * a single `lookupCoveringFK` call sees only one hop.
694
+ * 2. **Structural fallback** (`lookupCoveringFK`, `!match.nullable`) — a NOT-NULL
695
+ * FK declared *on `T`* to the lookup table's PK. Retained verbatim so a
696
+ * missing IND never regresses an existing optimization.
697
+ *
698
+ * Both gate on the same preconditions and the same non-null inclusion to the
699
+ * parent's key, so they cannot disagree on the single-FK corpus (the seeded IND
700
+ * mirrors `lookupCoveringFK` exactly: same PK-cover validation, same nullability
701
+ * bit). The complementary no-fan-out (≤1) obligation is unchanged — it is the
702
+ * join-frame `isUnique(T.pk)` gate in `proveJoinNoFanout`, which a FK→PK join also
703
+ * satisfies (the PK side's key is covered by the equi-pairs).
704
+ */
705
+ function innerJoinRetainsConstrainedTable(join, tSide, lookupSide, baseTable, structuralOnly = false) {
706
+ const equiPairs = pureJoinEquiAttrPairs(join);
707
+ if (!equiPairs || equiPairs.length === 0)
708
+ return false;
709
+ // Shared precondition: the lookup side must expose the parent's full row set.
710
+ // COMPLETENESS LIMITATION (bushy lookup side, under-claim-safe): a bushy
711
+ // `T ⋈ (M ⋈ P)` makes `lookupSide` a join, so `resolveFullScanTableRef` returns
712
+ // undefined and the two-hop cover is silently lost (falls back to structural ⇒
713
+ // NotCovers). The empty-table PoC stays left-deep empirically, so this is
714
+ // unreachable today; a cost-based reorder on real statistics could go bushy. To
715
+ // extend: prove no-row-loss when the bushy lookup side carries a matching IND
716
+ // surface, or normalize the join to left-deep before proving — either path must
717
+ // preserve the over-claim-free guarantee.
718
+ const lookupRef = resolveFullScanTableRef(lookupSide);
719
+ if (!lookupRef)
720
+ return false;
721
+ // (1) IND-derived path (Wave 2), tried first — proves multi-hop chains the
722
+ // single-call structural check below cannot see. The `structuralOnly`
723
+ // verification seam disables it so the equivalence test can assert the two
724
+ // derivations agree on every single-FK shape.
725
+ if (!structuralOnly && indDerivedNoRowLoss(equiPairs, tSide, lookupRef))
726
+ return true;
727
+ // (2) Structural fallback (unchanged): a NOT-NULL FK declared on `T` to the
728
+ // lookup table's PK.
729
+ const tRef = findConstrainedTableRef(tSide, baseTable);
730
+ if (!tRef)
731
+ return false;
732
+ // Stable attribute id → base column index on each side.
733
+ const tAttrToCol = new Map();
734
+ tRef.getAttributes().forEach((a, i) => tAttrToCol.set(a.id, i));
735
+ const lookupAttrToCol = new Map();
736
+ lookupRef.getAttributes().forEach((a, i) => lookupAttrToCol.set(a.id, i));
737
+ // Split every equi-pair into (T-FK column, lookup-PK column). A pair that does
738
+ // not connect `T` to the lookup table cleanly (e.g. references a third source)
739
+ // is unprovable ⇒ reject.
740
+ const fkCols = [];
741
+ const pkCols = [];
742
+ for (const p of equiPairs) {
743
+ let fkCol = tAttrToCol.get(p.leftAttrId);
744
+ let pkCol = lookupAttrToCol.get(p.rightAttrId);
745
+ if (fkCol === undefined || pkCol === undefined) {
746
+ fkCol = tAttrToCol.get(p.rightAttrId);
747
+ pkCol = lookupAttrToCol.get(p.leftAttrId);
748
+ }
749
+ if (fkCol === undefined || pkCol === undefined)
750
+ return false;
751
+ fkCols.push(fkCol);
752
+ pkCols.push(pkCol);
753
+ }
754
+ const match = lookupCoveringFK(baseTable, lookupRef.tableSchema, fkCols, pkCols);
755
+ return match !== undefined && !match.nullable;
756
+ }
757
+ /**
758
+ * IND-derived no-row-loss proof (Wave 2). Discharges the inner/cross join's
759
+ * inclusion obligation from the **propagated** IND surface (`PhysicalProperties.inds`)
760
+ * on the `T`-side subtree, rather than re-reading the FK declaration on `T`.
761
+ *
762
+ * Admit when there is an IND on `tSide` whose `(cols → targetCols)` positional
763
+ * pairing equals (as a set) the join's `(tSide-output-col → lookup-base-col)`
764
+ * equi-pairs, with:
765
+ * - `nullRejecting === false` — a NULL-rejecting (nullable-FK) IND can drop `T`
766
+ * rows whose `cols` tuple is NULL, exactly the reason the structural path
767
+ * requires `!match.nullable`;
768
+ * - `target.kind === 'table'` matching the lookup parent's `(schema, table)`; and
769
+ * - the IND's `targetCols` (a key of the parent — seeded INDs target the parent
770
+ * PK) aligned positionally with the lookup-side equi-columns.
771
+ *
772
+ * Soundness. The IND `tSide.cols ⊆ parent.targetCols` (total, since not
773
+ * null-rejecting) guarantees, for every `tSide` row, a parent row `p` with
774
+ * `p.targetCols = tSide.cols`. When the join's equi-pairs are exactly that
775
+ * `(cols → targetCols)` pairing, `p` satisfies every equi-condition, so the row is
776
+ * retained — no row loss. The lookup-side full-row-set precondition (checked by the
777
+ * caller) ensures `p` is actually present in the lookup scan.
778
+ *
779
+ * Equivalence with the structural path. The IND set on a bare `T`-side is exactly
780
+ * `seedTableForeignKeyInds(T)` — one total/NOT-NULL IND per declared FK→parent-PK,
781
+ * with the same PK-cover and nullability validation `lookupCoveringFK` applies. The
782
+ * set-equality match below mirrors `lookupCoveringFK`'s "equi-pairs are exactly the
783
+ * FK columns paired to the whole parent PK" requirement, so the two paths admit the
784
+ * identical single-FK shapes. The IND path's additional reach is **composition**:
785
+ * a `T → M → P` chain carries a threaded IND (`M.cols ⊆ P.pk`) on the `T ⋈ M`
786
+ * sub-frame via Wave-1 join propagation, which discharges the outer `⋈ P` join no
787
+ * single `lookupCoveringFK(T, P, …)` call can prove.
788
+ */
789
+ function indDerivedNoRowLoss(equiPairs, tSide, lookupRef) {
790
+ const inds = tSide.physical?.inds;
791
+ if (!inds || inds.length === 0)
792
+ return false;
793
+ // Map each equi-pair to (tSide-output-col, lookup-base-col). The IND `cols`
794
+ // live in `tSide`'s output frame; the lookup base-col aligns with the target's
795
+ // `targetCols` (output index = base column index at the lookup TableReference).
796
+ const tSideAttrToCol = new Map();
797
+ tSide.getAttributes().forEach((a, i) => tSideAttrToCol.set(a.id, i));
798
+ const lookupAttrToCol = new Map();
799
+ lookupRef.getAttributes().forEach((a, i) => lookupAttrToCol.set(a.id, i));
800
+ const joinPairs = [];
801
+ for (const p of equiPairs) {
802
+ let tCol = tSideAttrToCol.get(p.leftAttrId);
803
+ let lCol = lookupAttrToCol.get(p.rightAttrId);
804
+ if (tCol === undefined || lCol === undefined) {
805
+ tCol = tSideAttrToCol.get(p.rightAttrId);
806
+ lCol = lookupAttrToCol.get(p.leftAttrId);
807
+ }
808
+ // A pair not cleanly split across tSide / lookup (e.g. a third source) is
809
+ // unprovable from this IND surface ⇒ abstain (caller falls back to structural).
810
+ if (tCol === undefined || lCol === undefined)
811
+ return false;
812
+ joinPairs.push([tCol, lCol]);
813
+ }
814
+ const lookupSchema = lookupRef.tableSchema.schemaName.toLowerCase();
815
+ const lookupTable = lookupRef.tableSchema.name.toLowerCase();
816
+ // COMPLETENESS LIMITATION (single-IND match, under-claim-safe): this matches
817
+ // *one* IND to *all* of the join's equi-pairs. A join whose equi-pairs are
818
+ // jointly covered by two INDs (no single IND covers them) abstains here. To
819
+ // extend: admit when a *set* of INDs jointly set-covers the equi-pairs, provided
820
+ // every contributing IND is non-nullRejecting and targets the same lookup-parent
821
+ // key. Under-claim only — never produces a false Covers.
822
+ for (const ind of inds) {
823
+ if (ind.nullRejecting)
824
+ continue;
825
+ if (ind.target.kind !== 'table')
826
+ continue;
827
+ if (ind.target.schema.toLowerCase() !== lookupSchema)
828
+ continue;
829
+ if (ind.target.table.toLowerCase() !== lookupTable)
830
+ continue;
831
+ if (indPairsMatchJoinPairs(ind, joinPairs))
832
+ return true;
833
+ }
834
+ return false;
835
+ }
836
+ /**
837
+ * True iff the IND's positional `(cols[j] → target.targetCols[j])` pairing, taken
838
+ * as a set, equals the join's `(tSideCol → lookupCol)` equi-pairs. Set (not
839
+ * ordered) comparison so the equi-pair extraction order is irrelevant; lengths
840
+ * must match so the join equates *exactly* the IND's columns to the parent's key
841
+ * — the same all-of-the-FK-columns, all-of-the-PK requirement `lookupCoveringFK`
842
+ * enforces, keeping the two derivations in lockstep on the single-FK corpus.
843
+ */
844
+ function indPairsMatchJoinPairs(ind, joinPairs) {
845
+ if (ind.cols.length !== joinPairs.length)
846
+ return false;
847
+ if (ind.target.targetCols.length !== ind.cols.length)
848
+ return false;
849
+ const indSet = new Set();
850
+ for (let j = 0; j < ind.cols.length; j++) {
851
+ indSet.add(`${ind.cols[j]}:${ind.target.targetCols[j]}`);
852
+ }
853
+ if (indSet.size !== ind.cols.length)
854
+ return false; // duplicate IND pair ⇒ not a clean match
855
+ for (const [tCol, lCol] of joinPairs) {
856
+ if (!indSet.has(`${tCol}:${lCol}`))
857
+ return false;
858
+ }
859
+ return true;
860
+ }
861
+ /**
862
+ * Lowercased names of the lookup-side columns in `topJoin`'s output frame — a
863
+ * `T` attribute is exactly one whose id is a key of `baseAttrToCol`, so every
864
+ * other join-output attribute belongs to a lookup side. Feeds the qualifier-aware
865
+ * resolver's unqualified-name ambiguity check.
866
+ */
867
+ function lookupColumnNames(topJoin, baseAttrToCol) {
868
+ const names = new Set();
869
+ for (const attr of topJoin.getAttributes()) {
870
+ if (!baseAttrToCol.has(attr.id))
871
+ names.add(attr.name.toLowerCase());
872
+ }
873
+ return names;
874
+ }
875
+ /**
876
+ * No-fan-out (≤1) gate for a join body: `T`'s primary key must be a unique key of
877
+ * `topJoin`'s output relation (`isUnique`), mapped into the join output frame via
878
+ * stable attribute ids. Checked at the join frame rather than the projected
879
+ * `root` — see the module doc ("Why the join frame, not the projected root").
880
+ *
881
+ * The complementary no-row-loss (≥1) obligation is the structural side/type gate
882
+ * in the shape walk; name-resolution safety is now the qualifier-aware resolver
883
+ * (`makeBodyColumnResolver`), which made the former bare-name collision guard
884
+ * unnecessary.
885
+ */
886
+ export function proveJoinNoFanout(topJoin, tableRef, baseTable) {
887
+ const joinAttrToIndex = new Map();
888
+ topJoin.getAttributes().forEach((a, i) => joinAttrToIndex.set(a.id, i));
889
+ const tAttrs = tableRef.getAttributes();
890
+ const pkInJoinFrame = [];
891
+ for (const pk of baseTable.primaryKeyDefinition) {
892
+ const attrId = tAttrs[pk.index]?.id;
893
+ const joinIdx = attrId !== undefined ? joinAttrToIndex.get(attrId) : undefined;
894
+ if (joinIdx === undefined)
895
+ return notCovers('fanout');
896
+ pkInJoinFrame.push(joinIdx);
897
+ }
898
+ if (!isUnique(pkInJoinFrame, topJoin))
899
+ return notCovers('fanout');
900
+ return COVERS;
901
+ }
902
+ /**
903
+ * Builds the qualifier-aware {@link ColumnIndexResolver} the AST ORDER BY / WHERE
904
+ * checks use to map a column reference to a base-table `T` column index:
905
+ *
906
+ * - **Qualified** (`alias.col` / `table.col` / `schema.table.col`) — a `T`
907
+ * column only when the qualifier denotes `T`'s reference (its alias, or its
908
+ * table name when unaliased, collected from the body FROM clause) *and*, when
909
+ * the reference also carries a `schema` qualifier, that schema is `T`'s schema.
910
+ * Matching is thus (schema, table)-aware: a `schema.table.col` whose table
911
+ * name collides with `T`'s but whose schema denotes a different schema resolves
912
+ * to `undefined` rather than mis-mapping onto a same-named `T` column. A bare
913
+ * `table.col` keeps today's table-name match (the unqualified schema is
914
+ * resolved against the schema search path at plan time, so `t.col` still
915
+ * denotes `T`). A qualifier denoting a lookup source (or any unknown qualifier)
916
+ * yields `undefined`.
917
+ * - **Unqualified** (`col`) — a `T` column only when `T` has it *and* no
918
+ * lookup-side column shares the name (`lookupNames`). An ambiguous bare name
919
+ * would be a plan-time error for a real body, but resolving to `undefined`
920
+ * here is the sound fallback regardless.
921
+ *
922
+ * `undefined` means "not a (resolvable) `T` column", which the ORDER BY check
923
+ * turns into `ordering-mismatch` and the WHERE recognizer turns into an
924
+ * unrecognized conjunct (⇒ `predicate-entailment`). For a single-source body
925
+ * `lookupNames` is empty and `T`'s sole qualifier is in the set, so this reduces
926
+ * to bare-name resolution — v1 behavior unchanged.
927
+ */
928
+ function makeBodyColumnResolver(selectAst, baseTable, lookupNames) {
929
+ const tQualifiers = collectBaseTableQualifiers(selectAst, baseTable);
930
+ const baseSchema = baseTable.schemaName.toLowerCase();
931
+ return (expr) => {
932
+ const ref = columnRefParts(expr);
933
+ if (ref === undefined)
934
+ return undefined;
935
+ if (ref.qualifier !== undefined) {
936
+ // (schema, table)-aware: a present schema must denote `T`'s schema; an
937
+ // absent schema falls back to the table-name match (the schema search path
938
+ // resolves the bare qualifier to `T` at plan time).
939
+ if (ref.schema !== undefined && ref.schema !== baseSchema)
940
+ return undefined;
941
+ return tQualifiers.has(ref.qualifier) ? baseTable.columnIndexMap.get(ref.name) : undefined;
942
+ }
943
+ if (lookupNames.has(ref.name))
944
+ return undefined;
945
+ return baseTable.columnIndexMap.get(ref.name);
946
+ };
947
+ }
948
+ /**
949
+ * The `(schema?, qualifier?, name)` of a column reference (all lowercased), or
950
+ * `undefined` when `expr` is not a column reference the prover resolves. A
951
+ * `ColumnExpr` carries an optional `table` qualifier *and* an optional `schema`
952
+ * qualifier — both are surfaced so qualifier matching can be (schema, table)-aware
953
+ * (see `makeBodyColumnResolver`). A bare `IdentifierExpr` has neither, and a
954
+ * schema-qualified identifier is rejected (matches `columnIndexFromExpr`).
955
+ *
956
+ * Note: the binder rejects every 3-part `schema.table.column` reference before a
957
+ * plan (let alone an MV) exists (see the module doc § cross-schema), so a present
958
+ * `schema` here is only reachable through a hand-built `selectAst` — the resolver
959
+ * still honors it for defense-in-depth.
960
+ */
961
+ function columnRefParts(expr) {
962
+ if (expr.type === 'column') {
963
+ const c = expr;
964
+ return { schema: c.schema?.toLowerCase(), qualifier: c.table?.toLowerCase(), name: c.name.toLowerCase() };
965
+ }
966
+ if (expr.type === 'identifier') {
967
+ const id = expr;
968
+ if (id.schema)
969
+ return undefined;
970
+ return { name: id.name.toLowerCase() };
971
+ }
972
+ return undefined;
973
+ }
974
+ /**
975
+ * The set of lowercased FROM-clause qualifiers (alias, or table name when
976
+ * unaliased) that denote the base table `T`. Walks the body FROM clause through
977
+ * nested joins. Subquery / function sources cannot be `T` (the shape walk binds
978
+ * `T` to a `TableReferenceNode`), so their alias is intentionally absent — a
979
+ * reference qualified by it resolves to `undefined` (a lookup/derived column).
980
+ */
981
+ function collectBaseTableQualifiers(selectAst, baseTable) {
982
+ const out = new Set();
983
+ if (selectAst.type !== 'select' || !selectAst.from)
984
+ return out;
985
+ const stack = [...selectAst.from];
986
+ while (stack.length > 0) {
987
+ const f = stack.pop();
988
+ if (f.type === 'join') {
989
+ stack.push(f.left, f.right);
990
+ continue;
991
+ }
992
+ if (f.type === 'table') {
993
+ const ts = f;
994
+ const denotesT = ts.table.name.toLowerCase() === baseTable.name.toLowerCase()
995
+ && (ts.table.schema === undefined || ts.table.schema.toLowerCase() === baseTable.schemaName.toLowerCase());
996
+ if (denotesT)
997
+ out.add((ts.alias ?? ts.table.name).toLowerCase());
998
+ }
999
+ }
1000
+ return out;
1001
+ }
1002
+ /**
1003
+ * Base-table column indices named by the body's `ORDER BY`, in order, or
1004
+ * `undefined` when there is no `ORDER BY`, the body is not a plain SELECT, or any
1005
+ * ordering term does not resolve to a `T` column via `resolve` (the prover never
1006
+ * invents an ordering). `resolve` is qualifier-aware for join bodies, so an
1007
+ * `ORDER BY` on a *lookup*-side column yields `undefined` here ⇒ the caller
1008
+ * reports `ordering-mismatch`, the correct reason (it is not a `T` ordering).
1009
+ */
1010
+ function bodyOrderByColumns(selectAst, resolve) {
1011
+ if (selectAst.type !== 'select')
1012
+ return undefined;
1013
+ const orderBy = selectAst.orderBy;
1014
+ if (!orderBy || orderBy.length === 0)
1015
+ return undefined;
1016
+ const cols = [];
1017
+ for (const term of orderBy) {
1018
+ const col = resolve(term.expr);
1019
+ if (col === undefined)
1020
+ return undefined;
1021
+ cols.push(col);
1022
+ }
1023
+ return cols;
1024
+ }
1025
+ /** True when `a` and `b` contain the same column indices (order-insensitive, distinct). */
1026
+ function isPermutation(a, b) {
1027
+ if (a.length !== b.length)
1028
+ return false;
1029
+ const setA = new Set(a);
1030
+ const setB = new Set(b);
1031
+ if (setA.size !== a.length || setB.size !== b.length)
1032
+ return false;
1033
+ for (const x of setA)
1034
+ if (!setB.has(x))
1035
+ return false;
1036
+ return true;
1037
+ }
1038
+ //# sourceMappingURL=coverage-prover.js.map