@quereus/quereus 4.5.0 → 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 (468) hide show
  1. package/README.md +4 -3
  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-plan-builders.d.ts.map +1 -1
  7. package/dist/src/core/database-materialized-views-plan-builders.js +29 -2
  8. package/dist/src/core/database-materialized-views-plan-builders.js.map +1 -1
  9. package/dist/src/core/database-transaction.d.ts +9 -0
  10. package/dist/src/core/database-transaction.d.ts.map +1 -1
  11. package/dist/src/core/database-transaction.js +9 -0
  12. package/dist/src/core/database-transaction.js.map +1 -1
  13. package/dist/src/core/database.d.ts +7 -1
  14. package/dist/src/core/database.d.ts.map +1 -1
  15. package/dist/src/core/database.js +20 -5
  16. package/dist/src/core/database.js.map +1 -1
  17. package/dist/src/func/builtins/aggregate.js +11 -11
  18. package/dist/src/func/builtins/aggregate.js.map +1 -1
  19. package/dist/src/func/builtins/builtin-window-functions.d.ts.map +1 -1
  20. package/dist/src/func/builtins/builtin-window-functions.js +15 -85
  21. package/dist/src/func/builtins/builtin-window-functions.js.map +1 -1
  22. package/dist/src/func/builtins/conversion.d.ts.map +1 -1
  23. package/dist/src/func/builtins/conversion.js +10 -9
  24. package/dist/src/func/builtins/conversion.js.map +1 -1
  25. package/dist/src/func/builtins/datetime.d.ts.map +1 -1
  26. package/dist/src/func/builtins/datetime.js +28 -10
  27. package/dist/src/func/builtins/datetime.js.map +1 -1
  28. package/dist/src/func/builtins/json.d.ts.map +1 -1
  29. package/dist/src/func/builtins/json.js +23 -17
  30. package/dist/src/func/builtins/json.js.map +1 -1
  31. package/dist/src/func/builtins/mutation.js +2 -2
  32. package/dist/src/func/builtins/mutation.js.map +1 -1
  33. package/dist/src/func/builtins/return-types.d.ts +327 -0
  34. package/dist/src/func/builtins/return-types.d.ts.map +1 -0
  35. package/dist/src/func/builtins/return-types.js +43 -0
  36. package/dist/src/func/builtins/return-types.js.map +1 -0
  37. package/dist/src/func/builtins/scalar.d.ts.map +1 -1
  38. package/dist/src/func/builtins/scalar.js +138 -71
  39. package/dist/src/func/builtins/scalar.js.map +1 -1
  40. package/dist/src/func/builtins/schema.d.ts.map +1 -1
  41. package/dist/src/func/builtins/schema.js +11 -3
  42. package/dist/src/func/builtins/schema.js.map +1 -1
  43. package/dist/src/func/builtins/string.d.ts.map +1 -1
  44. package/dist/src/func/builtins/string.js +4 -2
  45. package/dist/src/func/builtins/string.js.map +1 -1
  46. package/dist/src/func/builtins/timespan.d.ts +3 -0
  47. package/dist/src/func/builtins/timespan.d.ts.map +1 -1
  48. package/dist/src/func/builtins/timespan.js +15 -11
  49. package/dist/src/func/builtins/timespan.js.map +1 -1
  50. package/dist/src/func/registration.d.ts +35 -1
  51. package/dist/src/func/registration.d.ts.map +1 -1
  52. package/dist/src/func/registration.js +235 -41
  53. package/dist/src/func/registration.js.map +1 -1
  54. package/dist/src/index.d.ts +11 -4
  55. package/dist/src/index.d.ts.map +1 -1
  56. package/dist/src/index.js +12 -3
  57. package/dist/src/index.js.map +1 -1
  58. package/dist/src/parser/parser.d.ts +46 -0
  59. package/dist/src/parser/parser.d.ts.map +1 -1
  60. package/dist/src/parser/parser.js +160 -44
  61. package/dist/src/parser/parser.js.map +1 -1
  62. package/dist/src/planner/analysis/check-extraction.d.ts.map +1 -1
  63. package/dist/src/planner/analysis/check-extraction.js +37 -4
  64. package/dist/src/planner/analysis/check-extraction.js.map +1 -1
  65. package/dist/src/planner/analysis/comparison-collation.d.ts +20 -22
  66. package/dist/src/planner/analysis/comparison-collation.d.ts.map +1 -1
  67. package/dist/src/planner/analysis/comparison-collation.js +29 -26
  68. package/dist/src/planner/analysis/comparison-collation.js.map +1 -1
  69. package/dist/src/planner/analysis/constraint-extractor.d.ts +0 -7
  70. package/dist/src/planner/analysis/constraint-extractor.d.ts.map +1 -1
  71. package/dist/src/planner/analysis/constraint-extractor.js +59 -59
  72. package/dist/src/planner/analysis/constraint-extractor.js.map +1 -1
  73. package/dist/src/planner/building/alter-table.d.ts.map +1 -1
  74. package/dist/src/planner/building/alter-table.js +65 -27
  75. package/dist/src/planner/building/alter-table.js.map +1 -1
  76. package/dist/src/planner/building/coercion.d.ts +21 -45
  77. package/dist/src/planner/building/coercion.d.ts.map +1 -1
  78. package/dist/src/planner/building/coercion.js +42 -91
  79. package/dist/src/planner/building/coercion.js.map +1 -1
  80. package/dist/src/planner/building/expression.d.ts +17 -0
  81. package/dist/src/planner/building/expression.d.ts.map +1 -1
  82. package/dist/src/planner/building/expression.js +28 -17
  83. package/dist/src/planner/building/expression.js.map +1 -1
  84. package/dist/src/planner/building/function-call.d.ts.map +1 -1
  85. package/dist/src/planner/building/function-call.js +7 -2
  86. package/dist/src/planner/building/function-call.js.map +1 -1
  87. package/dist/src/planner/building/select-aggregates.d.ts +1 -1
  88. package/dist/src/planner/building/select-aggregates.d.ts.map +1 -1
  89. package/dist/src/planner/building/select-aggregates.js +53 -2
  90. package/dist/src/planner/building/select-aggregates.js.map +1 -1
  91. package/dist/src/planner/building/select-context.d.ts +7 -0
  92. package/dist/src/planner/building/select-context.d.ts.map +1 -1
  93. package/dist/src/planner/building/select-context.js +10 -40
  94. package/dist/src/planner/building/select-context.js.map +1 -1
  95. package/dist/src/planner/building/select.d.ts +37 -1
  96. package/dist/src/planner/building/select.d.ts.map +1 -1
  97. package/dist/src/planner/building/select.js +112 -51
  98. package/dist/src/planner/building/select.js.map +1 -1
  99. package/dist/src/planner/cost/conjunct-cost.d.ts +40 -0
  100. package/dist/src/planner/cost/conjunct-cost.d.ts.map +1 -1
  101. package/dist/src/planner/cost/conjunct-cost.js +45 -0
  102. package/dist/src/planner/cost/conjunct-cost.js.map +1 -1
  103. package/dist/src/planner/cost/index.d.ts +10 -0
  104. package/dist/src/planner/cost/index.d.ts.map +1 -1
  105. package/dist/src/planner/cost/index.js +15 -0
  106. package/dist/src/planner/cost/index.js.map +1 -1
  107. package/dist/src/planner/nodes/aggregate-node.d.ts +6 -0
  108. package/dist/src/planner/nodes/aggregate-node.d.ts.map +1 -1
  109. package/dist/src/planner/nodes/aggregate-node.js +10 -2
  110. package/dist/src/planner/nodes/aggregate-node.js.map +1 -1
  111. package/dist/src/planner/nodes/alias-node.d.ts.map +1 -1
  112. package/dist/src/planner/nodes/alias-node.js +2 -1
  113. package/dist/src/planner/nodes/alias-node.js.map +1 -1
  114. package/dist/src/planner/nodes/alter-table-node.d.ts +24 -8
  115. package/dist/src/planner/nodes/alter-table-node.d.ts.map +1 -1
  116. package/dist/src/planner/nodes/alter-table-node.js.map +1 -1
  117. package/dist/src/planner/nodes/asof-scan-node.d.ts.map +1 -1
  118. package/dist/src/planner/nodes/asof-scan-node.js +4 -1
  119. package/dist/src/planner/nodes/asof-scan-node.js.map +1 -1
  120. package/dist/src/planner/nodes/asserted-keys-node.d.ts.map +1 -1
  121. package/dist/src/planner/nodes/asserted-keys-node.js +2 -1
  122. package/dist/src/planner/nodes/asserted-keys-node.js.map +1 -1
  123. package/dist/src/planner/nodes/bloom-join-node.d.ts.map +1 -1
  124. package/dist/src/planner/nodes/bloom-join-node.js +8 -3
  125. package/dist/src/planner/nodes/bloom-join-node.js.map +1 -1
  126. package/dist/src/planner/nodes/cache-node.d.ts.map +1 -1
  127. package/dist/src/planner/nodes/cache-node.js +2 -1
  128. package/dist/src/planner/nodes/cache-node.js.map +1 -1
  129. package/dist/src/planner/nodes/distinct-node.d.ts +6 -0
  130. package/dist/src/planner/nodes/distinct-node.d.ts.map +1 -1
  131. package/dist/src/planner/nodes/distinct-node.js +10 -2
  132. package/dist/src/planner/nodes/distinct-node.js.map +1 -1
  133. package/dist/src/planner/nodes/eager-prefetch-node.d.ts.map +1 -1
  134. package/dist/src/planner/nodes/eager-prefetch-node.js +2 -1
  135. package/dist/src/planner/nodes/eager-prefetch-node.js.map +1 -1
  136. package/dist/src/planner/nodes/fanout-lookup-join-node.d.ts +5 -0
  137. package/dist/src/planner/nodes/fanout-lookup-join-node.d.ts.map +1 -1
  138. package/dist/src/planner/nodes/fanout-lookup-join-node.js +13 -6
  139. package/dist/src/planner/nodes/fanout-lookup-join-node.js.map +1 -1
  140. package/dist/src/planner/nodes/filter.d.ts.map +1 -1
  141. package/dist/src/planner/nodes/filter.js +12 -5
  142. package/dist/src/planner/nodes/filter.js.map +1 -1
  143. package/dist/src/planner/nodes/hash-aggregate.d.ts +6 -0
  144. package/dist/src/planner/nodes/hash-aggregate.d.ts.map +1 -1
  145. package/dist/src/planner/nodes/hash-aggregate.js +10 -2
  146. package/dist/src/planner/nodes/hash-aggregate.js.map +1 -1
  147. package/dist/src/planner/nodes/join-node.d.ts +20 -1
  148. package/dist/src/planner/nodes/join-node.d.ts.map +1 -1
  149. package/dist/src/planner/nodes/join-node.js +30 -9
  150. package/dist/src/planner/nodes/join-node.js.map +1 -1
  151. package/dist/src/planner/nodes/join-utils.d.ts +21 -0
  152. package/dist/src/planner/nodes/join-utils.d.ts.map +1 -1
  153. package/dist/src/planner/nodes/join-utils.js +26 -0
  154. package/dist/src/planner/nodes/join-utils.js.map +1 -1
  155. package/dist/src/planner/nodes/key-set-semi-join-node.d.ts.map +1 -1
  156. package/dist/src/planner/nodes/key-set-semi-join-node.js +5 -1
  157. package/dist/src/planner/nodes/key-set-semi-join-node.js.map +1 -1
  158. package/dist/src/planner/nodes/lens-auxiliary-access-node.d.ts.map +1 -1
  159. package/dist/src/planner/nodes/lens-auxiliary-access-node.js +2 -1
  160. package/dist/src/planner/nodes/lens-auxiliary-access-node.js.map +1 -1
  161. package/dist/src/planner/nodes/limit-offset.d.ts +6 -0
  162. package/dist/src/planner/nodes/limit-offset.d.ts.map +1 -1
  163. package/dist/src/planner/nodes/limit-offset.js +10 -2
  164. package/dist/src/planner/nodes/limit-offset.js.map +1 -1
  165. package/dist/src/planner/nodes/merge-join-node.d.ts.map +1 -1
  166. package/dist/src/planner/nodes/merge-join-node.js +8 -3
  167. package/dist/src/planner/nodes/merge-join-node.js.map +1 -1
  168. package/dist/src/planner/nodes/ordinal-slice-node.d.ts +5 -0
  169. package/dist/src/planner/nodes/ordinal-slice-node.d.ts.map +1 -1
  170. package/dist/src/planner/nodes/ordinal-slice-node.js +9 -2
  171. package/dist/src/planner/nodes/ordinal-slice-node.js.map +1 -1
  172. package/dist/src/planner/nodes/plan-node.d.ts +24 -0
  173. package/dist/src/planner/nodes/plan-node.d.ts.map +1 -1
  174. package/dist/src/planner/nodes/plan-node.js.map +1 -1
  175. package/dist/src/planner/nodes/project-node.d.ts.map +1 -1
  176. package/dist/src/planner/nodes/project-node.js +2 -1
  177. package/dist/src/planner/nodes/project-node.js.map +1 -1
  178. package/dist/src/planner/nodes/reference.d.ts.map +1 -1
  179. package/dist/src/planner/nodes/reference.js +3 -2
  180. package/dist/src/planner/nodes/reference.js.map +1 -1
  181. package/dist/src/planner/nodes/retrieve-node.d.ts.map +1 -1
  182. package/dist/src/planner/nodes/retrieve-node.js +2 -1
  183. package/dist/src/planner/nodes/retrieve-node.js.map +1 -1
  184. package/dist/src/planner/nodes/scalar.d.ts.map +1 -1
  185. package/dist/src/planner/nodes/scalar.js +5 -18
  186. package/dist/src/planner/nodes/scalar.js.map +1 -1
  187. package/dist/src/planner/nodes/sort.d.ts.map +1 -1
  188. package/dist/src/planner/nodes/sort.js +3 -1
  189. package/dist/src/planner/nodes/sort.js.map +1 -1
  190. package/dist/src/planner/nodes/stream-aggregate.d.ts +6 -0
  191. package/dist/src/planner/nodes/stream-aggregate.d.ts.map +1 -1
  192. package/dist/src/planner/nodes/stream-aggregate.js +10 -2
  193. package/dist/src/planner/nodes/stream-aggregate.js.map +1 -1
  194. package/dist/src/planner/nodes/table-access-nodes.d.ts.map +1 -1
  195. package/dist/src/planner/nodes/table-access-nodes.js +5 -0
  196. package/dist/src/planner/nodes/table-access-nodes.js.map +1 -1
  197. package/dist/src/planner/nodes/window-function.d.ts.map +1 -1
  198. package/dist/src/planner/nodes/window-function.js +8 -0
  199. package/dist/src/planner/nodes/window-function.js.map +1 -1
  200. package/dist/src/planner/nodes/window-node.d.ts +1 -1
  201. package/dist/src/planner/nodes/window-node.d.ts.map +1 -1
  202. package/dist/src/planner/nodes/window-node.js +3 -1
  203. package/dist/src/planner/nodes/window-node.js.map +1 -1
  204. package/dist/src/planner/optimizer.d.ts +9 -1
  205. package/dist/src/planner/optimizer.d.ts.map +1 -1
  206. package/dist/src/planner/optimizer.js +77 -6
  207. package/dist/src/planner/optimizer.js.map +1 -1
  208. package/dist/src/planner/rules/access/rule-key-set-seek.d.ts.map +1 -1
  209. package/dist/src/planner/rules/access/rule-key-set-seek.js +3 -68
  210. package/dist/src/planner/rules/access/rule-key-set-seek.js.map +1 -1
  211. package/dist/src/planner/rules/access/rule-select-access-path.d.ts +19 -0
  212. package/dist/src/planner/rules/access/rule-select-access-path.d.ts.map +1 -1
  213. package/dist/src/planner/rules/access/rule-select-access-path.js +24 -3
  214. package/dist/src/planner/rules/access/rule-select-access-path.js.map +1 -1
  215. package/dist/src/planner/rules/cache/rule-cte-optimization.d.ts.map +1 -1
  216. package/dist/src/planner/rules/cache/rule-cte-optimization.js +9 -0
  217. package/dist/src/planner/rules/cache/rule-cte-optimization.js.map +1 -1
  218. package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.d.ts.map +1 -1
  219. package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.js +6 -4
  220. package/dist/src/planner/rules/cache/rule-nested-loop-right-cache.js.map +1 -1
  221. package/dist/src/planner/rules/join/equi-pair-extractor.d.ts +5 -31
  222. package/dist/src/planner/rules/join/equi-pair-extractor.d.ts.map +1 -1
  223. package/dist/src/planner/rules/join/equi-pair-extractor.js +4 -44
  224. package/dist/src/planner/rules/join/equi-pair-extractor.js.map +1 -1
  225. package/dist/src/planner/rules/join/index-nested-loop.d.ts +49 -0
  226. package/dist/src/planner/rules/join/index-nested-loop.d.ts.map +1 -0
  227. package/dist/src/planner/rules/join/index-nested-loop.js +285 -0
  228. package/dist/src/planner/rules/join/index-nested-loop.js.map +1 -0
  229. package/dist/src/planner/rules/join/rule-fanout-batched-outer.js +8 -8
  230. package/dist/src/planner/rules/join/rule-join-physical-selection.d.ts +10 -4
  231. package/dist/src/planner/rules/join/rule-join-physical-selection.d.ts.map +1 -1
  232. package/dist/src/planner/rules/join/rule-join-physical-selection.js +83 -27
  233. package/dist/src/planner/rules/join/rule-join-physical-selection.js.map +1 -1
  234. package/dist/src/planner/rules/join/rule-monotonic-merge-join.js +4 -4
  235. package/dist/src/planner/rules/join/rule-monotonic-merge-join.js.map +1 -1
  236. package/dist/src/planner/rules/predicate/rule-filter-conjunct-ordering.d.ts +21 -8
  237. package/dist/src/planner/rules/predicate/rule-filter-conjunct-ordering.d.ts.map +1 -1
  238. package/dist/src/planner/rules/predicate/rule-filter-conjunct-ordering.js +70 -14
  239. package/dist/src/planner/rules/predicate/rule-filter-conjunct-ordering.js.map +1 -1
  240. package/dist/src/planner/rules/predicate/rule-filter-selectivity.d.ts +42 -17
  241. package/dist/src/planner/rules/predicate/rule-filter-selectivity.d.ts.map +1 -1
  242. package/dist/src/planner/rules/predicate/rule-filter-selectivity.js +84 -154
  243. package/dist/src/planner/rules/predicate/rule-filter-selectivity.js.map +1 -1
  244. package/dist/src/planner/rules/predicate/rule-join-predicate-pushdown.d.ts +73 -0
  245. package/dist/src/planner/rules/predicate/rule-join-predicate-pushdown.d.ts.map +1 -0
  246. package/dist/src/planner/rules/predicate/rule-join-predicate-pushdown.js +205 -0
  247. package/dist/src/planner/rules/predicate/rule-join-predicate-pushdown.js.map +1 -0
  248. package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.d.ts +14 -11
  249. package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.d.ts.map +1 -1
  250. package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.js +21 -85
  251. package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.js.map +1 -1
  252. package/dist/src/planner/rules/predicate/rule-predicate-pushdown.d.ts +7 -1
  253. package/dist/src/planner/rules/predicate/rule-predicate-pushdown.d.ts.map +1 -1
  254. package/dist/src/planner/rules/predicate/rule-predicate-pushdown.js +7 -1
  255. package/dist/src/planner/rules/predicate/rule-predicate-pushdown.js.map +1 -1
  256. package/dist/src/planner/rules/shared/access-leaf.d.ts +39 -0
  257. package/dist/src/planner/rules/shared/access-leaf.d.ts.map +1 -0
  258. package/dist/src/planner/rules/shared/access-leaf.js +79 -0
  259. package/dist/src/planner/rules/shared/access-leaf.js.map +1 -0
  260. package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.d.ts.map +1 -1
  261. package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.js +18 -8
  262. package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.js.map +1 -1
  263. package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.d.ts +3 -1
  264. package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.d.ts.map +1 -1
  265. package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.js +27 -10
  266. package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.js.map +1 -1
  267. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.d.ts.map +1 -1
  268. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js +69 -11
  269. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js.map +1 -1
  270. package/dist/src/planner/rules/window/rule-monotonic-window.d.ts +17 -7
  271. package/dist/src/planner/rules/window/rule-monotonic-window.d.ts.map +1 -1
  272. package/dist/src/planner/rules/window/rule-monotonic-window.js +124 -87
  273. package/dist/src/planner/rules/window/rule-monotonic-window.js.map +1 -1
  274. package/dist/src/planner/scopes/aliased.d.ts.map +1 -1
  275. package/dist/src/planner/scopes/aliased.js +6 -0
  276. package/dist/src/planner/scopes/aliased.js.map +1 -1
  277. package/dist/src/planner/stats/catalog-stats.d.ts +44 -13
  278. package/dist/src/planner/stats/catalog-stats.d.ts.map +1 -1
  279. package/dist/src/planner/stats/catalog-stats.js +137 -61
  280. package/dist/src/planner/stats/catalog-stats.js.map +1 -1
  281. package/dist/src/planner/stats/conjunct-selectivity.d.ts +48 -0
  282. package/dist/src/planner/stats/conjunct-selectivity.d.ts.map +1 -0
  283. package/dist/src/planner/stats/conjunct-selectivity.js +168 -0
  284. package/dist/src/planner/stats/conjunct-selectivity.js.map +1 -0
  285. package/dist/src/planner/stats/index.d.ts +22 -3
  286. package/dist/src/planner/stats/index.d.ts.map +1 -1
  287. package/dist/src/planner/stats/index.js.map +1 -1
  288. package/dist/src/planner/stats/table-cardinality.d.ts +28 -0
  289. package/dist/src/planner/stats/table-cardinality.d.ts.map +1 -0
  290. package/dist/src/planner/stats/table-cardinality.js +29 -0
  291. package/dist/src/planner/stats/table-cardinality.js.map +1 -0
  292. package/dist/src/planner/util/column-origins.d.ts +29 -8
  293. package/dist/src/planner/util/column-origins.d.ts.map +1 -1
  294. package/dist/src/planner/util/column-origins.js +74 -14
  295. package/dist/src/planner/util/column-origins.js.map +1 -1
  296. package/dist/src/planner/util/fd-utils.d.ts +32 -8
  297. package/dist/src/planner/util/fd-utils.d.ts.map +1 -1
  298. package/dist/src/planner/util/fd-utils.js +46 -9
  299. package/dist/src/planner/util/fd-utils.js.map +1 -1
  300. package/dist/src/planner/util/ind-utils.d.ts +56 -17
  301. package/dist/src/planner/util/ind-utils.d.ts.map +1 -1
  302. package/dist/src/planner/util/ind-utils.js +82 -21
  303. package/dist/src/planner/util/ind-utils.js.map +1 -1
  304. package/dist/src/planner/util/key-utils.d.ts +20 -2
  305. package/dist/src/planner/util/key-utils.d.ts.map +1 -1
  306. package/dist/src/planner/util/key-utils.js +37 -3
  307. package/dist/src/planner/util/key-utils.js.map +1 -1
  308. package/dist/src/planner/util/row-estimates.d.ts +28 -0
  309. package/dist/src/planner/util/row-estimates.d.ts.map +1 -0
  310. package/dist/src/planner/util/row-estimates.js +40 -0
  311. package/dist/src/planner/util/row-estimates.js.map +1 -0
  312. package/dist/src/planner/util/row-population.d.ts +42 -0
  313. package/dist/src/planner/util/row-population.d.ts.map +1 -0
  314. package/dist/src/planner/util/row-population.js +71 -0
  315. package/dist/src/planner/util/row-population.js.map +1 -0
  316. package/dist/src/runtime/emit/add-constraint.d.ts.map +1 -1
  317. package/dist/src/runtime/emit/add-constraint.js +39 -1
  318. package/dist/src/runtime/emit/add-constraint.js.map +1 -1
  319. package/dist/src/runtime/emit/aggregate.d.ts.map +1 -1
  320. package/dist/src/runtime/emit/aggregate.js +4 -4
  321. package/dist/src/runtime/emit/aggregate.js.map +1 -1
  322. package/dist/src/runtime/emit/alter-schema-event.d.ts +42 -0
  323. package/dist/src/runtime/emit/alter-schema-event.d.ts.map +1 -0
  324. package/dist/src/runtime/emit/alter-schema-event.js +28 -0
  325. package/dist/src/runtime/emit/alter-schema-event.js.map +1 -0
  326. package/dist/src/runtime/emit/alter-table.d.ts.map +1 -1
  327. package/dist/src/runtime/emit/alter-table.js +380 -154
  328. package/dist/src/runtime/emit/alter-table.js.map +1 -1
  329. package/dist/src/runtime/emit/analyze.d.ts.map +1 -1
  330. package/dist/src/runtime/emit/analyze.js +35 -3
  331. package/dist/src/runtime/emit/analyze.js.map +1 -1
  332. package/dist/src/runtime/emit/cast.d.ts.map +1 -1
  333. package/dist/src/runtime/emit/cast.js +4 -19
  334. package/dist/src/runtime/emit/cast.js.map +1 -1
  335. package/dist/src/runtime/emit/dml-executor.d.ts.map +1 -1
  336. package/dist/src/runtime/emit/dml-executor.js +64 -27
  337. package/dist/src/runtime/emit/dml-executor.js.map +1 -1
  338. package/dist/src/runtime/emit/drop-index.d.ts.map +1 -1
  339. package/dist/src/runtime/emit/drop-index.js +4 -3
  340. package/dist/src/runtime/emit/drop-index.js.map +1 -1
  341. package/dist/src/runtime/emit/hash-aggregate.d.ts.map +1 -1
  342. package/dist/src/runtime/emit/hash-aggregate.js +2 -2
  343. package/dist/src/runtime/emit/hash-aggregate.js.map +1 -1
  344. package/dist/src/runtime/emit/join.d.ts.map +1 -1
  345. package/dist/src/runtime/emit/join.js +8 -67
  346. package/dist/src/runtime/emit/join.js.map +1 -1
  347. package/dist/src/runtime/emit/key-set-semi-join.d.ts.map +1 -1
  348. package/dist/src/runtime/emit/key-set-semi-join.js +6 -0
  349. package/dist/src/runtime/emit/key-set-semi-join.js.map +1 -1
  350. package/dist/src/runtime/emit/operand-comparator.d.ts +30 -0
  351. package/dist/src/runtime/emit/operand-comparator.d.ts.map +1 -1
  352. package/dist/src/runtime/emit/operand-comparator.js +34 -0
  353. package/dist/src/runtime/emit/operand-comparator.js.map +1 -1
  354. package/dist/src/runtime/emit/schema-declarative.d.ts.map +1 -1
  355. package/dist/src/runtime/emit/schema-declarative.js +30 -0
  356. package/dist/src/runtime/emit/schema-declarative.js.map +1 -1
  357. package/dist/src/runtime/emit/subquery.d.ts.map +1 -1
  358. package/dist/src/runtime/emit/subquery.js +153 -52
  359. package/dist/src/runtime/emit/subquery.js.map +1 -1
  360. package/dist/src/runtime/emit/window.js +36 -23
  361. package/dist/src/runtime/emit/window.js.map +1 -1
  362. package/dist/src/schema/catalog-persistability.d.ts +19 -16
  363. package/dist/src/schema/catalog-persistability.d.ts.map +1 -1
  364. package/dist/src/schema/catalog-persistability.js +76 -20
  365. package/dist/src/schema/catalog-persistability.js.map +1 -1
  366. package/dist/src/schema/catalog.d.ts +67 -2
  367. package/dist/src/schema/catalog.d.ts.map +1 -1
  368. package/dist/src/schema/catalog.js +194 -3
  369. package/dist/src/schema/catalog.js.map +1 -1
  370. package/dist/src/schema/column.d.ts +26 -3
  371. package/dist/src/schema/column.d.ts.map +1 -1
  372. package/dist/src/schema/column.js.map +1 -1
  373. package/dist/src/schema/ddl-generator.d.ts.map +1 -1
  374. package/dist/src/schema/ddl-generator.js +19 -6
  375. package/dist/src/schema/ddl-generator.js.map +1 -1
  376. package/dist/src/schema/function.d.ts +32 -1
  377. package/dist/src/schema/function.d.ts.map +1 -1
  378. package/dist/src/schema/function.js +10 -2
  379. package/dist/src/schema/function.js.map +1 -1
  380. package/dist/src/schema/manager.d.ts +84 -7
  381. package/dist/src/schema/manager.d.ts.map +1 -1
  382. package/dist/src/schema/manager.js +153 -53
  383. package/dist/src/schema/manager.js.map +1 -1
  384. package/dist/src/schema/schema-differ.d.ts.map +1 -1
  385. package/dist/src/schema/schema-differ.js +104 -28
  386. package/dist/src/schema/schema-differ.js.map +1 -1
  387. package/dist/src/schema/table.d.ts +149 -1
  388. package/dist/src/schema/table.d.ts.map +1 -1
  389. package/dist/src/schema/table.js +248 -1
  390. package/dist/src/schema/table.js.map +1 -1
  391. package/dist/src/schema/unique-enforcement.d.ts +5 -3
  392. package/dist/src/schema/unique-enforcement.d.ts.map +1 -1
  393. package/dist/src/schema/unique-enforcement.js +5 -3
  394. package/dist/src/schema/unique-enforcement.js.map +1 -1
  395. package/dist/src/types/builtin-types.d.ts +16 -0
  396. package/dist/src/types/builtin-types.d.ts.map +1 -1
  397. package/dist/src/types/builtin-types.js +46 -8
  398. package/dist/src/types/builtin-types.js.map +1 -1
  399. package/dist/src/types/cast-semantics.d.ts +42 -0
  400. package/dist/src/types/cast-semantics.d.ts.map +1 -1
  401. package/dist/src/types/cast-semantics.js +64 -0
  402. package/dist/src/types/cast-semantics.js.map +1 -1
  403. package/dist/src/types/comparison-coercion.d.ts +101 -0
  404. package/dist/src/types/comparison-coercion.d.ts.map +1 -0
  405. package/dist/src/types/comparison-coercion.js +162 -0
  406. package/dist/src/types/comparison-coercion.js.map +1 -0
  407. package/dist/src/types/index.d.ts +2 -2
  408. package/dist/src/types/index.d.ts.map +1 -1
  409. package/dist/src/types/index.js +2 -2
  410. package/dist/src/types/index.js.map +1 -1
  411. package/dist/src/types/logical-type.d.ts +7 -0
  412. package/dist/src/types/logical-type.d.ts.map +1 -1
  413. package/dist/src/types/logical-type.js.map +1 -1
  414. package/dist/src/types/validation.d.ts +56 -0
  415. package/dist/src/types/validation.d.ts.map +1 -1
  416. package/dist/src/types/validation.js +68 -0
  417. package/dist/src/types/validation.js.map +1 -1
  418. package/dist/src/util/coercion.d.ts +8 -0
  419. package/dist/src/util/coercion.d.ts.map +1 -1
  420. package/dist/src/util/coercion.js +8 -0
  421. package/dist/src/util/coercion.js.map +1 -1
  422. package/dist/src/util/comparison.d.ts +16 -3
  423. package/dist/src/util/comparison.d.ts.map +1 -1
  424. package/dist/src/util/comparison.js +21 -5
  425. package/dist/src/util/comparison.js.map +1 -1
  426. package/dist/src/util/key-serializer.d.ts +46 -0
  427. package/dist/src/util/key-serializer.d.ts.map +1 -1
  428. package/dist/src/util/key-serializer.js +47 -0
  429. package/dist/src/util/key-serializer.js.map +1 -1
  430. package/dist/src/util/value-set.d.ts +21 -0
  431. package/dist/src/util/value-set.d.ts.map +1 -0
  432. package/dist/src/util/value-set.js +22 -0
  433. package/dist/src/util/value-set.js.map +1 -0
  434. package/dist/src/vtab/capabilities.d.ts +1 -1
  435. package/dist/src/vtab/events.d.ts +5 -1
  436. package/dist/src/vtab/events.d.ts.map +1 -1
  437. package/dist/src/vtab/events.js.map +1 -1
  438. package/dist/src/vtab/memory/layer/alter-column.d.ts +147 -0
  439. package/dist/src/vtab/memory/layer/alter-column.d.ts.map +1 -0
  440. package/dist/src/vtab/memory/layer/alter-column.js +214 -0
  441. package/dist/src/vtab/memory/layer/alter-column.js.map +1 -0
  442. package/dist/src/vtab/memory/layer/base.d.ts.map +1 -1
  443. package/dist/src/vtab/memory/layer/base.js +4 -3
  444. package/dist/src/vtab/memory/layer/base.js.map +1 -1
  445. package/dist/src/vtab/memory/layer/interface.d.ts +2 -2
  446. package/dist/src/vtab/memory/layer/interface.d.ts.map +1 -1
  447. package/dist/src/vtab/memory/layer/manager.d.ts +176 -25
  448. package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
  449. package/dist/src/vtab/memory/layer/manager.js +572 -495
  450. package/dist/src/vtab/memory/layer/manager.js.map +1 -1
  451. package/dist/src/vtab/memory/layer/scan-layer.d.ts.map +1 -1
  452. package/dist/src/vtab/memory/layer/scan-layer.js +32 -5
  453. package/dist/src/vtab/memory/layer/scan-layer.js.map +1 -1
  454. package/dist/src/vtab/memory/layer/transaction.d.ts +101 -15
  455. package/dist/src/vtab/memory/layer/transaction.d.ts.map +1 -1
  456. package/dist/src/vtab/memory/layer/transaction.js +133 -45
  457. package/dist/src/vtab/memory/layer/transaction.js.map +1 -1
  458. package/dist/src/vtab/memory/module.d.ts.map +1 -1
  459. package/dist/src/vtab/memory/module.js +2 -1
  460. package/dist/src/vtab/memory/module.js.map +1 -1
  461. package/dist/src/vtab/memory/table.d.ts.map +1 -1
  462. package/dist/src/vtab/memory/table.js +11 -6
  463. package/dist/src/vtab/memory/table.js.map +1 -1
  464. package/dist/src/vtab/module.d.ts +51 -21
  465. package/dist/src/vtab/module.d.ts.map +1 -1
  466. package/dist/src/vtab/table.d.ts +1 -1
  467. package/dist/src/vtab/table.js +1 -1
  468. package/package.json +3 -3
