@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.
- package/README.md +2 -0
- package/dist/src/common/types.d.ts +4 -4
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/schema/catalog-rendering.js +13 -1
- package/dist/src/schema/catalog-rendering.js.map +1 -1
- package/dist/src/schema/catalog.d.ts +35 -2
- package/dist/src/schema/catalog.d.ts.map +1 -1
- package/dist/src/schema/catalog.js +42 -33
- package/dist/src/schema/catalog.js.map +1 -1
- package/dist/src/schema/schema-differ.d.ts +1 -1
- package/dist/src/schema/schema-differ.d.ts.map +1 -1
- package/dist/src/schema/schema-differ.js +195 -33
- package/dist/src/schema/schema-differ.js.map +1 -1
- package/dist/src/schema/unique-enforcement.d.ts +23 -1
- package/dist/src/schema/unique-enforcement.d.ts.map +1 -1
- package/dist/src/schema/unique-enforcement.js +43 -1
- package/dist/src/schema/unique-enforcement.js.map +1 -1
- package/dist/src/vtab/memory/layer/manager.d.ts +15 -12
- package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/manager.js +87 -100
- package/dist/src/vtab/memory/layer/manager.js.map +1 -1
- package/package.json +7 -4
- package/test/README.md +173 -0
- package/test/logic/01-basic.sqllogic +39 -0
- package/test/logic/01.1-select-projection-extras.sqllogic +130 -0
- package/test/logic/01.2-strings.sqllogic +43 -0
- package/test/logic/01.5-insert-select.sqllogic +237 -0
- package/test/logic/01.6-update-extras.sqllogic +118 -0
- package/test/logic/01.7-update-from.sqllogic +67 -0
- package/test/logic/01.8-delete-extras.sqllogic +122 -0
- package/test/logic/01.8.1-delete-range-cow.sqllogic +115 -0
- package/test/logic/01.9-query-expr-dml-gates.sqllogic +32 -0
- package/test/logic/01.9-query-expr-dml.sqllogic +171 -0
- package/test/logic/01.9-query-expr-values.sqllogic +111 -0
- package/test/logic/01.9.1-limit-over-dml-subquery.sqllogic +119 -0
- package/test/logic/02-filters.sqllogic +54 -0
- package/test/logic/02-smoke.sqllogic +62 -0
- package/test/logic/02.1-bind-parameters.sqllogic +223 -0
- package/test/logic/03-expressions.sqllogic +190 -0
- package/test/logic/03.1-quoted-identifiers.sqllogic +55 -0
- package/test/logic/03.4-defaults.sqllogic +554 -0
- package/test/logic/03.4.1-default-edge-cases.sqllogic +99 -0
- package/test/logic/03.5-tvf.sqllogic +61 -0
- package/test/logic/03.6-type-system.sqllogic +544 -0
- package/test/logic/03.6.1-numeric-text-comparison-coercion.sqllogic +244 -0
- package/test/logic/03.6.2-value-to-text.sqllogic +224 -0
- package/test/logic/03.7-bigint-mixed-arithmetic.sqllogic +65 -0
- package/test/logic/03.8-not-precedence.sqllogic +255 -0
- package/test/logic/03.9-is-bool-predicate.sqllogic +150 -0
- package/test/logic/03.9.1-is-bool-predicate-partial-index.sqllogic +34 -0
- package/test/logic/04-order-by.sqllogic +38 -0
- package/test/logic/04-transactions.sqllogic +239 -0
- package/test/logic/04a-savepoint-lazy-attach.sqllogic +122 -0
- package/test/logic/05-vtab_memory.sqllogic +50 -0
- package/test/logic/05.0.1-vtab-memory-unique-index-collation.sqllogic +34 -0
- package/test/logic/05.1-composite-pk-range-scan.sqllogic +147 -0
- package/test/logic/05.1.1-secondary-index-range-scan.sqllogic +56 -0
- package/test/logic/05.2-cast-seek-correctness.sqllogic +124 -0
- package/test/logic/06-builtin_functions.sqllogic +149 -0
- package/test/logic/06.1-string-functions.sqllogic +92 -0
- package/test/logic/06.1.3-like-glob-edges.sqllogic +53 -0
- package/test/logic/06.2-math-functions.sqllogic +82 -0
- package/test/logic/06.3-schema.sqllogic +48 -0
- package/test/logic/06.3.1-schema-all-schemas.sqllogic +39 -0
- package/test/logic/06.3.2-schema-foreign-keys.sqllogic +208 -0
- package/test/logic/06.3.3-introspection-tags.sqllogic +202 -0
- package/test/logic/06.3.3.1-introspection-tags-index.sqllogic +74 -0
- package/test/logic/06.3.4-view-info.sqllogic +378 -0
- package/test/logic/06.3.5-column-info.sqllogic +347 -0
- package/test/logic/06.3.6-schema-views.sqllogic +29 -0
- package/test/logic/06.4-schema-search-path.sqllogic +354 -0
- package/test/logic/06.4.1-schema-case-insensitive.sqllogic +83 -0
- package/test/logic/06.4.2-collation-extras.sqllogic +472 -0
- package/test/logic/06.4.2.1-collation-index-access-paths.sqllogic +140 -0
- package/test/logic/06.4.3-write-path-collation.sqllogic +99 -0
- package/test/logic/06.4.4-comparison-collation-precedence.sqllogic +342 -0
- package/test/logic/06.4.5-any-collate-declared-keys.sqllogic +92 -0
- package/test/logic/06.5-polymorphic-types.sqllogic +169 -0
- package/test/logic/06.5.1-conversion-functions.sqllogic +173 -0
- package/test/logic/06.5.2-scalar-minmax.sqllogic +16 -0
- package/test/logic/06.5.3-undeclared-return-type-comparison.sqllogic +244 -0
- package/test/logic/06.5.4-declared-return-type-builtins.sqllogic +288 -0
- package/test/logic/06.6-aggregate-extended.sqllogic +78 -0
- package/test/logic/06.7-json-extended.sqllogic +53 -0
- package/test/logic/06.8-json-path-operators.sqllogic +99 -0
- package/test/logic/06.9-json-canonical-key.sqllogic +65 -0
- package/test/logic/06.9.1-json-coerce-once.sqllogic +417 -0
- package/test/logic/06.9.1.1-json-coerce-once-index.sqllogic +39 -0
- package/test/logic/06.9.2-json-structural-equality.sqllogic +382 -0
- package/test/logic/06.9.2.1-json-structural-equality-index.sqllogic +76 -0
- package/test/logic/06.9.3-json-index-range-seek.sqllogic +205 -0
- package/test/logic/07-aggregates.sqllogic +193 -0
- package/test/logic/07.1-aggregate-filter-clause.sqllogic +12 -0
- package/test/logic/07.2-aggregate-order-by.sqllogic +11 -0
- package/test/logic/07.3-group-by-extras.sqllogic +602 -0
- package/test/logic/07.3.1-group-by-order-by-key.sqllogic +164 -0
- package/test/logic/07.3.2-grouped-select-list-shape.sqllogic +231 -0
- package/test/logic/07.4-group-by-filter-composite-pk.sqllogic +120 -0
- package/test/logic/07.5-sum-mixed-exact-and-float.sqllogic +151 -0
- package/test/logic/07.5-window.sqllogic +1941 -0
- package/test/logic/07.5.1-window-named.sqllogic +13 -0
- package/test/logic/07.5.2-window-nth-value.sqllogic +13 -0
- package/test/logic/07.6-subqueries.sqllogic +78 -0
- package/test/logic/07.6.1-subquery-extras.sqllogic +93 -0
- package/test/logic/07.7-and-or-short-circuit.sqllogic +58 -0
- package/test/logic/07.7-in-subquery-caching.sqllogic +174 -0
- package/test/logic/07.7-scalar-agg-decorrelation.sqllogic +197 -0
- package/test/logic/07.7.1-in-extras.sqllogic +158 -0
- package/test/logic/07.7.1-scalar-agg-decorrelation-filter.sqllogic +105 -0
- package/test/logic/07.7.2-scalar-agg-decorrelation-nested.sqllogic +115 -0
- package/test/logic/07.7.3-exists-in-select-decorrelation.sqllogic +107 -0
- package/test/logic/07.7.4-where-conjunct-ordering.sqllogic +121 -0
- package/test/logic/07.7.5-filter-lost-under-index-order.sqllogic +134 -0
- package/test/logic/07.7.6-correlated-predicate-scope.sqllogic +178 -0
- package/test/logic/07.7.7-join-source-scope-shadowing.sqllogic +137 -0
- package/test/logic/07.7.8-correlated-ref-to-computed-column.sqllogic +165 -0
- package/test/logic/07.7.9-conjunct-monotonicity.sqllogic +200 -0
- package/test/logic/07.8-correlated-subquery-edges.sqllogic +71 -0
- package/test/logic/07.8.1-correlated-in-decorrelation-gates.sqllogic +156 -0
- package/test/logic/07.9-in-value-list.sqllogic +154 -0
- package/test/logic/07.9.1-in-value-list-composite-index.sqllogic +38 -0
- package/test/logic/08-views.sqllogic +64 -0
- package/test/logic/08.1-semi-anti-join.sqllogic +191 -0
- package/test/logic/08.1-view-edge-cases.sqllogic +118 -0
- package/test/logic/08.1.1-uncorrelated-in-semijoin.sqllogic +251 -0
- package/test/logic/08.2-existence-flag-semijoin-recovery.sqllogic +197 -0
- package/test/logic/08.3-existence-flag-inner-recovery.sqllogic +102 -0
- package/test/logic/08.4-key-set-semi-join.sqllogic +447 -0
- package/test/logic/09-set_operations.sqllogic +244 -0
- package/test/logic/09.1-set-op-cross-collation.sqllogic +230 -0
- package/test/logic/10-distinct_datatypes.sqllogic +127 -0
- package/test/logic/10.1-ddl-lifecycle.sqllogic +203 -0
- package/test/logic/10.1.1-create-table-syntax-edges.sqllogic +47 -0
- package/test/logic/10.1.2-ddl-in-transaction.sqllogic +143 -0
- package/test/logic/10.1.2.1-add-constraint-in-transaction.sqllogic +59 -0
- package/test/logic/10.1.3-ddl-drop-in-transaction.sqllogic +187 -0
- package/test/logic/10.1.3.1-drop-constraint-in-transaction.sqllogic +45 -0
- package/test/logic/10.1.4-create-table-duplicate-constraint-names.sqllogic +149 -0
- package/test/logic/10.1.4-ddl-transaction-policy.sqllogic +314 -0
- package/test/logic/10.1.5-alter-add-constraint-minted-name-disambiguation.sqllogic +219 -0
- package/test/logic/10.1.5-create-index-lifecycle.sqllogic +72 -0
- package/test/logic/10.1.6-ddl-transaction-policy-index.sqllogic +143 -0
- package/test/logic/10.1.7-create-table-default-type-check.sqllogic +119 -0
- package/test/logic/10.1.8-alter-add-check-existing-rows.sqllogic +117 -0
- package/test/logic/10.2-column-features.sqllogic +365 -0
- package/test/logic/10.2.1-table-options-rejection.sqllogic +63 -0
- package/test/logic/10.2.2-default-collation-memory.sqllogic +30 -0
- package/test/logic/10.3-function-features.sqllogic +247 -0
- package/test/logic/10.4-schema-scale.sqllogic +168 -0
- package/test/logic/10.4.1-schema-scale-indexes.sqllogic +121 -0
- package/test/logic/10.5-indexes.sqllogic +164 -0
- package/test/logic/10.5.1-partial-indexes.sqllogic +526 -0
- package/test/logic/10.5.2-expression-indexes.sqllogic +34 -0
- package/test/logic/10.5.3-desc-index-ordering.sqllogic +130 -0
- package/test/logic/10.5.4-composite-pk-index-update-phantom.sqllogic +55 -0
- package/test/logic/10.5.5-index-name-uniqueness.sqllogic +76 -0
- package/test/logic/10.5.6-minmax-index-boundary.sqllogic +204 -0
- package/test/logic/10.5.7-implicit-unique-index-lifecycle.sqllogic +1216 -0
- package/test/logic/10.6-distinct-edge-cases.sqllogic +119 -0
- package/test/logic/100-predicate-normalization-edge-cases.sqllogic +238 -0
- package/test/logic/100.1-where-extras.sqllogic +163 -0
- package/test/logic/100.1.1-where-join-on-order-indexed.sqllogic +35 -0
- package/test/logic/101-builtin-mutation-kills.sqllogic +974 -0
- package/test/logic/101-transaction-edge-cases.sqllogic +395 -0
- package/test/logic/102-schema-catalog-edge-cases.sqllogic +252 -0
- package/test/logic/102-unique-constraints.sqllogic +145 -0
- package/test/logic/102.0.1-schema-catalog-indexed-table.sqllogic +32 -0
- package/test/logic/102.1-unique-edge-cases.sqllogic +111 -0
- package/test/logic/102.1.1-unique-index-creation-edge-cases.sqllogic +75 -0
- package/test/logic/102.2-unique-collation.sqllogic +181 -0
- package/test/logic/102.2.1-unique-collation-index-derived.sqllogic +305 -0
- package/test/logic/103-database-options-edge-cases.sqllogic +108 -0
- package/test/logic/103.1-pragma-boolean-values.sqllogic +126 -0
- package/test/logic/104-emit-mutation-kills.sqllogic +236 -0
- package/test/logic/105-vtab-memory-mutation-kills.sqllogic +754 -0
- package/test/logic/105.1-vtab-memory-index-mutation-kills.sqllogic +540 -0
- package/test/logic/106-constraint-extractor-mutation-kills.sqllogic +350 -0
- package/test/logic/107-temporal-arithmetic-mutation-kills.sqllogic +833 -0
- package/test/logic/108-cardinality-estimation.sqllogic +146 -0
- package/test/logic/108.1-analyze-name-resolution.sqllogic +102 -0
- package/test/logic/109-aggregate-physical-selection.sqllogic +103 -0
- package/test/logic/11-joins.sqllogic +86 -0
- package/test/logic/11.1-join-using.sqllogic +267 -0
- package/test/logic/11.2-comma-join.sqllogic +35 -0
- package/test/logic/11.3-index-nested-loop-join.sqllogic +305 -0
- package/test/logic/11.3-mismatched-collation-join.sqllogic +74 -0
- package/test/logic/11.4-hash-join-side-swap.sqllogic +118 -0
- package/test/logic/110-scan-emitter-mutation-kills.sqllogic +121 -0
- package/test/logic/110.1-scan-emitter-index-scan-kills.sqllogic +47 -0
- package/test/logic/12-empty-primary-key.sqllogic +124 -0
- package/test/logic/12-join_padding_order.sqllogic +58 -0
- package/test/logic/12.1-orderby-index-consumption.sqllogic +40 -0
- package/test/logic/13-cte.sqllogic +137 -0
- package/test/logic/13.1-cte-multiple-recursive.sqllogic +104 -0
- package/test/logic/13.10-cte-qualified-name.sqllogic +136 -0
- package/test/logic/13.11-unreferenced-dml-cte.sqllogic +414 -0
- package/test/logic/13.12-nested-dml-cte-rejected.sqllogic +280 -0
- package/test/logic/13.2-cte-bind-params.sqllogic +98 -0
- package/test/logic/13.3-cte-edge-cases.sqllogic +120 -0
- package/test/logic/13.4-cte-extras.sqllogic +98 -0
- package/test/logic/13.5-cte-join-order.sqllogic +166 -0
- package/test/logic/13.6-cte-dml-runs-once.sqllogic +318 -0
- package/test/logic/13.7-cte-sibling-visibility.sqllogic +227 -0
- package/test/logic/13.8-insert-with-clause-visibility.sqllogic +254 -0
- package/test/logic/13.9-schema-authored-cte-isolation.sqllogic +328 -0
- package/test/logic/13.9.1-schema-authored-schema-path-isolation.sqllogic +408 -0
- package/test/logic/14-utilities.sqllogic +168 -0
- package/test/logic/15-timespan.sqllogic +279 -0
- package/test/logic/15.1-semantic-ordering.sqllogic +960 -0
- package/test/logic/15.1.1-json-check-coercion.sqllogic +178 -0
- package/test/logic/15.1.2-semantic-ordering-index.sqllogic +41 -0
- package/test/logic/15.1.3-declared-form-write-contract.sqllogic +519 -0
- package/test/logic/16-epoch.sqllogic +187 -0
- package/test/logic/17-weekday-modifier.sqllogic +78 -0
- package/test/logic/18-json-string-escapes.sqllogic +86 -0
- package/test/logic/18-strftime-extended-formats.sqllogic +68 -0
- package/test/logic/20-empty-single-row.sqllogic +261 -0
- package/test/logic/21-null-edge-cases.sqllogic +227 -0
- package/test/logic/21.1-where-null-comparisons.sqllogic +151 -0
- package/test/logic/21.1.1-where-null-comparisons-secondary-index.sqllogic +35 -0
- package/test/logic/21.2-between-edges.sqllogic +157 -0
- package/test/logic/22-boundary-values.sqllogic +175 -0
- package/test/logic/23-self-joins-duplicates.sqllogic +74 -0
- package/test/logic/24-builtin-branches.sqllogic +611 -0
- package/test/logic/24.1-substr-extras.sqllogic +75 -0
- package/test/logic/24.2-random-extras.sqllogic +39 -0
- package/test/logic/25-aggregate-edge-cases.sqllogic +289 -0
- package/test/logic/25.1-nested-aggregates.sqllogic +74 -0
- package/test/logic/25.2-having-edge-cases.sqllogic +318 -0
- package/test/logic/25.3-aggregate-isnull-empty.sqllogic +16 -0
- package/test/logic/25.4-groupby-fd-constant-empty.sqllogic +55 -0
- package/test/logic/25.5-ungrouped-aggregate-column-free-select-item.sqllogic +196 -0
- package/test/logic/26-join-edge-cases.sqllogic +333 -0
- package/test/logic/26.1-left-join-isnull-on-notnull.sqllogic +26 -0
- package/test/logic/26.2-left-join-on-vs-where.sqllogic +67 -0
- package/test/logic/26.3-join-on-constants.sqllogic +61 -0
- package/test/logic/26.4-join-on-is-null-nullable.sqllogic +44 -0
- package/test/logic/27-window-edge-cases.sqllogic +206 -0
- package/test/logic/27.1-window-groups-frame.sqllogic +13 -0
- package/test/logic/27.2-window-exclude.sqllogic +13 -0
- package/test/logic/27.3-window-json-aggregation.sqllogic +66 -0
- package/test/logic/28-set-ops-sort-edge-cases.sqllogic +444 -0
- package/test/logic/28.1-compound-limit-offset.sqllogic +143 -0
- package/test/logic/28.2-orderby-expression-extras.sqllogic +698 -0
- package/test/logic/28.2-set-op-branch-types.sqllogic +217 -0
- package/test/logic/29-constraint-edge-cases.sqllogic +442 -0
- package/test/logic/29.1-column-level-conflict-clause.sqllogic +171 -0
- package/test/logic/29.2-table-level-pk-conflict-clause.sqllogic +113 -0
- package/test/logic/40-constraints.sqllogic +418 -0
- package/test/logic/40.1-pk-desc-direction.sqllogic +76 -0
- package/test/logic/40.2-check-extras.sqllogic +683 -0
- package/test/logic/41-alter-table.sqllogic +191 -0
- package/test/logic/41-fk-cascade-conflict-and-self-ref.sqllogic +263 -0
- package/test/logic/41-fk-cross-schema.sqllogic +155 -0
- package/test/logic/41-fk-extended-targets.sqllogic +173 -0
- package/test/logic/41-foreign-keys.sqllogic +1001 -0
- package/test/logic/41-generated-column-errors.sqllogic +225 -0
- package/test/logic/41-generated-column-extras.sqllogic +598 -0
- package/test/logic/41-generated-column-scope.sqllogic +329 -0
- package/test/logic/41-generated-columns.sqllogic +361 -0
- package/test/logic/41.1-alter-pk.sqllogic +230 -0
- package/test/logic/41.1-fk-collation-conflict.sqllogic +277 -0
- package/test/logic/41.10-alter-drop-column-foreign-key.sqllogic +274 -0
- package/test/logic/41.10.1-alter-drop-column-unique-index.sqllogic +169 -0
- package/test/logic/41.10.2-alter-drop-column-check-and-assertion.sqllogic +1616 -0
- package/test/logic/41.10.3-alter-drop-column-referencing-fk.sqllogic +292 -0
- package/test/logic/41.10.4-drop-object-expression-dependents.sqllogic +602 -0
- package/test/logic/41.11-deferred-fk-with-rename.sqllogic +232 -0
- package/test/logic/41.12-alter-default-coercion.sqllogic +200 -0
- package/test/logic/41.13-alter-add-column-generated-backfill.sqllogic +566 -0
- package/test/logic/41.14-alter-add-column-subquery-backfill.sqllogic +129 -0
- package/test/logic/41.15-alter-column-default-type-check.sqllogic +178 -0
- package/test/logic/41.16-fk-unenforceable.sqllogic +364 -0
- package/test/logic/41.2-alter-column.sqllogic +382 -0
- package/test/logic/41.2.1-alter-column-retype-deleted-row-memory.sqllogic +32 -0
- package/test/logic/41.2.2-alter-column-retype-index-rebuild.sqllogic +77 -0
- package/test/logic/41.2.3-alter-column-set-not-null-pk-backfill.sqllogic +310 -0
- package/test/logic/41.2.3.1-alter-column-set-not-null-pk-backfill-secondary-index.sqllogic +37 -0
- package/test/logic/41.3-alter-add-column-unique.sqllogic +184 -0
- package/test/logic/41.3-alter-rename-propagation.sqllogic +2352 -0
- package/test/logic/41.3.1-alter-rename-index-propagation.sqllogic +94 -0
- package/test/logic/41.4-alter-add-column-constraints.sqllogic +855 -0
- package/test/logic/41.5-alter-misc.sqllogic +48 -0
- package/test/logic/41.5-cross-schema-foreign-keys.sqllogic +253 -0
- package/test/logic/41.6-alter-drop-rename-constraint.sqllogic +354 -0
- package/test/logic/41.6.1-alter-drop-constraint-index-derived.sqllogic +22 -0
- package/test/logic/41.7-alter-column-collate.sqllogic +105 -0
- package/test/logic/41.7.1-alter-column-collate-unique.sqllogic +45 -0
- package/test/logic/41.7.2-alter-column-collate-unique-store.sqllogic +208 -0
- package/test/logic/41.7.2.1-alter-column-collate-unique-index-store.sqllogic +114 -0
- package/test/logic/41.7.3-alter-column-retype-unique.sqllogic +293 -0
- package/test/logic/41.7.3.1-alter-column-retype-staged-rows-memory.sqllogic +41 -0
- package/test/logic/41.7.3.2-alter-column-retype-unique-index.sqllogic +72 -0
- package/test/logic/41.7.4-alter-column-retype-semantic-memory.sqllogic +445 -0
- package/test/logic/41.7.4.1-alter-column-retype-semantic-index-memory.sqllogic +91 -0
- package/test/logic/41.7.5-alter-column-collate-pk-staged-delete-memory.sqllogic +106 -0
- package/test/logic/41.8-alter-add-constraint-unique-fk.sqllogic +275 -0
- package/test/logic/41.8-alter-savepoint-staged-rows.sqllogic +443 -0
- package/test/logic/41.8.1-alter-rename-savepoint-staged-rows.sqllogic +408 -0
- package/test/logic/41.9-alter-constraint-body-change.sqllogic +180 -0
- package/test/logic/41.9-fk-restrict-batched.sqllogic +290 -0
- package/test/logic/42-committed-snapshot.sqllogic +254 -0
- package/test/logic/42-returning.sqllogic +159 -0
- package/test/logic/42.1-returning-extras.sqllogic +232 -0
- package/test/logic/42.2-returning-stored-row.sqllogic +165 -0
- package/test/logic/43-default-nullability.sqllogic +131 -0
- package/test/logic/43-transition-constraints.sqllogic +341 -0
- package/test/logic/43.1-default-collation.sqllogic +140 -0
- package/test/logic/43.1-notnull-or-conflict.sqllogic +79 -0
- package/test/logic/43.2-deferred-check-new-on-delete.sqllogic +95 -0
- package/test/logic/43.3-nullable-primary-key.sqllogic +587 -0
- package/test/logic/44-determinism-validation.sqllogic +164 -0
- package/test/logic/44-orthogonality.sqllogic +146 -0
- package/test/logic/44.1-nondeterministic-schema.sqllogic +316 -0
- package/test/logic/45-udf-determinism.sqllogic +39 -0
- package/test/logic/46-mutation-context.sqllogic +595 -0
- package/test/logic/47-upsert.sqllogic +255 -0
- package/test/logic/47.1-upsert-conflict-targets.sqllogic +169 -0
- package/test/logic/47.2-replace-and-or-clauses.sqllogic +164 -0
- package/test/logic/47.2.1-pk-replace-secondary-unique.sqllogic +374 -0
- package/test/logic/47.3-engine-or-fail.sqllogic +122 -0
- package/test/logic/47.3-upsert-conflict-target-collation.sqllogic +139 -0
- package/test/logic/47.3.1-upsert-conflict-index-derived-collation.sqllogic +25 -0
- package/test/logic/47.4-upsert-conflict-target-affinity.sqllogic +59 -0
- package/test/logic/47.5-upsert-do-update-constraints.sqllogic +440 -0
- package/test/logic/47.6-upsert-do-update-decomposed.sqllogic +100 -0
- package/test/logic/49-reference-graph.sqllogic +84 -0
- package/test/logic/50-declarative-schema.sqllogic +2550 -0
- package/test/logic/50-metadata-tags.sqllogic +1033 -0
- package/test/logic/50.0.1-metadata-tags-index.sqllogic +141 -0
- package/test/logic/50.1-declare-schema-pk.sqllogic +150 -0
- package/test/logic/50.2-declare-schema-renames.sqllogic +949 -0
- package/test/logic/50.2.1-declare-schema-index-renames.sqllogic +173 -0
- package/test/logic/50.3-declare-schema-duplicate-names.sqllogic +280 -0
- package/test/logic/50.4-declare-schema-apply-restore.sqllogic +192 -0
- package/test/logic/51-lens-foundation.sqllogic +147 -0
- package/test/logic/51-materialized-views.sqllogic +376 -0
- package/test/logic/51.5-materialized-views-coarsened-key.sqllogic +198 -0
- package/test/logic/51.7-maintained-table-attach-detach.sqllogic +468 -0
- package/test/logic/51.8-maintained-table-declared-constraints.sqllogic +440 -0
- package/test/logic/51.85-maintained-table-parent-fk.sqllogic +103 -0
- package/test/logic/51.9-maintained-table-secondary-unique.sqllogic +237 -0
- package/test/logic/51.9.1-maintained-table-partial-unique.sqllogic +36 -0
- package/test/logic/52-lens-overrides.sqllogic +566 -0
- package/test/logic/53-materialized-views-rowtime.sqllogic +1601 -0
- package/test/logic/53-reserved-tags.sqllogic +252 -0
- package/test/logic/53.1-materialized-view-write-through.sqllogic +329 -0
- package/test/logic/53.2-materialized-view-rename-propagation.sqllogic +483 -0
- package/test/logic/53.3-materialized-view-constraint-only-ddl.sqllogic +409 -0
- package/test/logic/53.3.1-materialized-view-index-ddl-irrelevance.sqllogic +29 -0
- package/test/logic/53.4-materialized-view-structural-alter-restore.sqllogic +436 -0
- package/test/logic/54-covering-mv-enforcement.sqllogic +314 -0
- package/test/logic/54.1-covering-mv-partial-enforcement.sqllogic +34 -0
- package/test/logic/55-internal-eviction-reporting.sqllogic +89 -0
- package/test/logic/55-lens-prover.sqllogic +202 -0
- package/test/logic/55.1-eviction-restrict-fk.sqllogic +148 -0
- package/test/logic/55.5-lens-authored-inverse.sqllogic +1468 -0
- package/test/logic/80-grow-retrieve-pass.sqllogic +79 -0
- package/test/logic/81-quickpick.sqllogic +24 -0
- package/test/logic/82-bloom-join.sqllogic +185 -0
- package/test/logic/83-merge-join.sqllogic +280 -0
- package/test/logic/84-asof-scan.sqllogic +238 -0
- package/test/logic/84-key-cardinality.sqllogic +50 -0
- package/test/logic/85-relational-const-folding.sqllogic +51 -0
- package/test/logic/86-scalar-cse.sqllogic +42 -0
- package/test/logic/90-error_paths.sqllogic +114 -0
- package/test/logic/90.1-parse-errors.sqllogic +77 -0
- package/test/logic/90.2-alter-table-errors.sqllogic +53 -0
- package/test/logic/90.2.1-alter-extra-errors.sqllogic +51 -0
- package/test/logic/90.3-expression-errors.sqllogic +43 -0
- package/test/logic/90.4-dml-errors.sqllogic +47 -0
- package/test/logic/90.5-unsupported-join-types.sqllogic +37 -0
- package/test/logic/90.5.1-right-full-join-read.sqllogic +157 -0
- package/test/logic/90.6-select-error-paths.sqllogic +57 -0
- package/test/logic/91-merge-join-edge-cases.sqllogic +159 -0
- package/test/logic/92-hash-aggregate-edge-cases.sqllogic +139 -0
- package/test/logic/93-ddl-view-edge-cases.sqllogic +104 -0
- package/test/logic/93.1-view-error-paths.sqllogic +74 -0
- package/test/logic/93.2-view-mutation-pending.sqllogic +108 -0
- package/test/logic/93.3-view-mutation-or-clause.sqllogic +60 -0
- package/test/logic/93.4-view-mutation.sqllogic +4881 -0
- package/test/logic/93.4.1-view-mutation-partial-unique-cardinality.sqllogic +31 -0
- package/test/logic/93.5-authored-inverse.sqllogic +415 -0
- package/test/logic/93.6-set-op-flagless-write.sqllogic +862 -0
- package/test/logic/94-tvf-edge-cases.sqllogic +58 -0
- package/test/logic/94.1-limit-offset-edge-cases.sqllogic +109 -0
- package/test/logic/94.2-limit-offset-extras.sqllogic +98 -0
- package/test/logic/95-assertions.sqllogic +1417 -0
- package/test/logic/96-subquery-edge-cases.sqllogic +276 -0
- package/test/logic/97-json-function-edge-cases.sqllogic +633 -0
- package/test/logic/97.1-json-blob-and-special-values.sqllogic +92 -0
- package/test/logic/98-temporal-edge-cases.sqllogic +515 -0
- package/test/logic/99-conversion-edge-cases.sqllogic +325 -0
- package/test/logic/99.0.1-schema-index-listing.sqllogic +21 -0
- package/test/logic/99.1-cast-syntax-extras.sqllogic +167 -0
- package/test/logic/drop-unique-index.sqllogic +88 -0
- 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;
|