@quereus/quereus 4.6.0 → 4.7.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 (535) hide show
  1. package/README.md +2 -2
  2. package/dist/src/common/errors.d.ts +17 -0
  3. package/dist/src/common/errors.d.ts.map +1 -1
  4. package/dist/src/common/errors.js +21 -0
  5. package/dist/src/common/errors.js.map +1 -1
  6. package/dist/src/core/database-assertions.d.ts +4 -3
  7. package/dist/src/core/database-assertions.d.ts.map +1 -1
  8. package/dist/src/core/database-assertions.js +44 -14
  9. package/dist/src/core/database-assertions.js.map +1 -1
  10. package/dist/src/core/database-events.d.ts +62 -0
  11. package/dist/src/core/database-events.d.ts.map +1 -1
  12. package/dist/src/core/database-events.js +88 -2
  13. package/dist/src/core/database-events.js.map +1 -1
  14. package/dist/src/core/database-internal.d.ts +5 -2
  15. package/dist/src/core/database-internal.d.ts.map +1 -1
  16. package/dist/src/core/database-materialized-views-plan-builders.d.ts.map +1 -1
  17. package/dist/src/core/database-materialized-views-plan-builders.js +4 -2
  18. package/dist/src/core/database-materialized-views-plan-builders.js.map +1 -1
  19. package/dist/src/core/database-materialized-views-plans.d.ts +12 -2
  20. package/dist/src/core/database-materialized-views-plans.d.ts.map +1 -1
  21. package/dist/src/core/database-materialized-views.d.ts +46 -0
  22. package/dist/src/core/database-materialized-views.d.ts.map +1 -1
  23. package/dist/src/core/database-materialized-views.js +75 -4
  24. package/dist/src/core/database-materialized-views.js.map +1 -1
  25. package/dist/src/core/database.d.ts +9 -1
  26. package/dist/src/core/database.d.ts.map +1 -1
  27. package/dist/src/core/database.js +36 -10
  28. package/dist/src/core/database.js.map +1 -1
  29. package/dist/src/core/derived-row-validator.d.ts.map +1 -1
  30. package/dist/src/core/derived-row-validator.js +7 -1
  31. package/dist/src/core/derived-row-validator.js.map +1 -1
  32. package/dist/src/core/statement.d.ts.map +1 -1
  33. package/dist/src/core/statement.js +15 -5
  34. package/dist/src/core/statement.js.map +1 -1
  35. package/dist/src/emit/ast-stringify.d.ts +18 -2
  36. package/dist/src/emit/ast-stringify.d.ts.map +1 -1
  37. package/dist/src/emit/ast-stringify.js +22 -4
  38. package/dist/src/emit/ast-stringify.js.map +1 -1
  39. package/dist/src/func/builtins/explain.d.ts.map +1 -1
  40. package/dist/src/func/builtins/explain.js +19 -5
  41. package/dist/src/func/builtins/explain.js.map +1 -1
  42. package/dist/src/func/builtins/scalar.d.ts.map +1 -1
  43. package/dist/src/func/builtins/scalar.js +24 -20
  44. package/dist/src/func/builtins/scalar.js.map +1 -1
  45. package/dist/src/func/builtins/schema.d.ts.map +1 -1
  46. package/dist/src/func/builtins/schema.js +32 -5
  47. package/dist/src/func/builtins/schema.js.map +1 -1
  48. package/dist/src/index.d.ts +4 -4
  49. package/dist/src/index.d.ts.map +1 -1
  50. package/dist/src/index.js +4 -4
  51. package/dist/src/index.js.map +1 -1
  52. package/dist/src/parser/ast.d.ts +58 -1
  53. package/dist/src/parser/ast.d.ts.map +1 -1
  54. package/dist/src/parser/parser.js +1 -1
  55. package/dist/src/parser/parser.js.map +1 -1
  56. package/dist/src/parser/utils.d.ts +13 -1
  57. package/dist/src/parser/utils.d.ts.map +1 -1
  58. package/dist/src/parser/utils.js +14 -0
  59. package/dist/src/parser/utils.js.map +1 -1
  60. package/dist/src/planner/analysis/assertion-classifier.d.ts.map +1 -1
  61. package/dist/src/planner/analysis/assertion-classifier.js +7 -2
  62. package/dist/src/planner/analysis/assertion-classifier.js.map +1 -1
  63. package/dist/src/planner/analysis/assertion-hoist-cache.d.ts.map +1 -1
  64. package/dist/src/planner/analysis/assertion-hoist-cache.js +5 -0
  65. package/dist/src/planner/analysis/assertion-hoist-cache.js.map +1 -1
  66. package/dist/src/planner/analysis/change-scope.d.ts +11 -3
  67. package/dist/src/planner/analysis/change-scope.d.ts.map +1 -1
  68. package/dist/src/planner/analysis/change-scope.js +5 -4
  69. package/dist/src/planner/analysis/change-scope.js.map +1 -1
  70. package/dist/src/planner/analysis/coverage-prover.d.ts.map +1 -1
  71. package/dist/src/planner/analysis/coverage-prover.js +13 -5
  72. package/dist/src/planner/analysis/coverage-prover.js.map +1 -1
  73. package/dist/src/planner/analysis/equi-correlation.d.ts +6 -1
  74. package/dist/src/planner/analysis/equi-correlation.d.ts.map +1 -1
  75. package/dist/src/planner/analysis/equi-correlation.js +8 -1
  76. package/dist/src/planner/analysis/equi-correlation.js.map +1 -1
  77. package/dist/src/planner/analysis/predicate-dependencies.d.ts +34 -0
  78. package/dist/src/planner/analysis/predicate-dependencies.d.ts.map +1 -0
  79. package/dist/src/planner/analysis/predicate-dependencies.js +60 -0
  80. package/dist/src/planner/analysis/predicate-dependencies.js.map +1 -0
  81. package/dist/src/planner/analysis/query-rewrite-matcher.d.ts +1 -1
  82. package/dist/src/planner/analysis/query-rewrite-matcher.d.ts.map +1 -1
  83. package/dist/src/planner/analysis/query-rewrite-matcher.js +0 -26
  84. package/dist/src/planner/analysis/query-rewrite-matcher.js.map +1 -1
  85. package/dist/src/planner/building/alter-table.d.ts.map +1 -1
  86. package/dist/src/planner/building/alter-table.js +53 -17
  87. package/dist/src/planner/building/alter-table.js.map +1 -1
  88. package/dist/src/planner/building/constraint-builder.d.ts.map +1 -1
  89. package/dist/src/planner/building/constraint-builder.js +9 -5
  90. package/dist/src/planner/building/constraint-builder.js.map +1 -1
  91. package/dist/src/planner/building/create-assertion.d.ts.map +1 -1
  92. package/dist/src/planner/building/create-assertion.js +72 -1
  93. package/dist/src/planner/building/create-assertion.js.map +1 -1
  94. package/dist/src/planner/building/create-view.d.ts +6 -1
  95. package/dist/src/planner/building/create-view.d.ts.map +1 -1
  96. package/dist/src/planner/building/create-view.js +12 -3
  97. package/dist/src/planner/building/create-view.js.map +1 -1
  98. package/dist/src/planner/building/ddl.d.ts.map +1 -1
  99. package/dist/src/planner/building/ddl.js +6 -2
  100. package/dist/src/planner/building/ddl.js.map +1 -1
  101. package/dist/src/planner/building/delete.d.ts.map +1 -1
  102. package/dist/src/planner/building/delete.js +23 -10
  103. package/dist/src/planner/building/delete.js.map +1 -1
  104. package/dist/src/planner/building/dml-target.d.ts.map +1 -1
  105. package/dist/src/planner/building/dml-target.js +4 -0
  106. package/dist/src/planner/building/dml-target.js.map +1 -1
  107. package/dist/src/planner/building/drop-assertion.d.ts.map +1 -1
  108. package/dist/src/planner/building/drop-assertion.js +3 -1
  109. package/dist/src/planner/building/drop-assertion.js.map +1 -1
  110. package/dist/src/planner/building/foreign-key-builder.d.ts.map +1 -1
  111. package/dist/src/planner/building/foreign-key-builder.js +7 -5
  112. package/dist/src/planner/building/foreign-key-builder.js.map +1 -1
  113. package/dist/src/planner/building/function-call.d.ts +35 -0
  114. package/dist/src/planner/building/function-call.d.ts.map +1 -1
  115. package/dist/src/planner/building/function-call.js +53 -40
  116. package/dist/src/planner/building/function-call.js.map +1 -1
  117. package/dist/src/planner/building/insert.d.ts.map +1 -1
  118. package/dist/src/planner/building/insert.js +185 -48
  119. package/dist/src/planner/building/insert.js.map +1 -1
  120. package/dist/src/planner/building/materialized-view.d.ts.map +1 -1
  121. package/dist/src/planner/building/materialized-view.js +3 -1
  122. package/dist/src/planner/building/materialized-view.js.map +1 -1
  123. package/dist/src/planner/building/schema-authored-context.d.ts +69 -0
  124. package/dist/src/planner/building/schema-authored-context.d.ts.map +1 -0
  125. package/dist/src/planner/building/schema-authored-context.js +75 -0
  126. package/dist/src/planner/building/schema-authored-context.js.map +1 -0
  127. package/dist/src/planner/building/schema-resolution.d.ts.map +1 -1
  128. package/dist/src/planner/building/schema-resolution.js +7 -4
  129. package/dist/src/planner/building/schema-resolution.js.map +1 -1
  130. package/dist/src/planner/building/select-aggregates.d.ts +187 -2
  131. package/dist/src/planner/building/select-aggregates.d.ts.map +1 -1
  132. package/dist/src/planner/building/select-aggregates.js +414 -81
  133. package/dist/src/planner/building/select-aggregates.js.map +1 -1
  134. package/dist/src/planner/building/select-compound.js +2 -2
  135. package/dist/src/planner/building/select-compound.js.map +1 -1
  136. package/dist/src/planner/building/select-context.d.ts +91 -0
  137. package/dist/src/planner/building/select-context.d.ts.map +1 -1
  138. package/dist/src/planner/building/select-context.js +113 -0
  139. package/dist/src/planner/building/select-context.js.map +1 -1
  140. package/dist/src/planner/building/select-modifiers.d.ts +10 -3
  141. package/dist/src/planner/building/select-modifiers.d.ts.map +1 -1
  142. package/dist/src/planner/building/select-modifiers.js +29 -8
  143. package/dist/src/planner/building/select-modifiers.js.map +1 -1
  144. package/dist/src/planner/building/select-ordinal.d.ts +64 -19
  145. package/dist/src/planner/building/select-ordinal.d.ts.map +1 -1
  146. package/dist/src/planner/building/select-ordinal.js +79 -30
  147. package/dist/src/planner/building/select-ordinal.js.map +1 -1
  148. package/dist/src/planner/building/select-projections.d.ts +1 -1
  149. package/dist/src/planner/building/select-projections.d.ts.map +1 -1
  150. package/dist/src/planner/building/select-projections.js +18 -11
  151. package/dist/src/planner/building/select-projections.js.map +1 -1
  152. package/dist/src/planner/building/select-window.d.ts +13 -3
  153. package/dist/src/planner/building/select-window.d.ts.map +1 -1
  154. package/dist/src/planner/building/select-window.js +142 -37
  155. package/dist/src/planner/building/select-window.js.map +1 -1
  156. package/dist/src/planner/building/select.d.ts.map +1 -1
  157. package/dist/src/planner/building/select.js +129 -59
  158. package/dist/src/planner/building/select.js.map +1 -1
  159. package/dist/src/planner/building/update.d.ts.map +1 -1
  160. package/dist/src/planner/building/update.js +27 -13
  161. package/dist/src/planner/building/update.js.map +1 -1
  162. package/dist/src/planner/building/view-mutation-builder.d.ts +1 -1
  163. package/dist/src/planner/building/view-mutation-builder.d.ts.map +1 -1
  164. package/dist/src/planner/building/view-mutation-builder.js +102 -8
  165. package/dist/src/planner/building/view-mutation-builder.js.map +1 -1
  166. package/dist/src/planner/building/with.d.ts.map +1 -1
  167. package/dist/src/planner/building/with.js +34 -4
  168. package/dist/src/planner/building/with.js.map +1 -1
  169. package/dist/src/planner/cache/correlation-detector.d.ts +15 -0
  170. package/dist/src/planner/cache/correlation-detector.d.ts.map +1 -1
  171. package/dist/src/planner/cache/correlation-detector.js +26 -0
  172. package/dist/src/planner/cache/correlation-detector.js.map +1 -1
  173. package/dist/src/planner/cache/materialization-advisory.d.ts +7 -0
  174. package/dist/src/planner/cache/materialization-advisory.d.ts.map +1 -1
  175. package/dist/src/planner/cache/materialization-advisory.js +12 -3
  176. package/dist/src/planner/cache/materialization-advisory.js.map +1 -1
  177. package/dist/src/planner/framework/characteristics.d.ts +9 -0
  178. package/dist/src/planner/framework/characteristics.d.ts.map +1 -1
  179. package/dist/src/planner/framework/characteristics.js.map +1 -1
  180. package/dist/src/planner/framework/pass.d.ts +2 -0
  181. package/dist/src/planner/framework/pass.d.ts.map +1 -1
  182. package/dist/src/planner/framework/pass.js +15 -0
  183. package/dist/src/planner/framework/pass.js.map +1 -1
  184. package/dist/src/planner/mutation/backward-body.d.ts.map +1 -1
  185. package/dist/src/planner/mutation/backward-body.js +4 -1
  186. package/dist/src/planner/mutation/backward-body.js.map +1 -1
  187. package/dist/src/planner/mutation/body-context.d.ts +23 -0
  188. package/dist/src/planner/mutation/body-context.d.ts.map +1 -0
  189. package/dist/src/planner/mutation/body-context.js +26 -0
  190. package/dist/src/planner/mutation/body-context.js.map +1 -0
  191. package/dist/src/planner/mutation/cte-flatten.js +15 -2
  192. package/dist/src/planner/mutation/cte-flatten.js.map +1 -1
  193. package/dist/src/planner/mutation/decomposition.d.ts +8 -0
  194. package/dist/src/planner/mutation/decomposition.d.ts.map +1 -1
  195. package/dist/src/planner/mutation/decomposition.js +8 -3
  196. package/dist/src/planner/mutation/decomposition.js.map +1 -1
  197. package/dist/src/planner/mutation/lens-enforcement.js +1 -1
  198. package/dist/src/planner/mutation/multi-source.d.ts +7 -0
  199. package/dist/src/planner/mutation/multi-source.d.ts.map +1 -1
  200. package/dist/src/planner/mutation/multi-source.js +5 -0
  201. package/dist/src/planner/mutation/multi-source.js.map +1 -1
  202. package/dist/src/planner/mutation/mutation-diagnostic.d.ts +1 -1
  203. package/dist/src/planner/mutation/mutation-diagnostic.d.ts.map +1 -1
  204. package/dist/src/planner/mutation/mutation-diagnostic.js.map +1 -1
  205. package/dist/src/planner/mutation/scope-transform.d.ts +32 -0
  206. package/dist/src/planner/mutation/scope-transform.d.ts.map +1 -1
  207. package/dist/src/planner/mutation/scope-transform.js +181 -33
  208. package/dist/src/planner/mutation/scope-transform.js.map +1 -1
  209. package/dist/src/planner/mutation/set-op.d.ts.map +1 -1
  210. package/dist/src/planner/mutation/set-op.js +66 -16
  211. package/dist/src/planner/mutation/set-op.js.map +1 -1
  212. package/dist/src/planner/mutation/single-source.d.ts.map +1 -1
  213. package/dist/src/planner/mutation/single-source.js +100 -24
  214. package/dist/src/planner/mutation/single-source.js.map +1 -1
  215. package/dist/src/planner/nodes/add-constraint-node.d.ts +15 -1
  216. package/dist/src/planner/nodes/add-constraint-node.d.ts.map +1 -1
  217. package/dist/src/planner/nodes/add-constraint-node.js +10 -1
  218. package/dist/src/planner/nodes/add-constraint-node.js.map +1 -1
  219. package/dist/src/planner/nodes/aggregate-node.d.ts +14 -5
  220. package/dist/src/planner/nodes/aggregate-node.d.ts.map +1 -1
  221. package/dist/src/planner/nodes/aggregate-node.js +28 -21
  222. package/dist/src/planner/nodes/aggregate-node.js.map +1 -1
  223. package/dist/src/planner/nodes/alter-table-node.d.ts +27 -2
  224. package/dist/src/planner/nodes/alter-table-node.d.ts.map +1 -1
  225. package/dist/src/planner/nodes/alter-table-node.js +49 -2
  226. package/dist/src/planner/nodes/alter-table-node.js.map +1 -1
  227. package/dist/src/planner/nodes/constraint-check-node.d.ts.map +1 -1
  228. package/dist/src/planner/nodes/constraint-check-node.js +17 -19
  229. package/dist/src/planner/nodes/constraint-check-node.js.map +1 -1
  230. package/dist/src/planner/nodes/create-assertion-node.d.ts +2 -1
  231. package/dist/src/planner/nodes/create-assertion-node.d.ts.map +1 -1
  232. package/dist/src/planner/nodes/create-assertion-node.js +5 -2
  233. package/dist/src/planner/nodes/create-assertion-node.js.map +1 -1
  234. package/dist/src/planner/nodes/cte-node.d.ts +19 -9
  235. package/dist/src/planner/nodes/cte-node.d.ts.map +1 -1
  236. package/dist/src/planner/nodes/cte-node.js +25 -9
  237. package/dist/src/planner/nodes/cte-node.js.map +1 -1
  238. package/dist/src/planner/nodes/delete-node.d.ts +20 -2
  239. package/dist/src/planner/nodes/delete-node.d.ts.map +1 -1
  240. package/dist/src/planner/nodes/delete-node.js +11 -2
  241. package/dist/src/planner/nodes/delete-node.js.map +1 -1
  242. package/dist/src/planner/nodes/dml-executor-node.d.ts +58 -1
  243. package/dist/src/planner/nodes/dml-executor-node.d.ts.map +1 -1
  244. package/dist/src/planner/nodes/dml-executor-node.js +107 -15
  245. package/dist/src/planner/nodes/dml-executor-node.js.map +1 -1
  246. package/dist/src/planner/nodes/drop-assertion-node.d.ts +2 -1
  247. package/dist/src/planner/nodes/drop-assertion-node.d.ts.map +1 -1
  248. package/dist/src/planner/nodes/drop-assertion-node.js +5 -2
  249. package/dist/src/planner/nodes/drop-assertion-node.js.map +1 -1
  250. package/dist/src/planner/nodes/filter.d.ts.map +1 -1
  251. package/dist/src/planner/nodes/filter.js +12 -6
  252. package/dist/src/planner/nodes/filter.js.map +1 -1
  253. package/dist/src/planner/nodes/hash-aggregate.d.ts +0 -5
  254. package/dist/src/planner/nodes/hash-aggregate.d.ts.map +1 -1
  255. package/dist/src/planner/nodes/hash-aggregate.js +17 -20
  256. package/dist/src/planner/nodes/hash-aggregate.js.map +1 -1
  257. package/dist/src/planner/nodes/insert-node.d.ts +19 -2
  258. package/dist/src/planner/nodes/insert-node.d.ts.map +1 -1
  259. package/dist/src/planner/nodes/insert-node.js +10 -2
  260. package/dist/src/planner/nodes/insert-node.js.map +1 -1
  261. package/dist/src/planner/nodes/key-set-semi-join-node.d.ts +42 -10
  262. package/dist/src/planner/nodes/key-set-semi-join-node.d.ts.map +1 -1
  263. package/dist/src/planner/nodes/key-set-semi-join-node.js +85 -16
  264. package/dist/src/planner/nodes/key-set-semi-join-node.js.map +1 -1
  265. package/dist/src/planner/nodes/lens-auxiliary-access-node.d.ts +5 -0
  266. package/dist/src/planner/nodes/lens-auxiliary-access-node.d.ts.map +1 -1
  267. package/dist/src/planner/nodes/lens-auxiliary-access-node.js.map +1 -1
  268. package/dist/src/planner/nodes/plan-node.d.ts +5 -0
  269. package/dist/src/planner/nodes/plan-node.d.ts.map +1 -1
  270. package/dist/src/planner/nodes/plan-node.js +12 -0
  271. package/dist/src/planner/nodes/plan-node.js.map +1 -1
  272. package/dist/src/planner/nodes/project-node.d.ts.map +1 -1
  273. package/dist/src/planner/nodes/project-node.js +16 -35
  274. package/dist/src/planner/nodes/project-node.js.map +1 -1
  275. package/dist/src/planner/nodes/retrieve-node.d.ts +16 -2
  276. package/dist/src/planner/nodes/retrieve-node.d.ts.map +1 -1
  277. package/dist/src/planner/nodes/retrieve-node.js +8 -1
  278. package/dist/src/planner/nodes/retrieve-node.js.map +1 -1
  279. package/dist/src/planner/nodes/returning-node.d.ts.map +1 -1
  280. package/dist/src/planner/nodes/returning-node.js +13 -32
  281. package/dist/src/planner/nodes/returning-node.js.map +1 -1
  282. package/dist/src/planner/nodes/stream-aggregate.d.ts +0 -5
  283. package/dist/src/planner/nodes/stream-aggregate.d.ts.map +1 -1
  284. package/dist/src/planner/nodes/stream-aggregate.js +18 -24
  285. package/dist/src/planner/nodes/stream-aggregate.js.map +1 -1
  286. package/dist/src/planner/nodes/table-access-nodes.d.ts +89 -1
  287. package/dist/src/planner/nodes/table-access-nodes.d.ts.map +1 -1
  288. package/dist/src/planner/nodes/table-access-nodes.js +64 -2
  289. package/dist/src/planner/nodes/table-access-nodes.js.map +1 -1
  290. package/dist/src/planner/nodes/update-node.d.ts +19 -2
  291. package/dist/src/planner/nodes/update-node.d.ts.map +1 -1
  292. package/dist/src/planner/nodes/update-node.js +10 -2
  293. package/dist/src/planner/nodes/update-node.js.map +1 -1
  294. package/dist/src/planner/optimizer.d.ts +18 -0
  295. package/dist/src/planner/optimizer.d.ts.map +1 -1
  296. package/dist/src/planner/optimizer.js +59 -10
  297. package/dist/src/planner/optimizer.js.map +1 -1
  298. package/dist/src/planner/planning-context.d.ts +24 -0
  299. package/dist/src/planner/planning-context.d.ts.map +1 -1
  300. package/dist/src/planner/planning-context.js.map +1 -1
  301. package/dist/src/planner/rules/access/rule-key-set-seek.d.ts +78 -20
  302. package/dist/src/planner/rules/access/rule-key-set-seek.d.ts.map +1 -1
  303. package/dist/src/planner/rules/access/rule-key-set-seek.js +297 -71
  304. package/dist/src/planner/rules/access/rule-key-set-seek.js.map +1 -1
  305. package/dist/src/planner/rules/access/rule-monotonic-range-access.d.ts.map +1 -1
  306. package/dist/src/planner/rules/access/rule-monotonic-range-access.js +2 -2
  307. package/dist/src/planner/rules/access/rule-monotonic-range-access.js.map +1 -1
  308. package/dist/src/planner/rules/access/rule-select-access-path.d.ts +11 -1
  309. package/dist/src/planner/rules/access/rule-select-access-path.d.ts.map +1 -1
  310. package/dist/src/planner/rules/access/rule-select-access-path.js +46 -2
  311. package/dist/src/planner/rules/access/rule-select-access-path.js.map +1 -1
  312. package/dist/src/planner/rules/aggregate/rule-groupby-fd-simplification.d.ts +7 -4
  313. package/dist/src/planner/rules/aggregate/rule-groupby-fd-simplification.d.ts.map +1 -1
  314. package/dist/src/planner/rules/aggregate/rule-groupby-fd-simplification.js +39 -5
  315. package/dist/src/planner/rules/aggregate/rule-groupby-fd-simplification.js.map +1 -1
  316. package/dist/src/planner/rules/cache/rule-cte-optimization.d.ts.map +1 -1
  317. package/dist/src/planner/rules/cache/rule-cte-optimization.js +6 -2
  318. package/dist/src/planner/rules/cache/rule-cte-optimization.js.map +1 -1
  319. package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.js +10 -3
  320. package/dist/src/planner/rules/cache/rule-materialized-view-rewrite.js.map +1 -1
  321. package/dist/src/planner/rules/join/index-nested-loop.d.ts.map +1 -1
  322. package/dist/src/planner/rules/join/index-nested-loop.js +13 -7
  323. package/dist/src/planner/rules/join/index-nested-loop.js.map +1 -1
  324. package/dist/src/planner/rules/join/rule-fanout-lookup-join.d.ts +4 -0
  325. package/dist/src/planner/rules/join/rule-fanout-lookup-join.d.ts.map +1 -1
  326. package/dist/src/planner/rules/join/rule-fanout-lookup-join.js +50 -15
  327. package/dist/src/planner/rules/join/rule-fanout-lookup-join.js.map +1 -1
  328. package/dist/src/planner/rules/join/rule-join-elimination.d.ts +6 -0
  329. package/dist/src/planner/rules/join/rule-join-elimination.d.ts.map +1 -1
  330. package/dist/src/planner/rules/join/rule-join-elimination.js +25 -9
  331. package/dist/src/planner/rules/join/rule-join-elimination.js.map +1 -1
  332. package/dist/src/planner/rules/join/rule-join-key-inference.d.ts +7 -0
  333. package/dist/src/planner/rules/join/rule-join-key-inference.d.ts.map +1 -1
  334. package/dist/src/planner/rules/join/rule-join-key-inference.js +23 -11
  335. package/dist/src/planner/rules/join/rule-join-key-inference.js.map +1 -1
  336. package/dist/src/planner/rules/join/rule-join-physical-selection.d.ts +2 -2
  337. package/dist/src/planner/rules/join/rule-join-physical-selection.d.ts.map +1 -1
  338. package/dist/src/planner/rules/join/rule-join-physical-selection.js +46 -16
  339. package/dist/src/planner/rules/join/rule-join-physical-selection.js.map +1 -1
  340. package/dist/src/planner/rules/join/rule-monotonic-merge-join.d.ts +2 -0
  341. package/dist/src/planner/rules/join/rule-monotonic-merge-join.d.ts.map +1 -1
  342. package/dist/src/planner/rules/join/rule-monotonic-merge-join.js +14 -0
  343. package/dist/src/planner/rules/join/rule-monotonic-merge-join.js.map +1 -1
  344. package/dist/src/planner/rules/predicate/rule-aggregate-predicate-pushdown.d.ts +2 -2
  345. package/dist/src/planner/rules/predicate/rule-aggregate-predicate-pushdown.d.ts.map +1 -1
  346. package/dist/src/planner/rules/predicate/rule-aggregate-predicate-pushdown.js +19 -22
  347. package/dist/src/planner/rules/predicate/rule-aggregate-predicate-pushdown.js.map +1 -1
  348. package/dist/src/planner/rules/predicate/rule-filter-selectivity.d.ts +33 -19
  349. package/dist/src/planner/rules/predicate/rule-filter-selectivity.d.ts.map +1 -1
  350. package/dist/src/planner/rules/predicate/rule-filter-selectivity.js +37 -18
  351. package/dist/src/planner/rules/predicate/rule-filter-selectivity.js.map +1 -1
  352. package/dist/src/planner/rules/predicate/rule-join-predicate-pushdown.d.ts +6 -3
  353. package/dist/src/planner/rules/predicate/rule-join-predicate-pushdown.d.ts.map +1 -1
  354. package/dist/src/planner/rules/predicate/rule-join-predicate-pushdown.js +6 -3
  355. package/dist/src/planner/rules/predicate/rule-join-predicate-pushdown.js.map +1 -1
  356. package/dist/src/planner/rules/predicate/rule-predicate-pushdown.d.ts.map +1 -1
  357. package/dist/src/planner/rules/predicate/rule-predicate-pushdown.js +11 -21
  358. package/dist/src/planner/rules/predicate/rule-predicate-pushdown.js.map +1 -1
  359. package/dist/src/planner/rules/shared/access-leaf.d.ts +16 -3
  360. package/dist/src/planner/rules/shared/access-leaf.d.ts.map +1 -1
  361. package/dist/src/planner/rules/shared/access-leaf.js +21 -5
  362. package/dist/src/planner/rules/shared/access-leaf.js.map +1 -1
  363. package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.js +1 -1
  364. package/dist/src/planner/rules/subquery/rule-anti-join-fk-empty.js.map +1 -1
  365. package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.js +1 -1
  366. package/dist/src/planner/rules/subquery/rule-semi-join-fk-trivial.js.map +1 -1
  367. package/dist/src/planner/stored-body-context.d.ts +57 -0
  368. package/dist/src/planner/stored-body-context.d.ts.map +1 -0
  369. package/dist/src/planner/stored-body-context.js +64 -0
  370. package/dist/src/planner/stored-body-context.js.map +1 -0
  371. package/dist/src/planner/util/ind-utils.d.ts +28 -20
  372. package/dist/src/planner/util/ind-utils.d.ts.map +1 -1
  373. package/dist/src/planner/util/ind-utils.js +36 -27
  374. package/dist/src/planner/util/ind-utils.js.map +1 -1
  375. package/dist/src/planner/util/key-utils.d.ts +19 -4
  376. package/dist/src/planner/util/key-utils.d.ts.map +1 -1
  377. package/dist/src/planner/util/key-utils.js +23 -7
  378. package/dist/src/planner/util/key-utils.js.map +1 -1
  379. package/dist/src/planner/util/output-names.d.ts +12 -0
  380. package/dist/src/planner/util/output-names.d.ts.map +1 -0
  381. package/dist/src/planner/util/output-names.js +20 -0
  382. package/dist/src/planner/util/output-names.js.map +1 -0
  383. package/dist/src/planner/util/row-estimates.d.ts +11 -0
  384. package/dist/src/planner/util/row-estimates.d.ts.map +1 -1
  385. package/dist/src/planner/util/row-estimates.js +28 -0
  386. package/dist/src/planner/util/row-estimates.js.map +1 -1
  387. package/dist/src/runtime/deferred-constraint-queue.d.ts.map +1 -1
  388. package/dist/src/runtime/deferred-constraint-queue.js +3 -2
  389. package/dist/src/runtime/deferred-constraint-queue.js.map +1 -1
  390. package/dist/src/runtime/emit/add-constraint.d.ts.map +1 -1
  391. package/dist/src/runtime/emit/add-constraint.js +22 -6
  392. package/dist/src/runtime/emit/add-constraint.js.map +1 -1
  393. package/dist/src/runtime/emit/alter-schema-event.d.ts +59 -4
  394. package/dist/src/runtime/emit/alter-schema-event.d.ts.map +1 -1
  395. package/dist/src/runtime/emit/alter-schema-event.js +63 -4
  396. package/dist/src/runtime/emit/alter-schema-event.js.map +1 -1
  397. package/dist/src/runtime/emit/alter-table.d.ts.map +1 -1
  398. package/dist/src/runtime/emit/alter-table.js +212 -92
  399. package/dist/src/runtime/emit/alter-table.js.map +1 -1
  400. package/dist/src/runtime/emit/analyze.d.ts.map +1 -1
  401. package/dist/src/runtime/emit/analyze.js +15 -4
  402. package/dist/src/runtime/emit/analyze.js.map +1 -1
  403. package/dist/src/runtime/emit/assertion-drop-guard.d.ts +37 -0
  404. package/dist/src/runtime/emit/assertion-drop-guard.d.ts.map +1 -0
  405. package/dist/src/runtime/emit/assertion-drop-guard.js +59 -0
  406. package/dist/src/runtime/emit/assertion-drop-guard.js.map +1 -0
  407. package/dist/src/runtime/emit/assertion-rename-helpers.d.ts +33 -0
  408. package/dist/src/runtime/emit/assertion-rename-helpers.d.ts.map +1 -0
  409. package/dist/src/runtime/emit/assertion-rename-helpers.js +124 -0
  410. package/dist/src/runtime/emit/assertion-rename-helpers.js.map +1 -0
  411. package/dist/src/runtime/emit/constraint-check.d.ts.map +1 -1
  412. package/dist/src/runtime/emit/constraint-check.js +10 -227
  413. package/dist/src/runtime/emit/constraint-check.js.map +1 -1
  414. package/dist/src/runtime/emit/create-assertion.d.ts.map +1 -1
  415. package/dist/src/runtime/emit/create-assertion.js +31 -14
  416. package/dist/src/runtime/emit/create-assertion.js.map +1 -1
  417. package/dist/src/runtime/emit/cte.d.ts.map +1 -1
  418. package/dist/src/runtime/emit/cte.js +11 -6
  419. package/dist/src/runtime/emit/cte.js.map +1 -1
  420. package/dist/src/runtime/emit/dml-executor.d.ts.map +1 -1
  421. package/dist/src/runtime/emit/dml-executor.js +169 -1
  422. package/dist/src/runtime/emit/dml-executor.js.map +1 -1
  423. package/dist/src/runtime/emit/drop-assertion.js +8 -8
  424. package/dist/src/runtime/emit/drop-assertion.js.map +1 -1
  425. package/dist/src/runtime/emit/drop-column-guards.d.ts +151 -0
  426. package/dist/src/runtime/emit/drop-column-guards.d.ts.map +1 -0
  427. package/dist/src/runtime/emit/drop-column-guards.js +230 -0
  428. package/dist/src/runtime/emit/drop-column-guards.js.map +1 -0
  429. package/dist/src/runtime/emit/drop-table.d.ts.map +1 -1
  430. package/dist/src/runtime/emit/drop-table.js +6 -0
  431. package/dist/src/runtime/emit/drop-table.js.map +1 -1
  432. package/dist/src/runtime/emit/drop-view.d.ts.map +1 -1
  433. package/dist/src/runtime/emit/drop-view.js +4 -0
  434. package/dist/src/runtime/emit/drop-view.js.map +1 -1
  435. package/dist/src/runtime/emit/key-set-semi-join.d.ts.map +1 -1
  436. package/dist/src/runtime/emit/key-set-semi-join.js +5 -3
  437. package/dist/src/runtime/emit/key-set-semi-join.js.map +1 -1
  438. package/dist/src/runtime/emit/materialized-view-helpers.d.ts +4 -4
  439. package/dist/src/runtime/emit/materialized-view-helpers.d.ts.map +1 -1
  440. package/dist/src/runtime/emit/materialized-view-helpers.js +34 -22
  441. package/dist/src/runtime/emit/materialized-view-helpers.js.map +1 -1
  442. package/dist/src/runtime/emit/materialized-view.d.ts.map +1 -1
  443. package/dist/src/runtime/emit/materialized-view.js +7 -2
  444. package/dist/src/runtime/emit/materialized-view.js.map +1 -1
  445. package/dist/src/runtime/emit/recursive-cte.d.ts.map +1 -1
  446. package/dist/src/runtime/emit/recursive-cte.js +4 -5
  447. package/dist/src/runtime/emit/recursive-cte.js.map +1 -1
  448. package/dist/src/runtime/emit/update.d.ts.map +1 -1
  449. package/dist/src/runtime/emit/update.js +18 -6
  450. package/dist/src/runtime/emit/update.js.map +1 -1
  451. package/dist/src/runtime/row-constraints.d.ts +85 -0
  452. package/dist/src/runtime/row-constraints.d.ts.map +1 -0
  453. package/dist/src/runtime/row-constraints.js +239 -0
  454. package/dist/src/runtime/row-constraints.js.map +1 -0
  455. package/dist/src/runtime/types.d.ts +8 -11
  456. package/dist/src/runtime/types.d.ts.map +1 -1
  457. package/dist/src/runtime/types.js.map +1 -1
  458. package/dist/src/schema/assertion.d.ts +14 -1
  459. package/dist/src/schema/assertion.d.ts.map +1 -1
  460. package/dist/src/schema/assertion.js +14 -1
  461. package/dist/src/schema/assertion.js.map +1 -1
  462. package/dist/src/schema/catalog-persistability.js +19 -3
  463. package/dist/src/schema/catalog-persistability.js.map +1 -1
  464. package/dist/src/schema/catalog.d.ts +6 -0
  465. package/dist/src/schema/catalog.d.ts.map +1 -1
  466. package/dist/src/schema/catalog.js +26 -36
  467. package/dist/src/schema/catalog.js.map +1 -1
  468. package/dist/src/schema/column-source-resolver.d.ts +18 -0
  469. package/dist/src/schema/column-source-resolver.d.ts.map +1 -0
  470. package/dist/src/schema/column-source-resolver.js +22 -0
  471. package/dist/src/schema/column-source-resolver.js.map +1 -0
  472. package/dist/src/schema/constraint-builder.d.ts.map +1 -1
  473. package/dist/src/schema/constraint-builder.js +7 -1
  474. package/dist/src/schema/constraint-builder.js.map +1 -1
  475. package/dist/src/schema/ddl-generator.js +8 -0
  476. package/dist/src/schema/ddl-generator.js.map +1 -1
  477. package/dist/src/schema/lens-compiler.d.ts.map +1 -1
  478. package/dist/src/schema/lens-compiler.js +203 -51
  479. package/dist/src/schema/lens-compiler.js.map +1 -1
  480. package/dist/src/schema/lens-prover.d.ts +2 -3
  481. package/dist/src/schema/lens-prover.d.ts.map +1 -1
  482. package/dist/src/schema/lens-prover.js +19 -11
  483. package/dist/src/schema/lens-prover.js.map +1 -1
  484. package/dist/src/schema/manager.d.ts +30 -12
  485. package/dist/src/schema/manager.d.ts.map +1 -1
  486. package/dist/src/schema/manager.js +49 -17
  487. package/dist/src/schema/manager.js.map +1 -1
  488. package/dist/src/schema/rename-rewriter.d.ts +142 -0
  489. package/dist/src/schema/rename-rewriter.d.ts.map +1 -1
  490. package/dist/src/schema/rename-rewriter.js +254 -9
  491. package/dist/src/schema/rename-rewriter.js.map +1 -1
  492. package/dist/src/schema/reserved-tags.d.ts +1 -1
  493. package/dist/src/schema/reserved-tags.d.ts.map +1 -1
  494. package/dist/src/schema/reserved-tags.js +4 -3
  495. package/dist/src/schema/reserved-tags.js.map +1 -1
  496. package/dist/src/schema/schema-differ.d.ts +16 -0
  497. package/dist/src/schema/schema-differ.d.ts.map +1 -1
  498. package/dist/src/schema/schema-differ.js +122 -11
  499. package/dist/src/schema/schema-differ.js.map +1 -1
  500. package/dist/src/schema/view.d.ts +11 -0
  501. package/dist/src/schema/view.d.ts.map +1 -1
  502. package/dist/src/schema/view.js +12 -0
  503. package/dist/src/schema/view.js.map +1 -1
  504. package/dist/src/types/builtin-types.d.ts +38 -0
  505. package/dist/src/types/builtin-types.d.ts.map +1 -1
  506. package/dist/src/types/builtin-types.js +77 -26
  507. package/dist/src/types/builtin-types.js.map +1 -1
  508. package/dist/src/types/index.d.ts +1 -1
  509. package/dist/src/types/index.d.ts.map +1 -1
  510. package/dist/src/types/index.js +1 -1
  511. package/dist/src/types/index.js.map +1 -1
  512. package/dist/src/util/{working-table-iterable.d.ts → array-row-iterable.d.ts} +6 -6
  513. package/dist/src/util/array-row-iterable.d.ts.map +1 -0
  514. package/dist/src/util/{working-table-iterable.js → array-row-iterable.js} +6 -6
  515. package/dist/src/util/array-row-iterable.js.map +1 -0
  516. package/dist/src/vtab/events.d.ts +3 -0
  517. package/dist/src/vtab/events.d.ts.map +1 -1
  518. package/dist/src/vtab/events.js.map +1 -1
  519. package/dist/src/vtab/manifest.d.ts +15 -0
  520. package/dist/src/vtab/manifest.d.ts.map +1 -1
  521. package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
  522. package/dist/src/vtab/memory/layer/manager.js +3 -69
  523. package/dist/src/vtab/memory/layer/manager.js.map +1 -1
  524. package/dist/src/vtab/memory/module.d.ts +16 -1
  525. package/dist/src/vtab/memory/module.d.ts.map +1 -1
  526. package/dist/src/vtab/memory/module.js +62 -2
  527. package/dist/src/vtab/memory/module.js.map +1 -1
  528. package/dist/src/vtab/module.d.ts +26 -2
  529. package/dist/src/vtab/module.d.ts.map +1 -1
  530. package/dist/src/vtab/table.d.ts +8 -1
  531. package/dist/src/vtab/table.d.ts.map +1 -1
  532. package/dist/src/vtab/table.js.map +1 -1
  533. package/package.json +3 -3
  534. package/dist/src/util/working-table-iterable.d.ts.map +0 -1
  535. package/dist/src/util/working-table-iterable.js.map +0 -1
