@quereus/quereus 4.4.1 → 4.6.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 (593) hide show
  1. package/README.md +5 -4
  2. package/dist/src/core/database-events.d.ts +99 -1
  3. package/dist/src/core/database-events.d.ts.map +1 -1
  4. package/dist/src/core/database-events.js +219 -3
  5. package/dist/src/core/database-events.js.map +1 -1
  6. package/dist/src/core/database-materialized-views-analysis.d.ts.map +1 -1
  7. package/dist/src/core/database-materialized-views-analysis.js +1 -0
  8. package/dist/src/core/database-materialized-views-analysis.js.map +1 -1
  9. package/dist/src/core/database-materialized-views-plan-builders.d.ts.map +1 -1
  10. package/dist/src/core/database-materialized-views-plan-builders.js +29 -2
  11. package/dist/src/core/database-materialized-views-plan-builders.js.map +1 -1
  12. package/dist/src/core/database-transaction.d.ts +9 -0
  13. package/dist/src/core/database-transaction.d.ts.map +1 -1
  14. package/dist/src/core/database-transaction.js +9 -0
  15. package/dist/src/core/database-transaction.js.map +1 -1
  16. package/dist/src/core/database.d.ts +7 -1
  17. package/dist/src/core/database.d.ts.map +1 -1
  18. package/dist/src/core/database.js +20 -5
  19. package/dist/src/core/database.js.map +1 -1
  20. package/dist/src/func/builtins/aggregate.js +11 -11
  21. package/dist/src/func/builtins/aggregate.js.map +1 -1
  22. package/dist/src/func/builtins/builtin-window-functions.d.ts.map +1 -1
  23. package/dist/src/func/builtins/builtin-window-functions.js +15 -85
  24. package/dist/src/func/builtins/builtin-window-functions.js.map +1 -1
  25. package/dist/src/func/builtins/conversion.d.ts.map +1 -1
  26. package/dist/src/func/builtins/conversion.js +10 -9
  27. package/dist/src/func/builtins/conversion.js.map +1 -1
  28. package/dist/src/func/builtins/datetime.d.ts.map +1 -1
  29. package/dist/src/func/builtins/datetime.js +28 -10
  30. package/dist/src/func/builtins/datetime.js.map +1 -1
  31. package/dist/src/func/builtins/json.d.ts.map +1 -1
  32. package/dist/src/func/builtins/json.js +23 -17
  33. package/dist/src/func/builtins/json.js.map +1 -1
  34. package/dist/src/func/builtins/mutation.js +2 -2
  35. package/dist/src/func/builtins/mutation.js.map +1 -1
  36. package/dist/src/func/builtins/return-types.d.ts +327 -0
  37. package/dist/src/func/builtins/return-types.d.ts.map +1 -0
  38. package/dist/src/func/builtins/return-types.js +43 -0
  39. package/dist/src/func/builtins/return-types.js.map +1 -0
  40. package/dist/src/func/builtins/scalar.d.ts.map +1 -1
  41. package/dist/src/func/builtins/scalar.js +193 -37
  42. package/dist/src/func/builtins/scalar.js.map +1 -1
  43. package/dist/src/func/builtins/schema.d.ts.map +1 -1
  44. package/dist/src/func/builtins/schema.js +11 -3
  45. package/dist/src/func/builtins/schema.js.map +1 -1
  46. package/dist/src/func/builtins/string.d.ts.map +1 -1
  47. package/dist/src/func/builtins/string.js +4 -2
  48. package/dist/src/func/builtins/string.js.map +1 -1
  49. package/dist/src/func/builtins/timespan.d.ts +3 -0
  50. package/dist/src/func/builtins/timespan.d.ts.map +1 -1
  51. package/dist/src/func/builtins/timespan.js +15 -11
  52. package/dist/src/func/builtins/timespan.js.map +1 -1
  53. package/dist/src/func/registration.d.ts +39 -1
  54. package/dist/src/func/registration.d.ts.map +1 -1
  55. package/dist/src/func/registration.js +236 -41
  56. package/dist/src/func/registration.js.map +1 -1
  57. package/dist/src/index.d.ts +14 -7
  58. package/dist/src/index.d.ts.map +1 -1
  59. package/dist/src/index.js +14 -5
  60. package/dist/src/index.js.map +1 -1
  61. package/dist/src/parser/parser.d.ts +46 -0
  62. package/dist/src/parser/parser.d.ts.map +1 -1
  63. package/dist/src/parser/parser.js +160 -44
  64. package/dist/src/parser/parser.js.map +1 -1
  65. package/dist/src/planner/analysis/check-extraction.d.ts.map +1 -1
  66. package/dist/src/planner/analysis/check-extraction.js +37 -4
  67. package/dist/src/planner/analysis/check-extraction.js.map +1 -1
  68. package/dist/src/planner/analysis/coarsened-key.d.ts +4 -3
  69. package/dist/src/planner/analysis/coarsened-key.d.ts.map +1 -1
  70. package/dist/src/planner/analysis/coarsened-key.js +37 -3
  71. package/dist/src/planner/analysis/coarsened-key.js.map +1 -1
  72. package/dist/src/planner/analysis/comparison-collation.d.ts +41 -13
  73. package/dist/src/planner/analysis/comparison-collation.d.ts.map +1 -1
  74. package/dist/src/planner/analysis/comparison-collation.js +51 -14
  75. package/dist/src/planner/analysis/comparison-collation.js.map +1 -1
  76. package/dist/src/planner/analysis/constraint-extractor.d.ts +0 -7
  77. package/dist/src/planner/analysis/constraint-extractor.d.ts.map +1 -1
  78. package/dist/src/planner/analysis/constraint-extractor.js +59 -59
  79. package/dist/src/planner/analysis/constraint-extractor.js.map +1 -1
  80. package/dist/src/planner/analysis/coverage-prover.d.ts +13 -2
  81. package/dist/src/planner/analysis/coverage-prover.d.ts.map +1 -1
  82. package/dist/src/planner/analysis/coverage-prover.js +10 -14
  83. package/dist/src/planner/analysis/coverage-prover.js.map +1 -1
  84. package/dist/src/planner/analysis/predicate-conjuncts.d.ts +10 -4
  85. package/dist/src/planner/analysis/predicate-conjuncts.d.ts.map +1 -1
  86. package/dist/src/planner/analysis/predicate-conjuncts.js +28 -7
  87. package/dist/src/planner/analysis/predicate-conjuncts.js.map +1 -1
  88. package/dist/src/planner/analysis/query-rewrite-matcher.d.ts.map +1 -1
  89. package/dist/src/planner/analysis/query-rewrite-matcher.js +8 -27
  90. package/dist/src/planner/analysis/query-rewrite-matcher.js.map +1 -1
  91. package/dist/src/planner/analysis/scalar-subqueries.d.ts +22 -3
  92. package/dist/src/planner/analysis/scalar-subqueries.d.ts.map +1 -1
  93. package/dist/src/planner/analysis/scalar-subqueries.js +32 -3
  94. package/dist/src/planner/analysis/scalar-subqueries.js.map +1 -1
  95. package/dist/src/planner/analysis/set-op-type-merge.d.ts +64 -0
  96. package/dist/src/planner/analysis/set-op-type-merge.d.ts.map +1 -0
  97. package/dist/src/planner/analysis/set-op-type-merge.js +97 -0
  98. package/dist/src/planner/analysis/set-op-type-merge.js.map +1 -0
  99. package/dist/src/planner/building/alter-table.d.ts.map +1 -1
  100. package/dist/src/planner/building/alter-table.js +65 -27
  101. package/dist/src/planner/building/alter-table.js.map +1 -1
  102. package/dist/src/planner/building/coercion.d.ts +54 -0
  103. package/dist/src/planner/building/coercion.d.ts.map +1 -0
  104. package/dist/src/planner/building/coercion.js +88 -0
  105. package/dist/src/planner/building/coercion.js.map +1 -0
  106. package/dist/src/planner/building/constraint-builder.d.ts.map +1 -1
  107. package/dist/src/planner/building/constraint-builder.js +5 -18
  108. package/dist/src/planner/building/constraint-builder.js.map +1 -1
  109. package/dist/src/planner/building/expression.d.ts +17 -0
  110. package/dist/src/planner/building/expression.d.ts.map +1 -1
  111. package/dist/src/planner/building/expression.js +23 -115
  112. package/dist/src/planner/building/expression.js.map +1 -1
  113. package/dist/src/planner/building/function-call.d.ts.map +1 -1
  114. package/dist/src/planner/building/function-call.js +13 -0
  115. package/dist/src/planner/building/function-call.js.map +1 -1
  116. package/dist/src/planner/building/select-aggregates.d.ts +1 -1
  117. package/dist/src/planner/building/select-aggregates.d.ts.map +1 -1
  118. package/dist/src/planner/building/select-aggregates.js +53 -2
  119. package/dist/src/planner/building/select-aggregates.js.map +1 -1
  120. package/dist/src/planner/building/select-compound.d.ts.map +1 -1
  121. package/dist/src/planner/building/select-compound.js +10 -6
  122. package/dist/src/planner/building/select-compound.js.map +1 -1
  123. package/dist/src/planner/building/select-context.d.ts +7 -0
  124. package/dist/src/planner/building/select-context.d.ts.map +1 -1
  125. package/dist/src/planner/building/select-context.js +10 -40
  126. package/dist/src/planner/building/select-context.js.map +1 -1
  127. package/dist/src/planner/building/select.d.ts +37 -1
  128. package/dist/src/planner/building/select.d.ts.map +1 -1
  129. package/dist/src/planner/building/select.js +112 -51
  130. package/dist/src/planner/building/select.js.map +1 -1
  131. package/dist/src/planner/cost/conjunct-cost.d.ts +82 -0
  132. package/dist/src/planner/cost/conjunct-cost.d.ts.map +1 -0
  133. package/dist/src/planner/cost/conjunct-cost.js +107 -0
  134. package/dist/src/planner/cost/conjunct-cost.js.map +1 -0
  135. package/dist/src/planner/cost/index.d.ts +10 -0
  136. package/dist/src/planner/cost/index.d.ts.map +1 -1
  137. package/dist/src/planner/cost/index.js +15 -0
  138. package/dist/src/planner/cost/index.js.map +1 -1
  139. package/dist/src/planner/mutation/propagate.d.ts.map +1 -1
  140. package/dist/src/planner/mutation/propagate.js +1 -0
  141. package/dist/src/planner/mutation/propagate.js.map +1 -1
  142. package/dist/src/planner/nodes/aggregate-node.d.ts +6 -0
  143. package/dist/src/planner/nodes/aggregate-node.d.ts.map +1 -1
  144. package/dist/src/planner/nodes/aggregate-node.js +10 -2
  145. package/dist/src/planner/nodes/aggregate-node.js.map +1 -1
  146. package/dist/src/planner/nodes/alias-node.d.ts.map +1 -1
  147. package/dist/src/planner/nodes/alias-node.js +2 -1
  148. package/dist/src/planner/nodes/alias-node.js.map +1 -1
  149. package/dist/src/planner/nodes/alter-table-node.d.ts +24 -8
  150. package/dist/src/planner/nodes/alter-table-node.d.ts.map +1 -1
  151. package/dist/src/planner/nodes/alter-table-node.js.map +1 -1
  152. package/dist/src/planner/nodes/asof-scan-node.d.ts.map +1 -1
  153. package/dist/src/planner/nodes/asof-scan-node.js +4 -1
  154. package/dist/src/planner/nodes/asof-scan-node.js.map +1 -1
  155. package/dist/src/planner/nodes/asserted-keys-node.d.ts.map +1 -1
  156. package/dist/src/planner/nodes/asserted-keys-node.js +2 -1
  157. package/dist/src/planner/nodes/asserted-keys-node.js.map +1 -1
  158. package/dist/src/planner/nodes/async-gather-node.d.ts.map +1 -1
  159. package/dist/src/planner/nodes/async-gather-node.js +19 -8
  160. package/dist/src/planner/nodes/async-gather-node.js.map +1 -1
  161. package/dist/src/planner/nodes/bloom-join-node.d.ts +2 -0
  162. package/dist/src/planner/nodes/bloom-join-node.d.ts.map +1 -1
  163. package/dist/src/planner/nodes/bloom-join-node.js +17 -7
  164. package/dist/src/planner/nodes/bloom-join-node.js.map +1 -1
  165. package/dist/src/planner/nodes/cache-node.d.ts.map +1 -1
  166. package/dist/src/planner/nodes/cache-node.js +2 -1
  167. package/dist/src/planner/nodes/cache-node.js.map +1 -1
  168. package/dist/src/planner/nodes/distinct-node.d.ts +6 -0
  169. package/dist/src/planner/nodes/distinct-node.d.ts.map +1 -1
  170. package/dist/src/planner/nodes/distinct-node.js +10 -2
  171. package/dist/src/planner/nodes/distinct-node.js.map +1 -1
  172. package/dist/src/planner/nodes/eager-prefetch-node.d.ts.map +1 -1
  173. package/dist/src/planner/nodes/eager-prefetch-node.js +2 -1
  174. package/dist/src/planner/nodes/eager-prefetch-node.js.map +1 -1
  175. package/dist/src/planner/nodes/fanout-lookup-join-node.d.ts +5 -0
  176. package/dist/src/planner/nodes/fanout-lookup-join-node.d.ts.map +1 -1
  177. package/dist/src/planner/nodes/fanout-lookup-join-node.js +13 -6
  178. package/dist/src/planner/nodes/fanout-lookup-join-node.js.map +1 -1
  179. package/dist/src/planner/nodes/filter.d.ts.map +1 -1
  180. package/dist/src/planner/nodes/filter.js +12 -5
  181. package/dist/src/planner/nodes/filter.js.map +1 -1
  182. package/dist/src/planner/nodes/hash-aggregate.d.ts +6 -0
  183. package/dist/src/planner/nodes/hash-aggregate.d.ts.map +1 -1
  184. package/dist/src/planner/nodes/hash-aggregate.js +10 -2
  185. package/dist/src/planner/nodes/hash-aggregate.js.map +1 -1
  186. package/dist/src/planner/nodes/join-node.d.ts +25 -1
  187. package/dist/src/planner/nodes/join-node.d.ts.map +1 -1
  188. package/dist/src/planner/nodes/join-node.js +38 -10
  189. package/dist/src/planner/nodes/join-node.js.map +1 -1
  190. package/dist/src/planner/nodes/join-utils.d.ts +78 -0
  191. package/dist/src/planner/nodes/join-utils.d.ts.map +1 -1
  192. package/dist/src/planner/nodes/join-utils.js +73 -0
  193. package/dist/src/planner/nodes/join-utils.js.map +1 -1
  194. package/dist/src/planner/nodes/key-set-semi-join-node.d.ts +87 -0
  195. package/dist/src/planner/nodes/key-set-semi-join-node.d.ts.map +1 -0
  196. package/dist/src/planner/nodes/key-set-semi-join-node.js +141 -0
  197. package/dist/src/planner/nodes/key-set-semi-join-node.js.map +1 -0
  198. package/dist/src/planner/nodes/lens-auxiliary-access-node.d.ts.map +1 -1
  199. package/dist/src/planner/nodes/lens-auxiliary-access-node.js +2 -1
  200. package/dist/src/planner/nodes/lens-auxiliary-access-node.js.map +1 -1
  201. package/dist/src/planner/nodes/limit-offset.d.ts +6 -0
  202. package/dist/src/planner/nodes/limit-offset.d.ts.map +1 -1
  203. package/dist/src/planner/nodes/limit-offset.js +10 -2
  204. package/dist/src/planner/nodes/limit-offset.js.map +1 -1
  205. package/dist/src/planner/nodes/merge-join-node.d.ts +2 -0
  206. package/dist/src/planner/nodes/merge-join-node.d.ts.map +1 -1
  207. package/dist/src/planner/nodes/merge-join-node.js +21 -8
  208. package/dist/src/planner/nodes/merge-join-node.js.map +1 -1
  209. package/dist/src/planner/nodes/ordinal-slice-node.d.ts +5 -0
  210. package/dist/src/planner/nodes/ordinal-slice-node.d.ts.map +1 -1
  211. package/dist/src/planner/nodes/ordinal-slice-node.js +9 -2
  212. package/dist/src/planner/nodes/ordinal-slice-node.js.map +1 -1
  213. package/dist/src/planner/nodes/plan-node-type.d.ts +1 -0
  214. package/dist/src/planner/nodes/plan-node-type.d.ts.map +1 -1
  215. package/dist/src/planner/nodes/plan-node-type.js +1 -0
  216. package/dist/src/planner/nodes/plan-node-type.js.map +1 -1
  217. package/dist/src/planner/nodes/plan-node.d.ts +24 -0
  218. package/dist/src/planner/nodes/plan-node.d.ts.map +1 -1
  219. package/dist/src/planner/nodes/plan-node.js.map +1 -1
  220. package/dist/src/planner/nodes/project-node.d.ts.map +1 -1
  221. package/dist/src/planner/nodes/project-node.js +2 -1
  222. package/dist/src/planner/nodes/project-node.js.map +1 -1
  223. package/dist/src/planner/nodes/reference.d.ts.map +1 -1
  224. package/dist/src/planner/nodes/reference.js +3 -2
  225. package/dist/src/planner/nodes/reference.js.map +1 -1
  226. package/dist/src/planner/nodes/retrieve-node.d.ts.map +1 -1
  227. package/dist/src/planner/nodes/retrieve-node.js +2 -1
  228. package/dist/src/planner/nodes/retrieve-node.js.map +1 -1
  229. package/dist/src/planner/nodes/scalar.d.ts.map +1 -1
  230. package/dist/src/planner/nodes/scalar.js +5 -18
  231. package/dist/src/planner/nodes/scalar.js.map +1 -1
  232. package/dist/src/planner/nodes/set-operation-node.d.ts +68 -16
  233. package/dist/src/planner/nodes/set-operation-node.d.ts.map +1 -1
  234. package/dist/src/planner/nodes/set-operation-node.js +147 -26
  235. package/dist/src/planner/nodes/set-operation-node.js.map +1 -1
  236. package/dist/src/planner/nodes/sort.d.ts.map +1 -1
  237. package/dist/src/planner/nodes/sort.js +3 -1
  238. package/dist/src/planner/nodes/sort.js.map +1 -1
  239. package/dist/src/planner/nodes/stream-aggregate.d.ts +6 -0
  240. package/dist/src/planner/nodes/stream-aggregate.d.ts.map +1 -1
  241. package/dist/src/planner/nodes/stream-aggregate.js +10 -2
  242. package/dist/src/planner/nodes/stream-aggregate.js.map +1 -1
  243. package/dist/src/planner/nodes/table-access-nodes.d.ts +19 -1
  244. package/dist/src/planner/nodes/table-access-nodes.d.ts.map +1 -1
  245. package/dist/src/planner/nodes/table-access-nodes.js +18 -2
  246. package/dist/src/planner/nodes/table-access-nodes.js.map +1 -1
  247. package/dist/src/planner/nodes/window-function.d.ts.map +1 -1
  248. package/dist/src/planner/nodes/window-function.js +8 -0
  249. package/dist/src/planner/nodes/window-function.js.map +1 -1
  250. package/dist/src/planner/nodes/window-node.d.ts +1 -1
  251. package/dist/src/planner/nodes/window-node.d.ts.map +1 -1
  252. package/dist/src/planner/nodes/window-node.js +3 -1
  253. package/dist/src/planner/nodes/window-node.js.map +1 -1
  254. package/dist/src/planner/optimizer.d.ts +9 -1
  255. package/dist/src/planner/optimizer.d.ts.map +1 -1
  256. package/dist/src/planner/optimizer.js +126 -6
  257. package/dist/src/planner/optimizer.js.map +1 -1
  258. package/dist/src/planner/rules/access/rule-key-set-seek.d.ts +68 -0
  259. package/dist/src/planner/rules/access/rule-key-set-seek.d.ts.map +1 -0
  260. package/dist/src/planner/rules/access/rule-key-set-seek.js +343 -0
  261. package/dist/src/planner/rules/access/rule-key-set-seek.js.map +1 -0
  262. package/dist/src/planner/rules/access/rule-monotonic-range-access.d.ts.map +1 -1
  263. package/dist/src/planner/rules/access/rule-monotonic-range-access.js +2 -2
  264. package/dist/src/planner/rules/access/rule-monotonic-range-access.js.map +1 -1
  265. package/dist/src/planner/rules/access/rule-select-access-path.d.ts +46 -0
  266. package/dist/src/planner/rules/access/rule-select-access-path.d.ts.map +1 -1
  267. package/dist/src/planner/rules/access/rule-select-access-path.js +54 -13
  268. package/dist/src/planner/rules/access/rule-select-access-path.js.map +1 -1
  269. package/dist/src/planner/rules/cache/rule-cte-optimization.d.ts.map +1 -1
  270. package/dist/src/planner/rules/cache/rule-cte-optimization.js +9 -0
  271. package/dist/src/planner/rules/cache/rule-cte-optimization.js.map +1 -1
  272. package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.d.ts.map +1 -1
  273. package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.js +6 -4
  274. package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.js.map +1 -1
  275. package/dist/src/planner/rules/join/equi-pair-extractor.d.ts +49 -49
  276. package/dist/src/planner/rules/join/equi-pair-extractor.d.ts.map +1 -1
  277. package/dist/src/planner/rules/join/equi-pair-extractor.js +54 -58
  278. package/dist/src/planner/rules/join/equi-pair-extractor.js.map +1 -1
  279. package/dist/src/planner/rules/join/index-nested-loop.d.ts +49 -0
  280. package/dist/src/planner/rules/join/index-nested-loop.d.ts.map +1 -0
  281. package/dist/src/planner/rules/join/index-nested-loop.js +285 -0
  282. package/dist/src/planner/rules/join/index-nested-loop.js.map +1 -0
  283. package/dist/src/planner/rules/join/rule-fanout-batched-outer.js +8 -8
  284. package/dist/src/planner/rules/join/rule-join-physical-selection.d.ts +10 -4
  285. package/dist/src/planner/rules/join/rule-join-physical-selection.d.ts.map +1 -1
  286. package/dist/src/planner/rules/join/rule-join-physical-selection.js +97 -29
  287. package/dist/src/planner/rules/join/rule-join-physical-selection.js.map +1 -1
  288. package/dist/src/planner/rules/join/rule-monotonic-merge-join.d.ts.map +1 -1
  289. package/dist/src/planner/rules/join/rule-monotonic-merge-join.js +15 -5
  290. package/dist/src/planner/rules/join/rule-monotonic-merge-join.js.map +1 -1
  291. package/dist/src/planner/rules/predicate/rule-empty-relation-folding.d.ts +1 -1
  292. package/dist/src/planner/rules/predicate/rule-empty-relation-folding.js +1 -1
  293. package/dist/src/planner/rules/predicate/rule-filter-conjunct-ordering.d.ts +43 -0
  294. package/dist/src/planner/rules/predicate/rule-filter-conjunct-ordering.d.ts.map +1 -0
  295. package/dist/src/planner/rules/predicate/rule-filter-conjunct-ordering.js +119 -0
  296. package/dist/src/planner/rules/predicate/rule-filter-conjunct-ordering.js.map +1 -0
  297. package/dist/src/planner/rules/predicate/rule-filter-selectivity.d.ts +44 -3
  298. package/dist/src/planner/rules/predicate/rule-filter-selectivity.d.ts.map +1 -1
  299. package/dist/src/planner/rules/predicate/rule-filter-selectivity.js +142 -18
  300. package/dist/src/planner/rules/predicate/rule-filter-selectivity.js.map +1 -1
  301. package/dist/src/planner/rules/predicate/rule-join-predicate-pushdown.d.ts +73 -0
  302. package/dist/src/planner/rules/predicate/rule-join-predicate-pushdown.d.ts.map +1 -0
  303. package/dist/src/planner/rules/predicate/rule-join-predicate-pushdown.js +205 -0
  304. package/dist/src/planner/rules/predicate/rule-join-predicate-pushdown.js.map +1 -0
  305. package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.d.ts +14 -11
  306. package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.d.ts.map +1 -1
  307. package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.js +21 -85
  308. package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.js.map +1 -1
  309. package/dist/src/planner/rules/predicate/rule-predicate-pushdown.d.ts +10 -2
  310. package/dist/src/planner/rules/predicate/rule-predicate-pushdown.d.ts.map +1 -1
  311. package/dist/src/planner/rules/predicate/rule-predicate-pushdown.js +20 -2
  312. package/dist/src/planner/rules/predicate/rule-predicate-pushdown.js.map +1 -1
  313. package/dist/src/planner/rules/retrieve/rule-grow-retrieve.d.ts.map +1 -1
  314. package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js +18 -3
  315. package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js.map +1 -1
  316. package/dist/src/planner/rules/shared/access-leaf.d.ts +39 -0
  317. package/dist/src/planner/rules/shared/access-leaf.d.ts.map +1 -0
  318. package/dist/src/planner/rules/shared/access-leaf.js +79 -0
  319. package/dist/src/planner/rules/shared/access-leaf.js.map +1 -0
  320. package/dist/src/planner/rules/shared/index-style-context.d.ts +17 -0
  321. package/dist/src/planner/rules/shared/index-style-context.d.ts.map +1 -1
  322. package/dist/src/planner/rules/shared/index-style-context.js +7 -0
  323. package/dist/src/planner/rules/shared/index-style-context.js.map +1 -1
  324. package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.d.ts.map +1 -1
  325. package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.js +18 -8
  326. package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.js.map +1 -1
  327. package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.d.ts +3 -1
  328. package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.d.ts.map +1 -1
  329. package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.js +27 -10
  330. package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.js.map +1 -1
  331. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.d.ts +24 -6
  332. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.d.ts.map +1 -1
  333. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js +243 -70
  334. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js.map +1 -1
  335. package/dist/src/planner/rules/window/rule-monotonic-window.d.ts +17 -7
  336. package/dist/src/planner/rules/window/rule-monotonic-window.d.ts.map +1 -1
  337. package/dist/src/planner/rules/window/rule-monotonic-window.js +124 -87
  338. package/dist/src/planner/rules/window/rule-monotonic-window.js.map +1 -1
  339. package/dist/src/planner/scopes/aliased.d.ts.map +1 -1
  340. package/dist/src/planner/scopes/aliased.js +6 -0
  341. package/dist/src/planner/scopes/aliased.js.map +1 -1
  342. package/dist/src/planner/stats/catalog-stats.d.ts +87 -4
  343. package/dist/src/planner/stats/catalog-stats.d.ts.map +1 -1
  344. package/dist/src/planner/stats/catalog-stats.js +250 -28
  345. package/dist/src/planner/stats/catalog-stats.js.map +1 -1
  346. package/dist/src/planner/stats/conjunct-selectivity.d.ts +48 -0
  347. package/dist/src/planner/stats/conjunct-selectivity.d.ts.map +1 -0
  348. package/dist/src/planner/stats/conjunct-selectivity.js +168 -0
  349. package/dist/src/planner/stats/conjunct-selectivity.js.map +1 -0
  350. package/dist/src/planner/stats/index.d.ts +36 -2
  351. package/dist/src/planner/stats/index.d.ts.map +1 -1
  352. package/dist/src/planner/stats/index.js.map +1 -1
  353. package/dist/src/planner/stats/selectivity-combine.d.ts +53 -0
  354. package/dist/src/planner/stats/selectivity-combine.d.ts.map +1 -0
  355. package/dist/src/planner/stats/selectivity-combine.js +75 -0
  356. package/dist/src/planner/stats/selectivity-combine.js.map +1 -0
  357. package/dist/src/planner/stats/table-cardinality.d.ts +28 -0
  358. package/dist/src/planner/stats/table-cardinality.d.ts.map +1 -0
  359. package/dist/src/planner/stats/table-cardinality.js +29 -0
  360. package/dist/src/planner/stats/table-cardinality.js.map +1 -0
  361. package/dist/src/planner/util/column-origins.d.ts +79 -0
  362. package/dist/src/planner/util/column-origins.d.ts.map +1 -0
  363. package/dist/src/planner/util/column-origins.js +150 -0
  364. package/dist/src/planner/util/column-origins.js.map +1 -0
  365. package/dist/src/planner/util/fd-utils.d.ts +32 -8
  366. package/dist/src/planner/util/fd-utils.d.ts.map +1 -1
  367. package/dist/src/planner/util/fd-utils.js +46 -9
  368. package/dist/src/planner/util/fd-utils.js.map +1 -1
  369. package/dist/src/planner/util/ind-utils.d.ts +56 -17
  370. package/dist/src/planner/util/ind-utils.d.ts.map +1 -1
  371. package/dist/src/planner/util/ind-utils.js +82 -21
  372. package/dist/src/planner/util/ind-utils.js.map +1 -1
  373. package/dist/src/planner/util/key-utils.d.ts +20 -2
  374. package/dist/src/planner/util/key-utils.d.ts.map +1 -1
  375. package/dist/src/planner/util/key-utils.js +37 -3
  376. package/dist/src/planner/util/key-utils.js.map +1 -1
  377. package/dist/src/planner/util/row-estimates.d.ts +28 -0
  378. package/dist/src/planner/util/row-estimates.d.ts.map +1 -0
  379. package/dist/src/planner/util/row-estimates.js +40 -0
  380. package/dist/src/planner/util/row-estimates.js.map +1 -0
  381. package/dist/src/planner/util/row-population.d.ts +42 -0
  382. package/dist/src/planner/util/row-population.d.ts.map +1 -0
  383. package/dist/src/planner/util/row-population.js +71 -0
  384. package/dist/src/planner/util/row-population.js.map +1 -0
  385. package/dist/src/runtime/deferred-constraint-queue.d.ts +40 -0
  386. package/dist/src/runtime/deferred-constraint-queue.d.ts.map +1 -1
  387. package/dist/src/runtime/deferred-constraint-queue.js +90 -9
  388. package/dist/src/runtime/deferred-constraint-queue.js.map +1 -1
  389. package/dist/src/runtime/emit/add-constraint.d.ts.map +1 -1
  390. package/dist/src/runtime/emit/add-constraint.js +39 -1
  391. package/dist/src/runtime/emit/add-constraint.js.map +1 -1
  392. package/dist/src/runtime/emit/aggregate.d.ts.map +1 -1
  393. package/dist/src/runtime/emit/aggregate.js +4 -4
  394. package/dist/src/runtime/emit/aggregate.js.map +1 -1
  395. package/dist/src/runtime/emit/alter-schema-event.d.ts +42 -0
  396. package/dist/src/runtime/emit/alter-schema-event.d.ts.map +1 -0
  397. package/dist/src/runtime/emit/alter-schema-event.js +28 -0
  398. package/dist/src/runtime/emit/alter-schema-event.js.map +1 -0
  399. package/dist/src/runtime/emit/alter-table.d.ts.map +1 -1
  400. package/dist/src/runtime/emit/alter-table.js +386 -154
  401. package/dist/src/runtime/emit/alter-table.js.map +1 -1
  402. package/dist/src/runtime/emit/analyze.d.ts.map +1 -1
  403. package/dist/src/runtime/emit/analyze.js +35 -3
  404. package/dist/src/runtime/emit/analyze.js.map +1 -1
  405. package/dist/src/runtime/emit/asof-scan.d.ts.map +1 -1
  406. package/dist/src/runtime/emit/asof-scan.js +8 -3
  407. package/dist/src/runtime/emit/asof-scan.js.map +1 -1
  408. package/dist/src/runtime/emit/between.d.ts.map +1 -1
  409. package/dist/src/runtime/emit/between.js +4 -38
  410. package/dist/src/runtime/emit/between.js.map +1 -1
  411. package/dist/src/runtime/emit/binary.d.ts.map +1 -1
  412. package/dist/src/runtime/emit/binary.js +2 -23
  413. package/dist/src/runtime/emit/binary.js.map +1 -1
  414. package/dist/src/runtime/emit/bloom-join.d.ts.map +1 -1
  415. package/dist/src/runtime/emit/bloom-join.js +6 -35
  416. package/dist/src/runtime/emit/bloom-join.js.map +1 -1
  417. package/dist/src/runtime/emit/case.d.ts.map +1 -1
  418. package/dist/src/runtime/emit/case.js +40 -6
  419. package/dist/src/runtime/emit/case.js.map +1 -1
  420. package/dist/src/runtime/emit/cast.d.ts.map +1 -1
  421. package/dist/src/runtime/emit/cast.js +4 -19
  422. package/dist/src/runtime/emit/cast.js.map +1 -1
  423. package/dist/src/runtime/emit/constraint-check.d.ts.map +1 -1
  424. package/dist/src/runtime/emit/constraint-check.js +32 -8
  425. package/dist/src/runtime/emit/constraint-check.js.map +1 -1
  426. package/dist/src/runtime/emit/dml-executor.d.ts.map +1 -1
  427. package/dist/src/runtime/emit/dml-executor.js +90 -50
  428. package/dist/src/runtime/emit/dml-executor.js.map +1 -1
  429. package/dist/src/runtime/emit/drop-index.d.ts.map +1 -1
  430. package/dist/src/runtime/emit/drop-index.js +4 -3
  431. package/dist/src/runtime/emit/drop-index.js.map +1 -1
  432. package/dist/src/runtime/emit/filter.d.ts +18 -0
  433. package/dist/src/runtime/emit/filter.d.ts.map +1 -1
  434. package/dist/src/runtime/emit/filter.js +52 -10
  435. package/dist/src/runtime/emit/filter.js.map +1 -1
  436. package/dist/src/runtime/emit/hash-aggregate.d.ts.map +1 -1
  437. package/dist/src/runtime/emit/hash-aggregate.js +2 -2
  438. package/dist/src/runtime/emit/hash-aggregate.js.map +1 -1
  439. package/dist/src/runtime/emit/join-key-extractor.d.ts +46 -0
  440. package/dist/src/runtime/emit/join-key-extractor.d.ts.map +1 -0
  441. package/dist/src/runtime/emit/join-key-extractor.js +60 -0
  442. package/dist/src/runtime/emit/join-key-extractor.js.map +1 -0
  443. package/dist/src/runtime/emit/join.d.ts.map +1 -1
  444. package/dist/src/runtime/emit/join.js +8 -46
  445. package/dist/src/runtime/emit/join.js.map +1 -1
  446. package/dist/src/runtime/emit/key-set-semi-join.d.ts +29 -0
  447. package/dist/src/runtime/emit/key-set-semi-join.d.ts.map +1 -0
  448. package/dist/src/runtime/emit/key-set-semi-join.js +149 -0
  449. package/dist/src/runtime/emit/key-set-semi-join.js.map +1 -0
  450. package/dist/src/runtime/emit/merge-join.d.ts.map +1 -1
  451. package/dist/src/runtime/emit/merge-join.js +15 -8
  452. package/dist/src/runtime/emit/merge-join.js.map +1 -1
  453. package/dist/src/runtime/emit/operand-comparator.d.ts +70 -0
  454. package/dist/src/runtime/emit/operand-comparator.d.ts.map +1 -0
  455. package/dist/src/runtime/emit/operand-comparator.js +93 -0
  456. package/dist/src/runtime/emit/operand-comparator.js.map +1 -0
  457. package/dist/src/runtime/emit/scan.d.ts.map +1 -1
  458. package/dist/src/runtime/emit/scan.js +11 -2
  459. package/dist/src/runtime/emit/scan.js.map +1 -1
  460. package/dist/src/runtime/emit/schema-declarative.d.ts.map +1 -1
  461. package/dist/src/runtime/emit/schema-declarative.js +30 -0
  462. package/dist/src/runtime/emit/schema-declarative.js.map +1 -1
  463. package/dist/src/runtime/emit/subquery.d.ts.map +1 -1
  464. package/dist/src/runtime/emit/subquery.js +153 -52
  465. package/dist/src/runtime/emit/subquery.js.map +1 -1
  466. package/dist/src/runtime/emit/window.js +36 -23
  467. package/dist/src/runtime/emit/window.js.map +1 -1
  468. package/dist/src/runtime/parallel-driver.d.ts +5 -2
  469. package/dist/src/runtime/parallel-driver.d.ts.map +1 -1
  470. package/dist/src/runtime/parallel-driver.js +6 -2
  471. package/dist/src/runtime/parallel-driver.js.map +1 -1
  472. package/dist/src/runtime/register.d.ts.map +1 -1
  473. package/dist/src/runtime/register.js +2 -0
  474. package/dist/src/runtime/register.js.map +1 -1
  475. package/dist/src/runtime/types.d.ts +7 -0
  476. package/dist/src/runtime/types.d.ts.map +1 -1
  477. package/dist/src/runtime/types.js.map +1 -1
  478. package/dist/src/schema/catalog-persistability.d.ts +19 -16
  479. package/dist/src/schema/catalog-persistability.d.ts.map +1 -1
  480. package/dist/src/schema/catalog-persistability.js +76 -20
  481. package/dist/src/schema/catalog-persistability.js.map +1 -1
  482. package/dist/src/schema/catalog.d.ts +67 -2
  483. package/dist/src/schema/catalog.d.ts.map +1 -1
  484. package/dist/src/schema/catalog.js +194 -3
  485. package/dist/src/schema/catalog.js.map +1 -1
  486. package/dist/src/schema/column.d.ts +26 -3
  487. package/dist/src/schema/column.d.ts.map +1 -1
  488. package/dist/src/schema/column.js.map +1 -1
  489. package/dist/src/schema/ddl-generator.d.ts.map +1 -1
  490. package/dist/src/schema/ddl-generator.js +19 -6
  491. package/dist/src/schema/ddl-generator.js.map +1 -1
  492. package/dist/src/schema/function.d.ts +40 -0
  493. package/dist/src/schema/function.d.ts.map +1 -1
  494. package/dist/src/schema/function.js +10 -2
  495. package/dist/src/schema/function.js.map +1 -1
  496. package/dist/src/schema/manager.d.ts +84 -7
  497. package/dist/src/schema/manager.d.ts.map +1 -1
  498. package/dist/src/schema/manager.js +153 -53
  499. package/dist/src/schema/manager.js.map +1 -1
  500. package/dist/src/schema/schema-differ.d.ts.map +1 -1
  501. package/dist/src/schema/schema-differ.js +104 -28
  502. package/dist/src/schema/schema-differ.js.map +1 -1
  503. package/dist/src/schema/table.d.ts +149 -1
  504. package/dist/src/schema/table.d.ts.map +1 -1
  505. package/dist/src/schema/table.js +248 -1
  506. package/dist/src/schema/table.js.map +1 -1
  507. package/dist/src/schema/unique-enforcement.d.ts +5 -3
  508. package/dist/src/schema/unique-enforcement.d.ts.map +1 -1
  509. package/dist/src/schema/unique-enforcement.js +5 -3
  510. package/dist/src/schema/unique-enforcement.js.map +1 -1
  511. package/dist/src/types/builtin-types.d.ts +16 -0
  512. package/dist/src/types/builtin-types.d.ts.map +1 -1
  513. package/dist/src/types/builtin-types.js +76 -12
  514. package/dist/src/types/builtin-types.js.map +1 -1
  515. package/dist/src/types/cast-semantics.d.ts +42 -0
  516. package/dist/src/types/cast-semantics.d.ts.map +1 -1
  517. package/dist/src/types/cast-semantics.js +64 -0
  518. package/dist/src/types/cast-semantics.js.map +1 -1
  519. package/dist/src/types/comparison-coercion.d.ts +101 -0
  520. package/dist/src/types/comparison-coercion.d.ts.map +1 -0
  521. package/dist/src/types/comparison-coercion.js +162 -0
  522. package/dist/src/types/comparison-coercion.js.map +1 -0
  523. package/dist/src/types/index.d.ts +2 -2
  524. package/dist/src/types/index.d.ts.map +1 -1
  525. package/dist/src/types/index.js +2 -2
  526. package/dist/src/types/index.js.map +1 -1
  527. package/dist/src/types/logical-type.d.ts +7 -0
  528. package/dist/src/types/logical-type.d.ts.map +1 -1
  529. package/dist/src/types/logical-type.js.map +1 -1
  530. package/dist/src/types/validation.d.ts +56 -0
  531. package/dist/src/types/validation.d.ts.map +1 -1
  532. package/dist/src/types/validation.js +68 -0
  533. package/dist/src/types/validation.js.map +1 -1
  534. package/dist/src/util/coercion.d.ts +8 -0
  535. package/dist/src/util/coercion.d.ts.map +1 -1
  536. package/dist/src/util/coercion.js +8 -0
  537. package/dist/src/util/coercion.js.map +1 -1
  538. package/dist/src/util/comparison.d.ts +41 -3
  539. package/dist/src/util/comparison.d.ts.map +1 -1
  540. package/dist/src/util/comparison.js +52 -5
  541. package/dist/src/util/comparison.js.map +1 -1
  542. package/dist/src/util/key-serializer.d.ts +46 -0
  543. package/dist/src/util/key-serializer.d.ts.map +1 -1
  544. package/dist/src/util/key-serializer.js +47 -0
  545. package/dist/src/util/key-serializer.js.map +1 -1
  546. package/dist/src/util/value-set.d.ts +21 -0
  547. package/dist/src/util/value-set.d.ts.map +1 -0
  548. package/dist/src/util/value-set.js +22 -0
  549. package/dist/src/util/value-set.js.map +1 -0
  550. package/dist/src/vtab/best-access-plan.d.ts +87 -0
  551. package/dist/src/vtab/best-access-plan.d.ts.map +1 -1
  552. package/dist/src/vtab/best-access-plan.js +87 -0
  553. package/dist/src/vtab/best-access-plan.js.map +1 -1
  554. package/dist/src/vtab/capabilities.d.ts +1 -1
  555. package/dist/src/vtab/events.d.ts +5 -1
  556. package/dist/src/vtab/events.d.ts.map +1 -1
  557. package/dist/src/vtab/events.js.map +1 -1
  558. package/dist/src/vtab/memory/layer/alter-column.d.ts +147 -0
  559. package/dist/src/vtab/memory/layer/alter-column.d.ts.map +1 -0
  560. package/dist/src/vtab/memory/layer/alter-column.js +214 -0
  561. package/dist/src/vtab/memory/layer/alter-column.js.map +1 -0
  562. package/dist/src/vtab/memory/layer/base.d.ts +6 -4
  563. package/dist/src/vtab/memory/layer/base.d.ts.map +1 -1
  564. package/dist/src/vtab/memory/layer/base.js +10 -7
  565. package/dist/src/vtab/memory/layer/base.js.map +1 -1
  566. package/dist/src/vtab/memory/layer/interface.d.ts +2 -2
  567. package/dist/src/vtab/memory/layer/interface.d.ts.map +1 -1
  568. package/dist/src/vtab/memory/layer/manager.d.ts +232 -39
  569. package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
  570. package/dist/src/vtab/memory/layer/manager.js +657 -519
  571. package/dist/src/vtab/memory/layer/manager.js.map +1 -1
  572. package/dist/src/vtab/memory/layer/scan-layer.d.ts.map +1 -1
  573. package/dist/src/vtab/memory/layer/scan-layer.js +32 -5
  574. package/dist/src/vtab/memory/layer/scan-layer.js.map +1 -1
  575. package/dist/src/vtab/memory/layer/transaction.d.ts +111 -16
  576. package/dist/src/vtab/memory/layer/transaction.d.ts.map +1 -1
  577. package/dist/src/vtab/memory/layer/transaction.js +154 -51
  578. package/dist/src/vtab/memory/layer/transaction.js.map +1 -1
  579. package/dist/src/vtab/memory/module.d.ts +14 -2
  580. package/dist/src/vtab/memory/module.d.ts.map +1 -1
  581. package/dist/src/vtab/memory/module.js +53 -40
  582. package/dist/src/vtab/memory/module.js.map +1 -1
  583. package/dist/src/vtab/memory/table.d.ts +1 -1
  584. package/dist/src/vtab/memory/table.d.ts.map +1 -1
  585. package/dist/src/vtab/memory/table.js +15 -3
  586. package/dist/src/vtab/memory/table.js.map +1 -1
  587. package/dist/src/vtab/module.d.ts +51 -21
  588. package/dist/src/vtab/module.d.ts.map +1 -1
  589. package/dist/src/vtab/table.d.ts +10 -2
  590. package/dist/src/vtab/table.d.ts.map +1 -1
  591. package/dist/src/vtab/table.js +1 -1
  592. package/dist/src/vtab/table.js.map +1 -1
  593. package/package.json +3 -3
