@quereus/quereus 0.1.0 → 0.2.1

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 (477) hide show
  1. package/README.md +47 -23
  2. package/dist/src/common/types.d.ts +1 -0
  3. package/dist/src/common/types.d.ts.map +1 -1
  4. package/dist/src/core/database.d.ts +22 -4
  5. package/dist/src/core/database.d.ts.map +1 -1
  6. package/dist/src/core/database.js +44 -6
  7. package/dist/src/core/database.js.map +1 -1
  8. package/dist/src/core/statement.d.ts +0 -7
  9. package/dist/src/core/statement.d.ts.map +1 -1
  10. package/dist/src/core/statement.js +1 -51
  11. package/dist/src/core/statement.js.map +1 -1
  12. package/dist/src/func/builtins/explain.d.ts.map +1 -1
  13. package/dist/src/func/builtins/explain.js +0 -11
  14. package/dist/src/func/builtins/explain.js.map +1 -1
  15. package/dist/src/index.d.ts +13 -5
  16. package/dist/src/index.d.ts.map +1 -1
  17. package/dist/src/index.js +5 -2
  18. package/dist/src/index.js.map +1 -1
  19. package/dist/src/parser/ast.d.ts +10 -4
  20. package/dist/src/parser/ast.d.ts.map +1 -1
  21. package/dist/src/parser/parser.d.ts.map +1 -1
  22. package/dist/src/parser/parser.js +40 -44
  23. package/dist/src/parser/parser.js.map +1 -1
  24. package/dist/src/planner/analysis/const-pass.d.ts.map +1 -1
  25. package/dist/src/planner/analysis/const-pass.js +12 -6
  26. package/dist/src/planner/analysis/const-pass.js.map +1 -1
  27. package/dist/src/planner/building/constraint-builder.d.ts +11 -0
  28. package/dist/src/planner/building/constraint-builder.d.ts.map +1 -0
  29. package/dist/src/planner/building/constraint-builder.js +79 -0
  30. package/dist/src/planner/building/constraint-builder.js.map +1 -0
  31. package/dist/src/planner/building/delete.d.ts.map +1 -1
  32. package/dist/src/planner/building/delete.js +7 -4
  33. package/dist/src/planner/building/delete.js.map +1 -1
  34. package/dist/src/planner/building/expression.d.ts +3 -0
  35. package/dist/src/planner/building/expression.d.ts.map +1 -1
  36. package/dist/src/planner/building/expression.js +33 -7
  37. package/dist/src/planner/building/expression.js.map +1 -1
  38. package/dist/src/planner/building/insert.d.ts.map +1 -1
  39. package/dist/src/planner/building/insert.js +5 -2
  40. package/dist/src/planner/building/insert.js.map +1 -1
  41. package/dist/src/planner/building/select-aggregates.d.ts.map +1 -1
  42. package/dist/src/planner/building/select-aggregates.js +46 -9
  43. package/dist/src/planner/building/select-aggregates.js.map +1 -1
  44. package/dist/src/planner/building/select-context.js +20 -11
  45. package/dist/src/planner/building/select-context.js.map +1 -1
  46. package/dist/src/planner/building/select-modifiers.d.ts +5 -3
  47. package/dist/src/planner/building/select-modifiers.d.ts.map +1 -1
  48. package/dist/src/planner/building/select-modifiers.js +29 -20
  49. package/dist/src/planner/building/select-modifiers.js.map +1 -1
  50. package/dist/src/planner/building/select-projections.d.ts +3 -1
  51. package/dist/src/planner/building/select-projections.d.ts.map +1 -1
  52. package/dist/src/planner/building/select-projections.js +15 -20
  53. package/dist/src/planner/building/select-projections.js.map +1 -1
  54. package/dist/src/planner/building/select-window.d.ts.map +1 -1
  55. package/dist/src/planner/building/select-window.js +6 -3
  56. package/dist/src/planner/building/select-window.js.map +1 -1
  57. package/dist/src/planner/building/select.d.ts +25 -2
  58. package/dist/src/planner/building/select.d.ts.map +1 -1
  59. package/dist/src/planner/building/select.js +147 -24
  60. package/dist/src/planner/building/select.js.map +1 -1
  61. package/dist/src/planner/building/table.d.ts +0 -10
  62. package/dist/src/planner/building/table.d.ts.map +1 -1
  63. package/dist/src/planner/building/table.js +1 -35
  64. package/dist/src/planner/building/table.js.map +1 -1
  65. package/dist/src/planner/building/update.d.ts.map +1 -1
  66. package/dist/src/planner/building/update.js +8 -5
  67. package/dist/src/planner/building/update.js.map +1 -1
  68. package/dist/src/planner/building/with.d.ts.map +1 -1
  69. package/dist/src/planner/building/with.js +7 -8
  70. package/dist/src/planner/building/with.js.map +1 -1
  71. package/dist/src/planner/cache/correlation-detector.d.ts +11 -0
  72. package/dist/src/planner/cache/correlation-detector.d.ts.map +1 -0
  73. package/dist/src/planner/cache/correlation-detector.js +73 -0
  74. package/dist/src/planner/cache/correlation-detector.js.map +1 -0
  75. package/dist/src/planner/cache/materialization-advisory.d.ts +12 -18
  76. package/dist/src/planner/cache/materialization-advisory.d.ts.map +1 -1
  77. package/dist/src/planner/cache/materialization-advisory.js +65 -46
  78. package/dist/src/planner/cache/materialization-advisory.js.map +1 -1
  79. package/dist/src/planner/cache/reference-graph.d.ts +14 -9
  80. package/dist/src/planner/cache/reference-graph.d.ts.map +1 -1
  81. package/dist/src/planner/cache/reference-graph.js +93 -84
  82. package/dist/src/planner/cache/reference-graph.js.map +1 -1
  83. package/dist/src/planner/debug.d.ts +25 -0
  84. package/dist/src/planner/debug.d.ts.map +1 -1
  85. package/dist/src/planner/debug.js +127 -0
  86. package/dist/src/planner/debug.js.map +1 -1
  87. package/dist/src/planner/framework/context.d.ts +11 -0
  88. package/dist/src/planner/framework/context.d.ts.map +1 -1
  89. package/dist/src/planner/framework/context.js +25 -2
  90. package/dist/src/planner/framework/context.js.map +1 -1
  91. package/dist/src/planner/framework/registry.d.ts +3 -7
  92. package/dist/src/planner/framework/registry.d.ts.map +1 -1
  93. package/dist/src/planner/framework/registry.js +20 -31
  94. package/dist/src/planner/framework/registry.js.map +1 -1
  95. package/dist/src/planner/nodes/add-constraint-node.d.ts +2 -1
  96. package/dist/src/planner/nodes/add-constraint-node.d.ts.map +1 -1
  97. package/dist/src/planner/nodes/add-constraint-node.js +3 -0
  98. package/dist/src/planner/nodes/add-constraint-node.js.map +1 -1
  99. package/dist/src/planner/nodes/aggregate-node.d.ts.map +1 -1
  100. package/dist/src/planner/nodes/aggregate-node.js +6 -4
  101. package/dist/src/planner/nodes/aggregate-node.js.map +1 -1
  102. package/dist/src/planner/nodes/cache-node.d.ts.map +1 -1
  103. package/dist/src/planner/nodes/cache-node.js +2 -2
  104. package/dist/src/planner/nodes/cache-node.js.map +1 -1
  105. package/dist/src/planner/nodes/constraint-check-node.d.ts +13 -6
  106. package/dist/src/planner/nodes/constraint-check-node.d.ts.map +1 -1
  107. package/dist/src/planner/nodes/constraint-check-node.js +38 -12
  108. package/dist/src/planner/nodes/constraint-check-node.js.map +1 -1
  109. package/dist/src/planner/nodes/create-index-node.d.ts +2 -1
  110. package/dist/src/planner/nodes/create-index-node.d.ts.map +1 -1
  111. package/dist/src/planner/nodes/create-index-node.js +3 -0
  112. package/dist/src/planner/nodes/create-index-node.js.map +1 -1
  113. package/dist/src/planner/nodes/create-table-node.d.ts +2 -1
  114. package/dist/src/planner/nodes/create-table-node.d.ts.map +1 -1
  115. package/dist/src/planner/nodes/create-table-node.js +3 -0
  116. package/dist/src/planner/nodes/create-table-node.js.map +1 -1
  117. package/dist/src/planner/nodes/create-view-node.d.ts +2 -1
  118. package/dist/src/planner/nodes/create-view-node.d.ts.map +1 -1
  119. package/dist/src/planner/nodes/create-view-node.js +3 -0
  120. package/dist/src/planner/nodes/create-view-node.js.map +1 -1
  121. package/dist/src/planner/nodes/cte-node.d.ts +1 -1
  122. package/dist/src/planner/nodes/cte-node.d.ts.map +1 -1
  123. package/dist/src/planner/nodes/cte-node.js +33 -12
  124. package/dist/src/planner/nodes/cte-node.js.map +1 -1
  125. package/dist/src/planner/nodes/cte-reference-node.d.ts +18 -4
  126. package/dist/src/planner/nodes/cte-reference-node.d.ts.map +1 -1
  127. package/dist/src/planner/nodes/cte-reference-node.js +40 -10
  128. package/dist/src/planner/nodes/cte-reference-node.js.map +1 -1
  129. package/dist/src/planner/nodes/delete-node.d.ts +4 -3
  130. package/dist/src/planner/nodes/delete-node.d.ts.map +1 -1
  131. package/dist/src/planner/nodes/delete-node.js +20 -6
  132. package/dist/src/planner/nodes/delete-node.js.map +1 -1
  133. package/dist/src/planner/nodes/distinct-node.d.ts.map +1 -1
  134. package/dist/src/planner/nodes/distinct-node.js +2 -2
  135. package/dist/src/planner/nodes/distinct-node.js.map +1 -1
  136. package/dist/src/planner/nodes/dml-executor-node.d.ts +1 -1
  137. package/dist/src/planner/nodes/dml-executor-node.d.ts.map +1 -1
  138. package/dist/src/planner/nodes/dml-executor-node.js +2 -2
  139. package/dist/src/planner/nodes/dml-executor-node.js.map +1 -1
  140. package/dist/src/planner/nodes/drop-table-node.d.ts +2 -1
  141. package/dist/src/planner/nodes/drop-table-node.d.ts.map +1 -1
  142. package/dist/src/planner/nodes/drop-table-node.js +3 -0
  143. package/dist/src/planner/nodes/drop-table-node.js.map +1 -1
  144. package/dist/src/planner/nodes/drop-view-node.d.ts +2 -1
  145. package/dist/src/planner/nodes/drop-view-node.d.ts.map +1 -1
  146. package/dist/src/planner/nodes/drop-view-node.js +3 -0
  147. package/dist/src/planner/nodes/drop-view-node.js.map +1 -1
  148. package/dist/src/planner/nodes/filter.d.ts.map +1 -1
  149. package/dist/src/planner/nodes/filter.js +3 -3
  150. package/dist/src/planner/nodes/filter.js.map +1 -1
  151. package/dist/src/planner/nodes/insert-node.d.ts +2 -1
  152. package/dist/src/planner/nodes/insert-node.d.ts.map +1 -1
  153. package/dist/src/planner/nodes/insert-node.js +18 -5
  154. package/dist/src/planner/nodes/insert-node.js.map +1 -1
  155. package/dist/src/planner/nodes/internal-recursive-cte-ref-node.d.ts +28 -0
  156. package/dist/src/planner/nodes/internal-recursive-cte-ref-node.d.ts.map +1 -0
  157. package/dist/src/planner/nodes/internal-recursive-cte-ref-node.js +69 -0
  158. package/dist/src/planner/nodes/internal-recursive-cte-ref-node.js.map +1 -0
  159. package/dist/src/planner/nodes/join-node.d.ts.map +1 -1
  160. package/dist/src/planner/nodes/join-node.js +3 -3
  161. package/dist/src/planner/nodes/join-node.js.map +1 -1
  162. package/dist/src/planner/nodes/limit-offset.d.ts.map +1 -1
  163. package/dist/src/planner/nodes/limit-offset.js +2 -2
  164. package/dist/src/planner/nodes/limit-offset.js.map +1 -1
  165. package/dist/src/planner/nodes/plan-node-type.d.ts +1 -1
  166. package/dist/src/planner/nodes/plan-node-type.d.ts.map +1 -1
  167. package/dist/src/planner/nodes/plan-node-type.js +1 -1
  168. package/dist/src/planner/nodes/plan-node-type.js.map +1 -1
  169. package/dist/src/planner/nodes/plan-node.d.ts +23 -0
  170. package/dist/src/planner/nodes/plan-node.d.ts.map +1 -1
  171. package/dist/src/planner/nodes/plan-node.js +25 -2
  172. package/dist/src/planner/nodes/plan-node.js.map +1 -1
  173. package/dist/src/planner/nodes/project-node.d.ts +5 -1
  174. package/dist/src/planner/nodes/project-node.d.ts.map +1 -1
  175. package/dist/src/planner/nodes/project-node.js +39 -20
  176. package/dist/src/planner/nodes/project-node.js.map +1 -1
  177. package/dist/src/planner/nodes/recursive-cte-node.d.ts +2 -2
  178. package/dist/src/planner/nodes/recursive-cte-node.d.ts.map +1 -1
  179. package/dist/src/planner/nodes/recursive-cte-node.js +20 -8
  180. package/dist/src/planner/nodes/recursive-cte-node.js.map +1 -1
  181. package/dist/src/planner/nodes/reference.d.ts.map +1 -1
  182. package/dist/src/planner/nodes/reference.js +4 -2
  183. package/dist/src/planner/nodes/reference.js.map +1 -1
  184. package/dist/src/planner/nodes/returning-node.d.ts +1 -1
  185. package/dist/src/planner/nodes/returning-node.d.ts.map +1 -1
  186. package/dist/src/planner/nodes/returning-node.js +21 -13
  187. package/dist/src/planner/nodes/returning-node.js.map +1 -1
  188. package/dist/src/planner/nodes/scalar.d.ts +26 -2
  189. package/dist/src/planner/nodes/scalar.d.ts.map +1 -1
  190. package/dist/src/planner/nodes/scalar.js +82 -10
  191. package/dist/src/planner/nodes/scalar.js.map +1 -1
  192. package/dist/src/planner/nodes/sequencing-node.d.ts.map +1 -1
  193. package/dist/src/planner/nodes/sequencing-node.js +2 -2
  194. package/dist/src/planner/nodes/sequencing-node.js.map +1 -1
  195. package/dist/src/planner/nodes/set-operation-node.d.ts.map +1 -1
  196. package/dist/src/planner/nodes/set-operation-node.js +3 -3
  197. package/dist/src/planner/nodes/set-operation-node.js.map +1 -1
  198. package/dist/src/planner/nodes/single-row.d.ts +4 -2
  199. package/dist/src/planner/nodes/single-row.d.ts.map +1 -1
  200. package/dist/src/planner/nodes/single-row.js +3 -0
  201. package/dist/src/planner/nodes/single-row.js.map +1 -1
  202. package/dist/src/planner/nodes/sink-node.d.ts +1 -1
  203. package/dist/src/planner/nodes/sink-node.d.ts.map +1 -1
  204. package/dist/src/planner/nodes/sink-node.js +4 -4
  205. package/dist/src/planner/nodes/sink-node.js.map +1 -1
  206. package/dist/src/planner/nodes/sort.d.ts.map +1 -1
  207. package/dist/src/planner/nodes/sort.js +2 -2
  208. package/dist/src/planner/nodes/sort.js.map +1 -1
  209. package/dist/src/planner/nodes/stream-aggregate.d.ts +1 -0
  210. package/dist/src/planner/nodes/stream-aggregate.d.ts.map +1 -1
  211. package/dist/src/planner/nodes/stream-aggregate.js +64 -11
  212. package/dist/src/planner/nodes/stream-aggregate.js.map +1 -1
  213. package/dist/src/planner/nodes/subquery.d.ts +4 -4
  214. package/dist/src/planner/nodes/subquery.d.ts.map +1 -1
  215. package/dist/src/planner/nodes/subquery.js +68 -23
  216. package/dist/src/planner/nodes/subquery.js.map +1 -1
  217. package/dist/src/planner/nodes/table-access-nodes.d.ts +83 -0
  218. package/dist/src/planner/nodes/table-access-nodes.d.ts.map +1 -0
  219. package/dist/src/planner/nodes/table-access-nodes.js +226 -0
  220. package/dist/src/planner/nodes/table-access-nodes.js.map +1 -0
  221. package/dist/src/planner/nodes/update-node.d.ts +4 -2
  222. package/dist/src/planner/nodes/update-node.d.ts.map +1 -1
  223. package/dist/src/planner/nodes/update-node.js +26 -13
  224. package/dist/src/planner/nodes/update-node.js.map +1 -1
  225. package/dist/src/planner/nodes/window-node.d.ts.map +1 -1
  226. package/dist/src/planner/nodes/window-node.js +25 -23
  227. package/dist/src/planner/nodes/window-node.js.map +1 -1
  228. package/dist/src/planner/optimizer.d.ts.map +1 -1
  229. package/dist/src/planner/optimizer.js +46 -50
  230. package/dist/src/planner/optimizer.js.map +1 -1
  231. package/dist/src/planner/planning-context.d.ts +13 -0
  232. package/dist/src/planner/planning-context.d.ts.map +1 -1
  233. package/dist/src/planner/planning-context.js.map +1 -1
  234. package/dist/src/planner/rules/access/rule-select-access-path.d.ts +1 -1
  235. package/dist/src/planner/rules/access/rule-select-access-path.d.ts.map +1 -1
  236. package/dist/src/planner/rules/access/rule-select-access-path.js +59 -53
  237. package/dist/src/planner/rules/access/rule-select-access-path.js.map +1 -1
  238. package/dist/src/planner/rules/aggregate/rule-aggregate-streaming.d.ts.map +1 -1
  239. package/dist/src/planner/rules/aggregate/rule-aggregate-streaming.js +62 -2
  240. package/dist/src/planner/rules/aggregate/rule-aggregate-streaming.js.map +1 -1
  241. package/dist/src/planner/rules/cache/rule-materialization-advisory.d.ts.map +1 -1
  242. package/dist/src/planner/rules/cache/rule-materialization-advisory.js +31 -24
  243. package/dist/src/planner/rules/cache/rule-materialization-advisory.js.map +1 -1
  244. package/dist/src/planner/scopes/base.d.ts +0 -10
  245. package/dist/src/planner/scopes/base.d.ts.map +1 -1
  246. package/dist/src/planner/scopes/base.js +0 -14
  247. package/dist/src/planner/scopes/base.js.map +1 -1
  248. package/dist/src/planner/scopes/empty.d.ts +0 -2
  249. package/dist/src/planner/scopes/empty.d.ts.map +1 -1
  250. package/dist/src/planner/scopes/empty.js +0 -8
  251. package/dist/src/planner/scopes/empty.js.map +1 -1
  252. package/dist/src/planner/scopes/multi.d.ts.map +1 -1
  253. package/dist/src/planner/scopes/multi.js +0 -1
  254. package/dist/src/planner/scopes/multi.js.map +1 -1
  255. package/dist/src/planner/scopes/param.d.ts.map +1 -1
  256. package/dist/src/planner/scopes/param.js +0 -1
  257. package/dist/src/planner/scopes/param.js.map +1 -1
  258. package/dist/src/planner/scopes/registered.d.ts +0 -10
  259. package/dist/src/planner/scopes/registered.d.ts.map +1 -1
  260. package/dist/src/planner/scopes/registered.js +1 -17
  261. package/dist/src/planner/scopes/registered.js.map +1 -1
  262. package/dist/src/planner/scopes/scope.d.ts +0 -8
  263. package/dist/src/planner/scopes/scope.d.ts.map +1 -1
  264. package/dist/src/planner/validation/plan-validator.d.ts.map +1 -1
  265. package/dist/src/planner/validation/plan-validator.js +1 -7
  266. package/dist/src/planner/validation/plan-validator.js.map +1 -1
  267. package/dist/src/runtime/context-helpers.d.ts +45 -0
  268. package/dist/src/runtime/context-helpers.d.ts.map +1 -0
  269. package/dist/src/runtime/context-helpers.js +139 -0
  270. package/dist/src/runtime/context-helpers.js.map +1 -0
  271. package/dist/src/runtime/emission-context.d.ts +1 -0
  272. package/dist/src/runtime/emission-context.d.ts.map +1 -1
  273. package/dist/src/runtime/emission-context.js +2 -1
  274. package/dist/src/runtime/emission-context.js.map +1 -1
  275. package/dist/src/runtime/emit/aggregate.d.ts.map +1 -1
  276. package/dist/src/runtime/emit/aggregate.js +119 -86
  277. package/dist/src/runtime/emit/aggregate.js.map +1 -1
  278. package/dist/src/runtime/emit/between.d.ts +5 -0
  279. package/dist/src/runtime/emit/between.d.ts.map +1 -0
  280. package/dist/src/runtime/emit/between.js +38 -0
  281. package/dist/src/runtime/emit/between.js.map +1 -0
  282. package/dist/src/runtime/emit/binary.d.ts +0 -1
  283. package/dist/src/runtime/emit/binary.d.ts.map +1 -1
  284. package/dist/src/runtime/emit/binary.js +0 -36
  285. package/dist/src/runtime/emit/binary.js.map +1 -1
  286. package/dist/src/runtime/emit/column-reference.d.ts.map +1 -1
  287. package/dist/src/runtime/emit/column-reference.js +2 -26
  288. package/dist/src/runtime/emit/column-reference.js.map +1 -1
  289. package/dist/src/runtime/emit/constraint-check.d.ts.map +1 -1
  290. package/dist/src/runtime/emit/constraint-check.js +16 -123
  291. package/dist/src/runtime/emit/constraint-check.js.map +1 -1
  292. package/dist/src/runtime/emit/cte-reference.d.ts.map +1 -1
  293. package/dist/src/runtime/emit/cte-reference.js +16 -48
  294. package/dist/src/runtime/emit/cte-reference.js.map +1 -1
  295. package/dist/src/runtime/emit/distinct.d.ts.map +1 -1
  296. package/dist/src/runtime/emit/distinct.js +2 -8
  297. package/dist/src/runtime/emit/distinct.js.map +1 -1
  298. package/dist/src/runtime/emit/filter.d.ts.map +1 -1
  299. package/dist/src/runtime/emit/filter.js +6 -13
  300. package/dist/src/runtime/emit/filter.js.map +1 -1
  301. package/dist/src/runtime/emit/internal-recursive-cte-ref.d.ts +5 -0
  302. package/dist/src/runtime/emit/internal-recursive-cte-ref.d.ts.map +1 -0
  303. package/dist/src/runtime/emit/internal-recursive-cte-ref.js +23 -0
  304. package/dist/src/runtime/emit/internal-recursive-cte-ref.js.map +1 -0
  305. package/dist/src/runtime/emit/join.d.ts.map +1 -1
  306. package/dist/src/runtime/emit/join.js +40 -40
  307. package/dist/src/runtime/emit/join.js.map +1 -1
  308. package/dist/src/runtime/emit/project.d.ts.map +1 -1
  309. package/dist/src/runtime/emit/project.js +13 -13
  310. package/dist/src/runtime/emit/project.js.map +1 -1
  311. package/dist/src/runtime/emit/recursive-cte.d.ts.map +1 -1
  312. package/dist/src/runtime/emit/recursive-cte.js +3 -14
  313. package/dist/src/runtime/emit/recursive-cte.js.map +1 -1
  314. package/dist/src/runtime/emit/returning.d.ts.map +1 -1
  315. package/dist/src/runtime/emit/returning.js +7 -14
  316. package/dist/src/runtime/emit/returning.js.map +1 -1
  317. package/dist/src/runtime/emit/scan.d.ts +5 -2
  318. package/dist/src/runtime/emit/scan.d.ts.map +1 -1
  319. package/dist/src/runtime/emit/scan.js +21 -17
  320. package/dist/src/runtime/emit/scan.js.map +1 -1
  321. package/dist/src/runtime/emit/sort.d.ts.map +1 -1
  322. package/dist/src/runtime/emit/sort.js +8 -11
  323. package/dist/src/runtime/emit/sort.js.map +1 -1
  324. package/dist/src/runtime/emit/subquery.d.ts.map +1 -1
  325. package/dist/src/runtime/emit/subquery.js +95 -40
  326. package/dist/src/runtime/emit/subquery.js.map +1 -1
  327. package/dist/src/runtime/emit/table-valued-function.d.ts.map +1 -1
  328. package/dist/src/runtime/emit/table-valued-function.js +7 -22
  329. package/dist/src/runtime/emit/table-valued-function.js.map +1 -1
  330. package/dist/src/runtime/emit/update.d.ts.map +1 -1
  331. package/dist/src/runtime/emit/update.js +20 -27
  332. package/dist/src/runtime/emit/update.js.map +1 -1
  333. package/dist/src/runtime/emit/window.d.ts.map +1 -1
  334. package/dist/src/runtime/emit/window.js +55 -83
  335. package/dist/src/runtime/emit/window.js.map +1 -1
  336. package/dist/src/runtime/emitters.d.ts.map +1 -1
  337. package/dist/src/runtime/emitters.js +49 -1
  338. package/dist/src/runtime/emitters.js.map +1 -1
  339. package/dist/src/runtime/register.d.ts.map +1 -1
  340. package/dist/src/runtime/register.js +5 -4
  341. package/dist/src/runtime/register.js.map +1 -1
  342. package/dist/src/runtime/scheduler.d.ts.map +1 -1
  343. package/dist/src/runtime/scheduler.js +47 -42
  344. package/dist/src/runtime/scheduler.js.map +1 -1
  345. package/dist/src/runtime/types.d.ts +34 -0
  346. package/dist/src/runtime/types.d.ts.map +1 -1
  347. package/dist/src/runtime/types.js +21 -0
  348. package/dist/src/runtime/types.js.map +1 -1
  349. package/dist/src/schema/manager.d.ts.map +1 -1
  350. package/dist/src/schema/manager.js +29 -16
  351. package/dist/src/schema/manager.js.map +1 -1
  352. package/dist/src/schema/table.d.ts +4 -4
  353. package/dist/src/schema/table.d.ts.map +1 -1
  354. package/dist/src/schema/table.js +10 -10
  355. package/dist/src/schema/table.js.map +1 -1
  356. package/dist/src/util/plugin-loader.d.ts +10 -1
  357. package/dist/src/util/plugin-loader.d.ts.map +1 -1
  358. package/dist/src/util/plugin-loader.js +56 -1
  359. package/dist/src/util/plugin-loader.js.map +1 -1
  360. package/dist/src/util/working-table-iterable.d.ts.map +1 -1
  361. package/dist/src/util/working-table-iterable.js +8 -8
  362. package/dist/src/util/working-table-iterable.js.map +1 -1
  363. package/dist/src/vtab/manifest.d.ts +36 -0
  364. package/dist/src/vtab/manifest.d.ts.map +1 -1
  365. package/dist/src/vtab/table.d.ts +1 -1
  366. package/dist/src/vtab/table.d.ts.map +1 -1
  367. package/package.json +8 -3
  368. package/src/common/types.ts +1 -0
  369. package/src/core/database.ts +48 -6
  370. package/src/core/statement.ts +1 -49
  371. package/src/func/builtins/explain.ts +0 -11
  372. package/src/index.ts +39 -5
  373. package/src/parser/ast.ts +12 -6
  374. package/src/parser/parser.ts +45 -52
  375. package/src/planner/analysis/const-pass.ts +281 -270
  376. package/src/planner/building/constraint-builder.ts +114 -0
  377. package/src/planner/building/delete.ts +18 -5
  378. package/src/planner/building/expression.ts +35 -7
  379. package/src/planner/building/insert.ts +16 -3
  380. package/src/planner/building/select-aggregates.ts +57 -11
  381. package/src/planner/building/select-context.ts +22 -12
  382. package/src/planner/building/select-modifiers.ts +35 -21
  383. package/src/planner/building/select-projections.ts +25 -26
  384. package/src/planner/building/select-window.ts +14 -9
  385. package/src/planner/building/select.ts +163 -31
  386. package/src/planner/building/table.ts +1 -40
  387. package/src/planner/building/update.ts +22 -7
  388. package/src/planner/building/with.ts +12 -13
  389. package/src/planner/cache/correlation-detector.ts +83 -0
  390. package/src/planner/cache/materialization-advisory.ts +71 -50
  391. package/src/planner/cache/reference-graph.ts +115 -91
  392. package/src/planner/debug.ts +163 -0
  393. package/src/planner/framework/context.ts +36 -2
  394. package/src/planner/framework/registry.ts +261 -274
  395. package/src/planner/nodes/add-constraint-node.ts +5 -1
  396. package/src/planner/nodes/aggregate-node.ts +6 -4
  397. package/src/planner/nodes/cache-node.ts +2 -2
  398. package/src/planner/nodes/constraint-check-node.ts +49 -15
  399. package/src/planner/nodes/create-index-node.ts +5 -1
  400. package/src/planner/nodes/create-table-node.ts +5 -1
  401. package/src/planner/nodes/create-view-node.ts +5 -1
  402. package/src/planner/nodes/cte-node.ts +45 -14
  403. package/src/planner/nodes/cte-reference-node.ts +49 -13
  404. package/src/planner/nodes/delete-node.ts +31 -7
  405. package/src/planner/nodes/distinct-node.ts +2 -2
  406. package/src/planner/nodes/dml-executor-node.ts +3 -3
  407. package/src/planner/nodes/drop-table-node.ts +5 -1
  408. package/src/planner/nodes/drop-view-node.ts +5 -1
  409. package/src/planner/nodes/filter.ts +3 -3
  410. package/src/planner/nodes/function.ts +93 -93
  411. package/src/planner/nodes/insert-node.ts +28 -5
  412. package/src/planner/nodes/internal-recursive-cte-ref-node.ts +76 -0
  413. package/src/planner/nodes/join-node.ts +3 -3
  414. package/src/planner/nodes/limit-offset.ts +2 -2
  415. package/src/planner/nodes/plan-node-type.ts +1 -1
  416. package/src/planner/nodes/plan-node.ts +39 -2
  417. package/src/planner/nodes/project-node.ts +39 -19
  418. package/src/planner/nodes/recursive-cte-node.ts +37 -9
  419. package/src/planner/nodes/reference.ts +4 -2
  420. package/src/planner/nodes/returning-node.ts +25 -13
  421. package/src/planner/nodes/scalar.ts +95 -11
  422. package/src/planner/nodes/sequencing-node.ts +2 -2
  423. package/src/planner/nodes/set-operation-node.ts +3 -3
  424. package/src/planner/nodes/single-row.ts +7 -2
  425. package/src/planner/nodes/sink-node.ts +5 -5
  426. package/src/planner/nodes/sort.ts +2 -2
  427. package/src/planner/nodes/stream-aggregate.ts +76 -12
  428. package/src/planner/nodes/subquery.ts +90 -27
  429. package/src/planner/nodes/{physical-access-nodes.ts → table-access-nodes.ts} +6 -6
  430. package/src/planner/nodes/update-node.ts +31 -13
  431. package/src/planner/nodes/window-node.ts +28 -22
  432. package/src/planner/optimizer.ts +257 -263
  433. package/src/planner/planning-context.ts +15 -0
  434. package/src/planner/rules/access/rule-select-access-path.ts +68 -64
  435. package/src/planner/rules/aggregate/rule-aggregate-streaming.ts +74 -2
  436. package/src/planner/rules/cache/rule-materialization-advisory.ts +31 -27
  437. package/src/planner/scopes/base.ts +0 -17
  438. package/src/planner/scopes/empty.ts +0 -10
  439. package/src/planner/scopes/multi.ts +0 -1
  440. package/src/planner/scopes/param.ts +0 -1
  441. package/src/planner/scopes/registered.ts +1 -20
  442. package/src/planner/scopes/scope.ts +0 -12
  443. package/src/planner/validation/plan-validator.ts +1 -8
  444. package/src/runtime/context-helpers.ts +191 -0
  445. package/src/runtime/emission-context.ts +5 -2
  446. package/src/runtime/emit/aggregate.ts +131 -85
  447. package/src/runtime/emit/between.ts +51 -0
  448. package/src/runtime/emit/binary.ts +0 -46
  449. package/src/runtime/emit/column-reference.ts +3 -36
  450. package/src/runtime/emit/constraint-check.ts +19 -144
  451. package/src/runtime/emit/cte-reference.ts +23 -60
  452. package/src/runtime/emit/distinct.ts +2 -7
  453. package/src/runtime/emit/filter.ts +6 -13
  454. package/src/runtime/emit/internal-recursive-cte-ref.ts +37 -0
  455. package/src/runtime/emit/join.ts +45 -43
  456. package/src/runtime/emit/project.ts +18 -12
  457. package/src/runtime/emit/recursive-cte.ts +3 -12
  458. package/src/runtime/emit/returning.ts +7 -14
  459. package/src/runtime/emit/scan.ts +25 -23
  460. package/src/runtime/emit/sort.ts +8 -11
  461. package/src/runtime/emit/subquery.ts +108 -48
  462. package/src/runtime/emit/table-valued-function.ts +7 -20
  463. package/src/runtime/emit/update.ts +22 -29
  464. package/src/runtime/emit/window.ts +74 -88
  465. package/src/runtime/emitters.ts +52 -1
  466. package/src/runtime/register.ts +5 -4
  467. package/src/runtime/scheduler.ts +54 -54
  468. package/src/runtime/types.ts +45 -0
  469. package/src/schema/manager.ts +34 -19
  470. package/src/schema/table.ts +8 -8
  471. package/src/util/plugin-loader.ts +78 -4
  472. package/src/util/working-table-iterable.ts +15 -7
  473. package/src/vtab/manifest.ts +42 -0
  474. package/src/vtab/table.ts +1 -1
  475. package/src/planner/nodes/scan.ts +0 -103
  476. package/src/planner/rules/physical/rule-mark-physical.ts +0 -37
  477. package/src/runtime/emit/table-reference.ts +0 -92
