@quereus/quereus 2.9.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (339) hide show
  1. package/README.md +224 -222
  2. package/dist/src/core/database-assertions.d.ts +36 -16
  3. package/dist/src/core/database-assertions.d.ts.map +1 -1
  4. package/dist/src/core/database-assertions.js +222 -118
  5. package/dist/src/core/database-assertions.js.map +1 -1
  6. package/dist/src/core/database-transaction.d.ts +96 -13
  7. package/dist/src/core/database-transaction.d.ts.map +1 -1
  8. package/dist/src/core/database-transaction.js +294 -35
  9. package/dist/src/core/database-transaction.js.map +1 -1
  10. package/dist/src/core/database-watchers.d.ts +58 -0
  11. package/dist/src/core/database-watchers.d.ts.map +1 -0
  12. package/dist/src/core/database-watchers.js +206 -0
  13. package/dist/src/core/database-watchers.js.map +1 -0
  14. package/dist/src/core/database.d.ts +78 -5
  15. package/dist/src/core/database.d.ts.map +1 -1
  16. package/dist/src/core/database.js +120 -20
  17. package/dist/src/core/database.js.map +1 -1
  18. package/dist/src/core/statement.d.ts +9 -0
  19. package/dist/src/core/statement.d.ts.map +1 -1
  20. package/dist/src/core/statement.js +29 -0
  21. package/dist/src/core/statement.js.map +1 -1
  22. package/dist/src/core/table-handle.d.ts +45 -0
  23. package/dist/src/core/table-handle.d.ts.map +1 -0
  24. package/dist/src/core/table-handle.js +54 -0
  25. package/dist/src/core/table-handle.js.map +1 -0
  26. package/dist/src/func/builtins/conversion.d.ts.map +1 -1
  27. package/dist/src/func/builtins/conversion.js +12 -1
  28. package/dist/src/func/builtins/conversion.js.map +1 -1
  29. package/dist/src/func/builtins/explain.d.ts.map +1 -1
  30. package/dist/src/func/builtins/explain.js +22 -8
  31. package/dist/src/func/builtins/explain.js.map +1 -1
  32. package/dist/src/func/builtins/generation.d.ts.map +1 -1
  33. package/dist/src/func/builtins/generation.js +26 -1
  34. package/dist/src/func/builtins/generation.js.map +1 -1
  35. package/dist/src/func/builtins/index.d.ts.map +1 -1
  36. package/dist/src/func/builtins/index.js +5 -1
  37. package/dist/src/func/builtins/index.js.map +1 -1
  38. package/dist/src/func/builtins/json-tvf.d.ts.map +1 -1
  39. package/dist/src/func/builtins/json-tvf.js +16 -2
  40. package/dist/src/func/builtins/json-tvf.js.map +1 -1
  41. package/dist/src/func/builtins/schema.d.ts +4 -0
  42. package/dist/src/func/builtins/schema.d.ts.map +1 -1
  43. package/dist/src/func/builtins/schema.js +270 -11
  44. package/dist/src/func/builtins/schema.js.map +1 -1
  45. package/dist/src/func/registration.d.ts +19 -1
  46. package/dist/src/func/registration.d.ts.map +1 -1
  47. package/dist/src/func/registration.js +8 -3
  48. package/dist/src/func/registration.js.map +1 -1
  49. package/dist/src/index.d.ts +7 -1
  50. package/dist/src/index.d.ts.map +1 -1
  51. package/dist/src/index.js +5 -0
  52. package/dist/src/index.js.map +1 -1
  53. package/dist/src/parser/parser.d.ts.map +1 -1
  54. package/dist/src/parser/parser.js +12 -4
  55. package/dist/src/parser/parser.js.map +1 -1
  56. package/dist/src/planner/analysis/assertion-classifier.d.ts +71 -0
  57. package/dist/src/planner/analysis/assertion-classifier.d.ts.map +1 -0
  58. package/dist/src/planner/analysis/assertion-classifier.js +286 -0
  59. package/dist/src/planner/analysis/assertion-classifier.js.map +1 -0
  60. package/dist/src/planner/analysis/assertion-hoist-cache.d.ts +34 -0
  61. package/dist/src/planner/analysis/assertion-hoist-cache.d.ts.map +1 -0
  62. package/dist/src/planner/analysis/assertion-hoist-cache.js +119 -0
  63. package/dist/src/planner/analysis/assertion-hoist-cache.js.map +1 -0
  64. package/dist/src/planner/analysis/binding-extractor.d.ts +58 -0
  65. package/dist/src/planner/analysis/binding-extractor.d.ts.map +1 -0
  66. package/dist/src/planner/analysis/binding-extractor.js +110 -0
  67. package/dist/src/planner/analysis/binding-extractor.js.map +1 -0
  68. package/dist/src/planner/analysis/change-scope.d.ts +184 -0
  69. package/dist/src/planner/analysis/change-scope.d.ts.map +1 -0
  70. package/dist/src/planner/analysis/change-scope.js +825 -0
  71. package/dist/src/planner/analysis/change-scope.js.map +1 -0
  72. package/dist/src/planner/analysis/check-extraction.d.ts +29 -0
  73. package/dist/src/planner/analysis/check-extraction.d.ts.map +1 -0
  74. package/dist/src/planner/analysis/check-extraction.js +420 -0
  75. package/dist/src/planner/analysis/check-extraction.js.map +1 -0
  76. package/dist/src/planner/analysis/constraint-extractor.d.ts +47 -7
  77. package/dist/src/planner/analysis/constraint-extractor.d.ts.map +1 -1
  78. package/dist/src/planner/analysis/constraint-extractor.js +169 -92
  79. package/dist/src/planner/analysis/constraint-extractor.js.map +1 -1
  80. package/dist/src/planner/analysis/partial-unique-extraction.d.ts +68 -0
  81. package/dist/src/planner/analysis/partial-unique-extraction.d.ts.map +1 -0
  82. package/dist/src/planner/analysis/partial-unique-extraction.js +347 -0
  83. package/dist/src/planner/analysis/partial-unique-extraction.js.map +1 -0
  84. package/dist/src/planner/analysis/predicate-conjuncts.d.ts +14 -0
  85. package/dist/src/planner/analysis/predicate-conjuncts.d.ts.map +1 -0
  86. package/dist/src/planner/analysis/predicate-conjuncts.js +31 -0
  87. package/dist/src/planner/analysis/predicate-conjuncts.js.map +1 -0
  88. package/dist/src/planner/analysis/predicate-shape.d.ts +52 -0
  89. package/dist/src/planner/analysis/predicate-shape.d.ts.map +1 -0
  90. package/dist/src/planner/analysis/predicate-shape.js +119 -0
  91. package/dist/src/planner/analysis/predicate-shape.js.map +1 -0
  92. package/dist/src/planner/analysis/sat-checker.d.ts +43 -0
  93. package/dist/src/planner/analysis/sat-checker.d.ts.map +1 -0
  94. package/dist/src/planner/analysis/sat-checker.js +393 -0
  95. package/dist/src/planner/analysis/sat-checker.js.map +1 -0
  96. package/dist/src/planner/building/table.d.ts.map +1 -1
  97. package/dist/src/planner/building/table.js +1 -1
  98. package/dist/src/planner/building/table.js.map +1 -1
  99. package/dist/src/planner/framework/characteristics.d.ts +10 -1
  100. package/dist/src/planner/framework/characteristics.d.ts.map +1 -1
  101. package/dist/src/planner/framework/characteristics.js +24 -5
  102. package/dist/src/planner/framework/characteristics.js.map +1 -1
  103. package/dist/src/planner/framework/pass.d.ts.map +1 -1
  104. package/dist/src/planner/framework/pass.js +46 -16
  105. package/dist/src/planner/framework/pass.js.map +1 -1
  106. package/dist/src/planner/framework/physical-utils.d.ts +0 -9
  107. package/dist/src/planner/framework/physical-utils.d.ts.map +1 -1
  108. package/dist/src/planner/framework/physical-utils.js +0 -31
  109. package/dist/src/planner/framework/physical-utils.js.map +1 -1
  110. package/dist/src/planner/nodes/aggregate-node.d.ts +25 -0
  111. package/dist/src/planner/nodes/aggregate-node.d.ts.map +1 -1
  112. package/dist/src/planner/nodes/aggregate-node.js +75 -8
  113. package/dist/src/planner/nodes/aggregate-node.js.map +1 -1
  114. package/dist/src/planner/nodes/alias-node.d.ts.map +1 -1
  115. package/dist/src/planner/nodes/alias-node.js +6 -1
  116. package/dist/src/planner/nodes/alias-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 +17 -3
  119. package/dist/src/planner/nodes/asof-scan-node.js.map +1 -1
  120. package/dist/src/planner/nodes/bloom-join-node.d.ts.map +1 -1
  121. package/dist/src/planner/nodes/bloom-join-node.js +19 -9
  122. package/dist/src/planner/nodes/bloom-join-node.js.map +1 -1
  123. package/dist/src/planner/nodes/distinct-node.d.ts.map +1 -1
  124. package/dist/src/planner/nodes/distinct-node.js +10 -6
  125. package/dist/src/planner/nodes/distinct-node.js.map +1 -1
  126. package/dist/src/planner/nodes/empty-relation-node.d.ts +27 -0
  127. package/dist/src/planner/nodes/empty-relation-node.d.ts.map +1 -0
  128. package/dist/src/planner/nodes/empty-relation-node.js +61 -0
  129. package/dist/src/planner/nodes/empty-relation-node.js.map +1 -0
  130. package/dist/src/planner/nodes/filter.d.ts.map +1 -1
  131. package/dist/src/planner/nodes/filter.js +65 -5
  132. package/dist/src/planner/nodes/filter.js.map +1 -1
  133. package/dist/src/planner/nodes/hash-aggregate.d.ts +1 -1
  134. package/dist/src/planner/nodes/hash-aggregate.d.ts.map +1 -1
  135. package/dist/src/planner/nodes/hash-aggregate.js +8 -6
  136. package/dist/src/planner/nodes/hash-aggregate.js.map +1 -1
  137. package/dist/src/planner/nodes/join-node.d.ts.map +1 -1
  138. package/dist/src/planner/nodes/join-node.js +12 -9
  139. package/dist/src/planner/nodes/join-node.js.map +1 -1
  140. package/dist/src/planner/nodes/join-utils.d.ts +24 -1
  141. package/dist/src/planner/nodes/join-utils.d.ts.map +1 -1
  142. package/dist/src/planner/nodes/join-utils.js +86 -0
  143. package/dist/src/planner/nodes/join-utils.js.map +1 -1
  144. package/dist/src/planner/nodes/limit-offset.d.ts.map +1 -1
  145. package/dist/src/planner/nodes/limit-offset.js +6 -1
  146. package/dist/src/planner/nodes/limit-offset.js.map +1 -1
  147. package/dist/src/planner/nodes/merge-join-node.d.ts.map +1 -1
  148. package/dist/src/planner/nodes/merge-join-node.js +19 -9
  149. package/dist/src/planner/nodes/merge-join-node.js.map +1 -1
  150. package/dist/src/planner/nodes/ordinal-slice-node.d.ts.map +1 -1
  151. package/dist/src/planner/nodes/ordinal-slice-node.js +5 -2
  152. package/dist/src/planner/nodes/ordinal-slice-node.js.map +1 -1
  153. package/dist/src/planner/nodes/plan-node-type.d.ts +1 -0
  154. package/dist/src/planner/nodes/plan-node-type.d.ts.map +1 -1
  155. package/dist/src/planner/nodes/plan-node-type.js +1 -0
  156. package/dist/src/planner/nodes/plan-node-type.js.map +1 -1
  157. package/dist/src/planner/nodes/plan-node.d.ts +186 -4
  158. package/dist/src/planner/nodes/plan-node.d.ts.map +1 -1
  159. package/dist/src/planner/nodes/plan-node.js.map +1 -1
  160. package/dist/src/planner/nodes/project-node.d.ts.map +1 -1
  161. package/dist/src/planner/nodes/project-node.js +75 -30
  162. package/dist/src/planner/nodes/project-node.js.map +1 -1
  163. package/dist/src/planner/nodes/reference.d.ts +24 -2
  164. package/dist/src/planner/nodes/reference.d.ts.map +1 -1
  165. package/dist/src/planner/nodes/reference.js +101 -1
  166. package/dist/src/planner/nodes/reference.js.map +1 -1
  167. package/dist/src/planner/nodes/retrieve-node.d.ts +9 -1
  168. package/dist/src/planner/nodes/retrieve-node.d.ts.map +1 -1
  169. package/dist/src/planner/nodes/retrieve-node.js +21 -0
  170. package/dist/src/planner/nodes/retrieve-node.js.map +1 -1
  171. package/dist/src/planner/nodes/returning-node.d.ts.map +1 -1
  172. package/dist/src/planner/nodes/returning-node.js +64 -28
  173. package/dist/src/planner/nodes/returning-node.js.map +1 -1
  174. package/dist/src/planner/nodes/scalar.d.ts +1 -0
  175. package/dist/src/planner/nodes/scalar.d.ts.map +1 -1
  176. package/dist/src/planner/nodes/scalar.js +12 -0
  177. package/dist/src/planner/nodes/scalar.js.map +1 -1
  178. package/dist/src/planner/nodes/set-operation-node.d.ts.map +1 -1
  179. package/dist/src/planner/nodes/set-operation-node.js +15 -0
  180. package/dist/src/planner/nodes/set-operation-node.js.map +1 -1
  181. package/dist/src/planner/nodes/single-row.d.ts.map +1 -1
  182. package/dist/src/planner/nodes/single-row.js +3 -1
  183. package/dist/src/planner/nodes/single-row.js.map +1 -1
  184. package/dist/src/planner/nodes/sort.d.ts.map +1 -1
  185. package/dist/src/planner/nodes/sort.js +10 -3
  186. package/dist/src/planner/nodes/sort.js.map +1 -1
  187. package/dist/src/planner/nodes/stream-aggregate.d.ts +1 -1
  188. package/dist/src/planner/nodes/stream-aggregate.d.ts.map +1 -1
  189. package/dist/src/planner/nodes/stream-aggregate.js +8 -8
  190. package/dist/src/planner/nodes/stream-aggregate.js.map +1 -1
  191. package/dist/src/planner/nodes/table-access-nodes.d.ts +3 -3
  192. package/dist/src/planner/nodes/table-access-nodes.d.ts.map +1 -1
  193. package/dist/src/planner/nodes/table-access-nodes.js +26 -8
  194. package/dist/src/planner/nodes/table-access-nodes.js.map +1 -1
  195. package/dist/src/planner/nodes/table-function-call.d.ts +4 -1
  196. package/dist/src/planner/nodes/table-function-call.d.ts.map +1 -1
  197. package/dist/src/planner/nodes/table-function-call.js +224 -14
  198. package/dist/src/planner/nodes/table-function-call.js.map +1 -1
  199. package/dist/src/planner/nodes/window-node.d.ts.map +1 -1
  200. package/dist/src/planner/nodes/window-node.js +9 -2
  201. package/dist/src/planner/nodes/window-node.js.map +1 -1
  202. package/dist/src/planner/optimizer-tuning.d.ts +29 -1
  203. package/dist/src/planner/optimizer-tuning.d.ts.map +1 -1
  204. package/dist/src/planner/optimizer-tuning.js +3 -0
  205. package/dist/src/planner/optimizer-tuning.js.map +1 -1
  206. package/dist/src/planner/optimizer.d.ts.map +1 -1
  207. package/dist/src/planner/optimizer.js +187 -0
  208. package/dist/src/planner/optimizer.js.map +1 -1
  209. package/dist/src/planner/rules/access/rule-select-access-path.d.ts.map +1 -1
  210. package/dist/src/planner/rules/access/rule-select-access-path.js +22 -7
  211. package/dist/src/planner/rules/access/rule-select-access-path.js.map +1 -1
  212. package/dist/src/planner/rules/aggregate/rule-groupby-fd-simplification.d.ts +30 -0
  213. package/dist/src/planner/rules/aggregate/rule-groupby-fd-simplification.d.ts.map +1 -0
  214. package/dist/src/planner/rules/aggregate/rule-groupby-fd-simplification.js +116 -0
  215. package/dist/src/planner/rules/aggregate/rule-groupby-fd-simplification.js.map +1 -0
  216. package/dist/src/planner/rules/distinct/rule-distinct-elimination.d.ts +7 -7
  217. package/dist/src/planner/rules/distinct/rule-distinct-elimination.d.ts.map +1 -1
  218. package/dist/src/planner/rules/distinct/rule-distinct-elimination.js +18 -16
  219. package/dist/src/planner/rules/distinct/rule-distinct-elimination.js.map +1 -1
  220. package/dist/src/planner/rules/join/rule-join-elimination.d.ts +56 -0
  221. package/dist/src/planner/rules/join/rule-join-elimination.d.ts.map +1 -0
  222. package/dist/src/planner/rules/join/rule-join-elimination.js +326 -0
  223. package/dist/src/planner/rules/join/rule-join-elimination.js.map +1 -0
  224. package/dist/src/planner/rules/join/rule-join-greedy-commute.d.ts.map +1 -1
  225. package/dist/src/planner/rules/join/rule-join-greedy-commute.js +10 -2
  226. package/dist/src/planner/rules/join/rule-join-greedy-commute.js.map +1 -1
  227. package/dist/src/planner/rules/predicate/rule-aggregate-predicate-pushdown.d.ts +20 -0
  228. package/dist/src/planner/rules/predicate/rule-aggregate-predicate-pushdown.d.ts.map +1 -0
  229. package/dist/src/planner/rules/predicate/rule-aggregate-predicate-pushdown.js +181 -0
  230. package/dist/src/planner/rules/predicate/rule-aggregate-predicate-pushdown.js.map +1 -0
  231. package/dist/src/planner/rules/predicate/rule-empty-relation-folding.d.ts +46 -0
  232. package/dist/src/planner/rules/predicate/rule-empty-relation-folding.d.ts.map +1 -0
  233. package/dist/src/planner/rules/predicate/rule-empty-relation-folding.js +156 -0
  234. package/dist/src/planner/rules/predicate/rule-empty-relation-folding.js.map +1 -0
  235. package/dist/src/planner/rules/predicate/rule-filter-contradiction.d.ts +30 -0
  236. package/dist/src/planner/rules/predicate/rule-filter-contradiction.d.ts.map +1 -0
  237. package/dist/src/planner/rules/predicate/rule-filter-contradiction.js +60 -0
  238. package/dist/src/planner/rules/predicate/rule-filter-contradiction.js.map +1 -0
  239. package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.d.ts +45 -0
  240. package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.d.ts.map +1 -0
  241. package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.js +210 -0
  242. package/dist/src/planner/rules/predicate/rule-predicate-inference-equivalence.js.map +1 -0
  243. package/dist/src/planner/rules/predicate/rule-sargable-range-rewrite.d.ts +29 -0
  244. package/dist/src/planner/rules/predicate/rule-sargable-range-rewrite.d.ts.map +1 -0
  245. package/dist/src/planner/rules/predicate/rule-sargable-range-rewrite.js +161 -0
  246. package/dist/src/planner/rules/predicate/rule-sargable-range-rewrite.js.map +1 -0
  247. package/dist/src/planner/rules/sort/rule-orderby-fd-pruning.d.ts +39 -0
  248. package/dist/src/planner/rules/sort/rule-orderby-fd-pruning.d.ts.map +1 -0
  249. package/dist/src/planner/rules/sort/rule-orderby-fd-pruning.js +91 -0
  250. package/dist/src/planner/rules/sort/rule-orderby-fd-pruning.js.map +1 -0
  251. package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.d.ts +35 -0
  252. package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.d.ts.map +1 -0
  253. package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.js +74 -0
  254. package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.js.map +1 -0
  255. package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.d.ts +27 -0
  256. package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.d.ts.map +1 -0
  257. package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.js +103 -0
  258. package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.js.map +1 -0
  259. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.d.ts.map +1 -1
  260. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js +1 -25
  261. package/dist/src/planner/rules/subquery/rule-subquery-decorrelation.js.map +1 -1
  262. package/dist/src/planner/scopes/global.js +2 -2
  263. package/dist/src/planner/scopes/global.js.map +1 -1
  264. package/dist/src/planner/type-utils.d.ts.map +1 -1
  265. package/dist/src/planner/type-utils.js +11 -0
  266. package/dist/src/planner/type-utils.js.map +1 -1
  267. package/dist/src/planner/util/fd-utils.d.ts +245 -0
  268. package/dist/src/planner/util/fd-utils.d.ts.map +1 -0
  269. package/dist/src/planner/util/fd-utils.js +1416 -0
  270. package/dist/src/planner/util/fd-utils.js.map +1 -0
  271. package/dist/src/planner/util/ind-utils.d.ts +79 -0
  272. package/dist/src/planner/util/ind-utils.d.ts.map +1 -0
  273. package/dist/src/planner/util/ind-utils.js +146 -0
  274. package/dist/src/planner/util/ind-utils.js.map +1 -0
  275. package/dist/src/planner/util/key-utils.d.ts +75 -14
  276. package/dist/src/planner/util/key-utils.d.ts.map +1 -1
  277. package/dist/src/planner/util/key-utils.js +234 -57
  278. package/dist/src/planner/util/key-utils.js.map +1 -1
  279. package/dist/src/runtime/delta-executor.d.ts +134 -0
  280. package/dist/src/runtime/delta-executor.d.ts.map +1 -0
  281. package/dist/src/runtime/delta-executor.js +382 -0
  282. package/dist/src/runtime/delta-executor.js.map +1 -0
  283. package/dist/src/runtime/emit/alter-table.d.ts.map +1 -1
  284. package/dist/src/runtime/emit/alter-table.js +52 -16
  285. package/dist/src/runtime/emit/alter-table.js.map +1 -1
  286. package/dist/src/runtime/emit/create-assertion.d.ts.map +1 -1
  287. package/dist/src/runtime/emit/create-assertion.js +3 -2
  288. package/dist/src/runtime/emit/create-assertion.js.map +1 -1
  289. package/dist/src/runtime/emit/dml-executor.d.ts.map +1 -1
  290. package/dist/src/runtime/emit/dml-executor.js +40 -13
  291. package/dist/src/runtime/emit/dml-executor.js.map +1 -1
  292. package/dist/src/runtime/emit/drop-assertion.js +1 -1
  293. package/dist/src/runtime/emit/drop-assertion.js.map +1 -1
  294. package/dist/src/runtime/emit/empty-relation.d.ts +5 -0
  295. package/dist/src/runtime/emit/empty-relation.d.ts.map +1 -0
  296. package/dist/src/runtime/emit/empty-relation.js +11 -0
  297. package/dist/src/runtime/emit/empty-relation.js.map +1 -0
  298. package/dist/src/runtime/foreign-key-actions.d.ts +16 -0
  299. package/dist/src/runtime/foreign-key-actions.d.ts.map +1 -1
  300. package/dist/src/runtime/foreign-key-actions.js +81 -1
  301. package/dist/src/runtime/foreign-key-actions.js.map +1 -1
  302. package/dist/src/runtime/register.d.ts.map +1 -1
  303. package/dist/src/runtime/register.js +2 -0
  304. package/dist/src/runtime/register.js.map +1 -1
  305. package/dist/src/schema/assertion.d.ts +8 -0
  306. package/dist/src/schema/assertion.d.ts.map +1 -1
  307. package/dist/src/schema/change-events.d.ts +5 -1
  308. package/dist/src/schema/change-events.d.ts.map +1 -1
  309. package/dist/src/schema/change-events.js.map +1 -1
  310. package/dist/src/schema/function.d.ts +65 -1
  311. package/dist/src/schema/function.d.ts.map +1 -1
  312. package/dist/src/schema/function.js +31 -0
  313. package/dist/src/schema/function.js.map +1 -1
  314. package/dist/src/schema/manager.d.ts +33 -0
  315. package/dist/src/schema/manager.d.ts.map +1 -1
  316. package/dist/src/schema/manager.js +95 -4
  317. package/dist/src/schema/manager.js.map +1 -1
  318. package/dist/src/schema/rename-rewriter.d.ts.map +1 -1
  319. package/dist/src/schema/rename-rewriter.js +303 -102
  320. package/dist/src/schema/rename-rewriter.js.map +1 -1
  321. package/dist/src/schema/table.d.ts +21 -2
  322. package/dist/src/schema/table.d.ts.map +1 -1
  323. package/dist/src/schema/table.js +17 -8
  324. package/dist/src/schema/table.js.map +1 -1
  325. package/dist/src/types/temporal-types.d.ts.map +1 -1
  326. package/dist/src/types/temporal-types.js +32 -0
  327. package/dist/src/types/temporal-types.js.map +1 -1
  328. package/dist/src/vtab/events.d.ts +9 -0
  329. package/dist/src/vtab/events.d.ts.map +1 -1
  330. package/dist/src/vtab/events.js +19 -0
  331. package/dist/src/vtab/events.js.map +1 -1
  332. package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
  333. package/dist/src/vtab/memory/layer/manager.js +24 -5
  334. package/dist/src/vtab/memory/layer/manager.js.map +1 -1
  335. package/dist/src/vtab/memory/utils/predicate.d.ts +2 -1
  336. package/dist/src/vtab/memory/utils/predicate.d.ts.map +1 -1
  337. package/dist/src/vtab/memory/utils/predicate.js +32 -1
  338. package/dist/src/vtab/memory/utils/predicate.js.map +1 -1
  339. package/package.json +3 -3
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Rule: Predicate Inference (Equivalence-Class driven)
3
+ *
4
+ * Materializes inferred equality predicates derived from combining
5
+ * (predicate-derived) constant bindings with (source-derived) equivalence
6
+ * classes. When `t.k = u.k` is known via a join's equi-pair and `t.k = V`
7
+ * is asserted in the filter, the rule emits `u.k = V` so the predicate is
8
+ * visible to vtab access plans on the `u` side independently.
9
+ *
10
+ * Simple form (always run):
11
+ * Filter(predicate, source)
12
+ * - Extract `predBindings` from the predicate (col-index → constant value).
13
+ * - Cross with `source.physical.equivClasses`: for every EC member of a
14
+ * bound column that is not itself bound by the predicate, emit a new
15
+ * `col = value` conjunct.
16
+ * - AND the new conjuncts into the filter predicate.
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.
26
+ *
27
+ * Fixpoint guard: the rule's emission set is `{otherIdx ∈ EC | otherIdx
28
+ * is not already in predBoundIdx}`. On a second invocation the
29
+ * inferred conjuncts have themselves contributed bindings, so every EC
30
+ * member is in `predBoundIdx` and the rule yields nothing. The registry's
31
+ * per-node `markRuleApplied` is a belt-and-suspenders second guard.
32
+ *
33
+ * Safety:
34
+ * - LEFT/RIGHT/FULL joins: per `propagateJoinFds`, NULL-padded sides drop
35
+ * 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).
38
+ * - SEMI/ANTI: only the left side is in the output; no right inference
39
+ * can arise here. Treat as LEFT for branch injection.
40
+ *
41
+ * See ticket `3-rule-predicate-inference-equivalence` for the full design.
42
+ */
43
+ import { createLogger } from '../../../common/logger.js';
44
+ import { FilterNode } from '../../nodes/filter.js';
45
+ import { JoinNode } from '../../nodes/join-node.js';
46
+ import { BinaryOpNode, LiteralNode } from '../../nodes/scalar.js';
47
+ import { ColumnReferenceNode, ParameterReferenceNode } from '../../nodes/reference.js';
48
+ import { extractEqualityFds } from '../../util/fd-utils.js';
49
+ const log = createLogger('optimizer:rule:predicate-inference-equivalence');
50
+ export function rulePredicateInferenceEquivalence(node, _context) {
51
+ if (!(node instanceof FilterNode))
52
+ return null;
53
+ const filter = node;
54
+ const source = filter.source;
55
+ const sourcePhys = source.physical;
56
+ const ecs = sourcePhys?.equivClasses;
57
+ if (!ecs || ecs.length === 0)
58
+ return null;
59
+ const sourceAttrs = source.getAttributes();
60
+ const attrIdToIndex = new Map();
61
+ sourceAttrs.forEach((a, i) => attrIdToIndex.set(a.id, i));
62
+ const { constantBindings: predBindings } = extractEqualityFds(filter.predicate, attrIdToIndex);
63
+ if (predBindings.length === 0)
64
+ return null;
65
+ // Columns the predicate itself directly pins. Used both to find which
66
+ // EC members already have a binding and as the fixpoint guard: once
67
+ // every EC member is in this set, the rule contributes nothing further.
68
+ const predBoundIdx = new Set();
69
+ for (const b of predBindings)
70
+ for (const c of b.attrs)
71
+ predBoundIdx.add(c);
72
+ const inferred = [];
73
+ const seen = new Set();
74
+ for (const binding of predBindings) {
75
+ for (const predIdx of binding.attrs) {
76
+ for (const cls of ecs) {
77
+ if (!cls.includes(predIdx))
78
+ continue;
79
+ for (const otherIdx of cls) {
80
+ if (otherIdx === predIdx)
81
+ continue;
82
+ if (predBoundIdx.has(otherIdx))
83
+ continue;
84
+ const key = `${otherIdx}|${valueSignature(binding.value)}`;
85
+ if (seen.has(key))
86
+ continue;
87
+ seen.add(key);
88
+ const attr = sourceAttrs[otherIdx];
89
+ if (!attr)
90
+ continue;
91
+ const conjunct = synthesizeEquality(filter.scope, attr, otherIdx, binding.value);
92
+ inferred.push({ sourceColIdx: otherIdx, value: binding.value, conjunct });
93
+ }
94
+ }
95
+ }
96
+ }
97
+ if (inferred.length === 0)
98
+ return null;
99
+ log('Inferring %d new equality conjunct(s) on Filter from EC × bindings', inferred.length);
100
+ // AND every inferred conjunct into the predicate.
101
+ let combinedPredicate = filter.predicate;
102
+ for (const inf of inferred) {
103
+ combinedPredicate = andTogether(filter.scope, combinedPredicate, inf.conjunct);
104
+ }
105
+ // Powerful form: branch injection below inner/cross joins.
106
+ let newSource = source;
107
+ if (source instanceof JoinNode) {
108
+ newSource = tryBranchInjection(source, inferred) ?? source;
109
+ }
110
+ return new FilterNode(filter.scope, newSource, combinedPredicate);
111
+ }
112
+ /**
113
+ * For an inner or cross JoinNode whose output bears `inferred` conjuncts,
114
+ * inject single-side conjuncts as FilterNode wrappers on the corresponding
115
+ * branch. Returns the rebuilt join, or null if no inferred conjunct lands
116
+ * on either branch.
117
+ */
118
+ function tryBranchInjection(join, inferred) {
119
+ // Only inner / cross are safe — see file-level "Safety" notes.
120
+ if (join.joinType !== 'inner' && join.joinType !== 'cross')
121
+ return null;
122
+ const leftAttrs = join.left.getAttributes();
123
+ const rightAttrs = join.right.getAttributes();
124
+ const leftCount = leftAttrs.length;
125
+ const leftBranchConjuncts = [];
126
+ const rightBranchConjuncts = [];
127
+ for (const inf of inferred) {
128
+ if (inf.sourceColIdx < leftCount) {
129
+ // Left-branch: attribute id is stable, so re-synthesize against the
130
+ // branch's local column index (which is `sourceColIdx` itself).
131
+ const attr = leftAttrs[inf.sourceColIdx];
132
+ if (!attr)
133
+ continue;
134
+ leftBranchConjuncts.push(synthesizeEquality(join.scope, attr, inf.sourceColIdx, inf.value));
135
+ }
136
+ else {
137
+ const rightIdx = inf.sourceColIdx - leftCount;
138
+ const attr = rightAttrs[rightIdx];
139
+ if (!attr)
140
+ continue;
141
+ rightBranchConjuncts.push(synthesizeEquality(join.scope, attr, rightIdx, inf.value));
142
+ }
143
+ }
144
+ if (leftBranchConjuncts.length === 0 && rightBranchConjuncts.length === 0)
145
+ return null;
146
+ let newLeft = join.left;
147
+ let newRight = join.right;
148
+ if (leftBranchConjuncts.length > 0) {
149
+ const leftPred = combineAnds(join.scope, leftBranchConjuncts);
150
+ newLeft = new FilterNode(join.left.scope, join.left, leftPred);
151
+ }
152
+ if (rightBranchConjuncts.length > 0) {
153
+ const rightPred = combineAnds(join.scope, rightBranchConjuncts);
154
+ newRight = new FilterNode(join.right.scope, join.right, rightPred);
155
+ }
156
+ log('Injecting %d left + %d right branch filter(s) below %s join', leftBranchConjuncts.length, rightBranchConjuncts.length, join.joinType);
157
+ return new JoinNode(join.scope, newLeft, newRight, join.joinType, join.condition, join.usingColumns);
158
+ }
159
+ function synthesizeEquality(scope, attr, columnIndex, value) {
160
+ const colExpr = attr.relationName
161
+ ? { type: 'column', name: attr.name, table: attr.relationName }
162
+ : { type: 'column', name: attr.name };
163
+ const colRef = new ColumnReferenceNode(scope, colExpr, attr.type, attr.id, columnIndex);
164
+ let valueNode;
165
+ if (value.kind === 'literal') {
166
+ const litExpr = { type: 'literal', value: value.value };
167
+ valueNode = new LiteralNode(scope, litExpr);
168
+ }
169
+ else {
170
+ const paramExpr = typeof value.paramRef === 'string'
171
+ ? { type: 'parameter', name: value.paramRef }
172
+ : { type: 'parameter', index: value.paramRef };
173
+ valueNode = new ParameterReferenceNode(scope, paramExpr, value.paramRef, attr.type);
174
+ }
175
+ const eqAst = {
176
+ type: 'binary',
177
+ operator: '=',
178
+ left: colRef.expression,
179
+ right: valueNode.expression,
180
+ };
181
+ return new BinaryOpNode(scope, eqAst, colRef, valueNode);
182
+ }
183
+ function andTogether(scope, left, right) {
184
+ const ast = {
185
+ type: 'binary',
186
+ operator: 'AND',
187
+ left: left.expression,
188
+ right: right.expression,
189
+ };
190
+ return new BinaryOpNode(scope, ast, left, right);
191
+ }
192
+ function combineAnds(scope, conjuncts) {
193
+ let acc = conjuncts[0];
194
+ for (let i = 1; i < conjuncts.length; i++) {
195
+ acc = andTogether(scope, acc, conjuncts[i]);
196
+ }
197
+ return acc;
198
+ }
199
+ function valueSignature(value) {
200
+ if (value.kind === 'literal') {
201
+ const v = value.value;
202
+ if (v === null)
203
+ return 'lit:null';
204
+ if (v instanceof Uint8Array)
205
+ return `lit:blob:${Array.from(v).join(',')}`;
206
+ return `lit:${typeof v}:${String(v)}`;
207
+ }
208
+ return `param:${value.paramRef}`;
209
+ }
210
+ //# sourceMappingURL=rule-predicate-inference-equivalence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule-predicate-inference-equivalence.js","sourceRoot":"","sources":["../../../../../src/planner/rules/predicate/rule-predicate-inference-equivalence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Rule: Sargable Range Rewrite
3
+ *
4
+ * For predicates of the form `f(col) = c` where `f` is a monotone-but-lossy
5
+ * bucket conversion (e.g. `date(datetime_col) = '2024-01-15'`), rewrite the
6
+ * conjunct to a half-open range on the underlying column:
7
+ *
8
+ * f(col) = c → col >= lower(c) AND col < upper(c)
9
+ *
10
+ * The half-open bounds come from `ScalarPlanNode.rangeRewriteIn(attrId, c)`,
11
+ * which delegates to `LogicalType.bucketBounds` on the column's logical type.
12
+ * The rewritten `col op literal` shape is what `analysis/constraint-extractor`
13
+ * already recognizes, so the resulting range can be pushed through
14
+ * `rule-predicate-pushdown` into the Retrieve pipeline and consumed by
15
+ * `rule-select-access-path` (IndexSeek, range scans, etc.).
16
+ *
17
+ * NULL semantics: a null constant is left alone (`f(col) = null` is already
18
+ * null, which WHERE / ON treat as false). A null column value satisfies neither
19
+ * `col >= L` nor `col < U` (both yield null), so row-rejection behavior
20
+ * matches the original predicate.
21
+ *
22
+ * Only the `=` shape is handled in this pass; `<`/`<=`/`>`/`>=` need direction
23
+ * analysis on `monotonicityIn` and asymmetric bound mapping — tracked
24
+ * separately in the optimization backlog.
25
+ */
26
+ import type { PlanNode } from '../../nodes/plan-node.js';
27
+ import type { OptContext } from '../../framework/context.js';
28
+ export declare function ruleSargableRangeRewrite(node: PlanNode, _context: OptContext): PlanNode | null;
29
+ //# sourceMappingURL=rule-sargable-range-rewrite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule-sargable-range-rewrite.d.ts","sourceRoot":"","sources":["../../../../../src/planner/rules/predicate/rule-sargable-range-rewrite.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAkB,MAAM,0BAA0B,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAa7D,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,GAAG,QAAQ,GAAG,IAAI,CAuB9F"}
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Rule: Sargable Range Rewrite
3
+ *
4
+ * For predicates of the form `f(col) = c` where `f` is a monotone-but-lossy
5
+ * bucket conversion (e.g. `date(datetime_col) = '2024-01-15'`), rewrite the
6
+ * conjunct to a half-open range on the underlying column:
7
+ *
8
+ * f(col) = c → col >= lower(c) AND col < upper(c)
9
+ *
10
+ * The half-open bounds come from `ScalarPlanNode.rangeRewriteIn(attrId, c)`,
11
+ * which delegates to `LogicalType.bucketBounds` on the column's logical type.
12
+ * The rewritten `col op literal` shape is what `analysis/constraint-extractor`
13
+ * already recognizes, so the resulting range can be pushed through
14
+ * `rule-predicate-pushdown` into the Retrieve pipeline and consumed by
15
+ * `rule-select-access-path` (IndexSeek, range scans, etc.).
16
+ *
17
+ * NULL semantics: a null constant is left alone (`f(col) = null` is already
18
+ * null, which WHERE / ON treat as false). A null column value satisfies neither
19
+ * `col >= L` nor `col < U` (both yield null), so row-rejection behavior
20
+ * matches the original predicate.
21
+ *
22
+ * Only the `=` shape is handled in this pass; `<`/`<=`/`>`/`>=` need direction
23
+ * analysis on `monotonicityIn` and asymmetric bound mapping — tracked
24
+ * separately in the optimization backlog.
25
+ */
26
+ import { createLogger } from '../../../common/logger.js';
27
+ import { PlanNodeType } from '../../nodes/plan-node-type.js';
28
+ import { FilterNode } from '../../nodes/filter.js';
29
+ import { BinaryOpNode, LiteralNode } from '../../nodes/scalar.js';
30
+ import { ColumnReferenceNode, ParameterReferenceNode } from '../../nodes/reference.js';
31
+ import { splitConjuncts, combineConjuncts } from '../../analysis/predicate-conjuncts.js';
32
+ import { getSyncLiteral } from '../../../parser/utils.js';
33
+ const log = createLogger('optimizer:rule:sargable-range-rewrite');
34
+ export function ruleSargableRangeRewrite(node, _context) {
35
+ if (node.nodeType !== PlanNodeType.Filter)
36
+ return null;
37
+ const filter = node;
38
+ const conjuncts = splitConjuncts(filter.predicate);
39
+ let rewrittenCount = 0;
40
+ const out = [];
41
+ for (const c of conjuncts) {
42
+ const rewritten = tryRewriteEqualityToRange(c);
43
+ if (rewritten) {
44
+ out.push(rewritten);
45
+ rewrittenCount++;
46
+ }
47
+ else {
48
+ out.push(c);
49
+ }
50
+ }
51
+ if (rewrittenCount === 0)
52
+ return null;
53
+ const combined = combineConjuncts(out);
54
+ if (!combined)
55
+ return null;
56
+ log('Rewrote %d sargable bucket-equality conjunct(s)', rewrittenCount);
57
+ return new FilterNode(filter.scope, filter.source, combined);
58
+ }
59
+ /**
60
+ * Recognize a `f(col) = const` conjunct and lift it to a half-open range on
61
+ * `col`. Returns the rewritten AND-tree on success, or `undefined` when the
62
+ * conjunct is not in the recognized shape / the function declines the rewrite.
63
+ */
64
+ function tryRewriteEqualityToRange(expr) {
65
+ if (expr.nodeType !== PlanNodeType.BinaryOp)
66
+ return undefined;
67
+ const bin = expr;
68
+ if (bin.expression.operator !== '=')
69
+ return undefined;
70
+ // Exactly one side must be a literal constant; the other is the candidate
71
+ // function-shaped expression.
72
+ const leftLit = isLiteralConstant(bin.left);
73
+ const rightLit = isLiteralConstant(bin.right);
74
+ if (leftLit === rightLit)
75
+ return undefined; // both or neither
76
+ const literalSide = leftLit ? bin.left : bin.right;
77
+ const candidateSide = leftLit ? bin.right : bin.left;
78
+ const literalValue = getLiteralValue(literalSide);
79
+ if (literalValue === null)
80
+ return undefined;
81
+ // The candidate must depend on exactly one column attribute. Other leaves
82
+ // (literals / parameters) are fine — `rangeRewriteIn` itself enforces that
83
+ // the operand at the trait index is a bare ColumnReferenceNode.
84
+ const colRef = findUniqueColumnReference(candidateSide);
85
+ if (!colRef)
86
+ return undefined;
87
+ const bounds = candidateSide.rangeRewriteIn(colRef.attributeId, literalValue);
88
+ if (!bounds)
89
+ return undefined;
90
+ // Build `col >= L AND col < U` reusing the original ColumnReferenceNode (so
91
+ // the attribute id survives verbatim for downstream constraint extraction).
92
+ const scope = expr.scope;
93
+ const colType = colRef.getType();
94
+ const lower = makeComparison(scope, colRef, '>=', bounds.lowerInclusive, colType);
95
+ const upper = makeComparison(scope, colRef, '<', bounds.upperExclusive, colType);
96
+ const andAst = {
97
+ type: 'binary',
98
+ operator: 'AND',
99
+ left: lower.expression,
100
+ right: upper.expression,
101
+ };
102
+ return new BinaryOpNode(scope, andAst, lower, upper);
103
+ }
104
+ function makeComparison(scope, colRef, op, value, colType) {
105
+ const litExpr = { type: 'literal', value };
106
+ const literal = new LiteralNode(scope, litExpr, colType);
107
+ const ast = {
108
+ type: 'binary',
109
+ operator: op,
110
+ left: colRef.expression,
111
+ right: litExpr,
112
+ };
113
+ return new BinaryOpNode(scope, ast, colRef, literal);
114
+ }
115
+ /** Strip a planner-inserted CastNode wrapper. */
116
+ function unwrapCast(node) {
117
+ return node.nodeType === PlanNodeType.Cast ? node.operand : node;
118
+ }
119
+ function isLiteralConstant(node) {
120
+ return unwrapCast(node).nodeType === PlanNodeType.Literal;
121
+ }
122
+ function getLiteralValue(node) {
123
+ const lit = unwrapCast(node);
124
+ return getSyncLiteral(lit.expression);
125
+ }
126
+ /**
127
+ * Walk the subtree's leaves and return the single `ColumnReferenceNode` if
128
+ * exactly one is found and every other leaf is a literal or parameter; return
129
+ * undefined for zero, two, or any unrecognized leaf shape (subqueries,
130
+ * function-of-other-column, etc.).
131
+ */
132
+ function findUniqueColumnReference(node) {
133
+ let found;
134
+ let ok = true;
135
+ const visit = (n) => {
136
+ if (!ok)
137
+ return;
138
+ const children = n.getChildren();
139
+ if (children.length === 0) {
140
+ if (n instanceof ColumnReferenceNode) {
141
+ if (found && found !== n) {
142
+ ok = false;
143
+ return;
144
+ }
145
+ found = n;
146
+ return;
147
+ }
148
+ if (n instanceof LiteralNode || n instanceof ParameterReferenceNode) {
149
+ return;
150
+ }
151
+ ok = false;
152
+ return;
153
+ }
154
+ for (const c of children) {
155
+ visit(c);
156
+ }
157
+ };
158
+ visit(node);
159
+ return ok ? found : undefined;
160
+ }
161
+ //# sourceMappingURL=rule-sargable-range-rewrite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule-sargable-range-rewrite.js","sourceRoot":"","sources":["../../../../../src/planner/rules/predicate/rule-sargable-range-rewrite.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Rule: ORDER BY FD pruning
3
+ *
4
+ * Drops trailing ORDER BY keys that are functionally determined by the
5
+ * preceding bare-column keys under the source's FDs and equivalence classes.
6
+ *
7
+ * For a SortNode with ≥ 2 keys, walk the keys front-to-back maintaining
8
+ * `determined = closure({leading bare-column source-indices}, fds, ECs)`.
9
+ * Drop any trailing key whose expression is a bare `ColumnReferenceNode` and
10
+ * whose source-attribute index is already in `determined`. Direction and
11
+ * NULL placement on the dropped trailing key are irrelevant — once the
12
+ * preceding keys pin every value of that column to a single value per group,
13
+ * the trailing key cannot reorder anything.
14
+ *
15
+ * Sort-key matcher semantics: only bare `ColumnReferenceNode` keys
16
+ * participate in either direction of the reasoning. A non-bare-column key
17
+ * contributes nothing to `determined` (we can't prove what expression values
18
+ * "determine"), and a non-bare-column key cannot be dropped. The rule walks
19
+ * past non-bare keys treating them as opaque.
20
+ *
21
+ * Reasoning space: `fds`/`equivClasses` from `node.source.physical` are in
22
+ * source-attribute-INDEX space (positions in `source.getAttributes()`), NOT
23
+ * attribute IDs. The rule converts each sort-key's `ColumnReferenceNode.
24
+ * attributeId` to its source-attribute index before feeding `computeClosure`
25
+ * — mirroring how `SortNode.computePhysical` does its `leadIdx` lookup.
26
+ *
27
+ * Soundness: equality-class FDs from a `WHERE a = b` filter or a join key
28
+ * are sound here because every surviving row has equal values on the EC
29
+ * members, so the trailing key is a no-op tiebreaker.
30
+ *
31
+ * Ordering with other rules: this is a Structural-pass rule. It must run
32
+ * before `monotonic-limit-pushdown` (PostOptimization priority 8) so single-
33
+ * key reductions can enable the pushdown. That ordering is automatic since
34
+ * Structural runs before PostOptimization.
35
+ */
36
+ import type { PlanNode } from '../../nodes/plan-node.js';
37
+ import type { OptContext as _OptContext } from '../../framework/context.js';
38
+ export declare function ruleOrderByFdPruning(node: PlanNode, _context: _OptContext): PlanNode | null;
39
+ //# sourceMappingURL=rule-orderby-fd-pruning.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule-orderby-fd-pruning.d.ts","sourceRoot":"","sources":["../../../../../src/planner/rules/sort/rule-orderby-fd-pruning.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,IAAI,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAO5E,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,GAAG,QAAQ,GAAG,IAAI,CAmD3F"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Rule: ORDER BY FD pruning
3
+ *
4
+ * Drops trailing ORDER BY keys that are functionally determined by the
5
+ * preceding bare-column keys under the source's FDs and equivalence classes.
6
+ *
7
+ * For a SortNode with ≥ 2 keys, walk the keys front-to-back maintaining
8
+ * `determined = closure({leading bare-column source-indices}, fds, ECs)`.
9
+ * Drop any trailing key whose expression is a bare `ColumnReferenceNode` and
10
+ * whose source-attribute index is already in `determined`. Direction and
11
+ * NULL placement on the dropped trailing key are irrelevant — once the
12
+ * preceding keys pin every value of that column to a single value per group,
13
+ * the trailing key cannot reorder anything.
14
+ *
15
+ * Sort-key matcher semantics: only bare `ColumnReferenceNode` keys
16
+ * participate in either direction of the reasoning. A non-bare-column key
17
+ * contributes nothing to `determined` (we can't prove what expression values
18
+ * "determine"), and a non-bare-column key cannot be dropped. The rule walks
19
+ * past non-bare keys treating them as opaque.
20
+ *
21
+ * Reasoning space: `fds`/`equivClasses` from `node.source.physical` are in
22
+ * source-attribute-INDEX space (positions in `source.getAttributes()`), NOT
23
+ * attribute IDs. The rule converts each sort-key's `ColumnReferenceNode.
24
+ * attributeId` to its source-attribute index before feeding `computeClosure`
25
+ * — mirroring how `SortNode.computePhysical` does its `leadIdx` lookup.
26
+ *
27
+ * Soundness: equality-class FDs from a `WHERE a = b` filter or a join key
28
+ * are sound here because every surviving row has equal values on the EC
29
+ * members, so the trailing key is a no-op tiebreaker.
30
+ *
31
+ * Ordering with other rules: this is a Structural-pass rule. It must run
32
+ * before `monotonic-limit-pushdown` (PostOptimization priority 8) so single-
33
+ * key reductions can enable the pushdown. That ordering is automatic since
34
+ * Structural runs before PostOptimization.
35
+ */
36
+ import { createLogger } from '../../../common/logger.js';
37
+ import { SortNode } from '../../nodes/sort.js';
38
+ import { ColumnReferenceNode } from '../../nodes/reference.js';
39
+ import { computeClosure, expandEcsToFds } from '../../util/fd-utils.js';
40
+ const log = createLogger('optimizer:rule:orderby-fd-pruning');
41
+ export function ruleOrderByFdPruning(node, _context) {
42
+ if (!(node instanceof SortNode))
43
+ return null;
44
+ if (node.sortKeys.length < 2)
45
+ return null;
46
+ const source = node.source;
47
+ const sourceAttrs = source.getAttributes();
48
+ const sourcePhysical = source.physical;
49
+ const sourceFds = sourcePhysical.fds ?? [];
50
+ const sourceEcs = sourcePhysical.equivClasses ?? [];
51
+ if (sourceFds.length === 0 && sourceEcs.length === 0)
52
+ return null;
53
+ const combinedFds = expandEcsToFds(sourceEcs, sourceFds);
54
+ const survivors = [];
55
+ const determined = new Set();
56
+ let dropped = 0;
57
+ for (const key of node.sortKeys) {
58
+ const expr = key.expression;
59
+ if (!(expr instanceof ColumnReferenceNode)) {
60
+ // Non-bare-column keys are opaque: they neither contribute to nor
61
+ // consume `determined`. Always retained.
62
+ survivors.push(key);
63
+ continue;
64
+ }
65
+ const srcIdx = sourceAttrs.findIndex(a => a.id === expr.attributeId);
66
+ if (srcIdx < 0) {
67
+ // Defensive: column reference doesn't resolve into the source.
68
+ // Retain the key rather than mis-prune.
69
+ survivors.push(key);
70
+ continue;
71
+ }
72
+ if (determined.has(srcIdx)) {
73
+ dropped++;
74
+ continue;
75
+ }
76
+ survivors.push(key);
77
+ determined.add(srcIdx);
78
+ // Re-close under FDs so subsequent trailing keys can drop.
79
+ const closure = computeClosure(determined, combinedFds);
80
+ for (const x of closure)
81
+ determined.add(x);
82
+ }
83
+ if (dropped === 0)
84
+ return null;
85
+ // Defensive: should be impossible — the first key never gets dropped.
86
+ if (survivors.length === 0)
87
+ return null;
88
+ log('Dropped %d/%d ORDER BY key(s)', dropped, node.sortKeys.length);
89
+ return node.withSortKeys(survivors);
90
+ }
91
+ //# sourceMappingURL=rule-orderby-fd-pruning.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule-orderby-fd-pruning.js","sourceRoot":"","sources":["../../../../../src/planner/rules/sort/rule-orderby-fd-pruning.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAGzD,OAAO,EAAE,QAAQ,EAAgB,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExE,MAAM,GAAG,GAAG,YAAY,CAAC,mCAAmC,CAAC,CAAC;AAE9D,MAAM,UAAU,oBAAoB,CAAC,IAAc,EAAE,QAAqB;IACzE,IAAI,CAAC,CAAC,IAAI,YAAY,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7C,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAE1C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAC3B,MAAM,WAAW,GAAG,MAAM,CAAC,aAAa,EAAE,CAAC;IAC3C,MAAM,cAAc,GAAG,MAAM,CAAC,QAAQ,CAAC;IACvC,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,IAAI,EAAE,CAAC;IAC3C,MAAM,SAAS,GAAG,cAAc,CAAC,YAAY,IAAI,EAAE,CAAC;IAEpD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAElE,MAAM,WAAW,GAAG,cAAc,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAEzD,MAAM,SAAS,GAAc,EAAE,CAAC;IAChC,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IACrC,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QACjC,MAAM,IAAI,GAAG,GAAG,CAAC,UAAU,CAAC;QAC5B,IAAI,CAAC,CAAC,IAAI,YAAY,mBAAmB,CAAC,EAAE,CAAC;YAC5C,kEAAkE;YAClE,yCAAyC;YACzC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACpB,SAAS;QACV,CAAC;QACD,MAAM,MAAM,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,WAAW,CAAC,CAAC;QACrE,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;YAChB,+DAA+D;YAC/D,wCAAwC;YACxC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACpB,SAAS;QACV,CAAC;QACD,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5B,OAAO,EAAE,CAAC;YACV,SAAS;QACV,CAAC;QACD,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACpB,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACvB,2DAA2D;QAC3D,MAAM,OAAO,GAAG,cAAc,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QACxD,KAAK,MAAM,CAAC,IAAI,OAAO;YAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC5C,CAAC;IAED,IAAI,OAAO,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/B,sEAAsE;IACtE,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAExC,GAAG,CAAC,+BAA+B,EAAE,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAEpE,OAAO,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;AACrC,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Rule: Anti-Join FK → Empty
3
+ *
4
+ * Inclusion-dependency folding for `NOT EXISTS` patterns after
5
+ * `rule-subquery-decorrelation` has materialized them as anti-joins.
6
+ *
7
+ * Pattern:
8
+ * AntiJoin(L, R, p)
9
+ * where p is an AND-of-column-equalities,
10
+ * L's equi columns form a declared FK referencing R's PK (via the equi
11
+ * pairs in some permutation),
12
+ * every FK child column is NOT NULL, and
13
+ * R is a row-preserving path to its base table (no filter / limit / distinct
14
+ * between the anti-join and the parent table).
15
+ *
16
+ * Rewrite:
17
+ * EmptyRelationNode(L's attributes, L's RelationType)
18
+ *
19
+ * Why correct: under the FK inclusion `L.fk ⊆ R.pk`, every non-null FK row in L
20
+ * has a matching parent in R, so the anti-join contains no rows. With nullable
21
+ * FKs, NULL FK rows survive (the equality is UNKNOWN, never matched), so the
22
+ * rule conservatively requires all FK columns NOT NULL. Row-preserving R is
23
+ * required because the IND only guarantees the parent row exists in the table
24
+ * — a filter on the R side could remove it.
25
+ *
26
+ * The output schema of an anti-join is its left side (SEMI/ANTI take left
27
+ * columns only — see `buildJoinAttributes`), so we hand `EmptyRelationNode`
28
+ * L's attribute IDs and RelationType directly. The const-fold pass
29
+ * (Structural priority 27) then cascades that emptiness up through Filter /
30
+ * Project / Sort / LimitOffset / Distinct / inner-or-cross-or-semi joins.
31
+ */
32
+ import type { PlanNode } from '../../nodes/plan-node.js';
33
+ import type { OptContext } from '../../framework/context.js';
34
+ export declare function ruleAntiJoinFkEmpty(node: PlanNode, _context: OptContext): PlanNode | null;
35
+ //# sourceMappingURL=rule-anti-join-fk-empty.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule-anti-join-fk-empty.d.ts","sourceRoot":"","sources":["../../../../../src/planner/rules/subquery/rule-anti-join-fk-empty.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAS7D,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,GAAG,QAAQ,GAAG,IAAI,CAqCzF"}