@@ -4,18 +4,63 @@
4
4
  * Stamps a stats-derived selectivity onto a FilterNode so its `estimatedRows`
5
5
  * reflects real column statistics instead of the flat DEFAULT_FILTER_SELECTIVITY.
6
6
  *
7
- * Runs in the Physical pass (bottom-up), which fires AFTER the Structural pass —
8
- * predicate-pushdown / grow-retrieve have already put the Filter in its final
9
- * position over its final source, so `extractTableSchema` sees the settled tree.
7
+ * Registered TWICE, both bottom-up:
8
+ *
9
+ * - `filter-selectivity` (Physical pass), which fires AFTER the Structural pass —
10
+ * predicate-pushdown / grow-retrieve have already put the Filter in its final
11
+ * position over its final source, so the source subtree is settled (and may carry
12
+ * physical access nodes between the join and its table references). This stamp is
13
+ * what the physical and PostOptimization cost readers consult.
14
+ * - `filter-selectivity-restamp` (PostOptimization pass, registered first in that
15
+ * pass), which recovers the estimate for a Filter whose stamp was dropped by
16
+ * `FilterNode.withChildren` because PostOptimization rewrote something inside its
17
+ * predicate — `scalar-subquery-cache` wrapping an uncorrelated scalar subquery's
18
+ * inner re-mints every scalar ancestor up to the predicate. Without it, any query
19
+ * with a subquery in its `where` plans on the flat DEFAULT_FILTER_SELECTIVITY.
20
+ *
21
+ * The `selectivity !== undefined` guard below makes the second registration a no-op on
22
+ * every Filter whose stamp survived, so it only ever fills in, never overwrites. Both
23
+ * firings read a physical source subtree (`select-access-path` has already replaced
24
+ * Retrieve with an access node by the Physical pass's own bottom-up order);
25
+ * PostOptimization sources are the same shape or further lowered.
10
26
  *
11
27
  * Node-level accessors (`estimatedRows` / `computePhysical`) carry no OptContext,
12
28
  * so a Filter cannot consult `context.stats` from inside itself. This rule holds
13
29
  * the context, does the lookup, and mints a stamped Filter — the estimate then
14
30
  * flows through `estimatedRows` automatically.
31
+ *
32
+ * Two paths:
33
+ * - **single-table** — `extractRowSourceTableSchema` finds one base table under
34
+ * the Filter *whose rows are the ones arriving at it*; hand the whole predicate
35
+ * to the provider, which decomposes its boolean structure itself.
36
+ * - **multi-relation** — the source spans several tables (a join), or the strict
37
+ * walk declined. Split the predicate into conjuncts, attribute each to the base
38
+ * table(s) its columns come from, estimate per conjunct, and combine.
39
+ *
40
+ * The strict walk matters because an aggregate's output rows are a different
41
+ * population from its source's, so no fraction of the base table describes them at
42
+ * all: over `select cat, count(*) as ct from o group by cat having ct > 2` the
43
+ * permissive `extractTableSchema` reaches `o` through the aggregate, but `o`'s row
44
+ * count and column distributions say nothing about how many GROUPS survive `ct > 2`.
45
+ *
46
+ * Both paths hand the provider a {@link ColumnStatsResolver} built from
47
+ * `collectColumnOrigins`, so a column in the predicate is matched to statistics by
48
+ * ATTRIBUTE IDENTITY rather than by the name in its AST. `ProjectNode` forwards the
49
+ * source attribute id for a bare column reference and mints a fresh one for a
50
+ * computed expression, which is exactly the distinction wanted: `select cat as qty`
51
+ * still reads `o.cat`'s statistics, while `select id * 7 as qty` reads none rather
52
+ * than borrowing `o.qty`'s because the alias happens to collide. A CTE reference
53
+ * republishes its body's columns under per-reference relation instances, so a `with`
54
+ * clause estimates like the equivalent subquery while the two arms of a CTE self-join
55
+ * still count as two relations — see `column-origins.ts`.
15
56
  */
16
57
  import { createLogger } from '../../../common/logger.js';
17
58
  import { FilterNode } from '../../nodes/filter.js';
18
- import { extractTableSchema } from '../../util/key-utils.js';
59
+ import { extractRowSourceTableSchema } from '../../util/key-utils.js';
60
+ import { collectColumnOrigins } from '../../util/column-origins.js';
61
+ import { splitConjuncts } from '../../analysis/predicate-conjuncts.js';
62
+ import { combineConjunctive } from '../../stats/selectivity-combine.js';
63
+ import { estimateConjunctSelectivity, makeColumnStatsResolver } from '../../stats/conjunct-selectivity.js';
19
64
  const log = createLogger('optimizer:rule:filter-selectivity');
20
65
  export function ruleFilterSelectivity(node, context) {
21
66
  const filter = node;
@@ -24,25 +69,104 @@ export function ruleFilterSelectivity(node, context) {
24
69
  // makes the rule safe on any already-stamped node regardless.)
25
70
  if (filter.selectivity !== undefined)
26
71
  return null;
27
- // extractTableSchema walks single-child wrappers (Filter/Project/Sort/Retrieve/
28
- // TableReference) to the base table. It returns undefined for a join / other
29
- // multi-table source — leave the default 0.5 there (multi-column / join
30
- // selectivity is parked in backlog feat-conjunction-and-join-selectivity).
31
- const tableSchema = extractTableSchema(filter.source);
32
- if (!tableSchema)
33
- return null;
34
- // NOTE: conjunctive predicates (`a = 1 and b = 2`) are NOT decomposed. The
35
- // CatalogStatsProvider finds no single column child on the AND root and falls
36
- // back to NaiveStatsProvider's coarse per-nodeType heuristic (0.1 for any
37
- // BinaryOp). Crude but not a regression vs. the old flat 0.5 — conjunction
38
- // decomposition is parked in backlog feat-conjunction-and-join-selectivity.
39
- const sel = context.stats.selectivity(tableSchema, filter.predicate);
72
+ // extractRowSourceTableSchema walks single-child wrappers (Filter/Project/Sort/
73
+ // Retrieve/TableReference) to the base table, but stops at any operator whose
74
+ // output rows are not its source's rows (aggregate, recursive CTE, set operation).
75
+ // It returns undefined for those and for a join / other multi-relation source,
76
+ // which is what the second path handles.
77
+ const tableSchema = extractRowSourceTableSchema(filter.source);
78
+ // Attribute id → base-table column, for every base column under the Filter. Both
79
+ // paths need it: the multi-relation path to route a conjunct to a relation, and
80
+ // both paths to identify a predicate's columns by identity rather than by name.
81
+ //
82
+ // NOTE: this walk covers the whole source subtree and this rule fires per
83
+ // FilterNode, so a stack of N filters over one large subtree costs O(N·subtree) —
84
+ // and unlike before, it now runs for EVERY Filter, not only filters over joins.
85
+ // `rule-filter-conjunct-ordering` (PostOptimization) runs the SAME walk again on
86
+ // each Filter it ranks, so the walk now happens twice per Filter. The walk is
87
+ // cheap per node and filter stacks are shallow; if it ever shows up in an
88
+ // optimizer profile, memoize the map per pass on OptContext keyed by the source
89
+ // node (or — for the single-table path only — build the resolver from the one
90
+ // TableReferenceNode the strict walk already found, O(columns) not O(subtree)).
91
+ const origins = collectColumnOrigins(filter.source);
92
+ const sel = tableSchema
93
+ ? singleTableSelectivity(tableSchema, filter, origins, context)
94
+ : multiRelationSelectivity(filter, origins, context);
40
95
  if (sel === undefined)
41
96
  return null;
42
97
  const clamped = Math.min(1, Math.max(0, sel));
43
- log('Filter over %s: stamping selectivity %f', tableSchema.name, clamped);
44
98
  // Rebuild the identical Filter (same scope, source, predicate → same output
45
99
  // attribute ids) with only the added estimate — hence sideEffectMode 'safe'.
46
100
  return new FilterNode(filter.scope, filter.source, filter.predicate, undefined, clamped);
47
101
  }
102
+ // ── Single-table path ───────────────────────────────────────────────────
103
+ function singleTableSelectivity(tableSchema, filter, origins, context) {
104
+ // CatalogStatsProvider recurses over the predicate's boolean structure, so
105
+ // `a = 1 and b = 2` combines the two per-column estimates rather than falling
106
+ // back to a flat per-nodeType guess. It still returns undefined when it can say
107
+ // nothing at all, in which case the naive heuristic applies as before.
108
+ //
109
+ // NOTE: this path is deliberately NOT gated on real statistics existing — it may
110
+ // still stamp a NaiveStatsProvider number, as it always has. The multi-relation
111
+ // path below IS gated; see the comment there for why the asymmetry is on purpose.
112
+ //
113
+ // Schema equality is the right narrowing here: the strict walk established that
114
+ // exactly this table's rows arrive at the Filter, so any origin under it belongs
115
+ // to that one reference anyway.
116
+ const resolve = makeColumnStatsResolver(origins, origin => origin.table === tableSchema);
117
+ const sel = context.stats.selectivity(tableSchema, filter.predicate, resolve);
118
+ if (sel === undefined)
119
+ return undefined;
120
+ log('Filter over %s: stamping selectivity %f', tableSchema.name, sel);
121
+ return sel;
122
+ }
123
+ // ── Multi-relation path ─────────────────────────────────────────────────
124
+ /**
125
+ * Estimate a filter whose source spans several base tables by attributing each
126
+ * conjunct to the relation(s) its columns come from.
127
+ *
128
+ * NOTE: join type is ignored. A `left`/`right`/`full` join emits NULL-extended
129
+ * rows, which makes a predicate on the non-preserved side more selective than the
130
+ * base-table fraction suggests and one on the preserved side less so. Applying the
131
+ * base-table fraction either way is the conventional simplification, not an
132
+ * oversight.
133
+ *
134
+ * NOTE: an `aggregate` between the Filter and the join forwards group-key attribute
135
+ * ids unchanged, so a predicate on a group key is attributed to its base table and
136
+ * the base-table fraction is applied to post-aggregate cardinality. Imprecise but
137
+ * not unsound; deliberately not special-cased.
138
+ *
139
+ * NOTE: the stamped number does move `estimatedRows` above a join — the join family
140
+ * derives its physical cardinality from its children's PHYSICAL counts
141
+ * (`physicalSourceRows` / `joinPhysicalRows`), so a Filter over a join has a real
142
+ * number to multiply. It still has nothing to multiply above a `union`/`union all`,
143
+ * where `SetOperationNode` stamps no count at all (backlog
144
+ * `debt-row-estimates-die-at-set-operations`).
145
+ */
146
+ function multiRelationSelectivity(filter, origins, context) {
147
+ if (origins.size === 0)
148
+ return undefined;
149
+ const conjuncts = splitConjuncts(filter.predicate);
150
+ const known = [];
151
+ for (const conjunct of conjuncts) {
152
+ const sel = estimateConjunctSelectivity(conjunct, origins, context);
153
+ if (sel !== undefined)
154
+ known.push(sel);
155
+ }
156
+ // Nothing estimable → leave the Filter unstamped exactly as before this path existed.
157
+ if (known.length === 0)
158
+ return undefined;
159
+ const combined = combineConjunctive(known);
160
+ // countRelations walks the whole origin map; keep it off the hot path.
161
+ if (log.enabled) {
162
+ log('Filter over %d relations: %d/%d conjuncts estimated, stamping %f', countRelations(origins), known.length, conjuncts.length, combined);
163
+ }
164
+ return combined;
165
+ }
166
+ function countRelations(origins) {
167
+ const relations = new Set();
168
+ for (const origin of origins.values())
169
+ relations.add(origin.relation);
170
+ return relations.size;
171
+ }
48
172
  //# sourceMappingURL=rule-filter-selectivity.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"rule-filter-selectivity.js","sourceRoot":"","sources":["../../../../../src/planner/rules/predicate/rule-filter-selectivity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAGzD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D,MAAM,GAAG,GAAG,YAAY,CAAC,mCAAmC,CAAC,CAAC;AAE9D,MAAM,UAAU,qBAAqB,CAAC,IAAc,EAAE,OAAmB;IACxE,MAAM,MAAM,GAAG,IAAkB,CAAC;IAElC,4EAA4E;IAC5E,2EAA2E;IAC3E,+DAA+D;IAC/D,IAAI,MAAM,CAAC,WAAW,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAElD,gFAAgF;IAChF,6EAA6E;IAC7E,wEAAwE;IACxE,2EAA2E;IAC3E,MAAM,WAAW,GAAG,kBAAkB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACtD,IAAI,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAE9B,2EAA2E;IAC3E,8EAA8E;IAC9E,0EAA0E;IAC1E,2EAA2E;IAC3E,4EAA4E;IAC5E,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,WAAW,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IACrE,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAEnC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAC9C,GAAG,CAAC,yCAAyC,EAAE,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAE1E,4EAA4E;IAC5E,6EAA6E;IAC7E,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;AAC1F,CAAC"}
1
+ {"version":3,"file":"rule-filter-selectivity.js","sourceRoot":"","sources":["../../../../../src/planner/rules/predicate/rule-filter-selectivity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Rule: Join Predicate Pushdown
3
+ *
4
+ * For a `FilterNode(predicate, JoinNode)`, each conjunct of `predicate` whose
5
+ * column references all land on ONE side of the join is MOVED onto that side's
6
+ * branch (wrapped as a `FilterNode` around `join.left` / `join.right`).
7
+ * Cross-side conjuncts, and anything the refusals below reject, stay in a
8
+ * residual Filter above the rebuilt join.
9
+ *
10
+ * Why this is sound — the null-extension argument. A side may receive a
11
+ * conjunct exactly when that side's columns are NEVER null-extended in the
12
+ * join's output (read straight off `buildJoinAttributes` in
13
+ * `nodes/join-utils.ts`). For such a side, every output row carries that side's
14
+ * genuine input values, so rejecting an input row before the join removes
15
+ * precisely the output rows the conjunct would have removed after it. On a
16
+ * null-extended side the two differ: `left join r … where r.date > 'x'` drops
17
+ * the NULL-padded rows after the join, but pushing `r.date > 'x'` below would
18
+ * KEEP them (the left row simply finds no match and is padded again).
19
+ *
20
+ * | joinType | null-extended side | conjuncts pushable to |
21
+ * |----------|--------------------|-----------------------|
22
+ * | `inner` | neither | left and right |
23
+ * | `cross` | neither | left and right |
24
+ * | `left` | right | left only |
25
+ * | `right` | left | right only |
26
+ * | `full` | both | neither — rule declines |
27
+ * | `semi` | n/a (output is left columns) | left only |
28
+ * | `anti` | n/a (output is left columns) | left only |
29
+ *
30
+ * For `semi`/`anti` the left-only restriction is moot in practice —
31
+ * `buildJoinAttributes` returns only the left attributes, so a Filter above such
32
+ * a join cannot reference a right column at all — but it is encoded anyway so
33
+ * the table is exhaustive and the reasoning stays local.
34
+ *
35
+ * Attribution is a plain attribute-id set test: ids are minted per node instance
36
+ * and are stable across this pass's rewrites, so a self-join's two branches
37
+ * carry distinct ids, and a join's `exists … as` flag ids are in neither side's
38
+ * set (a conjunct over a flag falls out as un-pushable with no special case).
39
+ *
40
+ * Refusals:
41
+ * - A conjunct whose subtree references a RELATIONAL child (any subquery) is
42
+ * left above. The id collector descends through relational children too, so
43
+ * `exists (select 1 from x where x.a = e.id and x.b = t.id)` contributes `x`'s
44
+ * own ids — which belong to neither side — and the conjunct is declined. That
45
+ * descent is load-bearing: a scalar-only walk would see only `e.id` and push a
46
+ * conjunct onto the left branch where `t.id` does not resolve.
47
+ * - Symmetrically, a conjunct naming a column from OUTSIDE the join — an outer
48
+ * reference, when this `Filter(Join)` is itself the body of a correlated
49
+ * subquery — sees an id in neither side's set and is declined.
50
+ * NOTE: sound but pessimistic — `x.a = <outer>.b` would be safe on the `x`
51
+ * branch. Ignoring "in neither side" ids instead of refusing on them would
52
+ * recover that, but only after separating a genuinely-outer id from a
53
+ * subquery-internal one, which this walk does not currently distinguish.
54
+ * Left alone until a real correlated body is measured losing a seek to it.
55
+ * - A conjunct with NO column references (`where 1 = 1`, `where :p > 0`) stays
56
+ * above; pushing it buys nothing and would make the rule fire on plans it
57
+ * should leave alone.
58
+ * - A non-functional conjunct (`random() < e.amount`) stays above — moving it
59
+ * below the join changes how many times it is evaluated.
60
+ * - A branch whose subtree carries a write keeps ITS conjuncts above while the
61
+ * other branch still receives its own (per-branch refusal, unlike
62
+ * `rule-predicate-inference-equivalence`'s outright one).
63
+ *
64
+ * A pushed conjunct is MOVED, not copied. A redundant copy above would
65
+ * re-evaluate per output row for no gain and, worse, make the rule
66
+ * non-idempotent — it would find the same pushable conjunct on every visit.
67
+ * With a move, a re-visit of the residual Filter finds nothing pushable and
68
+ * returns null, which is the termination argument.
69
+ */
70
+ import type { PlanNode } from '../../nodes/plan-node.js';
71
+ import type { OptContext } from '../../framework/context.js';
72
+ export declare function ruleJoinPredicatePushdown(node: PlanNode, _context: OptContext): PlanNode | null;
73
+ //# sourceMappingURL=rule-join-predicate-pushdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule-join-predicate-pushdown.d.ts","sourceRoot":"","sources":["../../../../../src/planner/rules/predicate/rule-join-predicate-pushdown.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoEG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAsC,MAAM,0BAA0B,CAAC;AAC7F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAyE7D,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,GAAG,QAAQ,GAAG,IAAI,CA0E/F"}
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Rule: Join Predicate Pushdown
3
+ *
4
+ * For a `FilterNode(predicate, JoinNode)`, each conjunct of `predicate` whose
5
+ * column references all land on ONE side of the join is MOVED onto that side's
6
+ * branch (wrapped as a `FilterNode` around `join.left` / `join.right`).
7
+ * Cross-side conjuncts, and anything the refusals below reject, stay in a
8
+ * residual Filter above the rebuilt join.
9
+ *
10
+ * Why this is sound — the null-extension argument. A side may receive a
11
+ * conjunct exactly when that side's columns are NEVER null-extended in the
12
+ * join's output (read straight off `buildJoinAttributes` in
13
+ * `nodes/join-utils.ts`). For such a side, every output row carries that side's
14
+ * genuine input values, so rejecting an input row before the join removes
15
+ * precisely the output rows the conjunct would have removed after it. On a
16
+ * null-extended side the two differ: `left join r … where r.date > 'x'` drops
17
+ * the NULL-padded rows after the join, but pushing `r.date > 'x'` below would
18
+ * KEEP them (the left row simply finds no match and is padded again).
19
+ *
20
+ * | joinType | null-extended side | conjuncts pushable to |
21
+ * |----------|--------------------|-----------------------|
22
+ * | `inner` | neither | left and right |
23
+ * | `cross` | neither | left and right |
24
+ * | `left` | right | left only |
25
+ * | `right` | left | right only |
26
+ * | `full` | both | neither — rule declines |
27
+ * | `semi` | n/a (output is left columns) | left only |
28
+ * | `anti` | n/a (output is left columns) | left only |
29
+ *
30
+ * For `semi`/`anti` the left-only restriction is moot in practice —
31
+ * `buildJoinAttributes` returns only the left attributes, so a Filter above such
32
+ * a join cannot reference a right column at all — but it is encoded anyway so
33
+ * the table is exhaustive and the reasoning stays local.
34
+ *
35
+ * Attribution is a plain attribute-id set test: ids are minted per node instance
36
+ * and are stable across this pass's rewrites, so a self-join's two branches
37
+ * carry distinct ids, and a join's `exists … as` flag ids are in neither side's
38
+ * set (a conjunct over a flag falls out as un-pushable with no special case).
39
+ *
40
+ * Refusals:
41
+ * - A conjunct whose subtree references a RELATIONAL child (any subquery) is
42
+ * left above. The id collector descends through relational children too, so
43
+ * `exists (select 1 from x where x.a = e.id and x.b = t.id)` contributes `x`'s
44
+ * own ids — which belong to neither side — and the conjunct is declined. That
45
+ * descent is load-bearing: a scalar-only walk would see only `e.id` and push a
46
+ * conjunct onto the left branch where `t.id` does not resolve.
47
+ * - Symmetrically, a conjunct naming a column from OUTSIDE the join — an outer
48
+ * reference, when this `Filter(Join)` is itself the body of a correlated
49
+ * subquery — sees an id in neither side's set and is declined.
50
+ * NOTE: sound but pessimistic — `x.a = <outer>.b` would be safe on the `x`
51
+ * branch. Ignoring "in neither side" ids instead of refusing on them would
52
+ * recover that, but only after separating a genuinely-outer id from a
53
+ * subquery-internal one, which this walk does not currently distinguish.
54
+ * Left alone until a real correlated body is measured losing a seek to it.
55
+ * - A conjunct with NO column references (`where 1 = 1`, `where :p > 0`) stays
56
+ * above; pushing it buys nothing and would make the rule fire on plans it
57
+ * should leave alone.
58
+ * - A non-functional conjunct (`random() < e.amount`) stays above — moving it
59
+ * below the join changes how many times it is evaluated.
60
+ * - A branch whose subtree carries a write keeps ITS conjuncts above while the
61
+ * other branch still receives its own (per-branch refusal, unlike
62
+ * `rule-predicate-inference-equivalence`'s outright one).
63
+ *
64
+ * A pushed conjunct is MOVED, not copied. A redundant copy above would
65
+ * re-evaluate per output row for no gain and, worse, make the rule
66
+ * non-idempotent — it would find the same pushable conjunct on every visit.
67
+ * With a move, a re-visit of the residual Filter finds nothing pushable and
68
+ * returns null, which is the termination argument.
69
+ */
70
+ import { createLogger } from '../../../common/logger.js';
71
+ import { PlanNodeType } from '../../nodes/plan-node-type.js';
72
+ import { FilterNode } from '../../nodes/filter.js';
73
+ import { JoinNode } from '../../nodes/join-node.js';
74
+ import { ColumnReferenceNode } from '../../nodes/reference.js';
75
+ import { normalizePredicate } from '../../analysis/predicate-normalizer.js';
76
+ import { splitConjuncts, combineConjuncts } from '../../analysis/predicate-conjuncts.js';
77
+ import { PlanNodeCharacteristics } from '../../framework/characteristics.js';
78
+ const log = createLogger('optimizer:rule:join-predicate-pushdown');
79
+ /** The sides of `joinType` that are never null-extended in the output — see the header table. */
80
+ function pushableSides(joinType) {
81
+ switch (joinType) {
82
+ case 'inner':
83
+ case 'cross':
84
+ return new Set(['left', 'right']);
85
+ case 'left':
86
+ case 'semi':
87
+ case 'anti':
88
+ return new Set(['left']);
89
+ case 'right':
90
+ return new Set(['right']);
91
+ case 'full':
92
+ return new Set();
93
+ default:
94
+ return new Set();
95
+ }
96
+ }
97
+ /**
98
+ * Every attribute id any `ColumnReferenceNode` in `expr`'s WHOLE subtree names —
99
+ * descending through relational children as well as scalar ones. See the
100
+ * file-header refusal notes for why the relational descent is required.
101
+ */
102
+ function collectSubtreeAttributeIds(expr) {
103
+ const ids = new Set();
104
+ // Iterative worklist so a deep predicate cannot overflow the native stack.
105
+ const stack = [expr];
106
+ while (stack.length > 0) {
107
+ const current = stack.pop();
108
+ if (current instanceof ColumnReferenceNode) {
109
+ ids.add(current.attributeId);
110
+ }
111
+ for (const child of current.getChildren()) {
112
+ stack.push(child);
113
+ }
114
+ }
115
+ return ids;
116
+ }
117
+ /** The single side `ids` lands entirely on, or null when it spans / escapes both. */
118
+ function attributeSide(ids, leftIds, rightIds) {
119
+ let allLeft = true;
120
+ let allRight = true;
121
+ for (const id of ids) {
122
+ if (!leftIds.has(id))
123
+ allLeft = false;
124
+ if (!rightIds.has(id))
125
+ allRight = false;
126
+ if (!allLeft && !allRight)
127
+ return null;
128
+ }
129
+ // A self-join mints distinct ids per branch, so the two sets are disjoint and
130
+ // a non-empty `ids` can satisfy at most one of these.
131
+ if (allLeft)
132
+ return 'left';
133
+ if (allRight)
134
+ return 'right';
135
+ return null;
136
+ }
137
+ export function ruleJoinPredicatePushdown(node, _context) {
138
+ if (node.nodeType !== PlanNodeType.Filter)
139
+ return null;
140
+ const filter = node;
141
+ const join = filter.source;
142
+ if (!(join instanceof JoinNode))
143
+ return null;
144
+ const sides = pushableSides(join.joinType);
145
+ if (sides.size === 0)
146
+ return null;
147
+ const leftIds = new Set(join.left.getAttributes().map(a => a.id));
148
+ const rightIds = new Set(join.right.getAttributes().map(a => a.id));
149
+ const conjuncts = splitConjuncts(normalizePredicate(filter.predicate));
150
+ let leftPush = [];
151
+ let rightPush = [];
152
+ const residual = [];
153
+ for (const conj of conjuncts) {
154
+ const ids = collectSubtreeAttributeIds(conj);
155
+ // No column reference at all (`1 = 1`, `:p > 0`): nothing to gain below.
156
+ if (ids.size === 0) {
157
+ residual.push(conj);
158
+ continue;
159
+ }
160
+ // Non-deterministic / write-bearing conjunct: moving it changes how many
161
+ // times it is evaluated.
162
+ if (!PlanNodeCharacteristics.isFunctional(conj)) {
163
+ residual.push(conj);
164
+ continue;
165
+ }
166
+ const side = attributeSide(ids, leftIds, rightIds);
167
+ if (side === null || !sides.has(side)) {
168
+ residual.push(conj);
169
+ continue;
170
+ }
171
+ (side === 'left' ? leftPush : rightPush).push(conj);
172
+ }
173
+ // Per-branch side-effect refusal: a branch carrying a write keeps its own
174
+ // conjuncts above while the other branch still receives its.
175
+ if (leftPush.length > 0 && PlanNodeCharacteristics.subtreeHasSideEffects(join.left)) {
176
+ log('join-predicate-pushdown: left branch has side effects; keeping its conjuncts above');
177
+ residual.push(...leftPush);
178
+ leftPush = [];
179
+ }
180
+ if (rightPush.length > 0 && PlanNodeCharacteristics.subtreeHasSideEffects(join.right)) {
181
+ log('join-predicate-pushdown: right branch has side effects; keeping its conjuncts above');
182
+ residual.push(...rightPush);
183
+ rightPush = [];
184
+ }
185
+ if (leftPush.length === 0 && rightPush.length === 0)
186
+ return null;
187
+ const newLeft = leftPush.length > 0
188
+ ? new FilterNode(join.left.scope, join.left, combineConjuncts(leftPush))
189
+ : join.left;
190
+ const newRight = rightPush.length > 0
191
+ ? new FilterNode(join.right.scope, join.right, combineConjuncts(rightPush))
192
+ : join.right;
193
+ // `withChildren` (not `new JoinNode(...)`) so `existence` and `usingColumns`
194
+ // thread through — a dropped existence spec strands every upstream reference
195
+ // to the flag's attribute id.
196
+ const newChildren = join.condition
197
+ ? [newLeft, newRight, join.condition]
198
+ : [newLeft, newRight];
199
+ const newJoin = join.withChildren(newChildren);
200
+ log('Pushed %d left + %d right conjunct(s) below %s join (%d residual)', leftPush.length, rightPush.length, join.joinType, residual.length);
201
+ if (residual.length === 0)
202
+ return newJoin;
203
+ return new FilterNode(filter.scope, newJoin, combineConjuncts(residual));
204
+ }
205
+ //# sourceMappingURL=rule-join-predicate-pushdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule-join-predicate-pushdown.js","sourceRoot":"","sources":["../../../../../src/planner/rules/predicate/rule-join-predicate-pushdown.ts"],"names":[],"mappings":"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"}
@@ -15,14 +15,17 @@
15
15
  * `col = value` conjunct.
16
16
  * - AND the new conjuncts into the filter predicate.
17
17
  *
18
- * Powerful form (additional when source is an inner/cross JoinNode):
19
- * - Split the newly-inferred conjuncts by which side of the join their
20
- * columns reference. For each single-side conjunct, inject a FilterNode
21
- * wrapping that side of the join, re-keyed onto the branch's local
22
- * column indices.
23
- * - The outer FilterNode still carries the augmented predicate; the
24
- * branch filter is what subsequent predicate-pushdown can carry into
25
- * the leaf's Retrieve pipeline.
18
+ * Getting the inferred conjunct onto the branch is NOT this rule's job.
19
+ * `rule-join-predicate-pushdown` (registered immediately after this one, so it
20
+ * fires on this rule's own output within the same node visit) moves every
21
+ * single-side conjunct of the augmented predicate — original and inferred alike —
22
+ * onto the branch it constrains, and `rule-predicate-pushdown` then carries it
23
+ * across that branch's Alias into its Retrieve. This rule used to inject those
24
+ * branch Filters itself, back when no rule could cross a join; doing both now
25
+ * materializes the same conjunct twice on one branch (`u.k = 5 AND u.k = 5`), so
26
+ * the injection was removed rather than duplicated. Disabling
27
+ * `join-predicate-pushdown` therefore also stops inferred conjuncts from reaching
28
+ * a branch — they still land in the Filter above the join.
26
29
  *
27
30
  * Fixpoint guard: the rule's emission set is `{otherIdx ∈ EC | otherIdx
28
31
  * is not already in predBoundIdx}`. On a second invocation the
@@ -33,10 +36,10 @@
33
36
  * Safety:
34
37
  * - LEFT/RIGHT/FULL joins: per `propagateJoinFds`, NULL-padded sides drop
35
38
  * their bindings/ECs, so the EC visible at the filter's source is
36
- * restricted to the preserved side. The rule additionally refuses
37
- * branch injection on these join types (outer filter only).
39
+ * restricted to the preserved side — no conjunct over a null-extended
40
+ * side can be inferred here in the first place.
38
41
  * - SEMI/ANTI: only the left side is in the output; no right inference
39
- * can arise here. Treat as LEFT for branch injection.
42
+ * can arise here.
40
43
  *
41
44
  * See ticket `3-rule-predicate-inference-equivalence` for the full design.
42
45
  */
@@ -1 +1 @@
1
- {"version":3,"file":"rule-predicate-inference-equivalence.d.ts","sourceRoot":"","sources":["../../../../../src/planner/rules/predicate/rule-predicate-inference-equivalence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAGH,OAAO,KAAK,EAAE,UAAU,IAAI,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAqB5E,wBAAgB,iCAAiC,CAAC,IAAI,EAAE,OAAO,0BAA0B,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,GAAG,OAAO,0BAA0B,EAAE,QAAQ,GAAG,IAAI,CA2D9K"}
1
+ {"version":3,"file":"rule-predicate-inference-equivalence.d.ts","sourceRoot":"","sources":["../../../../../src/planner/rules/predicate/rule-predicate-inference-equivalence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAGH,OAAO,KAAK,EAAE,UAAU,IAAI,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAW5E,wBAAgB,iCAAiC,CAAC,IAAI,EAAE,OAAO,0BAA0B,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,GAAG,OAAO,0BAA0B,EAAE,QAAQ,GAAG,IAAI,CAuD9K"}