@quereus/quereus 4.20.0 → 4.20.2

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 (400) hide show
  1. package/README.md +2 -0
  2. package/dist/src/common/types.d.ts +4 -4
  3. package/dist/src/index.d.ts +1 -1
  4. package/dist/src/index.d.ts.map +1 -1
  5. package/dist/src/index.js +3 -2
  6. package/dist/src/index.js.map +1 -1
  7. package/dist/src/schema/catalog-rendering.js +13 -1
  8. package/dist/src/schema/catalog-rendering.js.map +1 -1
  9. package/dist/src/schema/catalog.d.ts +35 -2
  10. package/dist/src/schema/catalog.d.ts.map +1 -1
  11. package/dist/src/schema/catalog.js +42 -33
  12. package/dist/src/schema/catalog.js.map +1 -1
  13. package/dist/src/schema/schema-differ.d.ts +1 -1
  14. package/dist/src/schema/schema-differ.d.ts.map +1 -1
  15. package/dist/src/schema/schema-differ.js +195 -33
  16. package/dist/src/schema/schema-differ.js.map +1 -1
  17. package/dist/src/schema/unique-enforcement.d.ts +23 -1
  18. package/dist/src/schema/unique-enforcement.d.ts.map +1 -1
  19. package/dist/src/schema/unique-enforcement.js +43 -1
  20. package/dist/src/schema/unique-enforcement.js.map +1 -1
  21. package/dist/src/vtab/memory/layer/manager.d.ts +15 -12
  22. package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
  23. package/dist/src/vtab/memory/layer/manager.js +87 -100
  24. package/dist/src/vtab/memory/layer/manager.js.map +1 -1
  25. package/package.json +7 -4
  26. package/test/README.md +173 -0
  27. package/test/logic/01-basic.sqllogic +39 -0
  28. package/test/logic/01.1-select-projection-extras.sqllogic +130 -0
  29. package/test/logic/01.2-strings.sqllogic +43 -0
  30. package/test/logic/01.5-insert-select.sqllogic +237 -0
  31. package/test/logic/01.6-update-extras.sqllogic +118 -0
  32. package/test/logic/01.7-update-from.sqllogic +67 -0
  33. package/test/logic/01.8-delete-extras.sqllogic +122 -0
  34. package/test/logic/01.8.1-delete-range-cow.sqllogic +115 -0
  35. package/test/logic/01.9-query-expr-dml-gates.sqllogic +32 -0
  36. package/test/logic/01.9-query-expr-dml.sqllogic +171 -0
  37. package/test/logic/01.9-query-expr-values.sqllogic +111 -0
  38. package/test/logic/01.9.1-limit-over-dml-subquery.sqllogic +119 -0
  39. package/test/logic/02-filters.sqllogic +54 -0
  40. package/test/logic/02-smoke.sqllogic +62 -0
  41. package/test/logic/02.1-bind-parameters.sqllogic +223 -0
  42. package/test/logic/03-expressions.sqllogic +190 -0
  43. package/test/logic/03.1-quoted-identifiers.sqllogic +55 -0
  44. package/test/logic/03.4-defaults.sqllogic +554 -0
  45. package/test/logic/03.4.1-default-edge-cases.sqllogic +99 -0
  46. package/test/logic/03.5-tvf.sqllogic +61 -0
  47. package/test/logic/03.6-type-system.sqllogic +544 -0
  48. package/test/logic/03.6.1-numeric-text-comparison-coercion.sqllogic +244 -0
  49. package/test/logic/03.6.2-value-to-text.sqllogic +224 -0
  50. package/test/logic/03.7-bigint-mixed-arithmetic.sqllogic +65 -0
  51. package/test/logic/03.8-not-precedence.sqllogic +255 -0
  52. package/test/logic/03.9-is-bool-predicate.sqllogic +150 -0
  53. package/test/logic/03.9.1-is-bool-predicate-partial-index.sqllogic +34 -0
  54. package/test/logic/04-order-by.sqllogic +38 -0
  55. package/test/logic/04-transactions.sqllogic +239 -0
  56. package/test/logic/04a-savepoint-lazy-attach.sqllogic +122 -0
  57. package/test/logic/05-vtab_memory.sqllogic +50 -0
  58. package/test/logic/05.0.1-vtab-memory-unique-index-collation.sqllogic +34 -0
  59. package/test/logic/05.1-composite-pk-range-scan.sqllogic +147 -0
  60. package/test/logic/05.1.1-secondary-index-range-scan.sqllogic +56 -0
  61. package/test/logic/05.2-cast-seek-correctness.sqllogic +124 -0
  62. package/test/logic/06-builtin_functions.sqllogic +149 -0
  63. package/test/logic/06.1-string-functions.sqllogic +92 -0
  64. package/test/logic/06.1.3-like-glob-edges.sqllogic +53 -0
  65. package/test/logic/06.2-math-functions.sqllogic +82 -0
  66. package/test/logic/06.3-schema.sqllogic +48 -0
  67. package/test/logic/06.3.1-schema-all-schemas.sqllogic +39 -0
  68. package/test/logic/06.3.2-schema-foreign-keys.sqllogic +208 -0
  69. package/test/logic/06.3.3-introspection-tags.sqllogic +202 -0
  70. package/test/logic/06.3.3.1-introspection-tags-index.sqllogic +74 -0
  71. package/test/logic/06.3.4-view-info.sqllogic +378 -0
  72. package/test/logic/06.3.5-column-info.sqllogic +347 -0
  73. package/test/logic/06.3.6-schema-views.sqllogic +29 -0
  74. package/test/logic/06.4-schema-search-path.sqllogic +354 -0
  75. package/test/logic/06.4.1-schema-case-insensitive.sqllogic +83 -0
  76. package/test/logic/06.4.2-collation-extras.sqllogic +472 -0
  77. package/test/logic/06.4.2.1-collation-index-access-paths.sqllogic +140 -0
  78. package/test/logic/06.4.3-write-path-collation.sqllogic +99 -0
  79. package/test/logic/06.4.4-comparison-collation-precedence.sqllogic +342 -0
  80. package/test/logic/06.4.5-any-collate-declared-keys.sqllogic +92 -0
  81. package/test/logic/06.5-polymorphic-types.sqllogic +169 -0
  82. package/test/logic/06.5.1-conversion-functions.sqllogic +173 -0
  83. package/test/logic/06.5.2-scalar-minmax.sqllogic +16 -0
  84. package/test/logic/06.5.3-undeclared-return-type-comparison.sqllogic +244 -0
  85. package/test/logic/06.5.4-declared-return-type-builtins.sqllogic +288 -0
  86. package/test/logic/06.6-aggregate-extended.sqllogic +78 -0
  87. package/test/logic/06.7-json-extended.sqllogic +53 -0
  88. package/test/logic/06.8-json-path-operators.sqllogic +99 -0
  89. package/test/logic/06.9-json-canonical-key.sqllogic +65 -0
  90. package/test/logic/06.9.1-json-coerce-once.sqllogic +417 -0
  91. package/test/logic/06.9.1.1-json-coerce-once-index.sqllogic +39 -0
  92. package/test/logic/06.9.2-json-structural-equality.sqllogic +382 -0
  93. package/test/logic/06.9.2.1-json-structural-equality-index.sqllogic +76 -0
  94. package/test/logic/06.9.3-json-index-range-seek.sqllogic +205 -0
  95. package/test/logic/07-aggregates.sqllogic +193 -0
  96. package/test/logic/07.1-aggregate-filter-clause.sqllogic +12 -0
  97. package/test/logic/07.2-aggregate-order-by.sqllogic +11 -0
  98. package/test/logic/07.3-group-by-extras.sqllogic +602 -0
  99. package/test/logic/07.3.1-group-by-order-by-key.sqllogic +164 -0
  100. package/test/logic/07.3.2-grouped-select-list-shape.sqllogic +231 -0
  101. package/test/logic/07.4-group-by-filter-composite-pk.sqllogic +120 -0
  102. package/test/logic/07.5-sum-mixed-exact-and-float.sqllogic +151 -0
  103. package/test/logic/07.5-window.sqllogic +1941 -0
  104. package/test/logic/07.5.1-window-named.sqllogic +13 -0
  105. package/test/logic/07.5.2-window-nth-value.sqllogic +13 -0
  106. package/test/logic/07.6-subqueries.sqllogic +78 -0
  107. package/test/logic/07.6.1-subquery-extras.sqllogic +93 -0
  108. package/test/logic/07.7-and-or-short-circuit.sqllogic +58 -0
  109. package/test/logic/07.7-in-subquery-caching.sqllogic +174 -0
  110. package/test/logic/07.7-scalar-agg-decorrelation.sqllogic +197 -0
  111. package/test/logic/07.7.1-in-extras.sqllogic +158 -0
  112. package/test/logic/07.7.1-scalar-agg-decorrelation-filter.sqllogic +105 -0
  113. package/test/logic/07.7.2-scalar-agg-decorrelation-nested.sqllogic +115 -0
  114. package/test/logic/07.7.3-exists-in-select-decorrelation.sqllogic +107 -0
  115. package/test/logic/07.7.4-where-conjunct-ordering.sqllogic +121 -0
  116. package/test/logic/07.7.5-filter-lost-under-index-order.sqllogic +134 -0
  117. package/test/logic/07.7.6-correlated-predicate-scope.sqllogic +178 -0
  118. package/test/logic/07.7.7-join-source-scope-shadowing.sqllogic +137 -0
  119. package/test/logic/07.7.8-correlated-ref-to-computed-column.sqllogic +165 -0
  120. package/test/logic/07.7.9-conjunct-monotonicity.sqllogic +200 -0
  121. package/test/logic/07.8-correlated-subquery-edges.sqllogic +71 -0
  122. package/test/logic/07.8.1-correlated-in-decorrelation-gates.sqllogic +156 -0
  123. package/test/logic/07.9-in-value-list.sqllogic +154 -0
  124. package/test/logic/07.9.1-in-value-list-composite-index.sqllogic +38 -0
  125. package/test/logic/08-views.sqllogic +64 -0
  126. package/test/logic/08.1-semi-anti-join.sqllogic +191 -0
  127. package/test/logic/08.1-view-edge-cases.sqllogic +118 -0
  128. package/test/logic/08.1.1-uncorrelated-in-semijoin.sqllogic +251 -0
  129. package/test/logic/08.2-existence-flag-semijoin-recovery.sqllogic +197 -0
  130. package/test/logic/08.3-existence-flag-inner-recovery.sqllogic +102 -0
  131. package/test/logic/08.4-key-set-semi-join.sqllogic +447 -0
  132. package/test/logic/09-set_operations.sqllogic +244 -0
  133. package/test/logic/09.1-set-op-cross-collation.sqllogic +230 -0
  134. package/test/logic/10-distinct_datatypes.sqllogic +127 -0
  135. package/test/logic/10.1-ddl-lifecycle.sqllogic +203 -0
  136. package/test/logic/10.1.1-create-table-syntax-edges.sqllogic +47 -0
  137. package/test/logic/10.1.2-ddl-in-transaction.sqllogic +143 -0
  138. package/test/logic/10.1.2.1-add-constraint-in-transaction.sqllogic +59 -0
  139. package/test/logic/10.1.3-ddl-drop-in-transaction.sqllogic +187 -0
  140. package/test/logic/10.1.3.1-drop-constraint-in-transaction.sqllogic +45 -0
  141. package/test/logic/10.1.4-create-table-duplicate-constraint-names.sqllogic +149 -0
  142. package/test/logic/10.1.4-ddl-transaction-policy.sqllogic +314 -0
  143. package/test/logic/10.1.5-alter-add-constraint-minted-name-disambiguation.sqllogic +219 -0
  144. package/test/logic/10.1.5-create-index-lifecycle.sqllogic +72 -0
  145. package/test/logic/10.1.6-ddl-transaction-policy-index.sqllogic +143 -0
  146. package/test/logic/10.1.7-create-table-default-type-check.sqllogic +119 -0
  147. package/test/logic/10.1.8-alter-add-check-existing-rows.sqllogic +117 -0
  148. package/test/logic/10.2-column-features.sqllogic +365 -0
  149. package/test/logic/10.2.1-table-options-rejection.sqllogic +63 -0
  150. package/test/logic/10.2.2-default-collation-memory.sqllogic +30 -0
  151. package/test/logic/10.3-function-features.sqllogic +247 -0
  152. package/test/logic/10.4-schema-scale.sqllogic +168 -0
  153. package/test/logic/10.4.1-schema-scale-indexes.sqllogic +121 -0
  154. package/test/logic/10.5-indexes.sqllogic +164 -0
  155. package/test/logic/10.5.1-partial-indexes.sqllogic +526 -0
  156. package/test/logic/10.5.2-expression-indexes.sqllogic +34 -0
  157. package/test/logic/10.5.3-desc-index-ordering.sqllogic +130 -0
  158. package/test/logic/10.5.4-composite-pk-index-update-phantom.sqllogic +55 -0
  159. package/test/logic/10.5.5-index-name-uniqueness.sqllogic +76 -0
  160. package/test/logic/10.5.6-minmax-index-boundary.sqllogic +204 -0
  161. package/test/logic/10.5.7-implicit-unique-index-lifecycle.sqllogic +1216 -0
  162. package/test/logic/10.6-distinct-edge-cases.sqllogic +119 -0
  163. package/test/logic/100-predicate-normalization-edge-cases.sqllogic +238 -0
  164. package/test/logic/100.1-where-extras.sqllogic +163 -0
  165. package/test/logic/100.1.1-where-join-on-order-indexed.sqllogic +35 -0
  166. package/test/logic/101-builtin-mutation-kills.sqllogic +974 -0
  167. package/test/logic/101-transaction-edge-cases.sqllogic +395 -0
  168. package/test/logic/102-schema-catalog-edge-cases.sqllogic +252 -0
  169. package/test/logic/102-unique-constraints.sqllogic +145 -0
  170. package/test/logic/102.0.1-schema-catalog-indexed-table.sqllogic +32 -0
  171. package/test/logic/102.1-unique-edge-cases.sqllogic +111 -0
  172. package/test/logic/102.1.1-unique-index-creation-edge-cases.sqllogic +75 -0
  173. package/test/logic/102.2-unique-collation.sqllogic +181 -0
  174. package/test/logic/102.2.1-unique-collation-index-derived.sqllogic +305 -0
  175. package/test/logic/103-database-options-edge-cases.sqllogic +108 -0
  176. package/test/logic/103.1-pragma-boolean-values.sqllogic +126 -0
  177. package/test/logic/104-emit-mutation-kills.sqllogic +236 -0
  178. package/test/logic/105-vtab-memory-mutation-kills.sqllogic +754 -0
  179. package/test/logic/105.1-vtab-memory-index-mutation-kills.sqllogic +540 -0
  180. package/test/logic/106-constraint-extractor-mutation-kills.sqllogic +350 -0
  181. package/test/logic/107-temporal-arithmetic-mutation-kills.sqllogic +833 -0
  182. package/test/logic/108-cardinality-estimation.sqllogic +146 -0
  183. package/test/logic/108.1-analyze-name-resolution.sqllogic +102 -0
  184. package/test/logic/109-aggregate-physical-selection.sqllogic +103 -0
  185. package/test/logic/11-joins.sqllogic +86 -0
  186. package/test/logic/11.1-join-using.sqllogic +267 -0
  187. package/test/logic/11.2-comma-join.sqllogic +35 -0
  188. package/test/logic/11.3-index-nested-loop-join.sqllogic +305 -0
  189. package/test/logic/11.3-mismatched-collation-join.sqllogic +74 -0
  190. package/test/logic/11.4-hash-join-side-swap.sqllogic +118 -0
  191. package/test/logic/110-scan-emitter-mutation-kills.sqllogic +121 -0
  192. package/test/logic/110.1-scan-emitter-index-scan-kills.sqllogic +47 -0
  193. package/test/logic/12-empty-primary-key.sqllogic +124 -0
  194. package/test/logic/12-join_padding_order.sqllogic +58 -0
  195. package/test/logic/12.1-orderby-index-consumption.sqllogic +40 -0
  196. package/test/logic/13-cte.sqllogic +137 -0
  197. package/test/logic/13.1-cte-multiple-recursive.sqllogic +104 -0
  198. package/test/logic/13.10-cte-qualified-name.sqllogic +136 -0
  199. package/test/logic/13.11-unreferenced-dml-cte.sqllogic +414 -0
  200. package/test/logic/13.12-nested-dml-cte-rejected.sqllogic +280 -0
  201. package/test/logic/13.2-cte-bind-params.sqllogic +98 -0
  202. package/test/logic/13.3-cte-edge-cases.sqllogic +120 -0
  203. package/test/logic/13.4-cte-extras.sqllogic +98 -0
  204. package/test/logic/13.5-cte-join-order.sqllogic +166 -0
  205. package/test/logic/13.6-cte-dml-runs-once.sqllogic +318 -0
  206. package/test/logic/13.7-cte-sibling-visibility.sqllogic +227 -0
  207. package/test/logic/13.8-insert-with-clause-visibility.sqllogic +254 -0
  208. package/test/logic/13.9-schema-authored-cte-isolation.sqllogic +328 -0
  209. package/test/logic/13.9.1-schema-authored-schema-path-isolation.sqllogic +408 -0
  210. package/test/logic/14-utilities.sqllogic +168 -0
  211. package/test/logic/15-timespan.sqllogic +279 -0
  212. package/test/logic/15.1-semantic-ordering.sqllogic +960 -0
  213. package/test/logic/15.1.1-json-check-coercion.sqllogic +178 -0
  214. package/test/logic/15.1.2-semantic-ordering-index.sqllogic +41 -0
  215. package/test/logic/15.1.3-declared-form-write-contract.sqllogic +519 -0
  216. package/test/logic/16-epoch.sqllogic +187 -0
  217. package/test/logic/17-weekday-modifier.sqllogic +78 -0
  218. package/test/logic/18-json-string-escapes.sqllogic +86 -0
  219. package/test/logic/18-strftime-extended-formats.sqllogic +68 -0
  220. package/test/logic/20-empty-single-row.sqllogic +261 -0
  221. package/test/logic/21-null-edge-cases.sqllogic +227 -0
  222. package/test/logic/21.1-where-null-comparisons.sqllogic +151 -0
  223. package/test/logic/21.1.1-where-null-comparisons-secondary-index.sqllogic +35 -0
  224. package/test/logic/21.2-between-edges.sqllogic +157 -0
  225. package/test/logic/22-boundary-values.sqllogic +175 -0
  226. package/test/logic/23-self-joins-duplicates.sqllogic +74 -0
  227. package/test/logic/24-builtin-branches.sqllogic +611 -0
  228. package/test/logic/24.1-substr-extras.sqllogic +75 -0
  229. package/test/logic/24.2-random-extras.sqllogic +39 -0
  230. package/test/logic/25-aggregate-edge-cases.sqllogic +289 -0
  231. package/test/logic/25.1-nested-aggregates.sqllogic +74 -0
  232. package/test/logic/25.2-having-edge-cases.sqllogic +318 -0
  233. package/test/logic/25.3-aggregate-isnull-empty.sqllogic +16 -0
  234. package/test/logic/25.4-groupby-fd-constant-empty.sqllogic +55 -0
  235. package/test/logic/25.5-ungrouped-aggregate-column-free-select-item.sqllogic +196 -0
  236. package/test/logic/26-join-edge-cases.sqllogic +333 -0
  237. package/test/logic/26.1-left-join-isnull-on-notnull.sqllogic +26 -0
  238. package/test/logic/26.2-left-join-on-vs-where.sqllogic +67 -0
  239. package/test/logic/26.3-join-on-constants.sqllogic +61 -0
  240. package/test/logic/26.4-join-on-is-null-nullable.sqllogic +44 -0
  241. package/test/logic/27-window-edge-cases.sqllogic +206 -0
  242. package/test/logic/27.1-window-groups-frame.sqllogic +13 -0
  243. package/test/logic/27.2-window-exclude.sqllogic +13 -0
  244. package/test/logic/27.3-window-json-aggregation.sqllogic +66 -0
  245. package/test/logic/28-set-ops-sort-edge-cases.sqllogic +444 -0
  246. package/test/logic/28.1-compound-limit-offset.sqllogic +143 -0
  247. package/test/logic/28.2-orderby-expression-extras.sqllogic +698 -0
  248. package/test/logic/28.2-set-op-branch-types.sqllogic +217 -0
  249. package/test/logic/29-constraint-edge-cases.sqllogic +442 -0
  250. package/test/logic/29.1-column-level-conflict-clause.sqllogic +171 -0
  251. package/test/logic/29.2-table-level-pk-conflict-clause.sqllogic +113 -0
  252. package/test/logic/40-constraints.sqllogic +418 -0
  253. package/test/logic/40.1-pk-desc-direction.sqllogic +76 -0
  254. package/test/logic/40.2-check-extras.sqllogic +683 -0
  255. package/test/logic/41-alter-table.sqllogic +191 -0
  256. package/test/logic/41-fk-cascade-conflict-and-self-ref.sqllogic +263 -0
  257. package/test/logic/41-fk-cross-schema.sqllogic +155 -0
  258. package/test/logic/41-fk-extended-targets.sqllogic +173 -0
  259. package/test/logic/41-foreign-keys.sqllogic +1001 -0
  260. package/test/logic/41-generated-column-errors.sqllogic +225 -0
  261. package/test/logic/41-generated-column-extras.sqllogic +598 -0
  262. package/test/logic/41-generated-column-scope.sqllogic +329 -0
  263. package/test/logic/41-generated-columns.sqllogic +361 -0
  264. package/test/logic/41.1-alter-pk.sqllogic +230 -0
  265. package/test/logic/41.1-fk-collation-conflict.sqllogic +277 -0
  266. package/test/logic/41.10-alter-drop-column-foreign-key.sqllogic +274 -0
  267. package/test/logic/41.10.1-alter-drop-column-unique-index.sqllogic +169 -0
  268. package/test/logic/41.10.2-alter-drop-column-check-and-assertion.sqllogic +1616 -0
  269. package/test/logic/41.10.3-alter-drop-column-referencing-fk.sqllogic +292 -0
  270. package/test/logic/41.10.4-drop-object-expression-dependents.sqllogic +602 -0
  271. package/test/logic/41.11-deferred-fk-with-rename.sqllogic +232 -0
  272. package/test/logic/41.12-alter-default-coercion.sqllogic +200 -0
  273. package/test/logic/41.13-alter-add-column-generated-backfill.sqllogic +566 -0
  274. package/test/logic/41.14-alter-add-column-subquery-backfill.sqllogic +129 -0
  275. package/test/logic/41.15-alter-column-default-type-check.sqllogic +178 -0
  276. package/test/logic/41.16-fk-unenforceable.sqllogic +364 -0
  277. package/test/logic/41.2-alter-column.sqllogic +382 -0
  278. package/test/logic/41.2.1-alter-column-retype-deleted-row-memory.sqllogic +32 -0
  279. package/test/logic/41.2.2-alter-column-retype-index-rebuild.sqllogic +77 -0
  280. package/test/logic/41.2.3-alter-column-set-not-null-pk-backfill.sqllogic +310 -0
  281. package/test/logic/41.2.3.1-alter-column-set-not-null-pk-backfill-secondary-index.sqllogic +37 -0
  282. package/test/logic/41.3-alter-add-column-unique.sqllogic +184 -0
  283. package/test/logic/41.3-alter-rename-propagation.sqllogic +2352 -0
  284. package/test/logic/41.3.1-alter-rename-index-propagation.sqllogic +94 -0
  285. package/test/logic/41.4-alter-add-column-constraints.sqllogic +855 -0
  286. package/test/logic/41.5-alter-misc.sqllogic +48 -0
  287. package/test/logic/41.5-cross-schema-foreign-keys.sqllogic +253 -0
  288. package/test/logic/41.6-alter-drop-rename-constraint.sqllogic +354 -0
  289. package/test/logic/41.6.1-alter-drop-constraint-index-derived.sqllogic +22 -0
  290. package/test/logic/41.7-alter-column-collate.sqllogic +105 -0
  291. package/test/logic/41.7.1-alter-column-collate-unique.sqllogic +45 -0
  292. package/test/logic/41.7.2-alter-column-collate-unique-store.sqllogic +208 -0
  293. package/test/logic/41.7.2.1-alter-column-collate-unique-index-store.sqllogic +114 -0
  294. package/test/logic/41.7.3-alter-column-retype-unique.sqllogic +293 -0
  295. package/test/logic/41.7.3.1-alter-column-retype-staged-rows-memory.sqllogic +41 -0
  296. package/test/logic/41.7.3.2-alter-column-retype-unique-index.sqllogic +72 -0
  297. package/test/logic/41.7.4-alter-column-retype-semantic-memory.sqllogic +445 -0
  298. package/test/logic/41.7.4.1-alter-column-retype-semantic-index-memory.sqllogic +91 -0
  299. package/test/logic/41.7.5-alter-column-collate-pk-staged-delete-memory.sqllogic +106 -0
  300. package/test/logic/41.8-alter-add-constraint-unique-fk.sqllogic +275 -0
  301. package/test/logic/41.8-alter-savepoint-staged-rows.sqllogic +443 -0
  302. package/test/logic/41.8.1-alter-rename-savepoint-staged-rows.sqllogic +408 -0
  303. package/test/logic/41.9-alter-constraint-body-change.sqllogic +180 -0
  304. package/test/logic/41.9-fk-restrict-batched.sqllogic +290 -0
  305. package/test/logic/42-committed-snapshot.sqllogic +254 -0
  306. package/test/logic/42-returning.sqllogic +159 -0
  307. package/test/logic/42.1-returning-extras.sqllogic +232 -0
  308. package/test/logic/42.2-returning-stored-row.sqllogic +165 -0
  309. package/test/logic/43-default-nullability.sqllogic +131 -0
  310. package/test/logic/43-transition-constraints.sqllogic +341 -0
  311. package/test/logic/43.1-default-collation.sqllogic +140 -0
  312. package/test/logic/43.1-notnull-or-conflict.sqllogic +79 -0
  313. package/test/logic/43.2-deferred-check-new-on-delete.sqllogic +95 -0
  314. package/test/logic/43.3-nullable-primary-key.sqllogic +587 -0
  315. package/test/logic/44-determinism-validation.sqllogic +164 -0
  316. package/test/logic/44-orthogonality.sqllogic +146 -0
  317. package/test/logic/44.1-nondeterministic-schema.sqllogic +316 -0
  318. package/test/logic/45-udf-determinism.sqllogic +39 -0
  319. package/test/logic/46-mutation-context.sqllogic +595 -0
  320. package/test/logic/47-upsert.sqllogic +255 -0
  321. package/test/logic/47.1-upsert-conflict-targets.sqllogic +169 -0
  322. package/test/logic/47.2-replace-and-or-clauses.sqllogic +164 -0
  323. package/test/logic/47.2.1-pk-replace-secondary-unique.sqllogic +374 -0
  324. package/test/logic/47.3-engine-or-fail.sqllogic +122 -0
  325. package/test/logic/47.3-upsert-conflict-target-collation.sqllogic +139 -0
  326. package/test/logic/47.3.1-upsert-conflict-index-derived-collation.sqllogic +25 -0
  327. package/test/logic/47.4-upsert-conflict-target-affinity.sqllogic +59 -0
  328. package/test/logic/47.5-upsert-do-update-constraints.sqllogic +440 -0
  329. package/test/logic/47.6-upsert-do-update-decomposed.sqllogic +100 -0
  330. package/test/logic/49-reference-graph.sqllogic +84 -0
  331. package/test/logic/50-declarative-schema.sqllogic +2550 -0
  332. package/test/logic/50-metadata-tags.sqllogic +1033 -0
  333. package/test/logic/50.0.1-metadata-tags-index.sqllogic +141 -0
  334. package/test/logic/50.1-declare-schema-pk.sqllogic +150 -0
  335. package/test/logic/50.2-declare-schema-renames.sqllogic +949 -0
  336. package/test/logic/50.2.1-declare-schema-index-renames.sqllogic +173 -0
  337. package/test/logic/50.3-declare-schema-duplicate-names.sqllogic +280 -0
  338. package/test/logic/50.4-declare-schema-apply-restore.sqllogic +192 -0
  339. package/test/logic/51-lens-foundation.sqllogic +147 -0
  340. package/test/logic/51-materialized-views.sqllogic +376 -0
  341. package/test/logic/51.5-materialized-views-coarsened-key.sqllogic +198 -0
  342. package/test/logic/51.7-maintained-table-attach-detach.sqllogic +468 -0
  343. package/test/logic/51.8-maintained-table-declared-constraints.sqllogic +440 -0
  344. package/test/logic/51.85-maintained-table-parent-fk.sqllogic +103 -0
  345. package/test/logic/51.9-maintained-table-secondary-unique.sqllogic +237 -0
  346. package/test/logic/51.9.1-maintained-table-partial-unique.sqllogic +36 -0
  347. package/test/logic/52-lens-overrides.sqllogic +566 -0
  348. package/test/logic/53-materialized-views-rowtime.sqllogic +1601 -0
  349. package/test/logic/53-reserved-tags.sqllogic +252 -0
  350. package/test/logic/53.1-materialized-view-write-through.sqllogic +329 -0
  351. package/test/logic/53.2-materialized-view-rename-propagation.sqllogic +483 -0
  352. package/test/logic/53.3-materialized-view-constraint-only-ddl.sqllogic +409 -0
  353. package/test/logic/53.3.1-materialized-view-index-ddl-irrelevance.sqllogic +29 -0
  354. package/test/logic/53.4-materialized-view-structural-alter-restore.sqllogic +436 -0
  355. package/test/logic/54-covering-mv-enforcement.sqllogic +314 -0
  356. package/test/logic/54.1-covering-mv-partial-enforcement.sqllogic +34 -0
  357. package/test/logic/55-internal-eviction-reporting.sqllogic +89 -0
  358. package/test/logic/55-lens-prover.sqllogic +202 -0
  359. package/test/logic/55.1-eviction-restrict-fk.sqllogic +148 -0
  360. package/test/logic/55.5-lens-authored-inverse.sqllogic +1468 -0
  361. package/test/logic/80-grow-retrieve-pass.sqllogic +79 -0
  362. package/test/logic/81-quickpick.sqllogic +24 -0
  363. package/test/logic/82-bloom-join.sqllogic +185 -0
  364. package/test/logic/83-merge-join.sqllogic +280 -0
  365. package/test/logic/84-asof-scan.sqllogic +238 -0
  366. package/test/logic/84-key-cardinality.sqllogic +50 -0
  367. package/test/logic/85-relational-const-folding.sqllogic +51 -0
  368. package/test/logic/86-scalar-cse.sqllogic +42 -0
  369. package/test/logic/90-error_paths.sqllogic +114 -0
  370. package/test/logic/90.1-parse-errors.sqllogic +77 -0
  371. package/test/logic/90.2-alter-table-errors.sqllogic +53 -0
  372. package/test/logic/90.2.1-alter-extra-errors.sqllogic +51 -0
  373. package/test/logic/90.3-expression-errors.sqllogic +43 -0
  374. package/test/logic/90.4-dml-errors.sqllogic +47 -0
  375. package/test/logic/90.5-unsupported-join-types.sqllogic +37 -0
  376. package/test/logic/90.5.1-right-full-join-read.sqllogic +157 -0
  377. package/test/logic/90.6-select-error-paths.sqllogic +57 -0
  378. package/test/logic/91-merge-join-edge-cases.sqllogic +159 -0
  379. package/test/logic/92-hash-aggregate-edge-cases.sqllogic +139 -0
  380. package/test/logic/93-ddl-view-edge-cases.sqllogic +104 -0
  381. package/test/logic/93.1-view-error-paths.sqllogic +74 -0
  382. package/test/logic/93.2-view-mutation-pending.sqllogic +108 -0
  383. package/test/logic/93.3-view-mutation-or-clause.sqllogic +60 -0
  384. package/test/logic/93.4-view-mutation.sqllogic +4881 -0
  385. package/test/logic/93.4.1-view-mutation-partial-unique-cardinality.sqllogic +31 -0
  386. package/test/logic/93.5-authored-inverse.sqllogic +415 -0
  387. package/test/logic/93.6-set-op-flagless-write.sqllogic +862 -0
  388. package/test/logic/94-tvf-edge-cases.sqllogic +58 -0
  389. package/test/logic/94.1-limit-offset-edge-cases.sqllogic +109 -0
  390. package/test/logic/94.2-limit-offset-extras.sqllogic +98 -0
  391. package/test/logic/95-assertions.sqllogic +1417 -0
  392. package/test/logic/96-subquery-edge-cases.sqllogic +276 -0
  393. package/test/logic/97-json-function-edge-cases.sqllogic +633 -0
  394. package/test/logic/97.1-json-blob-and-special-values.sqllogic +92 -0
  395. package/test/logic/98-temporal-edge-cases.sqllogic +515 -0
  396. package/test/logic/99-conversion-edge-cases.sqllogic +325 -0
  397. package/test/logic/99.0.1-schema-index-listing.sqllogic +21 -0
  398. package/test/logic/99.1-cast-syntax-extras.sqllogic +167 -0
  399. package/test/logic/drop-unique-index.sqllogic +88 -0
  400. package/test/logic/pushdown-test.sqllogic +36 -0
