@quereus/quereus 0.1.0 → 0.2.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 (465) hide show
  1. package/README.md +47 -23
  2. package/dist/src/core/database.d.ts +22 -4
  3. package/dist/src/core/database.d.ts.map +1 -1
  4. package/dist/src/core/database.js +44 -6
  5. package/dist/src/core/database.js.map +1 -1
  6. package/dist/src/core/statement.d.ts +0 -7
  7. package/dist/src/core/statement.d.ts.map +1 -1
  8. package/dist/src/core/statement.js +1 -51
  9. package/dist/src/core/statement.js.map +1 -1
  10. package/dist/src/func/builtins/explain.d.ts.map +1 -1
  11. package/dist/src/func/builtins/explain.js +0 -11
  12. package/dist/src/func/builtins/explain.js.map +1 -1
  13. package/dist/src/index.d.ts +13 -5
  14. package/dist/src/index.d.ts.map +1 -1
  15. package/dist/src/index.js +5 -2
  16. package/dist/src/index.js.map +1 -1
  17. package/dist/src/parser/ast.d.ts +9 -2
  18. package/dist/src/parser/ast.d.ts.map +1 -1
  19. package/dist/src/parser/parser.d.ts.map +1 -1
  20. package/dist/src/parser/parser.js +40 -44
  21. package/dist/src/parser/parser.js.map +1 -1
  22. package/dist/src/planner/analysis/const-pass.d.ts.map +1 -1
  23. package/dist/src/planner/analysis/const-pass.js +12 -6
  24. package/dist/src/planner/analysis/const-pass.js.map +1 -1
  25. package/dist/src/planner/building/constraint-builder.d.ts +11 -0
  26. package/dist/src/planner/building/constraint-builder.d.ts.map +1 -0
  27. package/dist/src/planner/building/constraint-builder.js +79 -0
  28. package/dist/src/planner/building/constraint-builder.js.map +1 -0
  29. package/dist/src/planner/building/delete.d.ts.map +1 -1
  30. package/dist/src/planner/building/delete.js +6 -3
  31. package/dist/src/planner/building/delete.js.map +1 -1
  32. package/dist/src/planner/building/expression.d.ts +3 -0
  33. package/dist/src/planner/building/expression.d.ts.map +1 -1
  34. package/dist/src/planner/building/expression.js +33 -7
  35. package/dist/src/planner/building/expression.js.map +1 -1
  36. package/dist/src/planner/building/insert.d.ts.map +1 -1
  37. package/dist/src/planner/building/insert.js +4 -1
  38. package/dist/src/planner/building/insert.js.map +1 -1
  39. package/dist/src/planner/building/select-aggregates.d.ts.map +1 -1
  40. package/dist/src/planner/building/select-aggregates.js +46 -9
  41. package/dist/src/planner/building/select-aggregates.js.map +1 -1
  42. package/dist/src/planner/building/select-context.js +20 -11
  43. package/dist/src/planner/building/select-context.js.map +1 -1
  44. package/dist/src/planner/building/select-modifiers.d.ts +5 -3
  45. package/dist/src/planner/building/select-modifiers.d.ts.map +1 -1
  46. package/dist/src/planner/building/select-modifiers.js +29 -20
  47. package/dist/src/planner/building/select-modifiers.js.map +1 -1
  48. package/dist/src/planner/building/select-projections.d.ts +3 -1
  49. package/dist/src/planner/building/select-projections.d.ts.map +1 -1
  50. package/dist/src/planner/building/select-projections.js +15 -20
  51. package/dist/src/planner/building/select-projections.js.map +1 -1
  52. package/dist/src/planner/building/select-window.d.ts.map +1 -1
  53. package/dist/src/planner/building/select-window.js +6 -3
  54. package/dist/src/planner/building/select-window.js.map +1 -1
  55. package/dist/src/planner/building/select.d.ts +25 -2
  56. package/dist/src/planner/building/select.d.ts.map +1 -1
  57. package/dist/src/planner/building/select.js +147 -24
  58. package/dist/src/planner/building/select.js.map +1 -1
  59. package/dist/src/planner/building/table.d.ts +0 -10
  60. package/dist/src/planner/building/table.d.ts.map +1 -1
  61. package/dist/src/planner/building/table.js +1 -35
  62. package/dist/src/planner/building/table.js.map +1 -1
  63. package/dist/src/planner/building/update.d.ts.map +1 -1
  64. package/dist/src/planner/building/update.js +7 -4
  65. package/dist/src/planner/building/update.js.map +1 -1
  66. package/dist/src/planner/building/with.d.ts.map +1 -1
  67. package/dist/src/planner/building/with.js +7 -8
  68. package/dist/src/planner/building/with.js.map +1 -1
  69. package/dist/src/planner/cache/correlation-detector.d.ts +11 -0
  70. package/dist/src/planner/cache/correlation-detector.d.ts.map +1 -0
  71. package/dist/src/planner/cache/correlation-detector.js +73 -0
  72. package/dist/src/planner/cache/correlation-detector.js.map +1 -0
  73. package/dist/src/planner/cache/materialization-advisory.d.ts +12 -18
  74. package/dist/src/planner/cache/materialization-advisory.d.ts.map +1 -1
  75. package/dist/src/planner/cache/materialization-advisory.js +65 -46
  76. package/dist/src/planner/cache/materialization-advisory.js.map +1 -1
  77. package/dist/src/planner/cache/reference-graph.d.ts +14 -9
  78. package/dist/src/planner/cache/reference-graph.d.ts.map +1 -1
  79. package/dist/src/planner/cache/reference-graph.js +93 -84
  80. package/dist/src/planner/cache/reference-graph.js.map +1 -1
  81. package/dist/src/planner/debug.d.ts +25 -0
  82. package/dist/src/planner/debug.d.ts.map +1 -1
  83. package/dist/src/planner/debug.js +127 -0
  84. package/dist/src/planner/debug.js.map +1 -1
  85. package/dist/src/planner/framework/context.d.ts +11 -0
  86. package/dist/src/planner/framework/context.d.ts.map +1 -1
  87. package/dist/src/planner/framework/context.js +25 -2
  88. package/dist/src/planner/framework/context.js.map +1 -1
  89. package/dist/src/planner/framework/registry.d.ts +3 -7
  90. package/dist/src/planner/framework/registry.d.ts.map +1 -1
  91. package/dist/src/planner/framework/registry.js +20 -31
  92. package/dist/src/planner/framework/registry.js.map +1 -1
  93. package/dist/src/planner/nodes/add-constraint-node.d.ts +2 -1
  94. package/dist/src/planner/nodes/add-constraint-node.d.ts.map +1 -1
  95. package/dist/src/planner/nodes/add-constraint-node.js +3 -0
  96. package/dist/src/planner/nodes/add-constraint-node.js.map +1 -1
  97. package/dist/src/planner/nodes/aggregate-node.d.ts.map +1 -1
  98. package/dist/src/planner/nodes/aggregate-node.js +6 -4
  99. package/dist/src/planner/nodes/aggregate-node.js.map +1 -1
  100. package/dist/src/planner/nodes/cache-node.d.ts.map +1 -1
  101. package/dist/src/planner/nodes/cache-node.js +2 -2
  102. package/dist/src/planner/nodes/cache-node.js.map +1 -1
  103. package/dist/src/planner/nodes/constraint-check-node.d.ts +11 -4
  104. package/dist/src/planner/nodes/constraint-check-node.d.ts.map +1 -1
  105. package/dist/src/planner/nodes/constraint-check-node.js +38 -12
  106. package/dist/src/planner/nodes/constraint-check-node.js.map +1 -1
  107. package/dist/src/planner/nodes/create-index-node.d.ts +2 -1
  108. package/dist/src/planner/nodes/create-index-node.d.ts.map +1 -1
  109. package/dist/src/planner/nodes/create-index-node.js +3 -0
  110. package/dist/src/planner/nodes/create-index-node.js.map +1 -1
  111. package/dist/src/planner/nodes/create-table-node.d.ts +2 -1
  112. package/dist/src/planner/nodes/create-table-node.d.ts.map +1 -1
  113. package/dist/src/planner/nodes/create-table-node.js +3 -0
  114. package/dist/src/planner/nodes/create-table-node.js.map +1 -1
  115. package/dist/src/planner/nodes/create-view-node.d.ts +2 -1
  116. package/dist/src/planner/nodes/create-view-node.d.ts.map +1 -1
  117. package/dist/src/planner/nodes/create-view-node.js +3 -0
  118. package/dist/src/planner/nodes/create-view-node.js.map +1 -1
  119. package/dist/src/planner/nodes/cte-node.d.ts +1 -1
  120. package/dist/src/planner/nodes/cte-node.d.ts.map +1 -1
  121. package/dist/src/planner/nodes/cte-node.js +33 -12
  122. package/dist/src/planner/nodes/cte-node.js.map +1 -1
  123. package/dist/src/planner/nodes/cte-reference-node.d.ts +18 -4
  124. package/dist/src/planner/nodes/cte-reference-node.d.ts.map +1 -1
  125. package/dist/src/planner/nodes/cte-reference-node.js +40 -10
  126. package/dist/src/planner/nodes/cte-reference-node.js.map +1 -1
  127. package/dist/src/planner/nodes/delete-node.d.ts +4 -3
  128. package/dist/src/planner/nodes/delete-node.d.ts.map +1 -1
  129. package/dist/src/planner/nodes/delete-node.js +20 -6
  130. package/dist/src/planner/nodes/delete-node.js.map +1 -1
  131. package/dist/src/planner/nodes/distinct-node.d.ts.map +1 -1
  132. package/dist/src/planner/nodes/distinct-node.js +2 -2
  133. package/dist/src/planner/nodes/distinct-node.js.map +1 -1
  134. package/dist/src/planner/nodes/dml-executor-node.d.ts.map +1 -1
  135. package/dist/src/planner/nodes/dml-executor-node.js +2 -2
  136. package/dist/src/planner/nodes/dml-executor-node.js.map +1 -1
  137. package/dist/src/planner/nodes/drop-table-node.d.ts +2 -1
  138. package/dist/src/planner/nodes/drop-table-node.d.ts.map +1 -1
  139. package/dist/src/planner/nodes/drop-table-node.js +3 -0
  140. package/dist/src/planner/nodes/drop-table-node.js.map +1 -1
  141. package/dist/src/planner/nodes/drop-view-node.d.ts +2 -1
  142. package/dist/src/planner/nodes/drop-view-node.d.ts.map +1 -1
  143. package/dist/src/planner/nodes/drop-view-node.js +3 -0
  144. package/dist/src/planner/nodes/drop-view-node.js.map +1 -1
  145. package/dist/src/planner/nodes/filter.d.ts.map +1 -1
  146. package/dist/src/planner/nodes/filter.js +3 -3
  147. package/dist/src/planner/nodes/filter.js.map +1 -1
  148. package/dist/src/planner/nodes/insert-node.d.ts +2 -1
  149. package/dist/src/planner/nodes/insert-node.d.ts.map +1 -1
  150. package/dist/src/planner/nodes/insert-node.js +18 -5
  151. package/dist/src/planner/nodes/insert-node.js.map +1 -1
  152. package/dist/src/planner/nodes/internal-recursive-cte-ref-node.d.ts +28 -0
  153. package/dist/src/planner/nodes/internal-recursive-cte-ref-node.d.ts.map +1 -0
  154. package/dist/src/planner/nodes/internal-recursive-cte-ref-node.js +69 -0
  155. package/dist/src/planner/nodes/internal-recursive-cte-ref-node.js.map +1 -0
  156. package/dist/src/planner/nodes/join-node.d.ts.map +1 -1
  157. package/dist/src/planner/nodes/join-node.js +3 -3
  158. package/dist/src/planner/nodes/join-node.js.map +1 -1
  159. package/dist/src/planner/nodes/limit-offset.d.ts.map +1 -1
  160. package/dist/src/planner/nodes/limit-offset.js +2 -2
  161. package/dist/src/planner/nodes/limit-offset.js.map +1 -1
  162. package/dist/src/planner/nodes/plan-node-type.d.ts +1 -1
  163. package/dist/src/planner/nodes/plan-node-type.d.ts.map +1 -1
  164. package/dist/src/planner/nodes/plan-node-type.js +1 -1
  165. package/dist/src/planner/nodes/plan-node-type.js.map +1 -1
  166. package/dist/src/planner/nodes/plan-node.d.ts +23 -0
  167. package/dist/src/planner/nodes/plan-node.d.ts.map +1 -1
  168. package/dist/src/planner/nodes/plan-node.js +25 -2
  169. package/dist/src/planner/nodes/plan-node.js.map +1 -1
  170. package/dist/src/planner/nodes/project-node.d.ts +5 -1
  171. package/dist/src/planner/nodes/project-node.d.ts.map +1 -1
  172. package/dist/src/planner/nodes/project-node.js +39 -20
  173. package/dist/src/planner/nodes/project-node.js.map +1 -1
  174. package/dist/src/planner/nodes/recursive-cte-node.d.ts +2 -2
  175. package/dist/src/planner/nodes/recursive-cte-node.d.ts.map +1 -1
  176. package/dist/src/planner/nodes/recursive-cte-node.js +20 -8
  177. package/dist/src/planner/nodes/recursive-cte-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 +4 -2
  180. package/dist/src/planner/nodes/reference.js.map +1 -1
  181. package/dist/src/planner/nodes/returning-node.d.ts +1 -1
  182. package/dist/src/planner/nodes/returning-node.d.ts.map +1 -1
  183. package/dist/src/planner/nodes/returning-node.js +21 -13
  184. package/dist/src/planner/nodes/returning-node.js.map +1 -1
  185. package/dist/src/planner/nodes/scalar.d.ts +26 -2
  186. package/dist/src/planner/nodes/scalar.d.ts.map +1 -1
  187. package/dist/src/planner/nodes/scalar.js +82 -10
  188. package/dist/src/planner/nodes/scalar.js.map +1 -1
  189. package/dist/src/planner/nodes/sequencing-node.d.ts.map +1 -1
  190. package/dist/src/planner/nodes/sequencing-node.js +2 -2
  191. package/dist/src/planner/nodes/sequencing-node.js.map +1 -1
  192. package/dist/src/planner/nodes/set-operation-node.d.ts.map +1 -1
  193. package/dist/src/planner/nodes/set-operation-node.js +3 -3
  194. package/dist/src/planner/nodes/set-operation-node.js.map +1 -1
  195. package/dist/src/planner/nodes/single-row.d.ts +4 -2
  196. package/dist/src/planner/nodes/single-row.d.ts.map +1 -1
  197. package/dist/src/planner/nodes/single-row.js +3 -0
  198. package/dist/src/planner/nodes/single-row.js.map +1 -1
  199. package/dist/src/planner/nodes/sink-node.d.ts +1 -1
  200. package/dist/src/planner/nodes/sink-node.d.ts.map +1 -1
  201. package/dist/src/planner/nodes/sink-node.js +4 -4
  202. package/dist/src/planner/nodes/sink-node.js.map +1 -1
  203. package/dist/src/planner/nodes/sort.d.ts.map +1 -1
  204. package/dist/src/planner/nodes/sort.js +2 -2
  205. package/dist/src/planner/nodes/sort.js.map +1 -1
  206. package/dist/src/planner/nodes/stream-aggregate.d.ts +1 -0
  207. package/dist/src/planner/nodes/stream-aggregate.d.ts.map +1 -1
  208. package/dist/src/planner/nodes/stream-aggregate.js +64 -11
  209. package/dist/src/planner/nodes/stream-aggregate.js.map +1 -1
  210. package/dist/src/planner/nodes/subquery.d.ts +4 -4
  211. package/dist/src/planner/nodes/subquery.d.ts.map +1 -1
  212. package/dist/src/planner/nodes/subquery.js +68 -23
  213. package/dist/src/planner/nodes/subquery.js.map +1 -1
  214. package/dist/src/planner/nodes/table-access-nodes.d.ts +83 -0
  215. package/dist/src/planner/nodes/table-access-nodes.d.ts.map +1 -0
  216. package/dist/src/planner/nodes/table-access-nodes.js +226 -0
  217. package/dist/src/planner/nodes/table-access-nodes.js.map +1 -0
  218. package/dist/src/planner/nodes/update-node.d.ts +4 -2
  219. package/dist/src/planner/nodes/update-node.d.ts.map +1 -1
  220. package/dist/src/planner/nodes/update-node.js +26 -13
  221. package/dist/src/planner/nodes/update-node.js.map +1 -1
  222. package/dist/src/planner/nodes/window-node.d.ts.map +1 -1
  223. package/dist/src/planner/nodes/window-node.js +25 -23
  224. package/dist/src/planner/nodes/window-node.js.map +1 -1
  225. package/dist/src/planner/optimizer.d.ts.map +1 -1
  226. package/dist/src/planner/optimizer.js +46 -50
  227. package/dist/src/planner/optimizer.js.map +1 -1
  228. package/dist/src/planner/planning-context.d.ts +13 -0
  229. package/dist/src/planner/planning-context.d.ts.map +1 -1
  230. package/dist/src/planner/planning-context.js.map +1 -1
  231. package/dist/src/planner/rules/access/rule-select-access-path.d.ts +1 -1
  232. package/dist/src/planner/rules/access/rule-select-access-path.d.ts.map +1 -1
  233. package/dist/src/planner/rules/access/rule-select-access-path.js +59 -53
  234. package/dist/src/planner/rules/access/rule-select-access-path.js.map +1 -1
  235. package/dist/src/planner/rules/aggregate/rule-aggregate-streaming.d.ts.map +1 -1
  236. package/dist/src/planner/rules/aggregate/rule-aggregate-streaming.js +62 -2
  237. package/dist/src/planner/rules/aggregate/rule-aggregate-streaming.js.map +1 -1
  238. package/dist/src/planner/rules/cache/rule-materialization-advisory.d.ts.map +1 -1
  239. package/dist/src/planner/rules/cache/rule-materialization-advisory.js +31 -24
  240. package/dist/src/planner/rules/cache/rule-materialization-advisory.js.map +1 -1
  241. package/dist/src/planner/scopes/base.d.ts +0 -10
  242. package/dist/src/planner/scopes/base.d.ts.map +1 -1
  243. package/dist/src/planner/scopes/base.js +0 -14
  244. package/dist/src/planner/scopes/base.js.map +1 -1
  245. package/dist/src/planner/scopes/empty.d.ts +0 -2
  246. package/dist/src/planner/scopes/empty.d.ts.map +1 -1
  247. package/dist/src/planner/scopes/empty.js +0 -8
  248. package/dist/src/planner/scopes/empty.js.map +1 -1
  249. package/dist/src/planner/scopes/multi.d.ts.map +1 -1
  250. package/dist/src/planner/scopes/multi.js +0 -1
  251. package/dist/src/planner/scopes/multi.js.map +1 -1
  252. package/dist/src/planner/scopes/param.d.ts.map +1 -1
  253. package/dist/src/planner/scopes/param.js +0 -1
  254. package/dist/src/planner/scopes/param.js.map +1 -1
  255. package/dist/src/planner/scopes/registered.d.ts +0 -10
  256. package/dist/src/planner/scopes/registered.d.ts.map +1 -1
  257. package/dist/src/planner/scopes/registered.js +1 -17
  258. package/dist/src/planner/scopes/registered.js.map +1 -1
  259. package/dist/src/planner/scopes/scope.d.ts +0 -8
  260. package/dist/src/planner/scopes/scope.d.ts.map +1 -1
  261. package/dist/src/planner/validation/plan-validator.d.ts.map +1 -1
  262. package/dist/src/planner/validation/plan-validator.js +1 -7
  263. package/dist/src/planner/validation/plan-validator.js.map +1 -1
  264. package/dist/src/runtime/context-helpers.d.ts +45 -0
  265. package/dist/src/runtime/context-helpers.d.ts.map +1 -0
  266. package/dist/src/runtime/context-helpers.js +139 -0
  267. package/dist/src/runtime/context-helpers.js.map +1 -0
  268. package/dist/src/runtime/emission-context.d.ts +1 -0
  269. package/dist/src/runtime/emission-context.d.ts.map +1 -1
  270. package/dist/src/runtime/emission-context.js +2 -1
  271. package/dist/src/runtime/emission-context.js.map +1 -1
  272. package/dist/src/runtime/emit/aggregate.d.ts.map +1 -1
  273. package/dist/src/runtime/emit/aggregate.js +119 -86
  274. package/dist/src/runtime/emit/aggregate.js.map +1 -1
  275. package/dist/src/runtime/emit/between.d.ts +5 -0
  276. package/dist/src/runtime/emit/between.d.ts.map +1 -0
  277. package/dist/src/runtime/emit/between.js +38 -0
  278. package/dist/src/runtime/emit/between.js.map +1 -0
  279. package/dist/src/runtime/emit/binary.d.ts +0 -1
  280. package/dist/src/runtime/emit/binary.d.ts.map +1 -1
  281. package/dist/src/runtime/emit/binary.js +0 -36
  282. package/dist/src/runtime/emit/binary.js.map +1 -1
  283. package/dist/src/runtime/emit/column-reference.d.ts.map +1 -1
  284. package/dist/src/runtime/emit/column-reference.js +2 -26
  285. package/dist/src/runtime/emit/column-reference.js.map +1 -1
  286. package/dist/src/runtime/emit/constraint-check.d.ts.map +1 -1
  287. package/dist/src/runtime/emit/constraint-check.js +14 -121
  288. package/dist/src/runtime/emit/constraint-check.js.map +1 -1
  289. package/dist/src/runtime/emit/cte-reference.d.ts.map +1 -1
  290. package/dist/src/runtime/emit/cte-reference.js +16 -48
  291. package/dist/src/runtime/emit/cte-reference.js.map +1 -1
  292. package/dist/src/runtime/emit/distinct.d.ts.map +1 -1
  293. package/dist/src/runtime/emit/distinct.js +2 -8
  294. package/dist/src/runtime/emit/distinct.js.map +1 -1
  295. package/dist/src/runtime/emit/filter.d.ts.map +1 -1
  296. package/dist/src/runtime/emit/filter.js +6 -13
  297. package/dist/src/runtime/emit/filter.js.map +1 -1
  298. package/dist/src/runtime/emit/internal-recursive-cte-ref.d.ts +5 -0
  299. package/dist/src/runtime/emit/internal-recursive-cte-ref.d.ts.map +1 -0
  300. package/dist/src/runtime/emit/internal-recursive-cte-ref.js +23 -0
  301. package/dist/src/runtime/emit/internal-recursive-cte-ref.js.map +1 -0
  302. package/dist/src/runtime/emit/join.d.ts.map +1 -1
  303. package/dist/src/runtime/emit/join.js +40 -40
  304. package/dist/src/runtime/emit/join.js.map +1 -1
  305. package/dist/src/runtime/emit/project.d.ts.map +1 -1
  306. package/dist/src/runtime/emit/project.js +13 -13
  307. package/dist/src/runtime/emit/project.js.map +1 -1
  308. package/dist/src/runtime/emit/recursive-cte.d.ts.map +1 -1
  309. package/dist/src/runtime/emit/recursive-cte.js +3 -14
  310. package/dist/src/runtime/emit/recursive-cte.js.map +1 -1
  311. package/dist/src/runtime/emit/returning.d.ts.map +1 -1
  312. package/dist/src/runtime/emit/returning.js +7 -14
  313. package/dist/src/runtime/emit/returning.js.map +1 -1
  314. package/dist/src/runtime/emit/scan.d.ts +5 -2
  315. package/dist/src/runtime/emit/scan.d.ts.map +1 -1
  316. package/dist/src/runtime/emit/scan.js +21 -17
  317. package/dist/src/runtime/emit/scan.js.map +1 -1
  318. package/dist/src/runtime/emit/sort.d.ts.map +1 -1
  319. package/dist/src/runtime/emit/sort.js +8 -11
  320. package/dist/src/runtime/emit/sort.js.map +1 -1
  321. package/dist/src/runtime/emit/subquery.d.ts.map +1 -1
  322. package/dist/src/runtime/emit/subquery.js +95 -40
  323. package/dist/src/runtime/emit/subquery.js.map +1 -1
  324. package/dist/src/runtime/emit/table-valued-function.d.ts.map +1 -1
  325. package/dist/src/runtime/emit/table-valued-function.js +7 -22
  326. package/dist/src/runtime/emit/table-valued-function.js.map +1 -1
  327. package/dist/src/runtime/emit/update.d.ts.map +1 -1
  328. package/dist/src/runtime/emit/update.js +20 -27
  329. package/dist/src/runtime/emit/update.js.map +1 -1
  330. package/dist/src/runtime/emit/window.d.ts.map +1 -1
  331. package/dist/src/runtime/emit/window.js +55 -83
  332. package/dist/src/runtime/emit/window.js.map +1 -1
  333. package/dist/src/runtime/emitters.d.ts.map +1 -1
  334. package/dist/src/runtime/emitters.js +49 -1
  335. package/dist/src/runtime/emitters.js.map +1 -1
  336. package/dist/src/runtime/register.d.ts.map +1 -1
  337. package/dist/src/runtime/register.js +5 -4
  338. package/dist/src/runtime/register.js.map +1 -1
  339. package/dist/src/runtime/scheduler.d.ts.map +1 -1
  340. package/dist/src/runtime/scheduler.js +47 -42
  341. package/dist/src/runtime/scheduler.js.map +1 -1
  342. package/dist/src/runtime/types.d.ts +34 -0
  343. package/dist/src/runtime/types.d.ts.map +1 -1
  344. package/dist/src/runtime/types.js +21 -0
  345. package/dist/src/runtime/types.js.map +1 -1
  346. package/dist/src/schema/manager.d.ts.map +1 -1
  347. package/dist/src/schema/manager.js +29 -16
  348. package/dist/src/schema/manager.js.map +1 -1
  349. package/dist/src/util/plugin-loader.d.ts +10 -1
  350. package/dist/src/util/plugin-loader.d.ts.map +1 -1
  351. package/dist/src/util/plugin-loader.js +56 -1
  352. package/dist/src/util/plugin-loader.js.map +1 -1
  353. package/dist/src/util/working-table-iterable.d.ts.map +1 -1
  354. package/dist/src/util/working-table-iterable.js +8 -8
  355. package/dist/src/util/working-table-iterable.js.map +1 -1
  356. package/dist/src/vtab/manifest.d.ts +36 -0
  357. package/dist/src/vtab/manifest.d.ts.map +1 -1
  358. package/package.json +8 -3
  359. package/src/core/database.ts +48 -6
  360. package/src/core/statement.ts +1 -49
  361. package/src/func/builtins/explain.ts +0 -11
  362. package/src/index.ts +39 -5
  363. package/src/parser/ast.ts +11 -2
  364. package/src/parser/parser.ts +40 -47
  365. package/src/planner/analysis/const-pass.ts +281 -270
  366. package/src/planner/building/constraint-builder.ts +114 -0
  367. package/src/planner/building/delete.ts +16 -3
  368. package/src/planner/building/expression.ts +35 -7
  369. package/src/planner/building/insert.ts +14 -1
  370. package/src/planner/building/select-aggregates.ts +57 -11
  371. package/src/planner/building/select-context.ts +22 -12
  372. package/src/planner/building/select-modifiers.ts +35 -21
  373. package/src/planner/building/select-projections.ts +25 -26
  374. package/src/planner/building/select-window.ts +14 -9
  375. package/src/planner/building/select.ts +163 -31
  376. package/src/planner/building/table.ts +1 -40
  377. package/src/planner/building/update.ts +19 -4
  378. package/src/planner/building/with.ts +12 -13
  379. package/src/planner/cache/correlation-detector.ts +83 -0
  380. package/src/planner/cache/materialization-advisory.ts +71 -50
  381. package/src/planner/cache/reference-graph.ts +115 -91
  382. package/src/planner/debug.ts +163 -0
  383. package/src/planner/framework/context.ts +36 -2
  384. package/src/planner/framework/registry.ts +261 -274
  385. package/src/planner/nodes/add-constraint-node.ts +5 -1
  386. package/src/planner/nodes/aggregate-node.ts +6 -4
  387. package/src/planner/nodes/cache-node.ts +2 -2
  388. package/src/planner/nodes/constraint-check-node.ts +47 -13
  389. package/src/planner/nodes/create-index-node.ts +5 -1
  390. package/src/planner/nodes/create-table-node.ts +5 -1
  391. package/src/planner/nodes/create-view-node.ts +5 -1
  392. package/src/planner/nodes/cte-node.ts +45 -14
  393. package/src/planner/nodes/cte-reference-node.ts +49 -13
  394. package/src/planner/nodes/delete-node.ts +31 -7
  395. package/src/planner/nodes/distinct-node.ts +2 -2
  396. package/src/planner/nodes/dml-executor-node.ts +2 -2
  397. package/src/planner/nodes/drop-table-node.ts +5 -1
  398. package/src/planner/nodes/drop-view-node.ts +5 -1
  399. package/src/planner/nodes/filter.ts +3 -3
  400. package/src/planner/nodes/function.ts +93 -93
  401. package/src/planner/nodes/insert-node.ts +28 -5
  402. package/src/planner/nodes/internal-recursive-cte-ref-node.ts +76 -0
  403. package/src/planner/nodes/join-node.ts +3 -3
  404. package/src/planner/nodes/limit-offset.ts +2 -2
  405. package/src/planner/nodes/plan-node-type.ts +1 -1
  406. package/src/planner/nodes/plan-node.ts +39 -2
  407. package/src/planner/nodes/project-node.ts +39 -19
  408. package/src/planner/nodes/recursive-cte-node.ts +37 -9
  409. package/src/planner/nodes/reference.ts +4 -2
  410. package/src/planner/nodes/returning-node.ts +25 -13
  411. package/src/planner/nodes/scalar.ts +95 -11
  412. package/src/planner/nodes/sequencing-node.ts +2 -2
  413. package/src/planner/nodes/set-operation-node.ts +3 -3
  414. package/src/planner/nodes/single-row.ts +7 -2
  415. package/src/planner/nodes/sink-node.ts +5 -5
  416. package/src/planner/nodes/sort.ts +2 -2
  417. package/src/planner/nodes/stream-aggregate.ts +76 -12
  418. package/src/planner/nodes/subquery.ts +90 -27
  419. package/src/planner/nodes/{physical-access-nodes.ts → table-access-nodes.ts} +6 -6
  420. package/src/planner/nodes/update-node.ts +31 -13
  421. package/src/planner/nodes/window-node.ts +28 -22
  422. package/src/planner/optimizer.ts +257 -263
  423. package/src/planner/planning-context.ts +15 -0
  424. package/src/planner/rules/access/rule-select-access-path.ts +68 -64
  425. package/src/planner/rules/aggregate/rule-aggregate-streaming.ts +74 -2
  426. package/src/planner/rules/cache/rule-materialization-advisory.ts +31 -27
  427. package/src/planner/scopes/base.ts +0 -17
  428. package/src/planner/scopes/empty.ts +0 -10
  429. package/src/planner/scopes/multi.ts +0 -1
  430. package/src/planner/scopes/param.ts +0 -1
  431. package/src/planner/scopes/registered.ts +1 -20
  432. package/src/planner/scopes/scope.ts +0 -12
  433. package/src/planner/validation/plan-validator.ts +1 -8
  434. package/src/runtime/context-helpers.ts +191 -0
  435. package/src/runtime/emission-context.ts +5 -2
  436. package/src/runtime/emit/aggregate.ts +131 -85
  437. package/src/runtime/emit/between.ts +51 -0
  438. package/src/runtime/emit/binary.ts +0 -46
  439. package/src/runtime/emit/column-reference.ts +3 -36
  440. package/src/runtime/emit/constraint-check.ts +17 -142
  441. package/src/runtime/emit/cte-reference.ts +23 -60
  442. package/src/runtime/emit/distinct.ts +2 -7
  443. package/src/runtime/emit/filter.ts +6 -13
  444. package/src/runtime/emit/internal-recursive-cte-ref.ts +37 -0
  445. package/src/runtime/emit/join.ts +45 -43
  446. package/src/runtime/emit/project.ts +18 -12
  447. package/src/runtime/emit/recursive-cte.ts +3 -12
  448. package/src/runtime/emit/returning.ts +7 -14
  449. package/src/runtime/emit/scan.ts +25 -23
  450. package/src/runtime/emit/sort.ts +8 -11
  451. package/src/runtime/emit/subquery.ts +108 -48
  452. package/src/runtime/emit/table-valued-function.ts +7 -20
  453. package/src/runtime/emit/update.ts +22 -29
  454. package/src/runtime/emit/window.ts +74 -88
  455. package/src/runtime/emitters.ts +52 -1
  456. package/src/runtime/register.ts +5 -4
  457. package/src/runtime/scheduler.ts +54 -54
  458. package/src/runtime/types.ts +45 -0
  459. package/src/schema/manager.ts +34 -19
  460. package/src/util/plugin-loader.ts +78 -4
  461. package/src/util/working-table-iterable.ts +15 -7
  462. package/src/vtab/manifest.ts +42 -0
  463. package/src/planner/nodes/scan.ts +0 -103
  464. package/src/planner/rules/physical/rule-mark-physical.ts +0 -37
  465. package/src/runtime/emit/table-reference.ts +0 -92