@@ -4,10 +4,25 @@
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 the source subtree is settled (and may carry
10
- * physical access nodes between the join and its table references).
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.
11
26
  *
12
27
  * Node-level accessors (`estimatedRows` / `computePhysical`) carry no OptContext,
13
28
  * so a Filter cannot consult `context.stats` from inside itself. This rule holds
@@ -15,29 +30,38 @@
15
30
  * flows through `estimatedRows` automatically.
16
31
  *
17
32
  * Two paths:
18
- * - **single-table** — `extractTableSchema` finds one base table under the
19
- * Filter; hand the whole predicate to the provider, which decomposes its
20
- * boolean structure itself.
21
- * - **multi-relation** — the source spans several tables (a join). Split the
22
- * predicate into conjuncts, attribute each to the base table(s) its columns
23
- * come from, estimate per conjunct, and combine.
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`.
24
56
  */
25
57
  import { createLogger } from '../../../common/logger.js';
26
58
  import { FilterNode } from '../../nodes/filter.js';
27
- import { BinaryOpNode } from '../../nodes/scalar.js';
28
- import { ColumnReferenceNode } from '../../nodes/reference.js';
29
- import { extractTableSchema } from '../../util/key-utils.js';
59
+ import { extractRowSourceTableSchema } from '../../util/key-utils.js';
30
60
  import { collectColumnOrigins } from '../../util/column-origins.js';
31
61
  import { splitConjuncts } from '../../analysis/predicate-conjuncts.js';
32
62
  import { combineConjunctive } from '../../stats/selectivity-combine.js';
63
+ import { estimateConjunctSelectivity, makeColumnStatsResolver } from '../../stats/conjunct-selectivity.js';
33
64
  const log = createLogger('optimizer:rule:filter-selectivity');
34
- /**
35
- * Selectivity of an inequality (`<` `<=` `>` `>=`) comparing a column of one table
36
- * to a column of another. The standard uniform-distribution estimate for a
37
- * two-sided inequality is 1/3: there is no cross-table histogram, so nothing
38
- * better than the uniform assumption is available here.
39
- */
40
- export const CROSS_RELATION_INEQUALITY_SELECTIVITY = 1 / 3;
41
65
  export function ruleFilterSelectivity(node, context) {
42
66
  const filter = node;
43
67
  // Idempotent: a prior fire already stamped this Filter → decline. (The pass
@@ -45,13 +69,29 @@ export function ruleFilterSelectivity(node, context) {
45
69
  // makes the rule safe on any already-stamped node regardless.)
46
70
  if (filter.selectivity !== undefined)
47
71
  return null;
48
- // extractTableSchema walks single-child wrappers (Filter/Project/Sort/Retrieve/
49
- // TableReference) to the base table. It returns undefined for a join / other
50
- // multi-relation source, which is what the second path handles.
51
- const tableSchema = extractTableSchema(filter.source);
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);
52
92
  const sel = tableSchema
53
- ? singleTableSelectivity(tableSchema, filter, context)
54
- : multiRelationSelectivity(filter, context);
93
+ ? singleTableSelectivity(tableSchema, filter, origins, context)
94
+ : multiRelationSelectivity(filter, origins, context);
55
95
  if (sel === undefined)
56
96
  return null;
57
97
  const clamped = Math.min(1, Math.max(0, sel));
@@ -60,7 +100,7 @@ export function ruleFilterSelectivity(node, context) {
60
100
  return new FilterNode(filter.scope, filter.source, filter.predicate, undefined, clamped);
61
101
  }
62
102
  // ── Single-table path ───────────────────────────────────────────────────
63
- function singleTableSelectivity(tableSchema, filter, context) {
103
+ function singleTableSelectivity(tableSchema, filter, origins, context) {
64
104
  // CatalogStatsProvider recurses over the predicate's boolean structure, so
65
105
  // `a = 1 and b = 2` combines the two per-column estimates rather than falling
66
106
  // back to a flat per-nodeType guess. It still returns undefined when it can say
@@ -69,7 +109,12 @@ function singleTableSelectivity(tableSchema, filter, context) {
69
109
  // NOTE: this path is deliberately NOT gated on real statistics existing — it may
70
110
  // still stamp a NaiveStatsProvider number, as it always has. The multi-relation
71
111
  // path below IS gated; see the comment there for why the asymmetry is on purpose.
72
- const sel = context.stats.selectivity(tableSchema, filter.predicate);
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);
73
118
  if (sel === undefined)
74
119
  return undefined;
75
120
  log('Filter over %s: stamping selectivity %f', tableSchema.name, sel);
@@ -91,26 +136,20 @@ function singleTableSelectivity(tableSchema, filter, context) {
91
136
  * the base-table fraction is applied to post-aggregate cardinality. Imprecise but
92
137
  * not unsound; deliberately not special-cased.
93
138
  *
94
- * NOTE: the stamped number is currently visible on `FilterNode.selectivity` but does
95
- * NOT yet move `estimatedRows` above a join: `JoinNode.computePhysical` derives its
96
- * own cardinality from its children's LOGICAL `estimatedRows`, and a physical access
97
- * node (SeqScan/IndexScan over a Retrieve) exposes none — so the join reports
98
- * undefined rows and the Filter has nothing to multiply. Tracked in backlog
99
- * `debt-join-rows-from-physical-children`; nothing here needs to change when it lands.
100
- *
101
- * NOTE: `collectColumnOrigins` walks the whole source subtree and this rule fires
102
- * per FilterNode, so a stack of N filters over one large subtree costs O(N·subtree).
103
- * Filters over joins are few and the walk is cheap per node; if this ever shows up
104
- * in optimizer profiles, compute the map once per pass and cache it on OptContext.
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`).
105
145
  */