@@ -11,12 +11,14 @@ import { StatusCode } from '../../common/types.js';
11
11
  import { CapabilityDetectors } from '../framework/characteristics.js';
12
12
  import { resolveFunctionSchema } from './schema-resolution.js';
13
13
  import { isAggregateFunctionSchema } from '../../schema/function.js';
14
- import { expressionToString } from '../../emit/ast-stringify.js';
15
- import { resolveOrdinalReference } from './select-ordinal.js';
14
+ import { expressionToString, expressionToIdentityString } from '../../emit/ast-stringify.js';
15
+ import { buildOrdinalAwareExpression, resolveOrdinalReference } from './select-ordinal.js';
16
+ import { collectDefinedAttrIds } from '../analysis/equi-correlation.js';
17
+ import { PlanNodeType } from '../nodes/plan-node-type.js';
16
18
  /**
17
19
  * Processes GROUP BY, aggregates, and HAVING clauses
18
20
  */
19
- export function buildAggregatePhase(input, stmt, selectContext, aggregates, hasAggregates, projections, hasWrappedAggregates = false, selectListAsts = []) {
21
+ export function buildAggregatePhase(input, stmt, selectContext, aggregates, hasAggregates, projections, hasWrappedAggregates = false, selectList = [], starProjectionsByColumn = new Map()) {
20
22
  const hasGroupBy = stmt.groupBy && stmt.groupBy.length > 0;
21
23
  // Pre-collect aggregate functions from the HAVING clause that are not already
22
24
  // present in the SELECT list. These need to be added to the AggregateNode so
@@ -35,7 +37,7 @@ export function buildAggregatePhase(input, stmt, selectContext, aggregates, hasA
35
37
  // or has a GROUP BY). When legal, any ORDER BY aggregate not already present
36
38
  // in the SELECT or HAVING aggregate list must be added to the AggregateNode
37
39
  // so it is computed and available to the post-aggregate sort.
38
- const orderByHasAggregates = orderByContainsAggregates(stmt.orderBy, selectContext);
40
+ const orderByHasAggregates = orderByContainsAggregates(stmt.orderBy, selectContext, selectList);
39
41
  let hasOrderByOnlyAggregates = false;
40
42
  if (orderByHasAggregates && (hasAggregates || hasGroupBy)) {
41
43
  const orderByAggs = collectOrderByAggregates(stmt.orderBy, selectContext, aggregates);
@@ -73,13 +75,10 @@ export function buildAggregatePhase(input, stmt, selectContext, aggregates, hasA
73
75
  // ORDER BY contains aggregates — those need to run against the post-aggregate
74
76
  // row(s), not the per-input rows.
75
77
  const preAggregateSort = Boolean(hasAggregates && !hasGroupBy && stmt.orderBy && stmt.orderBy.length > 0 && !orderByHasAggregates);
76
- currentInput = handlePreAggregateSort(currentInput, stmt, selectContext, hasAggregates, !!hasGroupBy, orderByHasAggregates, selectListAsts);
78
+ currentInput = handlePreAggregateSort(currentInput, stmt, selectContext, hasAggregates, !!hasGroupBy, orderByHasAggregates, selectList);
77
79
  // Build GROUP BY expressions, resolving 1-based positional references against the SELECT list.
78
80
  const groupByExpressions = stmt.groupBy ?
79
- stmt.groupBy.map(expr => {
80
- const resolved = resolveOrdinalReference(expr, selectListAsts, 'GROUP BY');
81
- return buildExpression(selectContext, resolved ?? expr, false);
82
- }) : [];
81
+ stmt.groupBy.map(expr => buildOrdinalAwareExpression(selectContext, expr, selectList, 'GROUP BY', false)) : [];
83
82
  // Validate aggregate/non-aggregate mixing (must run after groupByExpressions are built
84
83
  // so we can check column-coverage of SELECT projections against GROUP BY)
85
84
  validateAggregateProjections(projections, hasAggregates, !!hasGroupBy, groupByExpressions);
@@ -118,12 +117,14 @@ export function buildAggregatePhase(input, stmt, selectContext, aggregates, hasA
118
117
  // every grouped query changes the plan shape of a grouped materialized-view body
119
118
  // (`select k, count(*), sum(a) … group by k`) and re-routes its incremental
120
119
  // maintenance from residual-recompute to full-rebuild — see
121
- // test/incremental/delta-aggregate.spec.ts. It is also why an aggregate-only
122
- // select list still leaks its grouping key into the output
123
- // (backlog/bug-grouped-aggregate-only-select-returns-extra-column); fixing that
124
- // means reconciling the projection with maintenance routing, not just dropping
125
- // this guard.
126
- || Boolean(hasGroupBy && !hasAggregates && projections.length > 0);
120
+ // test/incremental/delta-aggregate.spec.ts. So the aggregate case is decided by
121
+ // exact shape agreement instead (`aggregateOutputIsSelectList` below), which
122
+ // leaves that body's bare-aggregate plan intact.
123
+ || Boolean(hasGroupBy && !hasAggregates && projections.length > 0)
124
+ // With aggregates present the AggregateNode may still be the root of the query.
125
+ // That is only sound when its own output already IS the select list; otherwise
126
+ // the grouping keys it advertises leak into (or reorder) the result.
127
+ || !aggregateOutputIsSelectList(stmt, projections, aggregates, groupByExpressions, starProjectionsByColumn, selectContext);
127
128
  return {
128
129
  output: currentInput,
129
130
  aggregateScope: aggregateOutputScope,
@@ -140,15 +141,16 @@ export function buildAggregatePhase(input, stmt, selectContext, aggregates, hasA
140
141
  /**
141
142
  * Handles pre-aggregate sorting for special cases
142
143
  */
143
- function handlePreAggregateSort(input, stmt, selectContext, hasAggregates, hasGroupBy, orderByHasAggregates, selectListAsts) {
144
+ function handlePreAggregateSort(input, stmt, selectContext, hasAggregates, hasGroupBy, orderByHasAggregates, selectList) {
144
145
  // Special handling for ORDER BY with aggregates but no GROUP BY.
145
146
  // Skip when ORDER BY itself references aggregates — those must run
146
147
  // post-aggregation, not on the per-row input.
147
148
  if (hasAggregates && !hasGroupBy && stmt.orderBy && stmt.orderBy.length > 0 && !orderByHasAggregates) {
148
- // Apply ORDER BY before aggregation
149
+ // Apply ORDER BY before aggregation. This sort sits BELOW the AggregateNode,
150
+ // so a positional reference resolves through the select list (no output
151
+ // attributes exist yet to bind to).
149
152
  const sortKeys = stmt.orderBy.map(orderByClause => {
150
- const resolved = resolveOrdinalReference(orderByClause.expr, selectListAsts, 'ORDER BY');
151
- const expression = buildExpression(selectContext, resolved ?? orderByClause.expr);
153
+ const expression = buildOrdinalAwareExpression(selectContext, orderByClause.expr, selectList, 'ORDER BY');
152
154
  return {
153
155
  expression,
154
156
  direction: orderByClause.direction,
@@ -159,6 +161,254 @@ function handlePreAggregateSort(input, stmt, selectContext, hasAggregates, hasGr
159
161
  }
160
162
  return input;
161
163
  }
164
+ /**
165
+ * Builds the coverage test for a grouped query. `groupedOutputAttributes` is the
166
+ * AggregateNode's output attributes (group keys followed by aggregate results),
167
+ * needed only when the expressions to be checked were built against the aggregate
168
+ * output scope.
169
+ */
170
+ export function buildGroupByCoverage(groupByExpressions, groupedOutputAttributes = []) {
171
+ const attrIds = new Set();
172
+ const fingerprints = new Set();
173
+ for (const expr of groupByExpressions) {
174
+ if (CapabilityDetectors.isColumnReference(expr)) {
175
+ attrIds.add(expr.attributeId);
176
+ }
177
+ fingerprints.add(expressionToIdentityString(expr.expression));
178
+ }
179
+ for (const attr of groupedOutputAttributes) {
180
+ attrIds.add(attr.id);
181
+ }
182
+ return { attrIds, fingerprints };
183
+ }
184
+ /**
185
+ * Raises the standard GROUP BY coverage error when `node` reads a column the
186
+ * grouped rows do not carry. Used by the SELECT-list check below; the window
187
+ * phase raises the same message from {@link assertGroupedWindowCoverage}.
188
+ */
189
+ export function assertGroupByCoverage(node, coverage) {
190
+ const ungrouped = findUngroupedColumnRef(node, coverage);
191
+ if (!ungrouped)
192
+ return;
193
+ throw new QuereusError(`Column '${expressionToString(ungrouped.expression)}' must appear in the GROUP BY clause or be used in an aggregate function`, StatusCode.ERROR, undefined, ungrouped.expression.loc?.start.line, ungrouped.expression.loc?.start.column);
194
+ }
195
+ /**
196
+ * Builds the {@link GroupKeyIndex} for a grouped query's GROUP BY list. The output
197
+ * column index is the key's position in that list, which is its position on the
198
+ * AggregateNode's output row.
199
+ */
200
+ export function indexGroupKeys(groupByExpressions) {
201
+ const byFingerprint = new Map();
202
+ const byBaseAttrId = new Map();
203
+ groupByExpressions.forEach((expr, index) => {
204
+ const fp = expressionToIdentityString(expr.expression);
205
+ if (!byFingerprint.has(fp))
206
+ byFingerprint.set(fp, index);
207
+ if (CapabilityDetectors.isColumnReference(expr)) {
208
+ const attrId = expr.attributeId;
209
+ if (!byBaseAttrId.has(attrId))
210
+ byBaseAttrId.set(attrId, index);
211
+ }
212
+ });
213
+ return { byFingerprint, byBaseAttrId };
214
+ }
215
+ /**
216
+ * Builds the {@link GroupedWindowContext} for a grouped, windowed query.
217
+ * `outputAttributes` is the AggregateNode's attribute list (group keys in GROUP BY
218
+ * order, then the aggregate results); `aggregateInput` is the AggregateNode's
219
+ * source relation, whose whole subtree defines
220
+ * {@link GroupedWindowContext.aggregateInputAttrIds}.
221
+ */
222
+ export function buildGroupedWindowContext(groupByExpressions, outputAttributes, aggregateInput) {
223
+ return {
224
+ groupKeys: indexGroupKeys(groupByExpressions),
225
+ outputAttributes,
226
+ aggregateInputAttrIds: collectDefinedAttrIds(aggregateInput, child => !isCteDefinition(child)),
227
+ outputAttrIds: new Set(outputAttributes.map(attr => attr.id)),
228
+ };
229
+ }
230
+ /**
231
+ * True for a CTE *definition* — the node a `with` clause builds once and every
232
+ * reference to that CTE then points at, as opposed to the per-reference
233
+ * CTEReferenceNode that mints its own attribute ids.
234
+ *
235
+ * Two consequences for the window phase, and one shape that needs both. A CTE body
236
+ * is a closed scope: it cannot name a column of the query that references it, so
237
+ * nothing inside it is ever a reference to this query's grouping key. And the SAME
238
+ * body node is reachable from this query's FROM clause and from a subquery inside a
239
+ * window specification that references the same CTE, so counting its internal
240
+ * attribute ids as this query's pre-grouping columns makes the body's own columns
241
+ * look ungrouped:
242
+ *
243
+ * with c as (select a, b from wg where b <> '')
244
+ * select a, row_number() over (order by (select count(*) from c z)) from c group by a
245
+ *
246
+ * — which rejected at plan time with "Column 'b' must appear in the GROUP BY clause",
247
+ * naming a column the user never wrote in the window specification.
248
+ */
249
+ function isCteDefinition(node) {
250
+ return node.nodeType === PlanNodeType.CTE || node.nodeType === PlanNodeType.RecursiveCTE;
251
+ }
252
+ /**
253
+ * Rewrites every subtree of a window specification / window-function argument that
254
+ * IS a grouping key into a reference to the AggregateNode's output column for that
255
+ * key, so the expression reads the grouped row instead of a base-table column that
256
+ * row does not carry.
257
+ *
258
+ * Two match rules, in order at each node:
259
+ *
260
+ * 1. The whole subtree's identity fingerprint equals a GROUP BY expression's — covers
261
+ * `group by a || '!'` + `over (order by a || '!')`, and nested occurrences such
262
+ * as `over (order by upper(a || '!'))` because the walk recurses. Identifier case
263
+ * is folded, so `group by A || '!'` matches too; quoted literals are byte-exact,
264
+ * so `a || 'X'` and `a || 'x'` remain different keys.
265
+ *
266
+ * Unconditional above any subquery, where the expression is written in this query's
267
+ * own scope. INSIDE a subquery it is guarded by {@link readsOnlyAggregateInput} —
268
+ * every column reference in the subtree must be a pre-grouping column of THIS query
269
+ * — because there the same text can name something else entirely: under `group by
270
+ * a`, a bare `a` written inside `over (order by (select … where t.a = a))` names the
271
+ * subquery's own `t.a` and yet fingerprints as `a`, so an unguarded rule 1 would
272
+ * silently rewrite it into the outer group column and change what the query means.
273
+ * The guard cannot replace the top-level case: `group by (select max(t.b) from wg t
274
+ * where t.a = wg.a)` repeated verbatim in the specification is a legal grouping key
275
+ * whose subtree also reads the subquery's own columns.
276
+ * 2. The node is a column reference whose attribute id is the *base* attribute id of
277
+ * a bare-column grouping key — covers `group by a` + `over (order by wg.a)` and
278
+ * `over (order by w.a)`. Both spellings fall through to the same base attribute
279
+ * the group key was built from, so the match is qualifier-independent. It needs no
280
+ * guard at any depth: attribute ids are minted per relation instance, so only a
281
+ * reference that genuinely resolves to this query's grouping column can match.
282
+ *
283
+ * Otherwise recurse into every child, relational ones included, rebuilding through
284
+ * `withChildren` — a correlated reference to a grouping key can live arbitrarily deep
285
+ * inside a subquery in the window specification, and it must be redirected there too
286
+ * or it reaches the runtime as a base-table attribute the grouped row never carried.
287
+ *
288
+ * NOTE: rule 1 matches by AST text, so a subtree that *reads* like a grouping key but
289
+ * resolves to something else could be redirected wrongly. Within one query the guard
290
+ * above closes that off; the residue is a subtree of ENCLOSING-query references that
291
+ * happens to spell a grouping key (`group by a` in an inner query whose window spec
292
+ * says `outer_alias.a`… only when that fingerprints identically). This is the same
293
+ * limitation the select list already carries through the shared {@link GroupKeyIndex};
294
+ * fixing it means comparing resolved attribute identity rather than text, for both
295
+ * callers at once.
296
+ */
297
+ export function redirectToGroupKeys(node, context, scope) {
298
+ return redirectNode(node, context, scope);
299
+ }
300
+ /**
301
+ * {@link redirectToGroupKeys} over any plan node — the walk crosses relational
302
+ * boundaries, so it cannot be typed scalar-to-scalar throughout.
303
+ *
304
+ * `insideSubquery` records whether the walk has crossed a relational child; it gates
305
+ * rule 1 (see {@link redirectToGroupKeys}).
306
+ *
307
+ * NOTE: this renders an identity fingerprint at every scalar node it visits, and a
308
+ * fingerprint hit inside a subquery then walks that node's subtree again for the guard
309
+ * — so a window specification containing a large subquery costs more to build than
310
+ * before, once per prepare of the query. Not measured; if preparing such queries ever
311
+ * shows up as slow, memoize the fingerprint per node or bail out of the walk for
312
+ * subtrees that contain no `aggregateInputAttrIds` reference at all.
313
+ */
314
+ function redirectNode(node, context, scope, insideSubquery = false) {
315
+ if ('expression' in node) {
316
+ const expression = node.expression;
317
+ const fingerprintIndex = context.groupKeys.byFingerprint.get(expressionToIdentityString(expression));
318
+ if (fingerprintIndex !== undefined && (!insideSubquery || readsOnlyAggregateInput(node, context))) {
319
+ return buildGroupKeyColumnRef(scope, context.outputAttributes[fingerprintIndex], expression, fingerprintIndex);
320
+ }
321
+ if (CapabilityDetectors.isColumnReference(node)) {
322
+ const baseIndex = context.groupKeys.byBaseAttrId.get(node.attributeId);
323
+ if (baseIndex !== undefined) {
324
+ return buildGroupKeyColumnRef(scope, context.outputAttributes[baseIndex], expression, baseIndex);
325
+ }
326
+ return node;
327
+ }
328
+ }
329
+ const newChildren = [];
330
+ let changed = false;
331
+ for (const child of node.getChildren()) {
332
+ // A CTE definition holds nothing this walk could legally rewrite, and is shared
333
+ // with the rest of the plan — descending would fingerprint its whole body for
334
+ // nothing. See {@link isCteDefinition}.
335
+ const rewritten = isCteDefinition(child)
336
+ ? child
337
+ : redirectNode(child, context, scope, insideSubquery || isRelationalNode(child));
338
+ if (rewritten !== child)
339
+ changed = true;
340
+ newChildren.push(rewritten);
341
+ }
342
+ return changed ? node.withChildren(newChildren) : node;
343
+ }
344
+ /**
345
+ * True when every column reference in `node`'s subtree names a column the grouped
346
+ * query could have read before it grouped — i.e. the whole subtree belongs to THIS
347
+ * query rather than to a subquery inside it or to an enclosing query. A subtree with
348
+ * no column references at all (a constant) trivially qualifies.
349
+ */
350
+ function readsOnlyAggregateInput(node, context) {
351
+ if (CapabilityDetectors.isColumnReference(node)) {
352
+ return context.aggregateInputAttrIds.has(node.attributeId);
353
+ }
354
+ for (const child of node.getChildren()) {
355
+ if (!readsOnlyAggregateInput(child, context))
356
+ return false;
357
+ }
358
+ return true;
359
+ }
360
+ /**
361
+ * Raises the GROUP BY coverage error for a window specification / window-function
362
+ * argument of a GROUPED query that still reads a pre-grouping column after
363
+ * {@link redirectToGroupKeys} has run.
364
+ *
365
+ * Distinct from {@link assertGroupByCoverage} in exactly two ways, both required by
366
+ * the fact that a window expression may contain a subquery:
367
+ *
368
+ * - it descends into relational children, so a correlated reference buried in a
369
+ * subquery is checked rather than skipped;
370
+ * - it flags a column reference only when the attribute id is one of THIS query's
371
+ * pre-grouping columns. A reference to anything else — the subquery's own columns,
372
+ * or a correlated reference to an enclosing query — is legal here and is left alone.
373
+ *
374
+ * The aggregate exemption is likewise narrowed to this query's OWN aggregates; see
375
+ * {@link findUngroupedWindowColumnRef}.
376
+ */
377
+ export function assertGroupedWindowCoverage(node, context) {
378
+ const ungrouped = findUngroupedWindowColumnRef(node, context);
379
+ if (!ungrouped)
380
+ return;
381
+ throw new QuereusError(`Column '${expressionToString(ungrouped.expression)}' must appear in the GROUP BY clause or be used in an aggregate function`, StatusCode.ERROR, undefined, ungrouped.expression.loc?.start.line, ungrouped.expression.loc?.start.column);
382
+ }
383
+ /**
384
+ * The first pre-grouping column reference in `node` that the grouped row cannot carry.
385
+ *
386
+ * `insideSubquery` tracks whether the walk has crossed into a relational child, and
387
+ * gates the aggregate exemption. THIS query's own aggregates read pre-grouping columns
388
+ * by definition (`over (order by count(b) desc)` against a select list that computes
389
+ * `count(b)`), and those sit at the top level. An aggregate reached through a subquery
390
+ * belongs to the subquery, and its arguments may correlate back out — `over (order by
391
+ * (select max(wg.b) from wg t))` reads an ungrouped column of this query and must say
392
+ * so at plan time, not die at runtime with "No row context found for column b".
393
+ */
394
+ function findUngroupedWindowColumnRef(node, context, insideSubquery = false) {
395
+ if (!insideSubquery && CapabilityDetectors.isAggregateFunction(node)) {
396
+ return null;
397
+ }
398
+ if (CapabilityDetectors.isColumnReference(node)) {
399
+ const attrId = node.attributeId;
400
+ const ungrouped = context.aggregateInputAttrIds.has(attrId) && !context.outputAttrIds.has(attrId);
401
+ return ungrouped ? node : null;
402
+ }
403
+ for (const child of node.getChildren()) {
404
+ if (isCteDefinition(child))
405
+ continue;
406
+ const found = findUngroupedWindowColumnRef(child, context, insideSubquery || isRelationalNode(child));
407
+ if (found)
408
+ return found;
409
+ }
410
+ return null;
411
+ }
162
412
  /**
163
413
  * Validates that aggregate and non-aggregate projections don't mix inappropriately.
164
414
  * With GROUP BY, every non-aggregate column reference in the SELECT list must
@@ -175,19 +425,11 @@ function validateAggregateProjections(projections, hasAggregates, hasGroupBy, gr
175
425
  }
176
426
  if (!hasGroupBy)
177
427
  return;
178
- const groupByAttrIds = new Set();
179
- const groupByExprFingerprints = new Set();
180
- for (const expr of groupByExpressions) {
181
- if (CapabilityDetectors.isColumnReference(expr)) {
182
- groupByAttrIds.add(expr.attributeId);
183
- }
184
- groupByExprFingerprints.add(expressionToString(expr.expression));
185
- }
428
+ // The SELECT list is built against the pre-aggregate scope, so no aggregate
429
+ // output attributes participate.
430
+ const coverage = buildGroupByCoverage(groupByExpressions);
186
431
  for (const proj of projections) {
187
- const ungrouped = findUngroupedColumnRef(proj.node, groupByAttrIds, groupByExprFingerprints);
188
- if (ungrouped) {
189
- throw new QuereusError('Cannot mix aggregate and non-aggregate columns in SELECT list without GROUP BY', StatusCode.ERROR);
190
- }
432
+ assertGroupByCoverage(proj.node, coverage);
191
433
  }
192
434
  }
193
435
  /**
@@ -197,18 +439,18 @@ function validateAggregateProjections(projections, hasAggregates, hasGroupBy, gr
197
439
  * resolve their own scope), or any subtree whose AST fingerprint matches a GROUP BY
198
440
  * expression (the whole subtree is grouped, e.g. SELECT id+1 ... GROUP BY id+1).
199
441
  */
200
- function findUngroupedColumnRef(node, groupByAttrIds, groupByExprFingerprints) {
442
+ function findUngroupedColumnRef(node, coverage) {
201
443
  if (CapabilityDetectors.isAggregateFunction(node)) {
202
444
  return null;
203
445
  }
204
446
  if ('expression' in node) {
205
- const fp = expressionToString(node.expression);
206
- if (groupByExprFingerprints.has(fp)) {
447
+ const fp = expressionToIdentityString(node.expression);
448
+ if (coverage.fingerprints.has(fp)) {
207
449
  return null;
208
450
  }
209
451
  }
210
452
  if (CapabilityDetectors.isColumnReference(node)) {
211
- if (!groupByAttrIds.has(node.attributeId)) {
453
+ if (!coverage.attrIds.has(node.attributeId)) {
212
454
  return node;
213
455
  }
214
456
  return null;
@@ -216,7 +458,7 @@ function findUngroupedColumnRef(node, groupByAttrIds, groupByExprFingerprints) {
216
458
  for (const child of node.getChildren()) {
217
459
  if (isRelationalNode(child))
218
460
  continue;
219
- const found = findUngroupedColumnRef(child, groupByAttrIds, groupByExprFingerprints);
461
+ const found = findUngroupedColumnRef(child, coverage);
220
462
  if (found)
221
463
  return found;
222
464
  }
@@ -289,6 +531,16 @@ function createAggregateOutputScope(parentScope, aggregateNode, groupByExpressio
289
531
  });
290
532
  // Register aggregate columns by their aliases. An alias colliding with a
291
533
  // group-key base name (or another alias) is ambiguous as a bare reference.
534
+ //
535
+ // NOTE: an un-aliased aggregate's `alias` is its whole rendered expression, and
536
+ // this key is lowercased — so two aggregates differing only in a quoted literal's
537
+ // case (`count(nullif(b,'A'))` / `count(nullif(b,'a'))`) register one ambiguous
538
+ // key here even though they are correctly distinct aggregates. Harmless today:
539
+ // nothing resolves an aggregate through this scope by its rendered text (HAVING /
540
+ // ORDER BY / window specs go through `findMatchingAggregate`, which compares
541
+ // literal-exact identity strings), and only a quoted identifier spelled exactly
542
+ // like the rendering could reach it. If such a lookup path is ever added, key
543
+ // these registrations off `expressionToIdentityString` instead of `toLowerCase`.
292
544
  aggregates.forEach((agg, index) => {
293
545
  const columnIndex = groupByExpressions.length + index;
294
546
  const attr = aggregateAttributes[columnIndex];
@@ -363,24 +615,101 @@ function buildHavingFilter(input, havingClause, selectContext, aggregateOutputSc
363
615
  // source columns (registered as a fallback) land on source attribute IDs.
364
616
  // We accept both flavors of "grouped" attribute, plus any subtree whose AST
365
617
  // fingerprint matches a GROUP BY expression.
366
- const allowedAttrIds = new Set();
367
- const groupByExprFingerprints = new Set();
368
- for (const expr of groupByExpressions) {
369
- if (CapabilityDetectors.isColumnReference(expr)) {
370
- allowedAttrIds.add(expr.attributeId);
371
- }
372
- groupByExprFingerprints.add(expressionToString(expr.expression));
373
- }
374
- for (let i = 0; i < groupByExpressions.length + aggregates.length; i++) {
375
- allowedAttrIds.add(aggregateAttributes[i].id);
376
- }
377
- const ungrouped = findUngroupedColumnRef(havingExpression, allowedAttrIds, groupByExprFingerprints);
618
+ const coverage = buildGroupByCoverage(groupByExpressions, aggregateAttributes.slice(0, groupByExpressions.length + aggregates.length));
619
+ const ungrouped = findUngroupedColumnRef(havingExpression, coverage);
378
620
  if (ungrouped) {
379
621
  throw new QuereusError(`HAVING references non-grouped column '${ungrouped.expression.name}'; ` +
380
622
  `HAVING may only reference GROUP BY columns or aggregate expressions`, StatusCode.ERROR, undefined, ungrouped.expression.loc?.start.line, ungrouped.expression.loc?.start.column);
381
623
  }
382
624
  return new FilterNode(hybridScope, input, havingExpression);
383
625
  }
626
+ /**
627
+ * True when the AggregateNode's own output already IS the SELECT list, column for
628
+ * column — its GROUP BY keys in GROUP BY order, then its aggregate results in
629
+ * SELECT order, and nothing left over.
630
+ *
631
+ * An AggregateNode advertises *every* grouping key it computes, so with no
632
+ * projection above it the query's declared result shape is the aggregate's shape,
633
+ * not the select list's. `select count(*) from t group by g` therefore hands back
634
+ * `g` as well as the count, and `select count(*) c, g from t group by g` hands the
635
+ * two back in aggregate order rather than select-list order. Only an exact
636
+ * positional match makes skipping the final projection sound.
637
+ *
638
+ * Callers reach this only after the other `needsFinalProjection` terms answered
639
+ * "no", which means every entry in `projections` is a bare, non-renaming
640
+ * {@link ColumnReferenceNode}; a group key is matched by attribute id so a
641
+ * qualified `select t.k … group by k` still counts as agreement.
642
+ *
643
+ * The agreement this establishes is a *build-time* one, so an optimizer rule that
644
+ * reshapes the aggregate must keep it. `rule-groupby-fd-simplification` drops a
645
+ * functionally-determined group key and re-emits it as a picker `min`, which lands
646
+ * at a different output position; it caps that rewrite with an order-restoring
647
+ * `Project` precisely so this build-time agreement still holds at runtime.
648
+ */
649
+ function aggregateOutputIsSelectList(stmt, projections, aggregates, groupByExpressions, starProjectionsByColumn, selectContext) {
650
+ // `projections` holds the expanded star columns *and* the non-aggregate SELECT-list
651
+ // columns. Stars are walked from `starProjectionsByColumn` below, so drop them from
652
+ // the cursor's list by object identity — that keeps the remaining entries in
653
+ // SELECT-list order no matter how buildSelectStmt interleaves the two groups
654
+ // (it assembles them in written select-list order).
655
+ const starProjections = new Set();
656
+ for (const expanded of starProjectionsByColumn.values()) {
657
+ for (const starProjection of expanded)
658
+ starProjections.add(starProjection);
659
+ }
660
+ const nonStarProjections = projections.filter(projection => !starProjections.has(projection));
661
+ let columnCursor = 0;
662
+ let aggregateCount = 0;
663
+ let nextGroupKey = 0;
664
+ let sawAggregate = false;
665
+ /** Does this select-list node reference exactly the group key we expect next? */
666
+ const claimsNextGroupKey = (node) => {
667
+ const key = groupByExpressions[nextGroupKey];
668
+ if (!key || sawAggregate)
669
+ return false;
670
+ if (!CapabilityDetectors.isColumnReference(node) || !CapabilityDetectors.isColumnReference(key))
671
+ return false;
672
+ return node.attributeId === key.attributeId;
673
+ };
674
+ for (const column of stmt.columns) {
675
+ if (column.type === 'all') {
676
+ for (const starProjection of starProjectionsByColumn.get(column) ?? []) {
677
+ if (!claimsNextGroupKey(starProjection.node))
678
+ return false;
679
+ nextGroupKey++;
680
+ }
681
+ continue;
682
+ }
683
+ if (column.type !== 'column')
684
+ continue;
685
+ if (containsAggregateFunction(column.expr, selectContext)) {
686
+ // An aggregate result column claims the next aggregate output slot. Those
687
+ // slots all follow the group keys, so nothing may claim a key after one.
688
+ sawAggregate = true;
689
+ aggregateCount++;
690
+ continue;
691
+ }
692
+ const projection = nonStarProjections[columnCursor++];
693
+ if (!projection || !claimsNextGroupKey(projection.node))
694
+ return false;
695
+ nextGroupKey++;
696
+ }
697
+ return nextGroupKey === groupByExpressions.length && aggregateCount === aggregates.length;
698
+ }
699
+ /**
700
+ * True when a SELECT-list expression contains an aggregate function call.
701
+ *
702
+ * NOTE: resolves a function schema per function node while walking, once per prepare
703
+ * of a grouped query, on top of the walk analyzeSelectColumns already does. Not
704
+ * measured; if preparing wide grouped select lists ever shows up as slow, have
705
+ * analyzeSelectColumns publish its per-column aggregate/non-aggregate verdict
706
+ * instead of re-deriving it here.
707
+ */
708
+ function containsAggregateFunction(expr, selectContext) {
709
+ const found = [];
710
+ findAggregateFunctionExprs(expr, selectContext, found);
711
+ return found.length > 0;
712
+ }
384
713
  /**
385
714
  * Checks if a final projection is needed for complex expressions or for
386
715
  * aliasing simple column refs whose alias differs from the underlying column.
@@ -464,6 +793,17 @@ function findAggregateFunctionExprs(expr, ctx, results) {
464
793
  break;
465
794
  }
466
795
  }
796
+ /**
797
+ * Every aggregate function call inside an AST expression, in source order.
798
+ * Does not descend into an aggregate's own arguments (nested aggregates are
799
+ * invalid SQL). Exported for callers that need to *inspect* the aggregates in a
800
+ * clause rather than collect them into the AggregateNode.
801
+ */
802
+ export function collectAggregateFunctionExprs(expr, ctx) {
803
+ const found = [];
804
+ findAggregateFunctionExprs(expr, ctx, found);
805
+ return found;
806
+ }
467
807
  /**
468
808
  * Collects aggregate functions from a HAVING clause AST that are not already
469
809
  * present in the existing aggregates list. Returns new aggregates to add.
@@ -486,17 +826,21 @@ function collectOrderByAggregates(orderBy, selectContext, existingAggregates) {
486
826
  }
487
827
  /**
488
828
  * Returns true if any ORDER BY clause expression contains an aggregate function call.
829
+ *
830
+ * A positional reference is resolved against the SELECT list FIRST: the literal `1`
831
+ * in `select count(*) as c from t order by 1` contains no aggregate itself, but it
832
+ * stands for one. Without this the query would take the pre-aggregate sort path and
833
+ * fail with "Aggregate function count not allowed in this context"; with it, it
834
+ * routes to the post-aggregate ORDER BY exactly like the spelled-out
835
+ * `order by count(*)`.
489
836
  */
490
- function orderByContainsAggregates(orderBy, selectContext) {
837
+ function orderByContainsAggregates(orderBy, selectContext, selectList) {
491
838
  if (!orderBy || orderBy.length === 0)
492
839
  return false;
493
- const found = [];
494
- for (const clause of orderBy) {
495
- findAggregateFunctionExprs(clause.expr, selectContext, found);
496
- if (found.length > 0)
497
- return true;
498
- }
499
- return false;
840
+ return orderBy.some(clause => {
841
+ const entry = resolveOrdinalReference(clause.expr, selectList, 'ORDER BY');
842
+ return containsAggregateFunction(entry?.expr ?? clause.expr, selectContext);
843
+ });
500
844
  }
501
845
  /**
502
846
  * Given a list of aggregate function call AST nodes, builds aggregate plan nodes
@@ -509,19 +853,20 @@ function dedupeNewAggregates(funcExprs, selectContext, existingAggregates) {
509
853
  const existingKeys = new Set();
510
854
  for (const agg of existingAggregates) {
511
855
  if (CapabilityDetectors.isAggregateFunction(agg.expression)) {
512
- const aggNode = agg.expression;
513
- existingKeys.add(expressionToString(aggNode.expression).toLowerCase());
856
+ existingKeys.add(expressionToIdentityString(agg.expression.expression));
514
857
  }
515
858
  }
516
859
  const newAggregates = [];
860
+ const newKeys = new Set();
517
861
  for (const funcExpr of funcExprs) {
518
- const key = expressionToString(funcExpr).toLowerCase();
862
+ const key = expressionToIdentityString(funcExpr);
519
863
  if (existingKeys.has(key))
520
864
  continue;
521
- if (newAggregates.some(a => a.alias.toLowerCase() === key))
865
+ if (newKeys.has(key))
522
866
  continue;
523
867
  const aggNode = buildFunctionCall(selectContext, funcExpr, true);
524
868
  newAggregates.push({ expression: aggNode, alias: expressionToString(funcExpr) });
869
+ newKeys.add(key);
525
870
  }
526
871
  return newAggregates;
527
872
  }
@@ -553,27 +898,15 @@ export function buildFinalAggregateProjections(stmt, selectContext, aggregateOut
553
898
  // it and the unique group-key FD is silently dropped at the projection
554
899
  // (`keysOf(root) = []`). Referencing the aggregate group column keeps the key
555
900
  // and republishes it under exactly its grouping collation (trivially sound).
556
- const groupByFingerprints = new Map();
557
- groupByExpressions.forEach((expr, index) => {
558
- const fp = expressionToString(expr.expression);
559
- if (!groupByFingerprints.has(fp))
560
- groupByFingerprints.set(fp, index);
561
- });
562
- // Bare source columns that are themselves group keys map straight to the
563
- // aggregate's group output column. Used to expand `SELECT *` in a grouped
564
- // query, which must emit source-column order rather than GROUP BY order.
565
- const groupKeyByAttrId = new Map();
566
- groupByExpressions.forEach((expr, index) => {
567
- if (CapabilityDetectors.isColumnReference(expr)) {
568
- const attrId = expr.attributeId;
569
- if (!groupKeyByAttrId.has(attrId))
570
- groupKeyByAttrId.set(attrId, index);
571
- }
572
- });
901
+ //
902
+ // The same index also maps bare source columns that are themselves group keys
903
+ // straight to the aggregate's group output column, which is what expands
904
+ // `SELECT *` in a grouped query in source-column order rather than GROUP BY order.
905
+ const groupKeys = indexGroupKeys(groupByExpressions);
573
906
  for (const column of stmt.columns) {
574
907
  if (column.type === 'all') {
575
908
  for (const starProj of starProjectionsByColumn.get(column) ?? []) {
576
- const gbIdx = starGroupKeyIndex(starProj, groupKeyByAttrId);
909
+ const gbIdx = starGroupKeyIndex(starProj, groupKeys.byBaseAttrId);
577
910
  if (gbIdx === undefined) {
578
911
  // validateAggregateProjections already rejected every star column that
579
912
  // is not a grouping key, so reaching here means the two disagree.
@@ -594,7 +927,7 @@ export function buildFinalAggregateProjections(stmt, selectContext, aggregateOut
594
927
  // group symbol (registered under the column name) in recompute, so their
595
928
  // key survives; only non-bare group expressions need the direct reference.
596
929
  const gbIdx = column.expr.type !== 'column'
597
- ? groupByFingerprints.get(expressionToString(column.expr))
930
+ ? groupKeys.byFingerprint.get(expressionToIdentityString(column.expr))
598
931
  : undefined;
599
932
  if (gbIdx !== undefined) {
600
933
  const colRef = buildGroupKeyColumnRef(aggregateOutputScope, aggregateAttributes[gbIdx], column.expr, gbIdx);
@@ -645,8 +978,8 @@ function starGroupKeyIndex(starProj, groupKeyByAttrId) {
645
978
  * keeps the same name `ProjectNode.buildOutputType` would have produced for the
646
979
  * recomputed expression.
647
980
  */
648
- function buildGroupKeyColumnRef(aggregateOutputScope, groupAttr, selectExpr, columnIndex) {
981
+ function buildGroupKeyColumnRef(scope, groupAttr, selectExpr, columnIndex) {
649
982
  const colExpr = { type: 'column', name: expressionToString(selectExpr) };
650
- return new ColumnReferenceNode(aggregateOutputScope, colExpr, groupAttr.type, groupAttr.id, columnIndex);
983
+ return new ColumnReferenceNode(scope, colExpr, groupAttr.type, groupAttr.id, columnIndex);
651
984
  }
652
985
  //# sourceMappingURL=select-aggregates.js.map