@@ -0,0 +1,602 @@
1
+ -- adapted from SQLite test/groupby.test
2
+ -- GROUP BY ordinal positions, expression grouping, alias resolution, and
3
+ -- combined with HAVING / ORDER BY in non-trivial shapes.
4
+
5
+ create table gx (id integer primary key, grp text, sub text, val integer);
6
+ insert into gx values
7
+ (1, 'a', 'x', 10),
8
+ (2, 'a', 'y', 20),
9
+ (3, 'b', 'x', 30),
10
+ (4, 'b', 'y', 40),
11
+ (5, 'a', 'x', 50);
12
+
13
+ -- GROUP BY / ORDER BY positional ordinal references the Nth SELECT-list output
14
+ select grp, count(*) as cnt from gx group by 1 order by 1;
15
+ → [{"grp":"a","cnt":3},{"grp":"b","cnt":2}]
16
+
17
+ -- Multiple ordinals in GROUP BY and ORDER BY
18
+ select grp, sub, sum(val) as total from gx group by 1, 2 order by 1, 2;
19
+ → [{"grp":"a","sub":"x","total":60},{"grp":"a","sub":"y","total":20},{"grp":"b","sub":"x","total":30},{"grp":"b","sub":"y","total":40}]
20
+
21
+ -- Equivalent using explicit expressions
22
+ select grp, count(*) as cnt from gx group by grp order by grp;
23
+ → [{"grp":"a","cnt":3},{"grp":"b","cnt":2}]
24
+
25
+ -- GROUP BY mixed expression
26
+ select grp || sub as combined, sum(val) as total
27
+ from gx group by grp || sub order by grp || sub;
28
+ → [{"combined":"ax","total":60},{"combined":"ay","total":20},{"combined":"bx","total":30},{"combined":"by","total":40}]
29
+
30
+ -- GROUP BY with arithmetic expression
31
+ select val % 20 as bucket, count(*) as cnt
32
+ from gx group by val % 20 order by val % 20;
33
+ → [{"bucket":0,"cnt":2},{"bucket":10,"cnt":3}]
34
+
35
+ -- GROUP BY ordinal combined with HAVING — the resolved expression is the same
36
+ -- plan node as the GROUP BY key, so HAVING still validates against that key.
37
+ select grp, count(*) as cnt from gx group by 1 having count(*) > 2 order by 1;
38
+ → [{"grp":"a","cnt":3}]
39
+
40
+ -- GROUP BY ordinal combined with ORDER BY ordinal on an aggregate output column
41
+ select grp, sum(val) as total from gx group by 1 order by 2 desc;
42
+ → [{"grp":"a","total":80},{"grp":"b","total":70}]
43
+
44
+ -- Equivalent using named columns
45
+ select grp, count(*) as cnt from gx group by grp having count(*) > 2 order by grp;
46
+ → [{"grp":"a","cnt":3}]
47
+
48
+ -- SELECT-list alias on a grouped column reference survives to the output and
49
+ -- is available to ORDER BY.
50
+ select grp as g, count(*) as cnt from gx group by grp order by g;
51
+ → [{"g":"a","cnt":3},{"g":"b","cnt":2}]
52
+
53
+ -- Same with HAVING — alias still survives.
54
+ select grp as g, count(*) as cnt from gx group by grp having count(*) > 0 order by g;
55
+ → [{"g":"a","cnt":3},{"g":"b","cnt":2}]
56
+
57
+ -- Minimal repro: alias-only on a grouped column ref with no aggregates.
58
+ select grp as g from gx group by grp order by g;
59
+ → [{"g":"a"},{"g":"b"}]
60
+
61
+ -- A non-bare GROUP BY key is matched against the select list by an identity
62
+ -- fingerprint that folds identifier case, so writing the same expression with
63
+ -- different identifier casing still names the same key.
64
+ select grp || sub as combined, count(*) as cnt
65
+ from gx group by GRP || Sub order by combined;
66
+ → [{"combined":"ax","cnt":2},{"combined":"ay","cnt":1},{"combined":"bx","cnt":1},{"combined":"by","cnt":1}]
67
+
68
+ -- Quoted literals are NOT case-folded by that fingerprint: `'-'` and the key's
69
+ -- `'.'` differ, so the select-list expression is not the grouping key and the
70
+ -- bare `grp` inside it is an ungrouped reference.
71
+ select grp || '-' as combined from gx group by grp || '.';
72
+ -- error: Column 'grp' must appear in the GROUP BY clause or be used in an aggregate function
73
+
74
+ drop table gx;
75
+
76
+ -- COLLATE NOCASE written in lowercase on a TEXT column is accepted at DDL (the
77
+ -- name normalizes to canonical NOCASE), and GROUP BY / DISTINCT over that column
78
+ -- honor the column's collation — case-variant values fold into a single group
79
+ -- (unique-collation-name-case-insensitive-normalization).
80
+ create table gn (id integer primary key, name text collate nocase, val integer);
81
+ insert into gn values (1, 'Hello', 10), (2, 'HELLO', 20), (3, 'world', 5);
82
+
83
+ -- GROUP BY folds 'Hello'/'HELLO' under NOCASE into one group. lower(name) keeps
84
+ -- the assertion independent of which case-variant the engine picks as the group
85
+ -- representative.
86
+ select lower(name) as ln, count(*) as c, sum(val) as s from gn group by name order by ln;
87
+ → [{"ln":"hello","c":2,"s":30},{"ln":"world","c":1,"s":5}]
88
+
89
+ -- count(distinct) honors the same collation: the two case-variants count as one.
90
+ select count(distinct name) as n from gn;
91
+ → [{"n":2}]
92
+
93
+ drop table gn;
94
+
95
+ -- GROUP BY a CASE expression
96
+ create table gc (id integer primary key, val integer);
97
+ insert into gc values (1, 5), (2, 15), (3, 25), (4, 35), (5, 45);
98
+
99
+ -- ORDER BY referencing an aggregate (count(*)) is allowed when the query has a GROUP BY.
100
+ select case when val < 20 then 'low' when val < 40 then 'mid' else 'high' end as bucket,
101
+ count(*) as cnt
102
+ from gc group by case when val < 20 then 'low' when val < 40 then 'mid' else 'high' end
103
+ order by count(*) desc, case when val < 20 then 'low' when val < 40 then 'mid' else 'high' end;
104
+ → [{"bucket":"low","cnt":2},{"bucket":"mid","cnt":2},{"bucket":"high","cnt":1}]
105
+
106
+ -- Equivalent without aggregate in ORDER BY: sort by the GROUP BY expression
107
+ select case when val < 20 then 'low' when val < 40 then 'mid' else 'high' end as bucket,
108
+ count(*) as cnt
109
+ from gc group by case when val < 20 then 'low' when val < 40 then 'mid' else 'high' end
110
+ order by case when val < 20 then 'low' when val < 40 then 'mid' else 'high' end;
111
+ → [{"bucket":"high","cnt":1},{"bucket":"low","cnt":2},{"bucket":"mid","cnt":2}]
112
+
113
+ drop table gc;
114
+
115
+ -- ORDER BY aggregate function — additional coverage
116
+ create table aob (id integer primary key, grp text, val integer);
117
+ insert into aob values
118
+ (1, 'a', 10), (2, 'a', 20), (3, 'a', 30),
119
+ (4, 'b', 40), (5, 'b', 50),
120
+ (6, 'c', 70);
121
+
122
+ -- Scalar aggregate sorted by itself: single-row result.
123
+ select count(*) as c from aob order by count(*);
124
+ → [{"c":6}]
125
+
126
+ -- Baseline: ORDER BY alias of an aggregate in SELECT.
127
+ select grp, sum(val) as s from aob group by grp order by s desc;
128
+ → [{"grp":"b","s":90},{"grp":"c","s":70},{"grp":"a","s":60}]
129
+
130
+ -- Same result via explicit aggregate expression in ORDER BY.
131
+ select grp, sum(val) as s from aob group by grp order by sum(val) desc;
132
+ → [{"grp":"b","s":90},{"grp":"c","s":70},{"grp":"a","s":60}]
133
+
134
+ -- Aggregate referenced in ORDER BY only (not in SELECT).
135
+ select grp from aob group by grp order by max(val) desc;
136
+ → [{"grp":"c"},{"grp":"b"},{"grp":"a"}]
137
+
138
+ -- Negative: ORDER BY aggregate in a non-aggregate query is still rejected.
139
+ select id from aob order by sum(val);
140
+ -- error: Aggregate function sum not allowed in this context
141
+
142
+ -- ...and a COLUMN-FREE select list does not change that. Such an item is legal
143
+ -- beside an aggregate (see 25.5), but it is not itself an aggregate, so this query
144
+ -- names no aggregate outside ORDER BY and is not an aggregate query. An aggregate
145
+ -- written only in ORDER BY does not promote it into one -- same as SQLite, which
146
+ -- answers "misuse of aggregate: count()". Add a HAVING (25.2) or select the
147
+ -- aggregate to make the sort key legal.
148
+ select 'k' from aob order by sum(val);
149
+ -- error: Aggregate function sum not allowed in this context
150
+
151
+ drop table aob;
152
+
153
+ -- GROUP BY everything filtered out: no rows
154
+ create table gf (id integer primary key, grp text, val integer);
155
+ insert into gf values (1, 'a', 10), (2, 'b', 20);
156
+
157
+ select grp, count(*) from gf where 1 = 0 group by grp;
158
+ → []
159
+
160
+ drop table gf;
161
+
162
+ -- ---------------------------------------------------------------------------
163
+ -- GROUP BY two qualified columns that share a base name (i.id / c.id → `id`).
164
+ -- Standard SQL allows this; it must group correctly rather than crash at plan
165
+ -- time on a duplicate scope symbol.
166
+ -- ---------------------------------------------------------------------------
167
+ create table items (id integer primary key, name text, category_id integer);
168
+ create table categories (id integer primary key, name text, type_id integer);
169
+ create table log_entry_items (entry_id integer primary key, item_id integer);
170
+ insert into items values (1, 'Widget', 100), (2, 'Gadget', 100), (3, 'Gizmo', 200);
171
+ insert into categories values (100, 'Tools', 7), (200, 'Toys', 7);
172
+ insert into log_entry_items values (10, 1), (11, 1), (12, 2);
173
+
174
+ -- The exact reproduction from the ticket: two qualified same-base-name keys
175
+ -- (`i.id`/`c.id`, `i.name`/`c.name`) group correctly; qualified SELECT columns
176
+ -- resolve to their respective group keys. `usageCount` is 0 for the item with
177
+ -- no log entries (count of a nullable left-join column).
178
+ select i.id, i.name, c.id as categoryId, c.name as categoryName, count(lei.entry_id) as usageCount
179
+ from items i
180
+ join categories c on c.id = i.category_id
181
+ left join log_entry_items lei on lei.item_id = i.id
182
+ where c.type_id = ?
183
+ group by i.id, i.name, c.id, c.name
184
+ order by i.id;
185
+ -- params: [7]
186
+ → [{"id":1,"name":"Widget","categoryId":100,"categoryName":"Tools","usageCount":2},{"id":2,"name":"Gadget","categoryId":100,"categoryName":"Tools","usageCount":1},{"id":3,"name":"Gizmo","categoryId":200,"categoryName":"Toys","usageCount":0}]
187
+
188
+ -- Qualified reference in ORDER BY resolves to the group key (bare `id` would be
189
+ -- ambiguous, but the qualifier disambiguates).
190
+ select i.id as itemId, c.id as catId, count(*) as n
191
+ from items i join categories c on c.id = i.category_id
192
+ group by i.id, c.id
193
+ order by c.id, i.id;
194
+ → [{"itemId":1,"catId":100,"n":1},{"itemId":2,"catId":100,"n":1},{"itemId":3,"catId":200,"n":1}]
195
+
196
+ -- Qualified reference in HAVING resolves to the group key.
197
+ select i.id as itemId, c.id as catId
198
+ from items i join categories c on c.id = i.category_id
199
+ group by i.id, c.id
200
+ having i.id >= 2
201
+ order by i.id;
202
+ → [{"itemId":2,"catId":100},{"itemId":3,"catId":200}]
203
+
204
+ -- Two same-base-name columns projected unqualified-but-aliased → distinct output
205
+ -- columns, no crash.
206
+ select i.id as a, c.id as b, count(*) as n
207
+ from items i join categories c on c.id = i.category_id
208
+ group by i.id, c.id
209
+ order by i.id;
210
+ → [{"a":1,"b":100,"n":1},{"a":2,"b":100,"n":1},{"a":3,"b":200,"n":1}]
211
+
212
+ -- Degenerate duplicate key `group by i.id, i.id` (same column twice) must not
213
+ -- crash; the qualified key still resolves.
214
+ select i.id as itemId, count(*) as n
215
+ from items i
216
+ group by i.id, i.id
217
+ order by i.id;
218
+ → [{"itemId":1,"n":1},{"itemId":2,"n":1},{"itemId":3,"n":1}]
219
+
220
+ -- Negative: a genuinely ambiguous *bare* reference (HAVING `id` with two `id`
221
+ -- group keys) raises the clear ambiguity error rather than crashing or silently
222
+ -- binding to one source column.
223
+ select i.id as itemId, c.id as catId
224
+ from items i join categories c on c.id = i.category_id
225
+ group by i.id, c.id
226
+ having id >= 0;
227
+ -- error: ambiguous column name: id
228
+
229
+ -- Regression: single-table `group by c.id, c.name` (distinct base names) still
230
+ -- works and resolves qualified references.
231
+ select c.id, c.name, count(*) as n
232
+ from categories c
233
+ group by c.id, c.name
234
+ order by c.id;
235
+ → [{"id":100,"name":"Tools","n":1},{"id":200,"name":"Toys","n":1}]
236
+
237
+ drop table items;
238
+ drop table categories;
239
+ drop table log_entry_items;
240
+
241
+ -- ---------------------------------------------------------------------------
242
+ -- HAVING / ORDER BY aggregate matching by canonical AST fingerprint, not a
243
+ -- shallow argument peek (bug-aggregate-reuse-matching-ignores-arguments).
244
+ --
245
+ -- A clause above the AggregateNode (HAVING, a top-level ORDER BY) that spells
246
+ -- out an aggregate must only bind to the SELECT list's computed column when the
247
+ -- argument expressions actually match; a differently-shaped argument must be
248
+ -- collected and computed as its own aggregate instead.
249
+ -- ---------------------------------------------------------------------------
250
+ create table wg (a text, b text);
251
+ insert into wg values ('x','1'),('y','2'),('x','3');
252
+
253
+ -- Fixed: HAVING spells a *different* aggregate (`sum(a+0)`) than the SELECT
254
+ -- list's `sum(b+0)`. `sum(a+0)` is 0 for every group, so no group qualifies.
255
+ select a, sum(b+0) as s from wg group by a having sum(a+0) > 3;
256
+ → []
257
+
258
+ -- Fixed: same divergence in ORDER BY. `sum(a+0)` is 0 for every group, so the
259
+ -- sort is a no-op and rows keep source (group-discovery) order.
260
+ select a, sum(b+0) as s from wg group by a order by sum(a+0);
261
+ → [{"a":"x","s":4},{"a":"y","s":2}]
262
+
263
+ -- Control: identical spelling (`count(*)`) still reads the computed column.
264
+ select a, count(*) as c from wg group by a having count(*) > 1;
265
+ → [{"a":"x","c":2}]
266
+
267
+ -- Control: DISTINCT participates in the match — `count(distinct b)` is its own
268
+ -- aggregate, matched by its own spelling.
269
+ select a, count(distinct b) as cd from wg group by a having count(distinct b) > 1;
270
+ → [{"a":"x","cd":2}]
271
+
272
+ -- Control: a SELECT-list alias reference resolves through the aggregate output
273
+ -- scope, not through this matching at all.
274
+ select a, sum(b) as s from wg group by a having s > 3;
275
+ → [{"a":"x","s":4}]
276
+
277
+ -- Control: whitespace and redundant parentheses don't defeat the match — the
278
+ -- fingerprint normalizes them.
279
+ select a, sum(b+0) as s from wg group by a having sum(b + 0) > 3;
280
+ → [{"a":"x","s":4}]
281
+
282
+ select a, sum(b) as s from wg group by a having sum((b)) > 3;
283
+ → [{"a":"x","s":4}]
284
+
285
+ -- Control: identifier case doesn't defeat the match.
286
+ select a, sum(B) as s from wg group by a having sum(b) > 3;
287
+ → [{"a":"x","s":4}]
288
+
289
+ -- Narrowing (documented, not fixed): a qualifier divergence (`w.b` vs bare `b`)
290
+ -- no longer matches, so HAVING computes a second, redundant aggregate over the
291
+ -- same column instead of reusing the SELECT list's — the answer is unaffected.
292
+ select a, sum(w.b) as s from wg w group by a having sum(b) > 3;
293
+ → [{"a":"x","s":4}]
294
+
295
+ -- ---------------------------------------------------------------------------
296
+ -- HAVING may name a GROUPING KEY by the SELECT-list alias of the column that
297
+ -- selects it, just as it can name an aggregate by its alias (the control above).
298
+ -- Both are ordinary output columns of the grouped query and both are registered
299
+ -- in the aggregate output scope
300
+ -- (bug-window-spec-cannot-name-group-key-by-select-alias).
301
+ -- ---------------------------------------------------------------------------
302
+
303
+ select a as k, count(*) as c from wg group by a having k = 'x';
304
+ → [{"k":"x","c":2}]
305
+
306
+ -- A COMPUTED grouping key's alias resolves too — the select-list column is
307
+ -- matched to its key by expression identity rather than by attribute.
308
+ select upper(a) as k, count(*) as c from wg group by upper(a) having k = 'X';
309
+ → [{"k":"X","c":2}]
310
+
311
+ -- The alias reaches inside a SUBQUERY in the predicate, where it correlates back to
312
+ -- the grouping key. Two rows have a='x', one has a='y'.
313
+ select a as k, count(*) as c from wg group by a having (select count(*) from wg t where t.a = k) > 1;
314
+ → [{"k":"x","c":2}]
315
+
316
+ -- Beside an aggregate alias, both resolving through the same scope.
317
+ select a as k, sum(b) as s from wg group by a having k = 'x' and s > 3;
318
+ → [{"k":"x","s":4}]
319
+
320
+ -- DELIBERATE: the alias SHADOWS a same-named base-table column. `b` is a real
321
+ -- column of `wg`, but in HAVING the alias wins and `b` is the grouping key `a`.
322
+ -- Same rule an aggregate alias already had.
323
+ select a as b, count(*) as c from wg group by a having b = 'x';
324
+ → [{"b":"x","c":2}]
325
+
326
+ -- DELIBERATE, the other way: an alias is the LOWEST-precedence name in that
327
+ -- scope and does not outrank a GROUPING KEY of the same name. `b` is both the
328
+ -- alias of the `a` key and a grouping key here; HAVING `b = '1'` filters on the
329
+ -- grouping key (one row survives), not on the alias (which would match nothing).
330
+ select a as b, count(*) as c from wg group by a, b having b = '1';
331
+ → [{"b":"x","c":1}]
332
+
333
+ -- Two aliases naming DIFFERENT grouping keys collide, and nothing in the scope
334
+ -- can arbitrate, so a bare reference to the shared name is ambiguous.
335
+ select a as k, b as k, count(*) as c from wg group by a, b having k = 'x';
336
+ -- error: ambiguous column name: k
337
+
338
+ -- The SELECT list itself is NOT widened by any of this: a select-list column
339
+ -- still cannot name a sibling's alias, aggregate or grouping key alike. It is
340
+ -- built against the pre-aggregate scope, before the aggregate output scope exists.
341
+ select a, count(*) as c, c + 0 as d from wg group by a;
342
+ -- error: Column not found: c
343
+
344
+ select a as k, k as k2 from wg group by a;
345
+ -- error: Column not found: k
346
+
347
+ -- A quoted alias may contain a dot, which the scope's flat string key cannot tell
348
+ -- apart from the qualified spelling of a grouping key. The alias is skipped rather
349
+ -- than registered, so `"wg.a"` here is the grouping key `wg.a` and the query plans
350
+ -- as it did before aliases were registered at all
351
+ -- (bug-scope-symbol-keys-collide-with-dotted-column-names owns the underlying
352
+ -- flat-key collision).
353
+ select wg.a as "wg.a", count(*) as c from wg group by wg.a having "wg.a" = 'x';
354
+ → [{"wg.a":"x","c":2}]
355
+
356
+ -- Same skip when the dotted alias names a DIFFERENT key than the qualified spelling
357
+ -- it collides with: HAVING filters on the grouping key `a`, not on the alias of `b`.
358
+ select wg.b as "wg.a", count(*) as c from wg group by wg.a, wg.b having "wg.a" = 'x';
359
+ → [{"wg.a":"1","c":1},{"wg.a":"3","c":1}]
360
+
361
+ -- An alias whose grouping key came from a GROUP BY ORDINAL resolves like any other.
362
+ select a as k, count(*) as c from wg group by 1 having k = 'x';
363
+ → [{"k":"x","c":2}]
364
+
365
+ -- An alias colliding with a bare group-key name that is ALREADY ambiguous stays
366
+ -- ambiguous — the skip leaves the existing marking untouched rather than resolving
367
+ -- the name to the alias's key.
368
+ select i.a as a, count(*) as c from wg i join wg c on i.a = c.a group by i.a, c.a having a = 'x';
369
+ -- error: ambiguous column name: a
370
+
371
+ -- A VIEW body is planned the same way, so a grouping-key alias works there too.
372
+ create view vw_key_alias as select a as k, count(*) as c from wg group by a having k = 'x';
373
+
374
+ select k, c from vw_key_alias;
375
+ → [{"k":"x","c":2}]
376
+
377
+ drop view vw_key_alias;
378
+
379
+ -- ---------------------------------------------------------------------------
380
+ -- A subquery's HAVING may name a column of the ENCLOSING query
381
+ -- (bug-having-rejects-correlated-outer-column).
382
+ --
383
+ -- The grouped-query restriction HAVING enforces is about THIS query's own
384
+ -- ungrouped columns. A correlated reference out to the surrounding query is a
385
+ -- different query's column and is legal in `having` exactly as it is in `where`.
386
+ -- ---------------------------------------------------------------------------
387
+
388
+ -- The inner HAVING compares a grouping key against the enclosing row's column.
389
+ select w.b, (select count(*) from wg t group by t.a having t.a = w.a) as c
390
+ from wg w order by w.b;
391
+ → [{"b":"1","c":2},{"b":"2","c":1},{"b":"3","c":2}]
392
+
393
+ -- Same, with the enclosing column compared against one of the inner aggregates.
394
+ -- Counts per group are x=2, y=1, so the group that survives differs per outer row.
395
+ select w.b, (select count(*) from wg t group by t.a having count(*) = w.b + 0) as c
396
+ from wg w order by w.b;
397
+ → [{"b":"1","c":1},{"b":"2","c":2},{"b":"3","c":null}]
398
+
399
+ -- Same again, with the enclosing column on the LEFT of the comparison and a
400
+ -- non-count aggregate on the right.
401
+ select w.b, (select count(*) from wg t group by t.a having w.a = max(t.a)) as c
402
+ from wg w order by w.b;
403
+ → [{"b":"1","c":2},{"b":"2","c":1},{"b":"3","c":2}]
404
+
405
+ -- Same, in a HAVING with no GROUP BY at all (implicit single group).
406
+ select w.b, (select count(*) from wg t having count(*) = 3 and w.b = '2') as c
407
+ from wg w order by w.b;
408
+ → [{"b":"1","c":null},{"b":"2","c":3},{"b":"3","c":null}]
409
+
410
+ -- Control: for comparison, the same correlation in WHERE, which always worked.
411
+ select w.b, (select count(*) from wg t where t.a = w.a group by t.a) as c
412
+ from wg w order by w.b;
413
+ → [{"b":"1","c":2},{"b":"2","c":1},{"b":"3","c":2}]
414
+
415
+ -- Negative, grouped: the inner query's OWN ungrouped column keeps its rejection.
416
+ select w.b, (select count(*) from wg t group by t.a having t.b = '1') as c from wg w;
417
+ -- error: HAVING references non-grouped column 'b'
418
+
419
+ -- Negative, no GROUP BY: same restriction, same message — pinned in full here, so
420
+ -- the "may only reference" tail is asserted somewhere and not just the prefix.
421
+ select w.b, (select count(*) from wg t having t.b = '1') as c from wg w;
422
+ -- error: HAVING references non-grouped column 'b'; HAVING may only reference GROUP BY columns or aggregate expressions
423
+
424
+ -- Correlating TWO levels out of a HAVING, not just one.
425
+ select o.b, (select count(*) from wg m where m.b = o.b
426
+ and (select count(*) from wg t group by t.a having t.a = o.a) > 0) as c
427
+ from wg o order by o.b;
428
+ → [{"b":"1","c":1},{"b":"2","c":1},{"b":"3","c":1}]
429
+
430
+ -- The ENCLOSING query is itself grouped, and the inner HAVING names its GROUPING KEY.
431
+ select w.a, count(*) as n, (select count(*) from wg t group by t.a having t.a = w.a) as c
432
+ from wg w group by w.a order by w.a;
433
+ → [{"a":"x","n":2,"c":2},{"a":"y","n":1,"c":1}]
434
+
435
+ -- Same shape, but the inner HAVING names an UNGROUPED column of the enclosing grouped
436
+ -- query. HAVING's own check cannot see it (`w.b` is not one of the INNER query's
437
+ -- pre-grouping columns), so it is the enclosing query's finished-plan check that
438
+ -- rejects it, with the general wording rather than HAVING's dedicated message.
439
+ select w.a, count(*) as n, (select count(*) from wg t group by t.a having t.a = w.b) as c
440
+ from wg w group by w.a;
441
+ -- error: Column 'w.b' must appear in the GROUP BY clause or be used in an aggregate function
442
+
443
+ -- The `skipSubqueries` contract: an ungrouped column of THIS query reached through a
444
+ -- subquery inside HAVING is left to the finished-plan check, so it raises the general
445
+ -- message and not HAVING's. This is the entire reason that parameter exists.
446
+ select a, count(*) as c from wg group by a
447
+ having (select max(t.a) from wg t where t.a = wg.b) = 'x';
448
+ -- error: Column 'wg.b' must appear in the GROUP BY clause or be used in an aggregate function
449
+
450
+ -- ---------------------------------------------------------------------------
451
+ -- An aggregate query with NO GROUP BY gets the same finished-plan check
452
+ -- (bug-no-group-by-aggregate-skips-subquery-coverage-check).
453
+ --
454
+ -- Such a query has exactly one implicit group, so every clause ABOVE the
455
+ -- aggregation — HAVING, an ORDER BY forced up there, LIMIT, OFFSET — may read
456
+ -- only the aggregate results. Reading a source column instead is the same user
457
+ -- error the grouped form already reports, and now reports the same way.
458
+ -- ---------------------------------------------------------------------------
459
+
460
+ -- HAVING, subquery correlating back to an ungrouped column of THIS query. The
461
+ -- `group by a` twin directly below raises the identical message; before the fix
462
+ -- this one silently answered off an arbitrary source row (returning []).
463
+ select count(*) as c from wg
464
+ having (select max(t.a) from wg t where t.b = wg.b) = 'x';
465
+ -- error: Column 'wg.b' must appear in the GROUP BY clause or be used in an aggregate function
466
+
467
+ select a, count(*) as c from wg group by a
468
+ having (select max(t.a) from wg t where t.b = wg.b) = 'x';
469
+ -- error: Column 'wg.b' must appear in the GROUP BY clause or be used in an aggregate function
470
+
471
+ -- ORDER BY, once a select-list alias or an aggregate has forced the whole list
472
+ -- above the aggregation. Both spellings of the forcing term are pinned.
473
+ select count(*) as c from wg order by c, (select max(t.a) from wg t where t.b = wg.b);
474
+ -- error: Column 'wg.b' must appear in the GROUP BY clause or be used in an aggregate function
475
+
476
+ select count(*) as c from wg order by count(*), (select max(t.a) from wg t where t.b = wg.b);
477
+ -- error: Column 'wg.b' must appear in the GROUP BY clause or be used in an aggregate function
478
+
479
+ -- LIMIT / OFFSET. These reached the runtime before the fix and died there with an
480
+ -- engine-internal "No row context found for column b" the user could not act on;
481
+ -- these cases pin the conversion to the plan-time message.
482
+ select count(*) as c from wg limit b;
483
+ -- error: Column 'b' must appear in the GROUP BY clause or be used in an aggregate function
484
+
485
+ select count(*) as c from wg limit (select count(*) from wg t where t.b = wg.b);
486
+ -- error: Column 'wg.b' must appear in the GROUP BY clause or be used in an aggregate function
487
+
488
+ select count(*) as c from wg limit 1 offset (select count(*) from wg t where t.b = wg.b);
489
+ -- error: Column 'wg.b' must appear in the GROUP BY clause or be used in an aggregate function
490
+
491
+ -- The grouped twin of the LIMIT case, which always reported at plan time.
492
+ select a, count(*) as c from wg group by a limit b;
493
+ -- error: Column 'b' must appear in the GROUP BY clause or be used in an aggregate function
494
+
495
+ -- Positives — the check must not over-reject. A subquery reading only its OWN
496
+ -- columns is not a reference to this query at all.
497
+ select count(*) as c from wg having (select max(t.a) from wg t) = 'y';
498
+ → [{"c":3}]
499
+
500
+ select count(*) as c from wg having (select max(t.a) from wg t) = 'zz';
501
+ → []
502
+
503
+ -- A correlated reference to an ENCLOSING query, made from an ungrouped inner
504
+ -- aggregate and buried one subquery deeper still. `w.b` belongs to the outer
505
+ -- query, so the inner query's check leaves it alone. max(u.a) per outer b is
506
+ -- 'x','y','x', so only b='2' fails the comparison.
507
+ select w.b, (select count(*) from wg t
508
+ having (select max(u.a) from wg u where u.b = w.b) = 'x') as c
509
+ from wg w order by w.b;
510
+ → [{"b":"1","c":3},{"b":"2","c":null},{"b":"3","c":3}]
511
+
512
+ select count(*) as c from wg order by count(*);
513
+ → [{"c":3}]
514
+
515
+ select count(*) as c from wg order by (select max(t.a) from wg t);
516
+ → [{"c":3}]
517
+
518
+ select count(*) as c from wg limit (select count(*) from wg t);
519
+ → [{"c":3}]
520
+
521
+ -- The documented pre-aggregate-sort extension stays legal. With no GROUP BY and
522
+ -- no term naming an alias or an aggregate, the whole ORDER BY sorts the INPUT
523
+ -- rows before aggregation, so a correlated subquery in it is evaluated once per
524
+ -- input row and is well defined. That sort sits BELOW the aggregate, which is
525
+ -- where the finished-plan walk stops. Asserted in both directions so the
526
+ -- ordering is observable rather than incidental.
527
+ select group_concat(b) as g from wg
528
+ order by (select max(t.b) from wg t where t.b = wg.b) desc;
529
+ → [{"g":"3,2,1"}]
530
+
531
+ select group_concat(b) as g from wg
532
+ order by (select max(t.b) from wg t where t.b = wg.b) asc;
533
+ → [{"g":"1,2,3"}]
534
+
535
+ -- DISTINCT above the implicit single group is unaffected either way.
536
+ select distinct count(*) as c from wg order by c;
537
+ → [{"c":3}]
538
+
539
+ -- A VIEW body is planned the same way, so the mistake is caught at `create view`
540
+ -- time rather than at first read of the view.
541
+ create view vw_ungrouped_limit as select count(*) as c from wg limit b;
542
+ -- error: Column 'b' must appear in the GROUP BY clause or be used in an aggregate function
543
+
544
+ -- Same for a MATERIALIZED VIEW body, which takes a different creation path.
545
+ create materialized view mvw_ungrouped_limit as select count(*) as c from wg limit b;
546
+ -- error: Column 'b' must appear in the GROUP BY clause or be used in an aggregate function
547
+
548
+ -- EXISTS is another spelling of the correlated-subquery mistake — the walk is
549
+ -- about the reference, not about the subquery being scalar.
550
+ select count(*) as c from wg having exists (select 1 from wg t where t.a = wg.a);
551
+ -- error: Column 'wg.a' must appear in the GROUP BY clause or be used in an aggregate function
552
+
553
+ -- LIMIT is newly covered by the check, so the shape it must NOT reject is pinned
554
+ -- too: an ungrouped aggregate SUBQUERY whose LIMIT correlates OUT to the
555
+ -- enclosing query. `w.a` is the enclosing query's column, not this one's.
556
+ select w.a, (select count(*) from wg t
557
+ limit (select count(*) from wg u where u.a = w.a)) as c
558
+ from wg w order by w.a;
559
+ → [{"a":"x","c":3},{"a":"x","c":3},{"a":"y","c":3}]
560
+
561
+ -- Compound and VALUES-fed ungrouped aggregates keep working: each arm is planned
562
+ -- as its own aggregate query, and neither reads anything above its aggregation.
563
+ select count(*) as c from wg union all select count(*) from wg;
564
+ → [{"c":3},{"c":3}]
565
+
566
+ select count(*) as c from (values ('x'),('y'));
567
+ → [{"c":2}]
568
+
569
+ drop table wg;
570
+
571
+ -- ---------------------------------------------------------------------------
572
+ -- HAVING / ORDER BY aggregate matching folds identifier case only, not literal
573
+ -- case (bug-aggregate-match-ignores-string-literal-case). A quoted string
574
+ -- literal's case is part of an aggregate's identity: two aggregates that differ
575
+ -- only in literal case (`nullif(b,'A')` vs `nullif(b,'a')`) must never collapse
576
+ -- into one, or a clause above the AggregateNode silently reads the wrong number.
577
+ -- ---------------------------------------------------------------------------
578
+ create table wgl (id integer primary key, g integer, b text);
579
+ insert into wgl values
580
+ (1, 1, 'A'), (2, 1, 'A'), (3, 1, 'a'),
581
+ (4, 2, 'A'), (5, 2, 'a'), (6, 2, 'a');
582
+
583
+ -- Fixed: HAVING spells a literal-case-distinct aggregate (`nullif(b,'a')`) from
584
+ -- the SELECT list's `nullif(b,'A')`; HAVING binds to its own aggregate rather
585
+ -- than reusing (and reporting) the SELECT list's.
586
+ select g, count(nullif(b,'A')) as c from wgl where g = 1 group by g having count(nullif(b,'a')) > 1;
587
+ → [{"g":1,"c":1}]
588
+
589
+ -- Same shape, both aggregates present in the SELECT list: HAVING must bind to
590
+ -- `d`, not silently reuse `c`.
591
+ select g, count(nullif(b,'A')) as c, count(nullif(b,'a')) as d from wgl where g = 1 group by g having count(nullif(b,'a')) > 1;
592
+ → [{"g":1,"c":1,"d":2}]
593
+
594
+ -- Fixed: same divergence in a top-level ORDER BY, using two groups so a wrong
595
+ -- bind changes row order (not just a displayed value). Ordering by
596
+ -- count(nullif(b,'a')) (g=1 → 2, g=2 → 1) puts g=2 first; the buggy fold would
597
+ -- instead have ordered by the SELECT list's count(nullif(b,'A')) (g=1 → 1,
598
+ -- g=2 → 2), putting g=1 first.
599
+ select g, count(nullif(b,'A')) as c from wgl group by g order by count(nullif(b,'a'));
600
+ → [{"g":2,"c":2},{"g":1,"c":1}]
601
+
602
+ drop table wgl;