@quereus/quereus 4.20.1 → 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/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,158 @@
|
|
|
1
|
+
-- adapted from SQLite test/in.test, test/in2.test, test/in4.test, test/in5.test
|
|
2
|
+
-- IN operator surface gaps: row-value (tuple) IN with literal list and subquery,
|
|
3
|
+
-- IN with extra parens around subquery, IN with CASE expression as operand,
|
|
4
|
+
-- DML with IN-subquery filters, and IN list with duplicate values.
|
|
5
|
+
|
|
6
|
+
create table inx_t (id integer primary key, a integer, b integer);
|
|
7
|
+
insert into inx_t values (1, 1, 10), (2, 2, 20), (3, 3, 30), (4, 4, 40);
|
|
8
|
+
|
|
9
|
+
-- =============================================================================
|
|
10
|
+
-- Row-value (tuple) IN with literal list — Quereus parser does not support
|
|
11
|
+
-- row-value tuple syntax in IN; convert to error assertion.
|
|
12
|
+
-- =============================================================================
|
|
13
|
+
|
|
14
|
+
select id from inx_t where (a, b) in ((1, 10), (3, 30), (99, 99)) order by id;
|
|
15
|
+
-- error: Expected ')'
|
|
16
|
+
|
|
17
|
+
-- =============================================================================
|
|
18
|
+
-- IN with extra parens around subquery: Quereus interprets extra parens as
|
|
19
|
+
-- forcing scalar context, so a multi-row subquery becomes a scalar-error case.
|
|
20
|
+
-- These do not apply.
|
|
21
|
+
-- =============================================================================
|
|
22
|
+
|
|
23
|
+
-- =============================================================================
|
|
24
|
+
-- IN with CASE expression as operand
|
|
25
|
+
-- =============================================================================
|
|
26
|
+
|
|
27
|
+
select id, (case when a > 2 then a else a + 100 end) in (101, 102, 3, 4) as matched from inx_t order by id;
|
|
28
|
+
→ [{"id":1,"matched":true},{"id":2,"matched":true},{"id":3,"matched":true},{"id":4,"matched":true}]
|
|
29
|
+
|
|
30
|
+
-- IN where the list contains expressions
|
|
31
|
+
select id from inx_t where a in (1 + 1, 1 + 2) order by id;
|
|
32
|
+
→ [{"id":2},{"id":3}]
|
|
33
|
+
|
|
34
|
+
-- =============================================================================
|
|
35
|
+
-- IN list with duplicate values (must dedupe — should not change result)
|
|
36
|
+
-- =============================================================================
|
|
37
|
+
|
|
38
|
+
select id from inx_t where a in (1, 1, 2, 2, 1) order by id;
|
|
39
|
+
→ [{"id":1},{"id":2}]
|
|
40
|
+
|
|
41
|
+
-- =============================================================================
|
|
42
|
+
-- UPDATE / DELETE with IN-subquery filter
|
|
43
|
+
-- =============================================================================
|
|
44
|
+
|
|
45
|
+
create table inx_dml (id integer primary key, val integer);
|
|
46
|
+
insert into inx_dml values (1, 10), (2, 20), (3, 30), (4, 40);
|
|
47
|
+
|
|
48
|
+
create table inx_keep (id integer primary key);
|
|
49
|
+
insert into inx_keep values (1), (3);
|
|
50
|
+
|
|
51
|
+
-- UPDATE WHERE id IN (subquery)
|
|
52
|
+
update inx_dml set val = val * 10 where id in (select id from inx_keep);
|
|
53
|
+
select id, val from inx_dml order by id;
|
|
54
|
+
→ [{"id":1,"val":100},{"id":2,"val":20},{"id":3,"val":300},{"id":4,"val":40}]
|
|
55
|
+
|
|
56
|
+
-- DELETE WHERE id NOT IN (subquery)
|
|
57
|
+
delete from inx_dml where id not in (select id from inx_keep);
|
|
58
|
+
select id, val from inx_dml order by id;
|
|
59
|
+
→ [{"id":1,"val":100},{"id":3,"val":300}]
|
|
60
|
+
|
|
61
|
+
drop table inx_dml;
|
|
62
|
+
drop table inx_keep;
|
|
63
|
+
|
|
64
|
+
-- =============================================================================
|
|
65
|
+
-- Single-placeholder `col in (?)` over a PK must match exactly the bound row(s),
|
|
66
|
+
-- never the whole table. Regression for the match-all defect: a one-element
|
|
67
|
+
-- parameterized IN reduced to a point-seek on Literal(undefined) and degraded to
|
|
68
|
+
-- a full-index walk, so `delete from T where pk in (?)` wiped every row.
|
|
69
|
+
-- See quereus-single-element-in-list-matches-all.
|
|
70
|
+
-- =============================================================================
|
|
71
|
+
|
|
72
|
+
create table inp (id integer primary key, label text);
|
|
73
|
+
insert into inp values (0, 'a'), (1, 'b'), (2, 'c'), (3, 'd');
|
|
74
|
+
|
|
75
|
+
-- select with a single placeholder matches just the bound row
|
|
76
|
+
-- params: [1]
|
|
77
|
+
select id from inp where id in (?) order by id;
|
|
78
|
+
→ [{"id":1}]
|
|
79
|
+
|
|
80
|
+
-- a different bind value selects a different single row
|
|
81
|
+
-- params: [2]
|
|
82
|
+
select id from inp where id in (?) order by id;
|
|
83
|
+
→ [{"id":2}]
|
|
84
|
+
|
|
85
|
+
-- one-, two-, three-placeholder IN agree, and with `= ?`
|
|
86
|
+
-- params: [1, 2]
|
|
87
|
+
select id from inp where id in (?, ?) order by id;
|
|
88
|
+
→ [{"id":1},{"id":2}]
|
|
89
|
+
|
|
90
|
+
-- params: [0, 2, 3]
|
|
91
|
+
select id from inp where id in (?, ?, ?) order by id;
|
|
92
|
+
→ [{"id":0},{"id":2},{"id":3}]
|
|
93
|
+
|
|
94
|
+
-- params: [3]
|
|
95
|
+
select id from inp where id = ? order by id;
|
|
96
|
+
→ [{"id":3}]
|
|
97
|
+
|
|
98
|
+
-- Correlated single-element IN (`p.id in (outer.target)`) — the inner scalar
|
|
99
|
+
-- subquery seeks inp's PK on a correlated outer column. Pre-fix this match-alled,
|
|
100
|
+
-- so the scalar subquery would have seen every row instead of exactly one.
|
|
101
|
+
create table inref (rid integer primary key, target integer);
|
|
102
|
+
insert into inref values (10, 2), (11, 3);
|
|
103
|
+
select o.rid, (select p.label from inp p where p.id in (o.target)) as label from inref o order by o.rid;
|
|
104
|
+
→ [{"rid":10,"label":"c"},{"rid":11,"label":"d"}]
|
|
105
|
+
|
|
106
|
+
-- Plan-mechanism guard: the single-placeholder IN must reduce to an index seek
|
|
107
|
+
-- whose seek key is the bound ParameterReference — NOT a Literal(undefined). The
|
|
108
|
+
-- defect emitted a Literal node (value undefined) as the seek key, which the scan
|
|
109
|
+
-- layer read as "no constraint" and walked the whole index.
|
|
110
|
+
select count(*) as params from query_plan('select id from inp where id in (?)') where node_type = 'ParameterReference';
|
|
111
|
+
→ [{"params":1}]
|
|
112
|
+
|
|
113
|
+
select count(*) as lits from query_plan('select id from inp where id in (?)') where node_type = 'Literal';
|
|
114
|
+
→ [{"lits":0}]
|
|
115
|
+
|
|
116
|
+
-- DESTRUCTIVE: delete with a single placeholder removes ONLY the bound row,
|
|
117
|
+
-- not the whole table.
|
|
118
|
+
-- params: [1]
|
|
119
|
+
delete from inp where id in (?);
|
|
120
|
+
→ []
|
|
121
|
+
|
|
122
|
+
select id from inp order by id;
|
|
123
|
+
→ [{"id":0},{"id":2},{"id":3}]
|
|
124
|
+
|
|
125
|
+
-- Composite multi-column seek with a single-element dynamic IN component.
|
|
126
|
+
-- A 2-column PK seek where one column carries a multi-value IN (`a in (1, 2)`)
|
|
127
|
+
-- and the other a single-placeholder IN (`b in (?)`) takes the composite
|
|
128
|
+
-- cross-product seek path. Pre-fix the single-element component was dropped to
|
|
129
|
+
-- Literal(undefined) (match-all on b); it must instead seek on the bound param,
|
|
130
|
+
-- so only the b = <param> rows match.
|
|
131
|
+
create table cmp (a integer, b integer, label text, primary key (a, b));
|
|
132
|
+
insert into cmp values (1, 5, 'a'), (1, 6, 'b'), (2, 5, 'c'), (2, 6, 'd');
|
|
133
|
+
|
|
134
|
+
-- b bound to 5 selects exactly the b=5 rows across both a values
|
|
135
|
+
-- params: [5]
|
|
136
|
+
select label from cmp where a in (1, 2) and b in (?) order by label;
|
|
137
|
+
→ [{"label":"a"},{"label":"c"}]
|
|
138
|
+
|
|
139
|
+
-- a different bind picks the other pair (proves the param is not constant-folded)
|
|
140
|
+
-- params: [6]
|
|
141
|
+
select label from cmp where a in (1, 2) and b in (?) order by label;
|
|
142
|
+
→ [{"label":"b"},{"label":"d"}]
|
|
143
|
+
|
|
144
|
+
-- Plan-mechanism guard: the dynamic component survives into the composite seek as
|
|
145
|
+
-- the bound ParameterReference, not a dropped Literal(undefined). Pre-fix the param
|
|
146
|
+
-- was lost entirely (0 ParameterReference nodes). Asserted as a presence check
|
|
147
|
+
-- rather than an exact count because the seek-key cardinality is module-specific
|
|
148
|
+
-- (the memory module expands the literal `a in (1, 2)` cross-product, emitting the
|
|
149
|
+
-- param once per tuple; the store module keeps a single seek with one param node).
|
|
150
|
+
select case when count(*) >= 1 then 'present' else 'absent' end as param from query_plan('select label from cmp where a in (1, 2) and b in (?)') where node_type = 'ParameterReference';
|
|
151
|
+
→ [{"param":"present"}]
|
|
152
|
+
|
|
153
|
+
drop table cmp;
|
|
154
|
+
|
|
155
|
+
drop table inref;
|
|
156
|
+
drop table inp;
|
|
157
|
+
|
|
158
|
+
drop table inx_t;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
-- 07.7.1-scalar-agg-decorrelation-filter.sqllogic
|
|
2
|
+
-- Correlated scalar-aggregate subqueries used in a WHERE or HAVING comparison
|
|
3
|
+
-- are decorrelated into grouped left joins (rule scalar-agg-decorrelation-filter,
|
|
4
|
+
-- the Filter anchor). A HAVING clause is a FilterNode whose source is an
|
|
5
|
+
-- Aggregate, so one anchor covers both WHERE and HAVING. These tests pin the
|
|
6
|
+
-- observable semantics of the decorrelated shapes AND the shapes the rule must
|
|
7
|
+
-- reject (which stay on the correlated per-row path, still correct).
|
|
8
|
+
|
|
9
|
+
-- Setup: outer `o` (some rows with no matching child, one NULL correlation key),
|
|
10
|
+
-- child `c` grouped by fk.
|
|
11
|
+
CREATE TABLE o (id INTEGER PRIMARY KEY, k INTEGER NULL, total INTEGER NULL);
|
|
12
|
+
CREATE TABLE c (id INTEGER PRIMARY KEY, fk INTEGER NULL, amount INTEGER NULL);
|
|
13
|
+
|
|
14
|
+
INSERT INTO o VALUES (1, 10, 8), (2, 20, 3), (3, 30, 100), (4, null, -5), (5, 40, 20);
|
|
15
|
+
INSERT INTO c VALUES (1, 10, 5), (2, 10, 7), (3, 20, 4), (4, 20, 8), (5, 40, 1);
|
|
16
|
+
|
|
17
|
+
-- Per-o subquery values (avg(amount) / count(*) where c.fk = o.k):
|
|
18
|
+
-- o1 k=10 → {5,7} avg 6, count 2
|
|
19
|
+
-- o2 k=20 → {4,8} avg 6, count 2
|
|
20
|
+
-- o3 k=30 → {} avg NULL, count 0
|
|
21
|
+
-- o4 k=NULL → {} avg NULL, count 0 (NULL key never matches)
|
|
22
|
+
-- o5 k=40 → {1} avg 1, count 1
|
|
23
|
+
|
|
24
|
+
-- WHERE comparison against a correlated avg: three-valued logic preserved by the
|
|
25
|
+
-- LEFT-join NULL-pad (o.total > NULL → NULL → row excluded).
|
|
26
|
+
SELECT o.id, o.total FROM o WHERE o.total > (SELECT avg(c.amount) FROM c WHERE c.fk = o.k) ORDER BY o.id;
|
|
27
|
+
→ [{"id":1,"total":8},{"id":5,"total":20}]
|
|
28
|
+
|
|
29
|
+
-- WHERE against a correlated count: the empty group must yield 0 (non-NULL empty
|
|
30
|
+
-- value → CASE marker path), so a no-match outer row SURVIVES the filter rather
|
|
31
|
+
-- than being dropped. This is the count-bug analogue for the Filter anchor.
|
|
32
|
+
SELECT o.id, o.total FROM o WHERE (SELECT count(*) FROM c WHERE c.fk = o.k) = 0 ORDER BY o.id;
|
|
33
|
+
→ [{"id":3,"total":100},{"id":4,"total":-5}]
|
|
34
|
+
|
|
35
|
+
-- Subquery inside a disjunction: the LEFT join is unconditional and matches
|
|
36
|
+
-- <=1 row per outer row (group keys are a unique key), so outer multiplicity is
|
|
37
|
+
-- preserved and the substituted value drives the OR correctly.
|
|
38
|
+
SELECT o.id, o.total FROM o WHERE o.total < 0 OR o.total > (SELECT avg(c.amount) FROM c WHERE c.fk = o.k) ORDER BY o.id;
|
|
39
|
+
→ [{"id":1,"total":8},{"id":4,"total":-5},{"id":5,"total":20}]
|
|
40
|
+
|
|
41
|
+
-- Two scalar-agg subqueries in one predicate: one stacked LEFT join each.
|
|
42
|
+
SELECT o.id, o.total FROM o WHERE o.total > (SELECT avg(c.amount) FROM c WHERE c.fk = o.k) AND (SELECT count(*) FROM c WHERE c.fk = o.k) >= 2 ORDER BY o.id;
|
|
43
|
+
→ [{"id":1,"total":8}]
|
|
44
|
+
|
|
45
|
+
-- EXISTS plus a scalar-agg comparison in the same WHERE: subquery-decorrelation
|
|
46
|
+
-- turns EXISTS into a semi-join first, then this rule decorrelates the avg
|
|
47
|
+
-- comparison over the already-rewritten source. Both fire; result stays correct.
|
|
48
|
+
SELECT o.id, o.total FROM o WHERE EXISTS (SELECT 1 FROM c WHERE c.fk = o.k) AND o.total > (SELECT avg(c.amount) FROM c WHERE c.fk = o.k) ORDER BY o.id;
|
|
49
|
+
→ [{"id":1,"total":8},{"id":5,"total":20}]
|
|
50
|
+
|
|
51
|
+
-- Bail-but-correct: non-equi correlation (c.fk < o.k) cannot become a group key,
|
|
52
|
+
-- so the subquery stays correlated. Result must still be right.
|
|
53
|
+
-- avg(amount) where fk < k: o1 {} NULL, o2 {10}=6, o3 {10,20}=6, o4 {} NULL, o5 {10,20}=6
|
|
54
|
+
SELECT o.id, o.total FROM o WHERE o.total > (SELECT avg(c.amount) FROM c WHERE c.fk < o.k) ORDER BY o.id;
|
|
55
|
+
→ [{"id":3,"total":100},{"id":5,"total":20}]
|
|
56
|
+
|
|
57
|
+
-- Bail-but-correct: a non-aggregate LIMIT 1 subquery is not the aggregate root
|
|
58
|
+
-- the rule requires, so it stays correlated. (ORDER BY makes the pick
|
|
59
|
+
-- deterministic.) min amount per k: o1 5, o2 4, o5 1; o3/o4 no rows → NULL.
|
|
60
|
+
-- o1 8>5 T, o2 3>4 F, o5 20>1 T.
|
|
61
|
+
SELECT o.id, o.total FROM o WHERE o.total > (SELECT c.amount FROM c WHERE c.fk = o.k ORDER BY c.amount LIMIT 1) ORDER BY o.id;
|
|
62
|
+
→ [{"id":1,"total":8},{"id":5,"total":20}]
|
|
63
|
+
|
|
64
|
+
-- Mixed: one decorrelatable (avg) and one bail (LIMIT 1) subquery in the SAME
|
|
65
|
+
-- predicate. The avg becomes a grouped left join; the LIMIT-1 subquery stays
|
|
66
|
+
-- correlated over the join source (its outer refs still resolve on the join's
|
|
67
|
+
-- left side). Both must evaluate correctly together.
|
|
68
|
+
-- avg/k: o1 6,o2 6,o3 NULL,o5 1 ; min/k: o1 5,o2 4,o3 NULL,o5 1.
|
|
69
|
+
-- o1 8>6 ∧ 8>5 T; o2 3>6 F; o3 100>NULL NULL; o4 NULL; o5 20>1 ∧ 20>1 T.
|
|
70
|
+
SELECT o.id FROM o WHERE o.total > (SELECT avg(c.amount) FROM c WHERE c.fk = o.k) AND o.total > (SELECT c.amount FROM c WHERE c.fk = o.k ORDER BY c.amount LIMIT 1) ORDER BY o.id;
|
|
71
|
+
→ [{"id":1},{"id":5}]
|
|
72
|
+
|
|
73
|
+
-- HAVING setup: group `ord` by k, correlate a per-group cap table `lim` on the
|
|
74
|
+
-- group key.
|
|
75
|
+
CREATE TABLE ord (id INTEGER PRIMARY KEY, k INTEGER NULL, amt INTEGER);
|
|
76
|
+
CREATE TABLE lim (id INTEGER PRIMARY KEY, gk INTEGER NULL, cap INTEGER);
|
|
77
|
+
|
|
78
|
+
INSERT INTO ord VALUES (1,10,5),(2,10,7),(3,20,4),(4,20,2),(5,30,9);
|
|
79
|
+
INSERT INTO lim VALUES (1,10,3),(2,10,6),(3,20,10);
|
|
80
|
+
-- group sums: k=10 → 12, k=20 → 6, k=30 → 9
|
|
81
|
+
|
|
82
|
+
-- HAVING comparison correlating to the group key (ord.k): decorrelates the same
|
|
83
|
+
-- as a WHERE, the Filter's source being the group Aggregate.
|
|
84
|
+
-- min(cap) where gk=k: k=10 → 3, k=20 → 10, k=30 → NULL
|
|
85
|
+
SELECT ord.k, sum(ord.amt) AS s FROM ord GROUP BY ord.k HAVING sum(ord.amt) > (SELECT min(lim.cap) FROM lim WHERE lim.gk = ord.k) ORDER BY ord.k;
|
|
86
|
+
→ [{"k":10,"s":12}]
|
|
87
|
+
|
|
88
|
+
-- HAVING with a correlated count empty-group: group k=30 has no lim rows →
|
|
89
|
+
-- count 0 → survives the HAVING filter (empty-value marker in the Filter path).
|
|
90
|
+
SELECT ord.k, sum(ord.amt) AS s FROM ord GROUP BY ord.k HAVING (SELECT count(*) FROM lim WHERE lim.gk = ord.k) = 0 ORDER BY ord.k;
|
|
91
|
+
→ [{"k":30,"s":9}]
|
|
92
|
+
|
|
93
|
+
-- HAVING correlating to the aggregate result itself (sum(ord.amt)): valid but
|
|
94
|
+
-- unusual. Whether it decorrelates or bails, the result must be correct.
|
|
95
|
+
-- count(*) where cap = sum: k=10 sum12 → 0, k=20 sum6 → 1 (cap 6), k=30 sum9 → 0
|
|
96
|
+
SELECT ord.k, sum(ord.amt) AS s FROM ord GROUP BY ord.k HAVING sum(ord.amt) > (SELECT count(*) FROM lim WHERE lim.cap = sum(ord.amt)) ORDER BY ord.k;
|
|
97
|
+
→ [{"k":10,"s":12},{"k":20,"s":6},{"k":30,"s":9}]
|
|
98
|
+
|
|
99
|
+
-- Two stacked scalar-agg subqueries in one HAVING predicate: one grouped left
|
|
100
|
+
-- join each, over the group Aggregate as source (the anchor-agnostic stacking
|
|
101
|
+
-- path, previously covered only for WHERE).
|
|
102
|
+
-- min(cap)/k: 10→3,20→10,30→NULL ; count/k: 10→2,20→1,30→0.
|
|
103
|
+
-- k=10 12>3 ∧ 12>2 T; k=20 6>10 F; k=30 9>NULL NULL.
|
|
104
|
+
SELECT ord.k, sum(ord.amt) AS s FROM ord GROUP BY ord.k HAVING sum(ord.amt) > (SELECT min(lim.cap) FROM lim WHERE lim.gk = ord.k) AND sum(ord.amt) > (SELECT count(*) FROM lim WHERE lim.gk = ord.k) ORDER BY ord.k;
|
|
105
|
+
→ [{"k":10,"s":12}]
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
-- 07.7.2-scalar-agg-decorrelation-nested.sqllogic
|
|
2
|
+
-- Scalar-aggregate subqueries nested inside other aggregate subqueries
|
|
3
|
+
-- (parent → child → grandchild JSON trees) are decorrelated level by level:
|
|
4
|
+
-- the Project-site rule (scalar-agg-decorrelation) rewrites the outer level,
|
|
5
|
+
-- and the aggregate-argument site (scalar-agg-decorrelation-aggregate) then
|
|
6
|
+
-- rewrites the subquery that lands inside the new grouped aggregate's
|
|
7
|
+
-- argument. These tests pin the observable semantics of the fully set-based
|
|
8
|
+
-- shapes and of the shapes that must stay (partially) correlated.
|
|
9
|
+
|
|
10
|
+
-- Setup: the 3-table hierarchy from the motivating perf report — log entries
|
|
11
|
+
-- → items on an entry (via a join table) → per-(entry, item) quantifier
|
|
12
|
+
-- values (joined to their quantifier definitions).
|
|
13
|
+
CREATE TABLE e (id INTEGER PRIMARY KEY, name TEXT);
|
|
14
|
+
CREATE TABLE lei (entry_id INTEGER, item_id INTEGER, PRIMARY KEY (entry_id, item_id));
|
|
15
|
+
CREATE TABLE items (id INTEGER PRIMARY KEY, label TEXT);
|
|
16
|
+
CREATE TABLE qv (entry_id INTEGER, item_id INTEGER, quantifier_id INTEGER, value REAL, PRIMARY KEY (entry_id, item_id, quantifier_id));
|
|
17
|
+
CREATE TABLE q (id INTEGER PRIMARY KEY, name TEXT);
|
|
18
|
+
|
|
19
|
+
INSERT INTO e VALUES (1,'a'),(2,'b'),(3,'empty');
|
|
20
|
+
INSERT INTO items VALUES (10,'i10'),(11,'i11'),(12,'i12');
|
|
21
|
+
-- entry 3 has no items; item 11 (on entry 1) has no quantifier values
|
|
22
|
+
INSERT INTO lei VALUES (1,10),(1,11),(2,12);
|
|
23
|
+
INSERT INTO q VALUES (100,'qa'),(101,'qb');
|
|
24
|
+
INSERT INTO qv VALUES (1,10,100,1.5),(1,10,101,2.5),(2,12,100,9.0);
|
|
25
|
+
|
|
26
|
+
-- The motivating 2-level query: json_group_array(json_object(...)) at both
|
|
27
|
+
-- levels, level-2 correlation spanning two ancestor levels (e.id and i.id).
|
|
28
|
+
-- An item with no quantifier values gets NULL (json_group_array over a
|
|
29
|
+
-- zero-row scalar-subquery group — same as the correlated baseline); an entry
|
|
30
|
+
-- with no items gets NULL at level 1 and level 2 never evaluates.
|
|
31
|
+
select e.id,
|
|
32
|
+
(select json_group_array(json_object(
|
|
33
|
+
'itemId', i.id,
|
|
34
|
+
'quantifiers', (
|
|
35
|
+
select json_group_array(json_object('id', q.id, 'value', qv.value))
|
|
36
|
+
from qv join q on q.id = qv.quantifier_id
|
|
37
|
+
where qv.entry_id = e.id and qv.item_id = i.id)))
|
|
38
|
+
from lei join items i on i.id = lei.item_id
|
|
39
|
+
where lei.entry_id = e.id) as items
|
|
40
|
+
from e order by e.id;
|
|
41
|
+
→ [{"id":1,"items":[{"itemId":10,"quantifiers":[{"id":100,"value":1.5},{"id":101,"value":2.5}]},{"itemId":11,"quantifiers":null}]},{"id":2,"items":[{"itemId":12,"quantifiers":[{"id":100,"value":9}]}]},{"id":3,"items":null}]
|
|
42
|
+
|
|
43
|
+
-- Nested count inside sum: non-NULL empty value (count → 0) at level 2 needs
|
|
44
|
+
-- the join-miss CASE marker below the level-1 aggregate; entry 3 (no items)
|
|
45
|
+
-- sums over zero rows → NULL.
|
|
46
|
+
select e.id,
|
|
47
|
+
(select sum((select count(*) from qv where qv.entry_id = e.id and qv.item_id = i.id))
|
|
48
|
+
from lei join items i on i.id = lei.item_id
|
|
49
|
+
where lei.entry_id = e.id) as total
|
|
50
|
+
from e order by e.id;
|
|
51
|
+
→ [{"id":1,"total":2},{"id":2,"total":1},{"id":3,"total":null}]
|
|
52
|
+
|
|
53
|
+
-- Three levels of nesting: the rewrite converges level by level.
|
|
54
|
+
CREATE TABLE tags (quantifier_id INTEGER, tag TEXT, PRIMARY KEY (quantifier_id, tag));
|
|
55
|
+
INSERT INTO tags VALUES (100,'t1'),(100,'t2');
|
|
56
|
+
select e.id,
|
|
57
|
+
(select json_group_array(json_object(
|
|
58
|
+
'itemId', i.id,
|
|
59
|
+
'quantifiers', (
|
|
60
|
+
select json_group_array(json_object('qid', qv.quantifier_id,
|
|
61
|
+
'tags', (select json_group_array(t.tag) from tags t where t.quantifier_id = qv.quantifier_id)))
|
|
62
|
+
from qv
|
|
63
|
+
where qv.entry_id = e.id and qv.item_id = i.id)))
|
|
64
|
+
from lei join items i on i.id = lei.item_id
|
|
65
|
+
where lei.entry_id = e.id) as items
|
|
66
|
+
from e order by e.id;
|
|
67
|
+
→ [{"id":1,"items":[{"itemId":10,"quantifiers":[{"qid":100,"tags":["t1","t2"]},{"qid":101,"tags":null}]},{"itemId":11,"quantifiers":null}]},{"id":2,"items":[{"itemId":12,"quantifiers":[{"qid":100,"tags":["t1","t2"]}]}]},{"id":3,"items":null}]
|
|
68
|
+
|
|
69
|
+
-- DISTINCT aggregate at level 2: the at-most-one join adds no duplicate rows,
|
|
70
|
+
-- so the distinct set is unchanged.
|
|
71
|
+
select e.id,
|
|
72
|
+
(select json_group_array((select count(distinct qv.quantifier_id) from qv where qv.entry_id = e.id and qv.item_id = i.id))
|
|
73
|
+
from lei join items i on i.id = lei.item_id
|
|
74
|
+
where lei.entry_id = e.id) as d
|
|
75
|
+
from e order by e.id;
|
|
76
|
+
→ [{"id":1,"d":[2,0]},{"id":2,"d":[1]},{"id":3,"d":null}]
|
|
77
|
+
|
|
78
|
+
-- Sibling subqueries inside one aggregate argument: each gets its own join.
|
|
79
|
+
select lei.entry_id, json_group_array(
|
|
80
|
+
(select count(*) from qv where qv.entry_id = lei.entry_id and qv.item_id = lei.item_id)
|
|
81
|
+
+ (select total(qv.value) from qv where qv.entry_id = lei.entry_id and qv.item_id = lei.item_id)) as j
|
|
82
|
+
from lei group by lei.entry_id order by lei.entry_id;
|
|
83
|
+
→ [{"entry_id":1,"j":[6,0]},{"entry_id":2,"j":[10]}]
|
|
84
|
+
|
|
85
|
+
-- The aggregate-argument site also fires on a top-level (user-written)
|
|
86
|
+
-- GROUP BY aggregate — not only on nested subqueries.
|
|
87
|
+
select lei.entry_id, json_group_array((select count(*) from qv where qv.entry_id = lei.entry_id and qv.item_id = lei.item_id)) as j
|
|
88
|
+
from lei group by lei.entry_id order by lei.entry_id;
|
|
89
|
+
→ [{"entry_id":1,"j":[2,0]},{"entry_id":2,"j":[1]}]
|
|
90
|
+
|
|
91
|
+
-- HAVING evaluates against the (attribute-id-preserved) aggregate output and
|
|
92
|
+
-- is undisturbed by the join inserted below the aggregate.
|
|
93
|
+
select lei.entry_id, sum((select count(*) from qv where qv.entry_id = lei.entry_id and qv.item_id = lei.item_id)) as s
|
|
94
|
+
from lei group by lei.entry_id having count(*) > 1 order by lei.entry_id;
|
|
95
|
+
→ [{"entry_id":1,"s":2}]
|
|
96
|
+
|
|
97
|
+
-- Correlated aggregate subquery as a GROUP BY expression (pathological but
|
|
98
|
+
-- supported: group-by expressions are per-source-row scalar trees too).
|
|
99
|
+
select (select count(*) from qv where qv.entry_id = lei.entry_id) as g, count(*) as n
|
|
100
|
+
from lei group by 1 order by g;
|
|
101
|
+
→ [{"g":1,"n":1},{"g":2,"n":2}]
|
|
102
|
+
|
|
103
|
+
-- Remap-bailed level 1: the NOCASE correlation cannot justify remapping
|
|
104
|
+
-- en.name (referenced in the aggregate argument) to ln.ename, so level 1
|
|
105
|
+
-- stays correlated — and both levels stay correct.
|
|
106
|
+
CREATE TABLE en (name TEXT PRIMARY KEY COLLATE NOCASE);
|
|
107
|
+
CREATE TABLE ln (ename TEXT COLLATE NOCASE, item_id INTEGER, PRIMARY KEY (ename, item_id));
|
|
108
|
+
INSERT INTO en VALUES ('A'),('b');
|
|
109
|
+
INSERT INTO ln VALUES ('a',10),('A',11),('B',12);
|
|
110
|
+
select en.name,
|
|
111
|
+
(select json_group_array(json_object('n', en.name, 'item', ln.item_id,
|
|
112
|
+
'cnt', (select count(*) from qv where qv.entry_id = 1 and qv.item_id = ln.item_id)))
|
|
113
|
+
from ln where ln.ename = en.name) as j
|
|
114
|
+
from en order by en.name;
|
|
115
|
+
→ [{"name":"A","j":[{"n":"A","item":10,"cnt":2},{"n":"A","item":11,"cnt":0}]},{"name":"b","j":[{"n":"b","item":12,"cnt":0}]}]
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
-- 07.7.3-exists-in-select-decorrelation.sqllogic
|
|
2
|
+
-- Correlated EXISTS / NOT EXISTS / IN in the SELECT list are decorrelated into
|
|
3
|
+
-- LEFT joins carrying an `exists right as` match flag (rule
|
|
4
|
+
-- exists-in-select-decorrelation). Every outer row must survive with the match
|
|
5
|
+
-- reported as a column — a semi/anti join cannot express that. These tests pin
|
|
6
|
+
-- the observable semantics of the decorrelated shapes AND the shapes the rule
|
|
7
|
+
-- must reject (which stay on the correlated per-row path).
|
|
8
|
+
|
|
9
|
+
-- Setup. c has THREE rows with fk = 10 — the fan-out hazard: a plain left join
|
|
10
|
+
-- would duplicate the outer row per match, so the rule must collapse the inner
|
|
11
|
+
-- side to one row per correlation key.
|
|
12
|
+
CREATE TABLE o (id INTEGER PRIMARY KEY, k INTEGER NULL, g INTEGER NULL);
|
|
13
|
+
CREATE TABLE c (id INTEGER PRIMARY KEY, fk INTEGER NULL, g INTEGER NULL, v INTEGER NULL);
|
|
14
|
+
INSERT INTO o VALUES (1, 10, 1), (2, 20, 1), (3, null, 2), (4, 30, 2);
|
|
15
|
+
INSERT INTO c VALUES (1, 10, 1, 5), (2, 10, 1, 6), (3, 10, 2, null), (4, 20, 2, 7), (5, null, 1, 8), (6, null, 1, 20);
|
|
16
|
+
|
|
17
|
+
-- EXISTS flag with inner fan-out (k=10 matches 3 inner rows): exactly one
|
|
18
|
+
-- output row per outer row; NULL outer key and no-match rows report false
|
|
19
|
+
SELECT o.id, EXISTS (SELECT 1 FROM c WHERE c.fk = o.k) AS f FROM o ORDER BY o.id;
|
|
20
|
+
→ [{"id":1,"f":true},{"id":2,"f":true},{"id":3,"f":false},{"id":4,"f":false}]
|
|
21
|
+
|
|
22
|
+
-- NOT EXISTS: the NOT wrapper survives over the two-valued flag
|
|
23
|
+
SELECT o.id, NOT EXISTS (SELECT 1 FROM c WHERE c.fk = o.k) AS f FROM o ORDER BY o.id;
|
|
24
|
+
→ [{"id":1,"f":false},{"id":2,"f":false},{"id":3,"f":true},{"id":4,"f":true}]
|
|
25
|
+
|
|
26
|
+
-- Residual inner-only predicate alongside the correlation
|
|
27
|
+
SELECT o.id, EXISTS (SELECT 1 FROM c WHERE c.fk = o.k AND c.v > 6) AS f FROM o ORDER BY o.id;
|
|
28
|
+
→ [{"id":1,"f":false},{"id":2,"f":true},{"id":3,"f":false},{"id":4,"f":false}]
|
|
29
|
+
|
|
30
|
+
-- Composite (multi-conjunct) correlation
|
|
31
|
+
SELECT o.id, EXISTS (SELECT 1 FROM c WHERE c.fk = o.k AND c.g = o.g) AS f FROM o ORDER BY o.id;
|
|
32
|
+
→ [{"id":1,"f":true},{"id":2,"f":false},{"id":3,"f":false},{"id":4,"f":false}]
|
|
33
|
+
|
|
34
|
+
-- Multiple EXISTS in one SELECT list: one stacked join per subquery, flags distinct
|
|
35
|
+
SELECT o.id, EXISTS (SELECT 1 FROM c WHERE c.fk = o.k) AS a, EXISTS (SELECT 1 FROM c WHERE c.fk = o.k AND c.v > 6) AS b FROM o ORDER BY o.id;
|
|
36
|
+
→ [{"id":1,"a":true,"b":false},{"id":2,"a":true,"b":true},{"id":3,"a":false,"b":false},{"id":4,"a":false,"b":false}]
|
|
37
|
+
|
|
38
|
+
-- EXISTS in the SELECT list AND in WHERE of the same query: the WHERE one
|
|
39
|
+
-- becomes a semi join (existing rule), the SELECT-list one a flag join
|
|
40
|
+
SELECT o.id, EXISTS (SELECT 1 FROM c WHERE c.fk = o.k AND c.v > 6) AS f FROM o WHERE EXISTS (SELECT 1 FROM c WHERE c.fk = o.k) ORDER BY o.id;
|
|
41
|
+
→ [{"id":1,"f":false},{"id":2,"f":true}]
|
|
42
|
+
|
|
43
|
+
-- EXISTS inside a CASE wrapper: only the inner node is substituted
|
|
44
|
+
SELECT o.id, CASE WHEN EXISTS (SELECT 1 FROM c WHERE c.fk = o.k) THEN 'y' ELSE 'n' END AS b FROM o ORDER BY o.id;
|
|
45
|
+
→ [{"id":1,"b":"y"},{"id":2,"b":"y"},{"id":3,"b":"n"},{"id":4,"b":"n"}]
|
|
46
|
+
|
|
47
|
+
-- SELECT * inner body (multi-column projection is irrelevant to EXISTS)
|
|
48
|
+
SELECT o.id, EXISTS (SELECT * FROM c WHERE c.fk = o.k) AS f FROM o ORDER BY o.id;
|
|
49
|
+
→ [{"id":1,"f":true},{"id":2,"f":true},{"id":3,"f":false},{"id":4,"f":false}]
|
|
50
|
+
|
|
51
|
+
-- Mixed with a correlated scalar-aggregate subquery in the same list (both
|
|
52
|
+
-- decorrelation rules fire on the same projection)
|
|
53
|
+
SELECT o.id, EXISTS (SELECT 1 FROM c WHERE c.fk = o.k) AS f, (SELECT count(*) FROM c WHERE c.fk = o.k) AS n FROM o ORDER BY o.id;
|
|
54
|
+
→ [{"id":1,"f":true,"n":3},{"id":2,"f":true,"n":1},{"id":3,"f":false,"n":0},{"id":4,"f":false,"n":0}]
|
|
55
|
+
|
|
56
|
+
-- Correlated IN in the projection, both comparison sides non-nullable (o.id and
|
|
57
|
+
-- c.id are PKs): decorrelated; true / false / empty-inner-false all correct
|
|
58
|
+
SELECT o.id, (o.id IN (SELECT c.id FROM c WHERE c.fk = o.k)) AS f FROM o ORDER BY o.id;
|
|
59
|
+
→ [{"id":1,"f":true},{"id":2,"f":false},{"id":3,"f":false},{"id":4,"f":false}]
|
|
60
|
+
|
|
61
|
+
-- NOT IN over the same non-nullable shape: NOT over the exact two-valued flag
|
|
62
|
+
SELECT o.id, (o.id NOT IN (SELECT c.id FROM c WHERE c.fk = o.k)) AS f FROM o ORDER BY o.id;
|
|
63
|
+
→ [{"id":1,"f":false},{"id":2,"f":true},{"id":3,"f":true},{"id":4,"f":true}]
|
|
64
|
+
|
|
65
|
+
-- Rejected shapes: these stay on the correlated per-row path and must keep
|
|
66
|
+
-- today's (three-valued where applicable) semantics.
|
|
67
|
+
|
|
68
|
+
-- IN with a NULLABLE inner column: must bail — a no-match against a set
|
|
69
|
+
-- containing NULL yields NULL, not false (o.id 2: the only v=20 row has fk
|
|
70
|
+
-- NULL, so `2 IN (NULL)` is NULL)
|
|
71
|
+
SELECT o.id, (o.id IN (SELECT c.fk FROM c WHERE c.v = o.k)) AS f FROM o ORDER BY o.id;
|
|
72
|
+
→ [{"id":1,"f":false},{"id":2,"f":null},{"id":3,"f":false},{"id":4,"f":false}]
|
|
73
|
+
|
|
74
|
+
-- NOT IN with inner NULLs: NULL propagates through the NOT (per-row path)
|
|
75
|
+
SELECT o.id, (o.id NOT IN (SELECT c.fk FROM c WHERE c.v = o.k)) AS f FROM o ORDER BY o.id;
|
|
76
|
+
→ [{"id":1,"f":true},{"id":2,"f":null},{"id":3,"f":true},{"id":4,"f":true}]
|
|
77
|
+
|
|
78
|
+
-- Non-equi correlation: bail via the extraction gate; stays correlated but correct
|
|
79
|
+
SELECT o.id, EXISTS (SELECT 1 FROM c WHERE c.v < o.k) AS f FROM o ORDER BY o.id;
|
|
80
|
+
→ [{"id":1,"f":true},{"id":2,"f":true},{"id":3,"f":false},{"id":4,"f":true}]
|
|
81
|
+
|
|
82
|
+
-- Outer reference outside the equi-conjuncts (c.v = o.id + 4 is not a bare
|
|
83
|
+
-- column equality): bail; per-row result preserved
|
|
84
|
+
SELECT o.id, EXISTS (SELECT 1 FROM c WHERE c.fk = o.k AND c.v = o.id + 4) AS f FROM o ORDER BY o.id;
|
|
85
|
+
→ [{"id":1,"f":true},{"id":2,"f":false},{"id":3,"f":false},{"id":4,"f":false}]
|
|
86
|
+
|
|
87
|
+
-- Uncorrelated EXISTS: not this rule's shape (cached per-statement already)
|
|
88
|
+
SELECT o.id, EXISTS (SELECT 1 FROM c WHERE c.v > 100) AS f FROM o ORDER BY o.id;
|
|
89
|
+
→ [{"id":1,"f":false},{"id":2,"f":false},{"id":3,"f":false},{"id":4,"f":false}]
|
|
90
|
+
|
|
91
|
+
-- Shape invariance: the decorrelated projection feeds a derived table consumed
|
|
92
|
+
-- by SELECT * — only the projected columns appear, no leaked join/flag columns
|
|
93
|
+
SELECT * FROM (SELECT o.id, EXISTS (SELECT 1 FROM c WHERE c.fk = o.k) AS f FROM o) sub ORDER BY sub.id;
|
|
94
|
+
→ [{"id":1,"f":true},{"id":2,"f":true},{"id":3,"f":false},{"id":4,"f":false}]
|
|
95
|
+
|
|
96
|
+
-- Flag consumed as a WHERE probe upstream (existence-flag recovery interaction):
|
|
97
|
+
-- results stay exact under any downstream semi/anti re-shaping
|
|
98
|
+
SELECT sub.id FROM (SELECT o.id, EXISTS (SELECT 1 FROM c WHERE c.fk = o.k) AS f FROM o) sub WHERE sub.f ORDER BY sub.id;
|
|
99
|
+
→ [{"id":1},{"id":2}]
|
|
100
|
+
|
|
101
|
+
SELECT sub.id FROM (SELECT o.id, EXISTS (SELECT 1 FROM c WHERE c.fk = o.k) AS f FROM o) sub WHERE NOT sub.f ORDER BY sub.id;
|
|
102
|
+
→ [{"id":3},{"id":4}]
|
|
103
|
+
|
|
104
|
+
-- Flag unused upstream (existence-flag pruning interaction): the outer query
|
|
105
|
+
-- never reads f; row count and values unchanged
|
|
106
|
+
SELECT sub.id FROM (SELECT o.id, EXISTS (SELECT 1 FROM c WHERE c.fk = o.k) AS f FROM o) sub ORDER BY sub.id;
|
|
107
|
+
→ [{"id":1},{"id":2},{"id":3},{"id":4}]
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
-- where-conjunct-ordering.sqllogic - WHERE conjunct cost ordering end-to-end
|
|
2
|
+
-- Complements test/where-conjunct-ordering.spec.ts (which owns the evaluation
|
|
3
|
+
-- counts and plan-shape assertions via a counting UDF). This file pins row-set
|
|
4
|
+
-- parity: `rule-filter-conjunct-ordering` reorders a Filter's AND conjuncts
|
|
5
|
+
-- cheapest-first, and that must NEVER change which rows a query returns — for
|
|
6
|
+
-- both written orders of each query, NULL conjuncts, the `v <> 0` guard idiom,
|
|
7
|
+
-- a HAVING conjunction, and the three-valued-logic truth table.
|
|
8
|
+
|
|
9
|
+
-- 13 rows: k = (id-1) % 3, v = id except the last row's v = 0 (the guard-idiom
|
|
10
|
+
-- divisor). k = 2 holds for ids {3,6,9,12}; v % 5 = 2 for ids {2,7,12}.
|
|
11
|
+
create table t (id integer primary key, k integer, v integer);
|
|
12
|
+
insert into t values
|
|
13
|
+
(1, 0, 1), (2, 1, 2), (3, 2, 3), (4, 0, 4), (5, 1, 5), (6, 2, 6),
|
|
14
|
+
(7, 0, 7), (8, 1, 8), (9, 2, 9), (10, 0, 10), (11, 1, 11), (12, 2, 12),
|
|
15
|
+
(13, 0, 0);
|
|
16
|
+
|
|
17
|
+
-- =============================================================================
|
|
18
|
+
-- Both written orders of a subquery + pure-arithmetic conjunction return the
|
|
19
|
+
-- same rows (the subquery conjunct is reordered last; results must not move).
|
|
20
|
+
-- =============================================================================
|
|
21
|
+
|
|
22
|
+
select id from t where (select length('x')) = 1 and v % 5 = 2 order by id;
|
|
23
|
+
→ [{"id":2},{"id":7},{"id":12}]
|
|
24
|
+
|
|
25
|
+
select id from t where v % 5 = 2 and (select length('x')) = 1 order by id;
|
|
26
|
+
→ [{"id":2},{"id":7},{"id":12}]
|
|
27
|
+
|
|
28
|
+
select id from t where (select count(*) from t) = 13 and k = 2 and v % 5 = 2 order by id;
|
|
29
|
+
→ [{"id":12}]
|
|
30
|
+
|
|
31
|
+
select id from t where k = 2 and v % 5 = 2 and (select count(*) from t) = 13 order by id;
|
|
32
|
+
→ [{"id":12}]
|
|
33
|
+
|
|
34
|
+
-- =============================================================================
|
|
35
|
+
-- NULL conjuncts: a Filter rejects on NULL exactly as on false, in either
|
|
36
|
+
-- position, so both orders return zero rows.
|
|
37
|
+
-- =============================================================================
|
|
38
|
+
|
|
39
|
+
select id from t where null and k = 2;
|
|
40
|
+
→ []
|
|
41
|
+
|
|
42
|
+
select id from t where k = 2 and null;
|
|
43
|
+
→ []
|
|
44
|
+
|
|
45
|
+
-- =============================================================================
|
|
46
|
+
-- Guard idiom: `v <> 0` protecting a division. Sound in either order (division
|
|
47
|
+
-- by zero yields NULL, which the Filter rejects), and cost ordering keeps the
|
|
48
|
+
-- simpler guard first anyway. Pinned so a future cost-model change cannot
|
|
49
|
+
-- silently break it. 10 / v <= 10 holds for every v >= 1.
|
|
50
|
+
-- =============================================================================
|
|
51
|
+
|
|
52
|
+
select id from t where v <> 0 and 10 / v <= 10 order by id;
|
|
53
|
+
→ [{"id":1},{"id":2},{"id":3},{"id":4},{"id":5},{"id":6},{"id":7},{"id":8},{"id":9},{"id":10},{"id":11},{"id":12}]
|
|
54
|
+
|
|
55
|
+
select id from t where 10 / v <= 10 and v <> 0 order by id;
|
|
56
|
+
→ [{"id":1},{"id":2},{"id":3},{"id":4},{"id":5},{"id":6},{"id":7},{"id":8},{"id":9},{"id":10},{"id":11},{"id":12}]
|
|
57
|
+
|
|
58
|
+
-- =============================================================================
|
|
59
|
+
-- HAVING conjunctions build FilterNodes too, so the rule applies there as well.
|
|
60
|
+
-- k = 0 has 5 rows, k = 1 and k = 2 have 4 each.
|
|
61
|
+
-- =============================================================================
|
|
62
|
+
|
|
63
|
+
select k, count(*) as c from t group by k having count(*) >= 4 and k > 0 order by k;
|
|
64
|
+
→ [{"k":1,"c":4},{"k":2,"c":4}]
|
|
65
|
+
|
|
66
|
+
select k, count(*) as c from t group by k having k > 0 and count(*) >= 4 order by k;
|
|
67
|
+
→ [{"k":1,"c":4},{"k":2,"c":4}]
|
|
68
|
+
|
|
69
|
+
-- =============================================================================
|
|
70
|
+
-- Three-valued logic under reordering: `a and b` vs `b and a` over every
|
|
71
|
+
-- {true,false,null}² pair. A Filter keeps a row only when the conjunction is
|
|
72
|
+
-- true, and AND is commutative under 3VL, so both orders keep exactly the rows
|
|
73
|
+
-- where both operands are true.
|
|
74
|
+
-- =============================================================================
|
|
75
|
+
|
|
76
|
+
create table tv (id integer primary key, a integer null, b integer null);
|
|
77
|
+
insert into tv values
|
|
78
|
+
(1, 1, 1), (2, 1, 0), (3, 1, null),
|
|
79
|
+
(4, 0, 1), (5, 0, 0), (6, 0, null),
|
|
80
|
+
(7, null, 1), (8, null, 0), (9, null, null);
|
|
81
|
+
|
|
82
|
+
select id from tv where a and b order by id;
|
|
83
|
+
→ [{"id":1}]
|
|
84
|
+
|
|
85
|
+
select id from tv where b and a order by id;
|
|
86
|
+
→ [{"id":1}]
|
|
87
|
+
|
|
88
|
+
-- =============================================================================
|
|
89
|
+
-- Selectivity-driven ordering (ANALYZEd table): within one cost tier the rule
|
|
90
|
+
-- now runs the conjunct that statistics say rejects more rows per unit work
|
|
91
|
+
-- first. `weak` has 2 distinct values, `strong` 50, so `strong in (2, 3)`
|
|
92
|
+
-- (est. 0.04) sorts ahead of `weak = 1` (est. 0.5) despite the pricier IN list.
|
|
93
|
+
-- Row-set parity for both written orders is what this file can pin; the plan
|
|
94
|
+
-- order itself is asserted in test/where-conjunct-ordering.spec.ts.
|
|
95
|
+
-- weak = id % 2, strong = id % 50 → the conjunction keeps ids {3, 53}.
|
|
96
|
+
-- =============================================================================
|
|
97
|
+
|
|
98
|
+
create table sel (id integer primary key, weak integer, strong integer);
|
|
99
|
+
insert into sel values
|
|
100
|
+
(1, 1, 1), (2, 0, 2), (3, 1, 3), (4, 0, 4), (5, 1, 5), (6, 0, 6), (7, 1, 7), (8, 0, 8), (9, 1, 9), (10, 0, 10),
|
|
101
|
+
(11, 1, 11), (12, 0, 12), (13, 1, 13), (14, 0, 14), (15, 1, 15), (16, 0, 16), (17, 1, 17), (18, 0, 18), (19, 1, 19), (20, 0, 20),
|
|
102
|
+
(21, 1, 21), (22, 0, 22), (23, 1, 23), (24, 0, 24), (25, 1, 25), (26, 0, 26), (27, 1, 27), (28, 0, 28), (29, 1, 29), (30, 0, 30),
|
|
103
|
+
(31, 1, 31), (32, 0, 32), (33, 1, 33), (34, 0, 34), (35, 1, 35), (36, 0, 36), (37, 1, 37), (38, 0, 38), (39, 1, 39), (40, 0, 40),
|
|
104
|
+
(41, 1, 41), (42, 0, 42), (43, 1, 43), (44, 0, 44), (45, 1, 45), (46, 0, 46), (47, 1, 47), (48, 0, 48), (49, 1, 49), (50, 0, 0),
|
|
105
|
+
(51, 1, 1), (52, 0, 2), (53, 1, 3), (54, 0, 4), (55, 1, 5), (56, 0, 6), (57, 1, 7), (58, 0, 8), (59, 1, 9), (60, 0, 10),
|
|
106
|
+
(61, 1, 11), (62, 0, 12), (63, 1, 13), (64, 0, 14), (65, 1, 15), (66, 0, 16), (67, 1, 17), (68, 0, 18), (69, 1, 19), (70, 0, 20),
|
|
107
|
+
(71, 1, 21), (72, 0, 22), (73, 1, 23), (74, 0, 24), (75, 1, 25), (76, 0, 26), (77, 1, 27), (78, 0, 28), (79, 1, 29), (80, 0, 30),
|
|
108
|
+
(81, 1, 31), (82, 0, 32), (83, 1, 33), (84, 0, 34), (85, 1, 35), (86, 0, 36), (87, 1, 37), (88, 0, 38), (89, 1, 39), (90, 0, 40),
|
|
109
|
+
(91, 1, 41), (92, 0, 42), (93, 1, 43), (94, 0, 44), (95, 1, 45), (96, 0, 46), (97, 1, 47), (98, 0, 48), (99, 1, 49), (100, 0, 0);
|
|
110
|
+
|
|
111
|
+
analyze sel;
|
|
112
|
+
|
|
113
|
+
select id from sel where weak = 1 and strong in (2, 3) order by id;
|
|
114
|
+
→ [{"id":3},{"id":53}]
|
|
115
|
+
|
|
116
|
+
select id from sel where strong in (2, 3) and weak = 1 order by id;
|
|
117
|
+
→ [{"id":3},{"id":53}]
|
|
118
|
+
|
|
119
|
+
drop table sel;
|
|
120
|
+
drop table tv;
|
|
121
|
+
drop table t;
|