@@ -4,11 +4,12 @@
4
4
  */
5
5
 
6
6
  import { createLogger } from '../../common/logger.js';
7
- import type { PlanNode, RelationalPlanNode } from '../nodes/plan-node.js';
7
+ import { isRelationalNode, type PlanNode, type RelationalPlanNode } from '../nodes/plan-node.js';
8
8
  import { CacheNode, type CacheStrategy } from '../nodes/cache-node.js';
9
9
  import { PlanNodeType } from '../nodes/plan-node-type.js';
10
10
  import type { OptimizerTuning } from '../optimizer-tuning.js';
11
11
  import { ReferenceGraphBuilder, type RefStats } from './reference-graph.js';
12
+ import { isCorrelatedSubquery } from './correlation-detector.js';
12
13
 
13
14
  const log = createLogger('optimizer:cache:materialization');
14
15
 
@@ -37,34 +38,38 @@ export class MaterializationAdvisory {
37
38
  }
38
39
 
39
40
  /**
40
- * Analyze a plan tree and return caching recommendations
41
+ * Analyze a plan tree and inject caching where beneficial
42
+ * Returns the transformed tree or the original if no caching was added
41
43
  */
42
- analyzeTree(root: PlanNode): Map<PlanNode, CacheRecommendation> {
44
+ analyzeAndTransform(root: PlanNode): PlanNode {
45
+ // Build reference graph
43
46
  const refGraph = this.referenceBuilder.buildReferenceGraph(root);
47
+
48
+ // Build recommendations
44
49
  const recommendations = new Map<PlanNode, CacheRecommendation>();
45
50
 
46
51
  for (const [node, stats] of refGraph) {
47
52
  // Only consider relational nodes for caching
48
- if (!this.isRelationalNode(node)) {
53
+ if (!isRelationalNode(node)) {
49
54
  continue;
50
55
  }
51
56
 
52
57
  const recommendation = this.adviseCaching(node, stats);
53
- recommendations.set(node, recommendation);
54
-
55
58
  if (recommendation.shouldCache) {
59
+ recommendations.set(node, recommendation);
56
60
  log('Recommending cache for %s: %s', node.nodeType, recommendation.reason);
57
61
  }
58
62
  }
59
63
 
60
- return recommendations;
61
- }
64
+ if (recommendations.size === 0) {
65
+ log('No caching opportunities identified');
66
+ return root;
67
+ }
62
68
 
63
- /**
64
- * Apply caching recommendations to a plan tree
65
- */
66
- applyCaching(root: PlanNode, recommendations: Map<PlanNode, CacheRecommendation>): PlanNode {
67
- return this.transformNode(root, recommendations);
69
+ log('Found %d caching opportunities', recommendations.size);
70
+
71
+ // Transform the tree by wrapping recommended nodes with CacheNode
72
+ return this.transformTree(root, recommendations);
68
73
  }
69
74
 
70
75
  /**
@@ -91,7 +96,18 @@ export class MaterializationAdvisory {
91
96
  };
92
97
  }
93
98
 
94
- // Rule 3: Single-parent nodes that don't appear in loops typically don't benefit from caching
99
+ // Rule 3: Correlated subqueries should not be cached
100
+ // Check if this node is part of a subquery context and if it's correlated
101
+ if (isRelationalNode(node) && this.isCorrelatedNode(node)) {
102
+ return {
103
+ shouldCache: false,
104
+ strategy: 'memory',
105
+ threshold: 0,
106
+ reason: 'Correlated subquery - must re-execute for each outer row'
107
+ };
108
+ }
109
+
110
+ // Rule 4: Single-parent nodes that don't appear in loops typically don't benefit from caching
95
111
  if (stats.parentCount <= 1 && !stats.appearsInLoop) {
96
112
  return {
97
113
  shouldCache: false,
@@ -101,7 +117,7 @@ export class MaterializationAdvisory {
101
117
  };
102
118
  }
103
119
 
104
- // Rule 4: Multi-parent nodes benefit from caching
120
+ // Rule 5: Multi-parent nodes benefit from caching
105
121
  if (stats.parentCount > 1) {
106
122
  const strategy = this.selectStrategy(stats.estimatedRows);
107
123
  const threshold = this.calculateThreshold(stats.estimatedRows, strategy);
@@ -114,7 +130,7 @@ export class MaterializationAdvisory {
114
130
  };
115
131
  }
116
132
 
117
- // Rule 5: Nodes in loop contexts benefit from caching even with single parent
133
+ // Rule 6: Nodes in loop contexts benefit from caching even with single parent
118
134
  if (stats.appearsInLoop) {
119
135
  // Check if the estimated size is reasonable for caching
120
136
  if (stats.estimatedRows > this.tuning.join.maxRightRowsForCaching) {
@@ -146,7 +162,7 @@ export class MaterializationAdvisory {
146
162
  };
147
163
  }
148
164
 
149
- /**
165
+ /**
150
166
  * Select appropriate cache strategy based on estimated size
151
167
  */
152
168
  private selectStrategy(estimatedRows: number): CacheStrategy {
@@ -174,22 +190,27 @@ export class MaterializationAdvisory {
174
190
  }
175
191
 
176
192
  /**
177
- * Check if a node is relational (can be cached)
193
+ * Check if a node is part of a correlated subquery
178
194
  */
179
- private isRelationalNode(node: PlanNode): boolean {
180
- return 'getAttributes' in node && typeof (node as any).getAttributes === 'function';
195
+ private isCorrelatedNode(node: PlanNode): boolean {
196
+ // Check if this is a relational node that could be correlated
197
+ if (isRelationalNode(node)) {
198
+ return isCorrelatedSubquery(node as RelationalPlanNode);
199
+ }
200
+ return false;
181
201
  }
182
202
 
183
203
  /**
184
- * Transform a node tree by applying cache recommendations
204
+ * Transform a tree by wrapping recommended nodes with CacheNode
205
+ * Uses a bottom-up approach to ensure proper transformation
185
206
  */
186
- private transformNode(node: PlanNode, recommendations: Map<PlanNode, CacheRecommendation>): PlanNode {
187
- // First, recursively transform children
207
+ private transformTree(node: PlanNode, recommendations: Map<PlanNode, CacheRecommendation>): PlanNode {
208
+ // First, transform all children recursively
188
209
  const transformedNode = this.transformChildren(node, recommendations);
189
210
 
190
- // Check if this node should be cached
211
+ // Then check if this node itself should be cached
191
212
  const recommendation = recommendations.get(node);
192
- if (recommendation?.shouldCache && this.isRelationalNode(transformedNode)) {
213
+ if (recommendation?.shouldCache && isRelationalNode(transformedNode)) {
193
214
  log('Injecting %s cache for %s (threshold: %d)',
194
215
  recommendation.strategy, transformedNode.nodeType, recommendation.threshold);
195
216
 
@@ -206,39 +227,39 @@ export class MaterializationAdvisory {
206
227
 
207
228
  /**
208
229
  * Transform children of a node
230
+ * This handles both scalar and relational children using a simpler approach
209
231
  */
210
232
  private transformChildren(node: PlanNode, recommendations: Map<PlanNode, CacheRecommendation>): PlanNode {
211
- // Handle different node types that have children
233
+ // For nodes that we know how to handle, transform their children
234
+ // For others, return the node as-is (the optimizer will handle it)
212
235
 
213
- // For nodes with relational children, we need to transform them
214
- if ('getRelations' in node) {
215
- const relations = (node as any).getRelations();
216
- const transformedRelations = relations.map((rel: PlanNode) =>
217
- this.transformNode(rel, recommendations)
218
- );
236
+ // First, try to transform scalar children using withChildren
237
+ const scalarChildren = node.getChildren();
238
+ const transformedScalarChildren = scalarChildren.map(child =>
239
+ this.transformTree(child, recommendations)
240
+ );
241
+
242
+ const scalarChanged = transformedScalarChildren.some((child, idx) =>
243
+ child !== scalarChildren[idx]
244
+ );
219
245
 
220
- // Check if any relations were transformed
221
- if (transformedRelations.some((rel: PlanNode, idx: number) => rel !== relations[idx])) {
222
- // Need to create a new node with transformed relations
223
- return this.recreateNodeWithNewRelations(node, transformedRelations);
246
+ if (scalarChanged) {
247
+ // Let withChildren handle the transformation
248
+ // This will maintain proper attribute IDs and node structure
249
+ try {
250
+ return node.withChildren(transformedScalarChildren);
251
+ } catch (e) {
252
+ // If withChildren fails, log and return original
253
+ log('Warning: withChildren failed for %s: %s', node.nodeType, e);
254
+ return node;
224
255
  }
225
256
  }
226
257
 
227
- // If no transformations needed, return original node
228
- return node;
229
- }
230
-
231
- /**
232
- * Recreate a node with new relational children
233
- * This is a simplified version - in practice, would need comprehensive node cloning
234
- */
235
- private recreateNodeWithNewRelations(node: PlanNode, _newRelations: RelationalPlanNode[]): PlanNode {
236
- // TODO: This is a simplified implementation
237
- // In practice, would need to handle all node types properly
258
+ // If no scalar children changed, check if this node has relational children
259
+ // that might need caching. For now, we'll return the node as-is and let
260
+ // individual optimization rules handle relational transformations.
261
+ // This is safer than trying to recreate complex nodes.
238
262
 
239
- // For now, just return the original node
240
- // This would need to be expanded to handle all node types
241
- log('Node recreation not yet implemented for %s', node.nodeType);
242
263
  return node;
243
264
  }
244
265
  }
@@ -1,12 +1,16 @@
1
1
  /**
2
2
  * Reference graph builder for materialization advisory
3
3
  * Analyzes plan tree to identify nodes that would benefit from caching
4
+ *
5
+ * Note: This builder works with logical plan nodes and their properties.
6
+ * It does not make assumptions about execution strategies (e.g., whether
7
+ * a join will use nested loops vs hash join). Loop detection and execution
8
+ * multipliers should be determined during physical optimization when
9
+ * concrete execution strategies are chosen.
4
10
  */
5
11
 
6
12
  import { createLogger } from '../../common/logger.js';
7
- import type { PlanNode } from '../nodes/plan-node.js';
8
- import { PlanNodeType } from '../nodes/plan-node-type.js';
9
- import { JoinNode } from '../nodes/join-node.js';
13
+ import { isRelationalNode, type PlanNode } from '../nodes/plan-node.js';
10
14
  import type { OptimizerTuning } from '../optimizer-tuning.js';
11
15
 
12
16
  const log = createLogger('optimizer:cache:reference-graph');
@@ -23,6 +27,22 @@ export interface RefStats {
23
27
  estimatedRows: number;
24
28
  /** Whether this node is deterministic (same inputs produce same outputs) */
25
29
  deterministic: boolean;
30
+ /** Parent nodes that reference this node (for debugging) */
31
+ parents: Set<PlanNode>;
32
+ /** Estimated execution multiplier due to loop contexts */
33
+ loopMultiplier: number;
34
+ }
35
+
36
+ /**
37
+ * Node traversal context
38
+ */
39
+ interface TraversalContext {
40
+ /** Current parent node */
41
+ parent: PlanNode | null;
42
+ /** Whether we're in a loop context */
43
+ inLoop: boolean;
44
+ /** Estimated loop iteration count */
45
+ loopIterations: number;
26
46
  }
27
47
 
28
48
  /**
@@ -30,7 +50,6 @@ export interface RefStats {
30
50
  */
31
51
  export class ReferenceGraphBuilder {
32
52
  private refMap = new Map<PlanNode, RefStats>();
33
- private visited = new Set<PlanNode>();
34
53
 
35
54
  constructor(private tuning: OptimizerTuning) {}
36
55
 
@@ -38,90 +57,105 @@ export class ReferenceGraphBuilder {
38
57
  * Build reference statistics for all nodes in the plan tree
39
58
  */
40
59
  buildReferenceGraph(root: PlanNode): Map<PlanNode, RefStats> {
60
+ if (!root) {
61
+ log('Warning: buildReferenceGraph called with null root');
62
+ return new Map();
63
+ }
64
+
41
65
  this.refMap.clear();
42
- this.visited.clear();
43
66
 
44
- // First pass: count parent references
45
- this.countReferences(root, false);
67
+ // Build the reference graph with proper parent tracking
68
+ const context: TraversalContext = {
69
+ parent: null,
70
+ inLoop: false,
71
+ loopIterations: 1
72
+ };
46
73
 
47
- // Second pass: identify loop contexts
48
- this.identifyLoopContexts(root, false);
74
+ this.buildReferences(root, context);
49
75
 
50
76
  log('Built reference graph with %d nodes', this.refMap.size);
51
77
  return new Map(this.refMap);
52
78
  }
53
79
 
54
80
  /**
55
- * First pass: count how many parents reference each node
81
+ * Build reference statistics recursively
56
82
  */
57
- private countReferences(node: PlanNode, inLoop: boolean): void {
58
- if (this.visited.has(node)) {
59
- // Node seen again - increment parent count
60
- const stats = this.refMap.get(node);
61
- if (stats) {
62
- stats.parentCount++;
63
- }
83
+ private buildReferences(node: PlanNode | null | undefined, context: TraversalContext): void {
84
+ if (!node) {
64
85
  return;
65
86
  }
66
87
 
67
- this.visited.add(node);
68
-
69
- // Initialize stats for this node
70
- const stats: RefStats = {
71
- parentCount: 1, // First time seeing this node
72
- appearsInLoop: inLoop,
73
- estimatedRows: this.getEstimatedRows(node),
74
- deterministic: this.isDeterministic(node)
75
- };
76
-
77
- this.refMap.set(node, stats);
78
-
79
- // Recurse to children
80
- this.visitChildren(node, (child) => {
81
- this.countReferences(child, inLoop);
82
- });
83
- }
88
+ // Get or create stats for this node
89
+ let stats = this.refMap.get(node);
90
+ if (!stats) {
91
+ // First time seeing this node
92
+ stats = {
93
+ parentCount: 0,
94
+ appearsInLoop: context.inLoop,
95
+ estimatedRows: this.getEstimatedRows(node),
96
+ deterministic: this.isDeterministic(node),
97
+ parents: new Set<PlanNode>(),
98
+ loopMultiplier: context.loopIterations
99
+ };
100
+ this.refMap.set(node, stats);
101
+ }
84
102
 
85
- /**
86
- * Second pass: identify nodes that appear in loop contexts
87
- */
88
- private identifyLoopContexts(node: PlanNode, inLoop: boolean): void {
89
- const stats = this.refMap.get(node);
90
- if (!stats) return;
103
+ // Update stats based on current traversal
104
+ if (context.parent && !stats.parents.has(context.parent)) {
105
+ stats.parents.add(context.parent);
106
+ stats.parentCount++;
107
+ }
91
108
 
92
- // Update loop status if we're now in a loop context
93
- if (inLoop && !stats.appearsInLoop) {
109
+ // Update loop context
110
+ if (context.inLoop) {
94
111
  stats.appearsInLoop = true;
95
- log('Node %s marked as appearing in loop', node.nodeType);
112
+ stats.loopMultiplier = Math.max(stats.loopMultiplier, context.loopIterations);
96
113
  }
97
114
 
98
- // Determine if children are in loop context
99
- if (node instanceof JoinNode && node.joinType === 'inner') {
100
- // Right side of nested loop join is in loop context
101
- const [left, right] = node.getRelations();
102
- this.identifyLoopContexts(left, inLoop);
103
- this.identifyLoopContexts(right, true); // Right side is in loop
104
- } else {
105
- // Recurse to all children with current loop status
106
- this.visitChildren(node, (child) => {
107
- this.identifyLoopContexts(child, inLoop);
108
- });
109
- }
115
+ // Create child context - for now, we propagate the parent context
116
+ // In the future, if nodes expose execution strategy hints, we could use those
117
+ const childContext: TraversalContext = {
118
+ parent: node,
119
+ inLoop: context.inLoop,
120
+ loopIterations: context.loopIterations
121
+ };
122
+
123
+ // Visit all children uniformly
124
+ this.visitAllChildren(node, childContext);
110
125
  }
111
126
 
112
127
  /**
113
128
  * Visit all children of a node
114
129
  */
115
- private visitChildren(node: PlanNode, visitor: (child: PlanNode) => void): void {
116
- // Visit scalar expression children
117
- for (const child of node.getChildren()) {
118
- visitor(child);
130
+ private visitAllChildren(node: PlanNode, childContext: TraversalContext): void {
131
+ // 1. Scalar children (expressions)
132
+ try {
133
+ const children = node.getChildren();
134
+ for (const child of children) {
135
+ if (child) {
136
+ this.buildReferences(child, childContext);
137
+ }
138
+ }
139
+ } catch (e) {
140
+ log('Warning: Failed to get children for node %s: %s', node.nodeType, e);
119
141
  }
120
142
 
121
- // Visit relational children
122
- if ('getRelations' in node) {
123
- for (const relation of (node as any).getRelations()) {
124
- visitor(relation);
143
+ // 2. Relational children
144
+ // Note: getRelations() returns a subset of getChildren() for nodes that have relational children
145
+ // We need to be careful not to double-count, but since we're using a Set for parents,
146
+ // and checking if we've already added a parent, this should be fine
147
+ if (isRelationalNode(node)) {
148
+ try {
149
+ const relations = node.getRelations();
150
+ for (const relation of relations) {
151
+ if (relation) {
152
+ // For now, treat all relational children the same
153
+ // In the future, nodes could provide hints about execution patterns
154
+ this.buildReferences(relation, childContext);
155
+ }
156
+ }
157
+ } catch (e) {
158
+ log('Warning: Failed to get relations for node %s: %s', node.nodeType, e);
125
159
  }
126
160
  }
127
161
  }
@@ -129,44 +163,34 @@ export class ReferenceGraphBuilder {
129
163
  /**
130
164
  * Get estimated row count for a node
131
165
  */
132
- private getEstimatedRows(node: PlanNode): number {
133
- if ('estimatedRows' in node && typeof node.estimatedRows === 'number') {
134
- return node.estimatedRows;
166
+ private getEstimatedRows(node: PlanNode | null | undefined): number {
167
+ if (!node) {
168
+ return this.tuning.defaultRowEstimate;
135
169
  }
136
- if (node.physical?.estimatedRows) {
170
+
171
+ // Use physical properties if available
172
+ if (node.physical?.estimatedRows !== undefined) {
137
173
  return node.physical.estimatedRows;
138
174
  }
175
+
176
+ // Fall back to node-specific estimates (for relational nodes)
177
+ if (isRelationalNode(node) && node.estimatedRows !== undefined) {
178
+ return node.estimatedRows;
179
+ }
180
+
181
+ // Default estimate
139
182
  return this.tuning.defaultRowEstimate;
140
183
  }
141
184
 
142
185
  /**
143
186
  * Determine if a node is deterministic
144
187
  */
145
- private isDeterministic(node: PlanNode): boolean {
146
- // Check physical properties first
147
- if (node.physical?.deterministic !== undefined) {
148
- return node.physical.deterministic;
188
+ private isDeterministic(node: PlanNode | null | undefined): boolean {
189
+ if (!node) {
190
+ return true;
149
191
  }
150
192
 
151
- // Node-type specific deterministic analysis
152
- switch (node.nodeType) {
153
- case PlanNodeType.TableScan:
154
- case PlanNodeType.Values:
155
- case PlanNodeType.Project:
156
- case PlanNodeType.Filter:
157
- case PlanNodeType.Sort:
158
- case PlanNodeType.Aggregate:
159
- case PlanNodeType.StreamAggregate:
160
- return true;
161
-
162
- case PlanNodeType.TableFunctionCall:
163
- // Would need to check if the table function is deterministic
164
- // For now, assume non-deterministic to be safe
165
- return false;
166
-
167
- default:
168
- // Conservative default - assume deterministic unless proven otherwise
169
- return true;
170
- }
193
+ // Use physical properties to determine determinism
194
+ return node.physical?.deterministic ?? true;
171
195
  }
172
196
  }
@@ -314,3 +314,166 @@ export function generateTraceReport(
314
314
  lines.push('=== END TRACE ===');
315
315
  return lines.join('\n');
316
316
  }
317
+
318
+ /**
319
+ * Options for plan formatting
320
+ */
321
+ export interface PlanDisplayOptions {
322
+ /** Show concise plan by default (true) or full details (false) */
323
+ concise?: boolean;
324
+ /** Node IDs to expand with full details (only applies when concise=true) */
325
+ expandNodes?: string[];
326
+ /** Maximum depth to display (default: no limit) */
327
+ maxDepth?: number;
328
+ /** Show physical properties if available */
329
+ showPhysical?: boolean;
330
+ }
331
+
332
+ /**
333
+ * Creates a concise, tree-like representation of the plan
334
+ */
335
+ export function formatPlanTree(rootNode: PlanNode, options: PlanDisplayOptions = {}): string {
336
+ const { concise = true, expandNodes = [], maxDepth, showPhysical = true } = options;
337
+ const lines: string[] = [];
338
+ const nodesSeen = new Set<PlanNode>();
339
+
340
+ function formatNode(node: PlanNode, depth: number, isLast: boolean, prefix: string): void {
341
+ if (maxDepth !== undefined && depth > maxDepth) {
342
+ return;
343
+ }
344
+
345
+ // Avoid infinite recursion for circular references
346
+ if (nodesSeen.has(node)) {
347
+ lines.push(`${prefix}├─ [CIRCULAR: ${node.nodeType}#${node.id}]`);
348
+ return;
349
+ }
350
+ nodesSeen.add(node);
351
+
352
+ // Determine if this node should be expanded
353
+ const shouldExpand = !concise || expandNodes.includes(node.id);
354
+
355
+ // Node header with connection lines
356
+ const connector = isLast ? '└─ ' : '├─ ';
357
+ const nodeType = node.nodeType;
358
+ const nodeId = `#${node.id}`;
359
+ const description = node.toString();
360
+
361
+ // Build the header line
362
+ let headerLine = `${prefix}${connector}${nodeType}${nodeId}`;
363
+ if (description && description !== nodeType) {
364
+ headerLine += `: ${description}`;
365
+ }
366
+
367
+ // Add cost information if available
368
+ const cost = node.estimatedCost;
369
+ const totalCost = node.getTotalCost();
370
+ if (cost > 0 || totalCost > 0) {
371
+ headerLine += ` [cost: ${cost}, total: ${totalCost}]`;
372
+ }
373
+
374
+ // Add physical properties if requested and available
375
+ if (showPhysical && (node as any).physical) {
376
+ const physical = (node as any).physical;
377
+ const physicalInfo = [];
378
+ if (physical.estimatedRows !== undefined) {
379
+ physicalInfo.push(`rows: ${physical.estimatedRows}`);
380
+ }
381
+ if (physical.ordering && physical.ordering.length > 0) {
382
+ physicalInfo.push(`ordered: ${physical.ordering.map((o: any) => `${o.attributeId}:${o.direction}`).join(',')}`);
383
+ }
384
+ if (physical.readonly !== undefined) {
385
+ physicalInfo.push(`readonly: ${physical.readonly}`);
386
+ }
387
+ if (physicalInfo.length > 0) {
388
+ headerLine += ` {${physicalInfo.join(', ')}}`;
389
+ }
390
+ }
391
+
392
+ lines.push(headerLine);
393
+
394
+ // Add expanded details if requested
395
+ if (shouldExpand) {
396
+ const logical = node.getLogicalAttributes();
397
+ if (logical && Object.keys(logical).length > 0) {
398
+ const logicalLines = JSON.stringify(logical, null, 2).split('\n');
399
+ const extendedPrefix = prefix + (isLast ? ' ' : '│ ');
400
+ lines.push(`${extendedPrefix}┌─ Logical Attributes:`);
401
+ for (let i = 0; i < logicalLines.length; i++) {
402
+ const line = logicalLines[i];
403
+ const isLastLogicalLine = i === logicalLines.length - 1;
404
+ const logicalConnector = isLastLogicalLine ? '└─ ' : '│ ';
405
+ lines.push(`${extendedPrefix}${logicalConnector}${line}`);
406
+ }
407
+ }
408
+ }
409
+
410
+ // Process children
411
+ const children = node.getChildren();
412
+ const relations = node.getRelations();
413
+ const allChildren = [...children, ...relations];
414
+
415
+ // Filter out duplicates (in case a child is both a child and relation)
416
+ const uniqueChildren = Array.from(new Set(allChildren));
417
+
418
+ for (let i = 0; i < uniqueChildren.length; i++) {
419
+ const child = uniqueChildren[i];
420
+ const isLastChild = i === uniqueChildren.length - 1;
421
+ const childPrefix = prefix + (isLast ? ' ' : '│ ');
422
+ formatNode(child, depth + 1, isLastChild, childPrefix);
423
+ }
424
+
425
+ nodesSeen.delete(node);
426
+ }
427
+
428
+ lines.push('Query Plan:');
429
+ formatNode(rootNode, 0, true, '');
430
+
431
+ // Add help text
432
+ if (concise && expandNodes.length === 0) {
433
+ lines.push('');
434
+ lines.push('Tip: Use --expand-nodes node1,node2,... to see detailed properties for specific nodes');
435
+ }
436
+
437
+ return lines.join('\n');
438
+ }
439
+
440
+ /**
441
+ * Generates a compact plan summary showing just the execution path
442
+ */
443
+ export function formatPlanSummary(rootNode: PlanNode): string {
444
+ const path: string[] = [];
445
+ const visited = new Set<PlanNode>();
446
+
447
+ function collectPath(node: PlanNode): void {
448
+ if (visited.has(node)) return;
449
+ visited.add(node);
450
+
451
+ const description = node.toString();
452
+ const nodeInfo = description && description !== node.nodeType
453
+ ? `${node.nodeType}(${description})`
454
+ : node.nodeType;
455
+
456
+ path.push(nodeInfo);
457
+
458
+ // Follow the main execution path (first child for most nodes)
459
+ const children = node.getChildren();
460
+ if (children.length > 0) {
461
+ collectPath(children[0]);
462
+ }
463
+ }
464
+
465
+ collectPath(rootNode);
466
+ return `Execution Path: ${path.join(' → ')}`;
467
+ }
468
+
469
+ /**
470
+ * Enhanced plan serialization with formatting options
471
+ */
472
+ export function serializePlanTreeWithOptions(rootNode: PlanNode, options: PlanDisplayOptions = {}): string {
473
+ if (options.concise !== false) {
474
+ return formatPlanTree(rootNode, options);
475
+ } else {
476
+ // Use the existing detailed serialization
477
+ return serializePlanTree(rootNode);
478
+ }
479
+ }