106
- function multiRelationSelectivity(filter, context) {
107
- const origins = collectColumnOrigins(filter.source);
146
+ function multiRelationSelectivity(filter, origins, context) {
108
147
  if (origins.size === 0)
109
148
  return undefined;
110
149
  const conjuncts = splitConjuncts(filter.predicate);
111
150
  const known = [];
112
151
  for (const conjunct of conjuncts) {
113
- const sel = estimateConjunct(conjunct, origins, context);
152
+ const sel = estimateConjunctSelectivity(conjunct, origins, context);
114
153
  if (sel !== undefined)
115
154
  known.push(sel);
116
155
  }
@@ -125,118 +164,9 @@ function multiRelationSelectivity(filter, context) {
125
164
  return combined;
126
165
  }
127
166
  function countRelations(origins) {
128
- const refs = new Set();
167
+ const relations = new Set();
129
168
  for (const origin of origins.values())
130
- refs.add(origin.ref);
131
- return refs.size;
132
- }
133
- /** Estimate one conjunct, or undefined when it cannot be attributed / estimated. */
134
- function estimateConjunct(conjunct, origins, context) {
135
- const refs = conjunctRelations(conjunct, origins);
136
- if (refs === undefined)
137
- return undefined;
138
- if (refs.size === 1) {
139
- const [ref] = refs;
140
- return singleRelationConjunct(ref.tableSchema, conjunct, context);
141
- }
142
- if (refs.size === 2) {
143
- return crossRelationConjunct(conjunct, origins, context);
144
- }
145
- // Three or more relations in one conjunct: no model for it here.
146
- return undefined;
147
- }
148
- /**
149
- * The distinct relations a conjunct's column references come from.
150
- *
151
- * Returns undefined when the conjunct references no column at all, or references
152
- * any attribute that is not a base-table column (a computed projection, an
153
- * aggregate output, a join existence flag, a set-operation output, a column of a
154
- * table inside a scalar subquery) — in either case there are no statistics to
155
- * consult.
156
- */
157
- function conjunctRelations(conjunct, origins) {
158
- const refs = new Set();
159
- const stack = [conjunct];
160
- while (stack.length > 0) {
161
- const n = stack.pop();
162
- if (n instanceof ColumnReferenceNode) {
163
- const origin = origins.get(n.attributeId);
164
- if (!origin)
165
- return undefined;
166
- refs.add(origin.ref);
167
- continue;
168
- }
169
- for (const child of n.getChildren())
170
- stack.push(child);
171
- }
172
- return refs.size > 0 ? refs : undefined;
173
- }
174
- /**
175
- * A conjunct over exactly one relation: hand it to the provider as if it were a
176
- * single-table predicate.
177
- *
178
- * `statsOnlySelectivity` — not `selectivity` — IS the statistics gate. `selectivity`
179
- * always returns a number (CatalogStatsProvider falls through to NaiveStatsProvider,
180
- * which answers a flat 0.1 for any BinaryOp), so using it here would replace 0.5 with
181
- * 0.1 on essentially every filter-over-join in the codebase — including the many tests
182
- * that never run ANALYZE — churning plan shapes with no information behind the change.
183
- * It also covers the subtler case of an analyzed table with a predicate the catalog
184
- * cannot read (`lower(o.cat) = 'x'`), which a column-stats-presence check would let
185
- * through. A provider that does not implement it is treated as having no statistics.
186
- */
187
- function singleRelationConjunct(table, conjunct, context) {
188
- return context.stats.statsOnlySelectivity?.(table, conjunct);
189
- }
190
- function hasColumnStats(origin) {
191
- return origin.table.statistics?.columnStats.has(origin.columnName.toLowerCase()) ?? false;
192
- }
193
- /**
194
- * A conjunct comparing a column of one relation to a column of another
195
- * (`o.qty > l.qty`, `a.id = b.id`). Only a plain binary comparison with a bare
196
- * column reference on each side is modelled; anything else is unknown.
197
- *
198
- * Gated on real column statistics for BOTH compared columns, for the same reason as
199
- * {@link singleRelationConjunct}: `joinSelectivity` falls back to
200
- * `NaiveStatsProvider`'s `1/max(rowCount)` whenever it cannot read a distinct count,
201
- * so table-level `statistics` being present is not enough on its own.
202
- */
203
- function crossRelationConjunct(conjunct, origins, context) {
204
- if (!(conjunct instanceof BinaryOpNode))
205
- return undefined;
206
- if (!(conjunct.left instanceof ColumnReferenceNode))
207
- return undefined;
208
- if (!(conjunct.right instanceof ColumnReferenceNode))
209
- return undefined;
210
- const leftOrigin = origins.get(conjunct.left.attributeId);
211
- const rightOrigin = origins.get(conjunct.right.attributeId);
212
- if (!leftOrigin || !rightOrigin)
213
- return undefined;
214
- if (!hasColumnStats(leftOrigin) || !hasColumnStats(rightOrigin))
215
- return undefined;
216
- const op = conjunct.expression.operator;
217
- if (op === '=' || op === '==')
218
- return equiJoinSelectivity(conjunct, leftOrigin, rightOrigin, context);
219
- // `extractEquiJoinColumns` accepts only `=`, so the catalog declines a `<>` and
220
- // `joinSelectivity` answers from NaiveStatsProvider, which is capped at 0.5. The
221
- // complement is therefore bounded to [0.5, 1] — it can only ever relax the
222
- // estimate relative to DEFAULT_FILTER_SELECTIVITY, and the true value for a
223
- // cross-relation `<>` is near 1, so the bound errs in the right direction.
224
- if (op === '!=' || op === '<>') {
225
- const eq = equiJoinSelectivity(conjunct, leftOrigin, rightOrigin, context);
226
- return eq === undefined ? undefined : 1 - eq;
227
- }
228
- if (op === '<' || op === '<=' || op === '>' || op === '>=') {
229
- return CROSS_RELATION_INEQUALITY_SELECTIVITY;
230
- }
231
- return undefined;
232
- }
233
- /**
234
- * Argument order matters: `CatalogStatsProvider.joinSelectivity` reads the column
235
- * pair off the condition's own child order (`extractEquiJoinColumns`) and
236
- * `fkPkSelectivity` interprets left/right against the tables it was handed. So the
237
- * table owning the conjunct's LEFT child must be passed first.
238
- */
239
- function equiJoinSelectivity(conjunct, leftOrigin, rightOrigin, context) {
240
- return context.stats.joinSelectivity?.(leftOrigin.table, rightOrigin.table, conjunct);
169
+ relations.add(origin.relation);
170
+ return relations.size;
241
171
  }
242
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":"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"}
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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"}