@@ -0,0 +1,191 @@
1
+ import type { RuntimeContext } from './types.js';
2
+ import type { RowDescriptor, RowGetter } from '../planner/nodes/plan-node.js';
3
+ import type { SqlValue, Row } from '../common/types.js';
4
+ import { QuereusError } from '../common/errors.js';
5
+ import { StatusCode } from '../common/types.js';
6
+ import { createLogger } from '../common/logger.js';
7
+
8
+ const ctxLog = createLogger('runtime:context');
9
+ const ctxLookupLog = createLogger('runtime:context:lookup');
10
+
11
+ /**
12
+ * A mutable slot for efficient row context management in streaming operations.
13
+ * Avoids per-row Map mutations while maintaining context safety.
14
+ */
15
+ export interface RowSlot {
16
+ /** Replace the current row (cheap field write) */
17
+ set(row: Row): void;
18
+ /** Tear down (removes descriptor from context) */
19
+ close(): void;
20
+ }
21
+
22
+ /**
23
+ * Create a row slot for efficient streaming context management.
24
+ * The slot installs a context entry once and updates it by reference.
25
+ * Perfect for scan/join/window operations that process many rows.
26
+ */
27
+ export function createRowSlot(
28
+ rctx: RuntimeContext,
29
+ descriptor: RowDescriptor
30
+ ): RowSlot {
31
+ // Internal boxed reference - one allocation per slot
32
+ const ref = { current: undefined as Row | undefined };
33
+
34
+ // Install only once
35
+ rctx.context.set(descriptor, () => ref.current!);
36
+
37
+ const attrs = Object.keys(descriptor).filter(k => descriptor[parseInt(k)] !== undefined);
38
+ ctxLog('CREATE slot with attrs=[%s]', attrs.join(','));
39
+
40
+ return {
41
+ set(row: Row) {
42
+ ref.current = row;
43
+ },
44
+ close() {
45
+ rctx.context.delete(descriptor);
46
+ ctxLog('CLOSE slot with attrs=[%s]', attrs.join(','));
47
+ }
48
+ };
49
+ }
50
+
51
+ /**
52
+ * Resolve an attribute ID to its column value in the current context.
53
+ * Searches from newest (innermost) to oldest (outermost) scope.
54
+ */
55
+ export function resolveAttribute(rctx: RuntimeContext, attributeId: number, columnName?: string): SqlValue {
56
+ // Iterate newest → oldest so the most recently pushed scope wins
57
+ const contextsReversed = Array.from(rctx.context.entries()).reverse();
58
+
59
+ ctxLookupLog('LOOKUP column %s (attr#%d) in %d contexts', columnName || '?', attributeId, contextsReversed.length);
60
+
61
+ for (const [descriptor, rowGetter] of contextsReversed) {
62
+ const columnIndex = descriptor[attributeId];
63
+ if (columnIndex !== undefined) {
64
+ const row = rowGetter();
65
+ if (Array.isArray(row) && columnIndex < row.length) {
66
+ ctxLookupLog('FOUND column %s at index %d in row', columnName || '?', columnIndex);
67
+ return row[columnIndex];
68
+ }
69
+ }
70
+ }
71
+
72
+ // Log available attributes for debugging
73
+ if (ctxLookupLog.enabled) {
74
+ ctxLookupLog('Available contexts:');
75
+ for (const [descriptor, _] of contextsReversed) {
76
+ const attrs = Object.keys(descriptor).filter(k => descriptor[parseInt(k)] !== undefined);
77
+ ctxLookupLog(' - Descriptor with attrs=[%s]', attrs.join(','));
78
+ }
79
+
80
+ // Log current plan execution stack if available
81
+ if (rctx.planStack && rctx.planStack.length > 0) {
82
+ const currentNode = rctx.planStack[rctx.planStack.length - 1];
83
+ ctxLookupLog('LOOKUP FAILED in node %s id=%d', currentNode.nodeType, currentNode.id);
84
+ ctxLookupLog('Execution stack: %s',
85
+ rctx.planStack.map(n => `${n.nodeType}#${n.id}`).join(' → '));
86
+ }
87
+ }
88
+
89
+ throw new QuereusError(
90
+ `No row context found for column ${columnName || `attr#${attributeId}`}. The column reference must be evaluated within the context of its source relation.`,
91
+ StatusCode.ERROR
92
+ );
93
+ }
94
+
95
+ /**
96
+ * Look up a specific column by descriptor and index.
97
+ * Useful when you already know which descriptor contains the column.
98
+ */
99
+ export function lookupColumn(rctx: RuntimeContext, descriptor: RowDescriptor, columnIndex: number): SqlValue | undefined {
100
+ const rowGetter = rctx.context.get(descriptor);
101
+ if (!rowGetter) {
102
+ ctxLookupLog('LOOKUP by index %d - no context found', columnIndex);
103
+ return undefined;
104
+ }
105
+
106
+ const row = rowGetter();
107
+ if (Array.isArray(row) && columnIndex < row.length) {
108
+ ctxLookupLog('LOOKUP by index %d - found value', columnIndex);
109
+ return row[columnIndex];
110
+ }
111
+ ctxLookupLog('LOOKUP by index %d - index out of bounds', columnIndex);
112
+ return undefined;
113
+ }
114
+
115
+ /**
116
+ * Execute a function with a row context, ensuring proper cleanup.
117
+ * This is the recommended pattern for all row-processing emitters.
118
+ */
119
+ export async function withAsyncRowContext<T>(
120
+ rctx: RuntimeContext,
121
+ descriptor: RowDescriptor,
122
+ rowGetter: RowGetter,
123
+ fn: () => T | Promise<T>
124
+ ): Promise<T> {
125
+ const attrs = Object.keys(descriptor).filter(k => descriptor[parseInt(k)] !== undefined);
126
+ ctxLog('PUSH async context with attrs=[%s]', attrs.join(','));
127
+
128
+ rctx.context.set(descriptor, rowGetter);
129
+ try {
130
+ return await fn();
131
+ } finally {
132
+ rctx.context.delete(descriptor);
133
+ ctxLog('POP async context with attrs=[%s]', attrs.join(','));
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Execute a function with a row context, ensuring proper cleanup.
139
+ * This is the recommended pattern for all row-processing emitters.
140
+ */
141
+ export function withRowContext<T>(
142
+ rctx: RuntimeContext,
143
+ descriptor: RowDescriptor,
144
+ rowGetter: RowGetter,
145
+ fn: () => T
146
+ ): T {
147
+ const attrs = Object.keys(descriptor).filter(k => descriptor[parseInt(k)] !== undefined);
148
+ ctxLog('PUSH context with attrs=[%s]', attrs.join(','));
149
+
150
+ rctx.context.set(descriptor, rowGetter);
151
+ try {
152
+ return fn();
153
+ } finally {
154
+ rctx.context.delete(descriptor);
155
+ ctxLog('POP context with attrs=[%s]', attrs.join(','));
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Execute a generator function with row context management.
161
+ * Useful for streaming operations that process multiple rows.
162
+ */
163
+ export async function* withRowContextGenerator<T>(
164
+ rctx: RuntimeContext,
165
+ descriptor: RowDescriptor,
166
+ rows: AsyncIterable<Row>,
167
+ fn: (row: Row) => AsyncIterable<T>
168
+ ): AsyncIterable<T> {
169
+ const attrs = Object.keys(descriptor).filter(k => descriptor[parseInt(k)] !== undefined);
170
+ let rowCount = 0;
171
+
172
+ for await (const row of rows) {
173
+ if (rowCount === 0) {
174
+ ctxLog('PUSH generator context with attrs=[%s]', attrs.join(','));
175
+ }
176
+ rctx.context.set(descriptor, () => row);
177
+ try {
178
+ yield* fn(row);
179
+ rowCount++;
180
+ } finally {
181
+ rctx.context.delete(descriptor);
182
+ if (ctxLog.enabled && rowCount % 1000 === 0) {
183
+ ctxLog('Generator context processed %d rows', rowCount);
184
+ }
185
+ }
186
+ }
187
+
188
+ if (rowCount > 0) {
189
+ ctxLog('POP generator context after %d rows', rowCount);
190
+ }
191
+ }
@@ -98,9 +98,12 @@ export class EmissionContext {
98
98
  private readonly schemaManager: SchemaManager;
99
99
  private readonly dependencyTracker = new DependencyTracker();
100
100
  private readonly schemaSnapshot = new Map<string, any>();
101
+ public readonly tracePlanStack: boolean;
101
102
 
102
- constructor(public readonly db: Database) {
103
- this.db = db;
103
+ constructor(
104
+ public readonly db: Database,
105
+ ) {
106
+ this.tracePlanStack = !!db.getOption('trace_plan_stack').value;
104
107
  this.schemaManager = db.schemaManager;
105
108
  }
106
109
 
@@ -56,10 +56,10 @@ function compareDistinctValues(a: SqlValue | SqlValue[], b: SqlValue | SqlValue[
56
56
  * This traverses up the tree to find the original table scan or similar node.
57
57
  */
58
58
  function findSourceRelation(node: PlanNode): PlanNode {
59
- // Keep going up until we find a table scan or values node
59
+ // Keep going up until we find a values node
60
60
  let current = node;
61
61
  while (current) {
62
- if (current.nodeType === 'TableScan' || current.nodeType === 'Values' || current.nodeType === 'SingleRow') {
62
+ if (current.nodeType === 'Values' || current.nodeType === 'SingleRow') {
63
63
  return current;
64
64
  }
65
65
  // Get the first relational source
@@ -79,11 +79,12 @@ export function emitStreamAggregate(plan: StreamAggregateNode, ctx: EmissionCont
79
79
 
80
80
  // Create row descriptors for context
81
81
  const sourceAttributes = plan.source.getAttributes();
82
- const sourceRowDescriptor = buildRowDescriptor(sourceAttributes);
83
82
 
84
- const sourceRelationRowDescriptor = sourceRelation !== plan.source
83
+ // Create separate descriptors for group yielding to avoid conflicts with source row processing
84
+ const groupSourceRowDescriptor = buildRowDescriptor(sourceAttributes);
85
+ const groupSourceRelationRowDescriptor = sourceRelation !== plan.source
85
86
  ? buildRowDescriptor((sourceRelation as any).getAttributes?.() || sourceAttributes)
86
- : sourceRowDescriptor;
87
+ : groupSourceRowDescriptor;
87
88
 
88
89
  ctxLog('StreamAggregate setup: source=%s, sourceRelation=%s', plan.source.nodeType, sourceRelation.nodeType);
89
90
  ctxLog('Source attributes: %O', sourceAttributes.map(attr => `${attr.name}(#${attr.id})`));
@@ -95,13 +96,16 @@ export function emitStreamAggregate(plan: StreamAggregateNode, ctx: EmissionCont
95
96
  // Create output row descriptor for the StreamAggregate's output
96
97
  const outputRowDescriptor = buildRowDescriptor(plan.getAttributes());
97
98
 
99
+ // Create scan row descriptor for source relation attributes (for Filter evaluation)
100
+ const scanRowDescriptor = buildRowDescriptor(sourceAttributes);
101
+
98
102
  // CRITICAL FIX: Create a combined descriptor that includes BOTH output and source attributes
99
103
  // This allows correlated subqueries to access original table attributes
100
- const combinedRowDescriptor: RowDescriptor = [...outputRowDescriptor];
104
+ const combinedRowDescriptor: RowDescriptor = {...outputRowDescriptor};
101
105
  sourceAttributes.forEach((attr, index) => {
102
106
  // Only add if not already present in output (avoid conflicts)
103
107
  if (combinedRowDescriptor[attr.id] === undefined) {
104
- combinedRowDescriptor[attr.id] = index;
108
+ combinedRowDescriptor[attr.id] = Object.keys(outputRowDescriptor).length + index;
105
109
  }
106
110
  });
107
111
 
@@ -182,15 +186,16 @@ export function emitStreamAggregate(plan: StreamAggregateNode, ctx: EmissionCont
182
186
  ) : new BTree<SqlValue | SqlValue[], SqlValue | SqlValue[]>((val: SqlValue | SqlValue[]) => val, compareDistinctValues) // Empty tree for non-distinct
183
187
  );
184
188
 
189
+ // Track the last source row for representative row in combined descriptor
190
+ let lastSourceRow: Row | null = null;
191
+
185
192
  // Process all rows
186
193
  for await (const row of sourceRows) {
187
- // Set the current row in the runtime context for evaluation using row descriptors
188
- ctx.context.set(sourceRowDescriptor, () => row);
189
- logContextPush(sourceRowDescriptor, 'source-row', sourceAttributes);
190
- if (sourceRelation !== plan.source) {
191
- ctx.context.set(sourceRelationRowDescriptor, () => row);
192
- logContextPush(sourceRelationRowDescriptor, 'source-relation-row');
193
- }
194
+ lastSourceRow = row;
195
+
196
+ // Set the current row in the runtime context for Filter and aggregate evaluation
197
+ ctx.context.set(scanRowDescriptor, () => row);
198
+ logContextPush(scanRowDescriptor, 'scan-row', sourceAttributes);
194
199
 
195
200
  try {
196
201
  // For each aggregate, call its step function
@@ -234,18 +239,14 @@ export function emitStreamAggregate(plan: StreamAggregateNode, ctx: EmissionCont
234
239
  }
235
240
  }
236
241
  } finally {
237
- // Clean up context for this row
238
- logContextPop(sourceRowDescriptor, 'source-row');
239
- ctx.context.delete(sourceRowDescriptor);
240
- if (sourceRelation !== plan.source) {
241
- logContextPop(sourceRelationRowDescriptor, 'source-relation-row');
242
- ctx.context.delete(sourceRelationRowDescriptor);
243
- }
242
+ // Clean up scan context for this row
243
+ logContextPop(scanRowDescriptor, 'scan-row');
244
+ ctx.context.delete(scanRowDescriptor);
244
245
  }
245
246
  }
246
247
 
247
248
  // Finalize and yield the result
248
- const resultRow: SqlValue[] = [];
249
+ const aggregateRow: SqlValue[] = [];
249
250
  for (let i = 0; i < plan.aggregates.length; i++) {
250
251
  const schema = aggregateSchemas[i];
251
252
 
@@ -256,18 +257,28 @@ export function emitStreamAggregate(plan: StreamAggregateNode, ctx: EmissionCont
256
257
  finalValue = accumulators[i];
257
258
  }
258
259
 
259
- resultRow.push(finalValue);
260
+ aggregateRow.push(finalValue);
260
261
  }
261
262
 
263
+ // Build combined row with aggregate results + representative source row
264
+ const fullRow = lastSourceRow ? [...aggregateRow, ...lastSourceRow] : aggregateRow;
265
+
262
266
  // Set up combined context for the result row (includes both output and source attributes)
263
- ctx.context.set(outputRowDescriptor, () => resultRow);
264
- logContextPush(outputRowDescriptor, 'output-row');
265
- // Note: For no GROUP BY case, we can't preserve source row context since we processed multiple rows
267
+ if (lastSourceRow) {
268
+ ctx.context.set(scanRowDescriptor, () => lastSourceRow);
269
+ logContextPush(scanRowDescriptor, 'aggregate-rep-row');
270
+ }
271
+ ctx.context.set(combinedRowDescriptor, () => fullRow);
272
+ logContextPush(combinedRowDescriptor, 'aggregate-full-row');
266
273
  try {
267
- yield resultRow;
274
+ yield aggregateRow;
268
275
  } finally {
269
- logContextPop(outputRowDescriptor, 'output-row');
270
- ctx.context.delete(outputRowDescriptor);
276
+ logContextPop(combinedRowDescriptor, 'aggregate-full-row');
277
+ ctx.context.delete(combinedRowDescriptor);
278
+ if (lastSourceRow) {
279
+ logContextPop(scanRowDescriptor, 'aggregate-rep-row');
280
+ ctx.context.delete(scanRowDescriptor);
281
+ }
271
282
  }
272
283
  } else {
273
284
  // Handle GROUP BY case with streaming aggregation
@@ -278,17 +289,19 @@ export function emitStreamAggregate(plan: StreamAggregateNode, ctx: EmissionCont
278
289
  let currentSourceRow: Row | null = null; // Track the current group's representative row
279
290
  let currentAccumulators: any[] = [];
280
291
  let currentDistinctTrees: BTree<SqlValue | SqlValue[], SqlValue | SqlValue[]>[] = [];
292
+ let cleanupPreviousGroupContext: (() => void) | null = null;
281
293
 
282
294
  // Process all rows
283
295
  for await (const row of sourceRows) {
284
- // Set the current row in the runtime context for evaluation using row descriptors
285
- ctx.context.set(sourceRowDescriptor, () => row);
286
- logContextPush(sourceRowDescriptor, 'source-row', sourceAttributes);
287
- if (sourceRelation !== plan.source) {
288
- ctx.context.set(sourceRelationRowDescriptor, () => row);
289
- logContextPush(sourceRelationRowDescriptor, 'source-relation-row');
296
+ if (cleanupPreviousGroupContext) {
297
+ cleanupPreviousGroupContext();
298
+ cleanupPreviousGroupContext = null;
290
299
  }
291
300
 
301
+ // Set the current row in the runtime context for Filter and GROUP BY evaluation
302
+ ctx.context.set(scanRowDescriptor, () => row);
303
+ logContextPush(scanRowDescriptor, 'scan-row', sourceAttributes);
304
+
292
305
  try {
293
306
  // Evaluate GROUP BY expressions to determine the group
294
307
  const groupValues: SqlValue[] = [];
@@ -323,11 +336,14 @@ export function emitStreamAggregate(plan: StreamAggregateNode, ctx: EmissionCont
323
336
 
324
337
  // Check if we've moved to a new group using proper SQL value comparison
325
338
  if (currentGroupKey !== null && compareGroupKeys(currentGroupKey, groupValues) !== 0) {
339
+ // CRITICAL: Save the previous group's representative row before yielding
340
+ const previousGroupSourceRow = currentSourceRow;
341
+
326
342
  // Yield the previous group's results
327
- const resultRow: SqlValue[] = [];
343
+ const aggregateRow: SqlValue[] = [];
328
344
 
329
345
  // First, add the GROUP BY values
330
- resultRow.push(...currentGroupValues);
346
+ aggregateRow.push(...currentGroupValues);
331
347
 
332
348
  // Then, add the finalized aggregate values
333
349
  for (let i = 0; i < plan.aggregates.length; i++) {
@@ -340,37 +356,49 @@ export function emitStreamAggregate(plan: StreamAggregateNode, ctx: EmissionCont
340
356
  finalValue = currentAccumulators[i];
341
357
  }
342
358
 
343
- resultRow.push(finalValue);
359
+ aggregateRow.push(finalValue);
344
360
  }
345
361
 
346
- // Set up combined context that allows access to both
347
- // the aggregated result AND the original source row attributes
348
- ctx.context.set(outputRowDescriptor, () => resultRow);
349
- logContextPush(outputRowDescriptor, 'output-row-groupby');
350
- if (currentSourceRow) {
351
- // Also provide access to a representative source row for this group
352
- // This enables correlated subqueries to access original table attributes
353
- ctx.context.set(sourceRowDescriptor, () => currentSourceRow!);
354
- logContextPush(sourceRowDescriptor, 'source-row-groupby', sourceAttributes);
362
+ // Build combined row with aggregate results + representative source row
363
+ const fullRow = previousGroupSourceRow ? [...aggregateRow, ...previousGroupSourceRow] : aggregateRow;
364
+
365
+ // Set up context with the PREVIOUS group's representative row (not the current row)
366
+ if (previousGroupSourceRow) {
367
+ ctx.context.set(scanRowDescriptor, () => previousGroupSourceRow);
368
+ logContextPush(scanRowDescriptor, 'group-rep-row');
369
+ }
370
+ ctx.context.set(combinedRowDescriptor, () => fullRow);
371
+ logContextPush(combinedRowDescriptor, 'output-row-groupby');
372
+ if (previousGroupSourceRow) {
373
+ // Use the previous group's representative row for HAVING evaluation
374
+ // Use separate descriptors to avoid conflicts with source row processing
375
+ ctx.context.set(groupSourceRowDescriptor, () => previousGroupSourceRow!);
376
+ logContextPush(groupSourceRowDescriptor, 'source-row-groupby', sourceAttributes);
355
377
  if (sourceRelation !== plan.source) {
356
- ctx.context.set(sourceRelationRowDescriptor, () => currentSourceRow!);
357
- logContextPush(sourceRelationRowDescriptor, 'source-relation-row-groupby');
378
+ ctx.context.set(groupSourceRelationRowDescriptor, () => previousGroupSourceRow!);
379
+ logContextPush(groupSourceRelationRowDescriptor, 'source-relation-row-groupby');
358
380
  }
359
381
  }
360
- try {
361
- yield resultRow;
362
- } finally {
363
- logContextPop(outputRowDescriptor, 'output-row-groupby');
364
- ctx.context.delete(outputRowDescriptor);
365
- if (currentSourceRow) {
366
- logContextPop(sourceRowDescriptor, 'source-row-groupby');
367
- ctx.context.delete(sourceRowDescriptor);
382
+
383
+ // Defer context cleanup
384
+ cleanupPreviousGroupContext = () => {
385
+ logContextPop(combinedRowDescriptor, 'output-row-groupby');
386
+ ctx.context.delete(combinedRowDescriptor);
387
+ if (previousGroupSourceRow) {
388
+ logContextPop(scanRowDescriptor, 'group-rep-row');
389
+ ctx.context.delete(scanRowDescriptor);
390
+ }
391
+ if (previousGroupSourceRow) {
392
+ logContextPop(groupSourceRowDescriptor, 'source-row-groupby');
393
+ ctx.context.delete(groupSourceRowDescriptor);
368
394
  if (sourceRelation !== plan.source) {
369
- logContextPop(sourceRelationRowDescriptor, 'source-relation-row-groupby');
370
- ctx.context.delete(sourceRelationRowDescriptor);
395
+ logContextPop(groupSourceRelationRowDescriptor, 'source-relation-row-groupby');
396
+ ctx.context.delete(groupSourceRelationRowDescriptor);
371
397
  }
372
398
  }
373
- }
399
+ };
400
+
401
+ yield aggregateRow;
374
402
 
375
403
  // Reset for new group
376
404
  currentAccumulators = aggregateSchemas.map(schema => {
@@ -392,6 +420,8 @@ export function emitStreamAggregate(plan: StreamAggregateNode, ctx: EmissionCont
392
420
  compareDistinctValues
393
421
  ) : new BTree<SqlValue | SqlValue[], SqlValue | SqlValue[]>((val: SqlValue | SqlValue[]) => val, compareDistinctValues)
394
422
  );
423
+ // Set representative row for the new group (which is the current row)
424
+ currentSourceRow = row;
395
425
  }
396
426
 
397
427
  // Initialize if first group
@@ -415,12 +445,13 @@ export function emitStreamAggregate(plan: StreamAggregateNode, ctx: EmissionCont
415
445
  compareDistinctValues
416
446
  ) : new BTree<SqlValue | SqlValue[], SqlValue | SqlValue[]>((val: SqlValue | SqlValue[]) => val, compareDistinctValues)
417
447
  );
448
+ // Set representative row for the first group
449
+ currentSourceRow = row;
418
450
  }
419
451
 
420
452
  // Update current group
421
453
  currentGroupKey = groupValues;
422
454
  currentGroupValues = groupValues;
423
- currentSourceRow = row; // Keep a representative row for this group
424
455
 
425
456
  // For each aggregate, call its step function using the pre-evaluated arguments
426
457
  for (let i = 0; i < plan.aggregates.length; i++) {
@@ -444,22 +475,23 @@ export function emitStreamAggregate(plan: StreamAggregateNode, ctx: EmissionCont
444
475
  }
445
476
  }
446
477
  } finally {
447
- // Clean up context for this row
448
- logContextPop(sourceRowDescriptor, 'source-row');
449
- ctx.context.delete(sourceRowDescriptor);
450
- if (sourceRelation !== plan.source) {
451
- logContextPop(sourceRelationRowDescriptor, 'source-relation-row');
452
- ctx.context.delete(sourceRelationRowDescriptor);
453
- }
478
+ // Clean up scan context for this row
479
+ logContextPop(scanRowDescriptor, 'scan-row');
480
+ ctx.context.delete(scanRowDescriptor);
454
481
  }
455
482
  }
456
483
 
484
+ if (cleanupPreviousGroupContext) {
485
+ cleanupPreviousGroupContext();
486
+ cleanupPreviousGroupContext = null;
487
+ }
488
+
457
489
  // Yield the final group if any rows were processed
458
490
  if (currentGroupKey !== null) {
459
- const resultRow: SqlValue[] = [];
491
+ const aggregateRow: SqlValue[] = [];
460
492
 
461
493
  // First, add the GROUP BY values
462
- resultRow.push(...currentGroupValues);
494
+ aggregateRow.push(...currentGroupValues);
463
495
 
464
496
  // Then, add the finalized aggregate values
465
497
  for (let i = 0; i < plan.aggregates.length; i++) {
@@ -472,31 +504,45 @@ export function emitStreamAggregate(plan: StreamAggregateNode, ctx: EmissionCont
472
504
  finalValue = currentAccumulators[i];
473
505
  }
474
506
 
475
- resultRow.push(finalValue);
507
+ aggregateRow.push(finalValue);
476
508
  }
477
509
 
478
- // CRITICAL FIX: Set up combined context for final group
479
- ctx.context.set(outputRowDescriptor, () => resultRow);
480
- logContextPush(outputRowDescriptor, 'final-output-row');
510
+ // Build combined row with aggregate results + representative source row
511
+ const fullRow = currentSourceRow ? [...aggregateRow, ...currentSourceRow] : aggregateRow;
512
+
513
+ // Set up context for final group with correct source row
514
+ if (currentSourceRow) {
515
+ ctx.context.set(scanRowDescriptor, () => currentSourceRow);
516
+ logContextPush(scanRowDescriptor, 'final-group-rep-row');
517
+ }
518
+ ctx.context.set(combinedRowDescriptor, () => fullRow);
519
+ logContextPush(combinedRowDescriptor, 'final-output-row');
481
520
  if (currentSourceRow) {
482
- ctx.context.set(sourceRowDescriptor, () => currentSourceRow);
483
- logContextPush(sourceRowDescriptor, 'final-source-row', sourceAttributes);
521
+ // Use the final group's representative row for HAVING evaluation
522
+ // Use separate descriptors to avoid conflicts with source row processing
523
+ ctx.context.set(groupSourceRowDescriptor, () => currentSourceRow!);
524
+ logContextPush(groupSourceRowDescriptor, 'final-source-row', sourceAttributes);
484
525
  if (sourceRelation !== plan.source) {
485
- ctx.context.set(sourceRelationRowDescriptor, () => currentSourceRow);
486
- logContextPush(sourceRelationRowDescriptor, 'final-source-relation-row');
526
+ ctx.context.set(groupSourceRelationRowDescriptor, () => currentSourceRow!);
527
+ logContextPush(groupSourceRelationRowDescriptor, 'final-source-relation-row');
487
528
  }
488
529
  }
530
+
489
531
  try {
490
- yield resultRow;
532
+ yield aggregateRow;
491
533
  } finally {
492
- logContextPop(outputRowDescriptor, 'final-output-row');
493
- ctx.context.delete(outputRowDescriptor);
534
+ logContextPop(combinedRowDescriptor, 'final-output-row');
535
+ ctx.context.delete(combinedRowDescriptor);
536
+ if (currentSourceRow) {
537
+ logContextPop(scanRowDescriptor, 'final-group-rep-row');
538
+ ctx.context.delete(scanRowDescriptor);
539
+ }
494
540
  if (currentSourceRow) {
495
- logContextPop(sourceRowDescriptor, 'final-source-row');
496
- ctx.context.delete(sourceRowDescriptor);
541
+ logContextPop(groupSourceRowDescriptor, 'final-source-row');
542
+ ctx.context.delete(groupSourceRowDescriptor);
497
543
  if (sourceRelation !== plan.source) {
498
- logContextPop(sourceRelationRowDescriptor, 'final-source-relation-row');
499
- ctx.context.delete(sourceRelationRowDescriptor);
544
+ logContextPop(groupSourceRelationRowDescriptor, 'final-source-relation-row');
545
+ ctx.context.delete(groupSourceRelationRowDescriptor);
500
546
  }
501
547
  }
502
548
  }
@@ -0,0 +1,51 @@
1
+ import type { SqlValue } from "../../common/types.js";
2
+ import type { Instruction, InstructionRun, RuntimeContext } from "../types.js";
3
+ import type { BetweenNode } from "../../planner/nodes/scalar.js";
4
+ import { emitPlanNode } from "../emitters.js";
5
+ import { compareSqlValuesFast, resolveCollation } from "../../util/comparison.js";
6
+ import { coerceForComparison } from "../../util/coercion.js";
7
+ import type { EmissionContext } from "../emission-context.js";
8
+
9
+ export function emitBetween(plan: BetweenNode, ctx: EmissionContext): Instruction {
10
+ // Pre-resolve collation function for optimal performance (using BINARY as default for BETWEEN)
11
+ const collationFunc = resolveCollation('BINARY');
12
+
13
+ function run(ctx: RuntimeContext, value: SqlValue, lowerBound: SqlValue, upperBound: SqlValue): SqlValue {
14
+ // SQL BETWEEN logic: value BETWEEN lower AND upper
15
+ // Equivalent to: value >= lower AND value <= upper
16
+ // NULL handling: if any operand is NULL, result is NULL
17
+ if (value === null || lowerBound === null || upperBound === null) {
18
+ return null;
19
+ }
20
+
21
+ // Apply type coercion before comparison
22
+ const [coercedValue1, coercedLower] = coerceForComparison(value, lowerBound);
23
+ const [coercedValue2, coercedUpper] = coerceForComparison(value, upperBound);
24
+
25
+ // Use pre-resolved collation function for optimal performance
26
+ const lowerResult = compareSqlValuesFast(coercedValue1, coercedLower, collationFunc);
27
+ const upperResult = compareSqlValuesFast(coercedValue2, coercedUpper, collationFunc);
28
+
29
+ // value >= lowerBound AND value <= upperBound
30
+ const betweenResult = (lowerResult >= 0 && upperResult <= 0) ? 1 : 0;
31
+
32
+ // Handle NOT BETWEEN
33
+ if (plan.expression.not) {
34
+ return betweenResult ? 0 : 1;
35
+ }
36
+
37
+ return betweenResult;
38
+ }
39
+
40
+ const valueExpr = emitPlanNode(plan.expr, ctx);
41
+ const lowerExpr = emitPlanNode(plan.lower, ctx);
42
+ const upperExpr = emitPlanNode(plan.upper, ctx);
43
+
44
+ const notPrefix = plan.expression.not ? 'NOT ' : '';
45
+
46
+ return {
47
+ params: [valueExpr, lowerExpr, upperExpr],
48
+ run: run as InstructionRun,
49
+ note: `${notPrefix}BETWEEN`
50
+ };
51
+ }