@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,164 @@
|
|
|
1
|
+
-- indexes.sqllogic - Testing index creation and usage
|
|
2
|
+
--
|
|
3
|
+
-- requires-capability: standalone-index-ddl
|
|
4
|
+
|
|
5
|
+
-- Setup base table for index testing
|
|
6
|
+
CREATE TABLE idx_test (
|
|
7
|
+
id INTEGER PRIMARY KEY,
|
|
8
|
+
name TEXT,
|
|
9
|
+
age INTEGER,
|
|
10
|
+
city TEXT,
|
|
11
|
+
score REAL,
|
|
12
|
+
active INTEGER
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
INSERT INTO idx_test VALUES
|
|
16
|
+
(1, 'Alice', 30, 'New York', 95.5, 1),
|
|
17
|
+
(2, 'Bob', 25, 'London', 87.2, 1),
|
|
18
|
+
(3, 'Charlie', 35, 'New York', 92.1, 0),
|
|
19
|
+
(4, 'David', 30, 'Paris', 89.8, 1),
|
|
20
|
+
(5, 'Eve', 28, 'London', 96.3, 1);
|
|
21
|
+
|
|
22
|
+
-- Basic CREATE INDEX
|
|
23
|
+
CREATE INDEX idx_name ON idx_test (name);
|
|
24
|
+
|
|
25
|
+
-- Verify table still works after index creation
|
|
26
|
+
SELECT name FROM idx_test WHERE name = 'Alice';
|
|
27
|
+
→ [{"name":"Alice"}]
|
|
28
|
+
|
|
29
|
+
-- CREATE INDEX with IF NOT EXISTS
|
|
30
|
+
CREATE INDEX IF NOT EXISTS idx_age ON idx_test (age);
|
|
31
|
+
|
|
32
|
+
-- Try to create same index again (should succeed with IF NOT EXISTS)
|
|
33
|
+
CREATE INDEX IF NOT EXISTS idx_age ON idx_test (age);
|
|
34
|
+
|
|
35
|
+
-- Multi-column index
|
|
36
|
+
CREATE INDEX idx_city_age ON idx_test (city, age);
|
|
37
|
+
|
|
38
|
+
-- Index with DESC ordering
|
|
39
|
+
CREATE INDEX idx_score_desc ON idx_test (score DESC);
|
|
40
|
+
|
|
41
|
+
-- Index on different data types
|
|
42
|
+
CREATE INDEX idx_active ON idx_test (active);
|
|
43
|
+
|
|
44
|
+
-- Verify queries still work with indexes
|
|
45
|
+
SELECT id, name FROM idx_test WHERE age = 30 ORDER BY name;
|
|
46
|
+
→ [{"id":1,"name":"Alice"},{"id":4,"name":"David"}]
|
|
47
|
+
|
|
48
|
+
SELECT name FROM idx_test WHERE city = 'London' ORDER BY age;
|
|
49
|
+
→ [{"name":"Bob"},{"name":"Eve"}]
|
|
50
|
+
|
|
51
|
+
SELECT name, score FROM idx_test WHERE score > 90 ORDER BY score DESC;
|
|
52
|
+
→ [{"name":"Eve","score":96.3},{"name":"Alice","score":95.5},{"name":"Charlie","score":92.1}]
|
|
53
|
+
|
|
54
|
+
-- Test UNIQUE index
|
|
55
|
+
CREATE TABLE unique_test (id INTEGER PRIMARY KEY, email TEXT);
|
|
56
|
+
INSERT INTO unique_test VALUES (1, 'alice@example.com'), (2, 'bob@example.com');
|
|
57
|
+
|
|
58
|
+
CREATE UNIQUE INDEX idx_email_unique ON unique_test (email);
|
|
59
|
+
|
|
60
|
+
-- Query with unique index
|
|
61
|
+
SELECT id FROM unique_test WHERE email = 'alice@example.com';
|
|
62
|
+
→ [{"id":1}]
|
|
63
|
+
|
|
64
|
+
-- Test index on NULL values
|
|
65
|
+
CREATE TABLE null_test (id INTEGER PRIMARY KEY, optional_field TEXT NULL);
|
|
66
|
+
INSERT INTO null_test VALUES (1, 'value1'), (2, NULL), (3, 'value3'), (4, NULL);
|
|
67
|
+
|
|
68
|
+
CREATE INDEX idx_optional ON null_test (optional_field);
|
|
69
|
+
|
|
70
|
+
-- Query with NULL values
|
|
71
|
+
SELECT id FROM null_test WHERE optional_field IS NULL ORDER BY id;
|
|
72
|
+
→ [{"id":2},{"id":4}]
|
|
73
|
+
|
|
74
|
+
SELECT id FROM null_test WHERE optional_field = 'value1';
|
|
75
|
+
→ [{"id":1}]
|
|
76
|
+
|
|
77
|
+
-- Test complex WHERE clauses with indexed columns
|
|
78
|
+
SELECT name, age FROM idx_test WHERE city = 'New York' AND age > 30 ORDER BY name;
|
|
79
|
+
→ [{"name":"Charlie","age":35}]
|
|
80
|
+
|
|
81
|
+
-- Test JOIN with indexed columns
|
|
82
|
+
CREATE TABLE departments (id INTEGER PRIMARY KEY, name TEXT, city TEXT);
|
|
83
|
+
INSERT INTO departments VALUES (1, 'Engineering', 'New York'), (2, 'Sales', 'London'), (3, 'Marketing', 'Paris');
|
|
84
|
+
|
|
85
|
+
CREATE INDEX idx_dept_city ON departments (city);
|
|
86
|
+
|
|
87
|
+
SELECT i.name, d.name as dept FROM idx_test i
|
|
88
|
+
JOIN departments d ON i.city = d.city
|
|
89
|
+
WHERE i.active = 1
|
|
90
|
+
ORDER BY i.name;
|
|
91
|
+
→ [{"name":"Alice","dept":"Engineering"},{"name":"Bob","dept":"Sales"},{"name":"David","dept":"Marketing"},{"name":"Eve","dept":"Sales"}]
|
|
92
|
+
|
|
93
|
+
-- Test ORDER BY with indexed columns (should be optimized)
|
|
94
|
+
SELECT name FROM idx_test ORDER BY name;
|
|
95
|
+
→ [{"name":"Alice"},{"name":"Bob"},{"name":"Charlie"},{"name":"David"},{"name":"Eve"}]
|
|
96
|
+
|
|
97
|
+
SELECT name FROM idx_test ORDER BY age, name;
|
|
98
|
+
→ [{"name":"Bob"},{"name":"Eve"},{"name":"Alice"},{"name":"David"},{"name":"Charlie"}]
|
|
99
|
+
|
|
100
|
+
-- Test range queries on indexed columns
|
|
101
|
+
SELECT name FROM idx_test WHERE age BETWEEN 25 AND 30 ORDER BY age, name;
|
|
102
|
+
→ [{"name":"Bob"},{"name":"Eve"},{"name":"Alice"},{"name":"David"}]
|
|
103
|
+
|
|
104
|
+
-- Error cases
|
|
105
|
+
|
|
106
|
+
-- Try to create index on non-existent table
|
|
107
|
+
CREATE INDEX idx_bad_table ON non_existent_table (col);
|
|
108
|
+
-- error: no such table
|
|
109
|
+
|
|
110
|
+
-- Try to create index on non-existent column
|
|
111
|
+
CREATE INDEX idx_bad_col ON idx_test (non_existent_column);
|
|
112
|
+
-- error: Column 'non_existent_column' not found in table 'idx_test'
|
|
113
|
+
|
|
114
|
+
-- Try to create duplicate index without IF NOT EXISTS
|
|
115
|
+
CREATE INDEX idx_name ON idx_test (name);
|
|
116
|
+
-- error: Index idx_name already exists
|
|
117
|
+
|
|
118
|
+
-- ========================================
|
|
119
|
+
-- DROP INDEX tests
|
|
120
|
+
-- ========================================
|
|
121
|
+
|
|
122
|
+
-- DROP INDEX: basic drop
|
|
123
|
+
CREATE TABLE drop_idx_test (id INTEGER PRIMARY KEY, name TEXT, age INTEGER);
|
|
124
|
+
INSERT INTO drop_idx_test VALUES (1, 'Alice', 30), (2, 'Bob', 25);
|
|
125
|
+
|
|
126
|
+
CREATE INDEX idx_drop_name ON drop_idx_test (name);
|
|
127
|
+
|
|
128
|
+
-- Verify index works
|
|
129
|
+
SELECT name FROM drop_idx_test WHERE name = 'Alice';
|
|
130
|
+
→ [{"name":"Alice"}]
|
|
131
|
+
|
|
132
|
+
-- Drop the index
|
|
133
|
+
DROP INDEX idx_drop_name;
|
|
134
|
+
|
|
135
|
+
-- Queries should still work after dropping index
|
|
136
|
+
SELECT name FROM drop_idx_test WHERE name = 'Alice';
|
|
137
|
+
→ [{"name":"Alice"}]
|
|
138
|
+
|
|
139
|
+
-- Re-creating the same index should succeed after drop
|
|
140
|
+
CREATE INDEX idx_drop_name ON drop_idx_test (name);
|
|
141
|
+
DROP INDEX idx_drop_name;
|
|
142
|
+
|
|
143
|
+
-- DROP INDEX IF EXISTS: index exists
|
|
144
|
+
CREATE INDEX idx_drop_age ON drop_idx_test (age);
|
|
145
|
+
DROP INDEX IF EXISTS idx_drop_age;
|
|
146
|
+
|
|
147
|
+
-- DROP INDEX IF EXISTS: index does not exist (should be no-op)
|
|
148
|
+
DROP INDEX IF EXISTS idx_nonexistent;
|
|
149
|
+
|
|
150
|
+
-- DROP INDEX: error when index does not exist (no IF EXISTS)
|
|
151
|
+
DROP INDEX idx_nonexistent;
|
|
152
|
+
-- error: no such index
|
|
153
|
+
|
|
154
|
+
-- DROP TRIGGER: parser rejects (not a supported object type)
|
|
155
|
+
DROP TRIGGER some_trigger;
|
|
156
|
+
-- error: Expected TABLE, VIEW, MATERIALIZED VIEW, INDEX, or ASSERTION after DROP
|
|
157
|
+
|
|
158
|
+
DROP TABLE drop_idx_test;
|
|
159
|
+
|
|
160
|
+
-- Clean up
|
|
161
|
+
DROP TABLE departments;
|
|
162
|
+
DROP TABLE null_test;
|
|
163
|
+
DROP TABLE unique_test;
|
|
164
|
+
DROP TABLE idx_test;
|
|
@@ -0,0 +1,526 @@
|
|
|
1
|
+
-- adapted from SQLite test/index6.test, test/index7.test
|
|
2
|
+
-- partial indexes (CREATE INDEX ... WHERE expr) — both regular and UNIQUE.
|
|
3
|
+
-- Quereus's parser accepts partial indexes; this fixture pins the runtime semantics:
|
|
4
|
+
-- only rows matching the WHERE clause participate in the index, but query results must
|
|
5
|
+
-- remain correct regardless of which rows the index covers.
|
|
6
|
+
--
|
|
7
|
+
-- requires-capability: standalone-index-ddl
|
|
8
|
+
|
|
9
|
+
-- =====================================================
|
|
10
|
+
-- 1. Basic partial index — rows outside WHERE still queryable
|
|
11
|
+
-- =====================================================
|
|
12
|
+
create table p_basic (id integer primary key, status text, val integer);
|
|
13
|
+
insert into p_basic values (1, 'active', 10);
|
|
14
|
+
insert into p_basic values (2, 'inactive', 20);
|
|
15
|
+
insert into p_basic values (3, 'active', 30);
|
|
16
|
+
insert into p_basic values (4, 'inactive', 5);
|
|
17
|
+
|
|
18
|
+
create index ix_p_basic_active on p_basic(val) where status = 'active';
|
|
19
|
+
|
|
20
|
+
-- Query inside the partial scope
|
|
21
|
+
select id from p_basic where status = 'active' order by id;
|
|
22
|
+
→ [{"id":1},{"id":3}]
|
|
23
|
+
|
|
24
|
+
-- Query outside the partial scope still returns correct rows (index need not apply)
|
|
25
|
+
select id from p_basic where status = 'inactive' order by id;
|
|
26
|
+
→ [{"id":2},{"id":4}]
|
|
27
|
+
|
|
28
|
+
-- Combined predicate using the partial scope
|
|
29
|
+
select id from p_basic where status = 'active' and val > 15;
|
|
30
|
+
→ [{"id":3}]
|
|
31
|
+
|
|
32
|
+
drop table p_basic;
|
|
33
|
+
|
|
34
|
+
-- =====================================================
|
|
35
|
+
-- 2. Partial UNIQUE index — uniqueness limited to WHERE scope
|
|
36
|
+
-- =====================================================
|
|
37
|
+
create table p_uniq (id integer primary key, status text, code text);
|
|
38
|
+
create unique index ix_p_uniq_active_code on p_uniq(code) where status = 'active';
|
|
39
|
+
|
|
40
|
+
-- First active row claims code 'A'
|
|
41
|
+
insert into p_uniq values (1, 'active', 'A');
|
|
42
|
+
|
|
43
|
+
-- Same code outside scope: allowed (partial UNIQUE excludes inactive rows)
|
|
44
|
+
insert into p_uniq values (2, 'inactive', 'A');
|
|
45
|
+
|
|
46
|
+
select id, status, code from p_uniq order by id;
|
|
47
|
+
→ [{"id":1,"status":"active","code":"A"},{"id":2,"status":"inactive","code":"A"}]
|
|
48
|
+
|
|
49
|
+
-- Same code inside scope: rejected
|
|
50
|
+
insert into p_uniq values (3, 'active', 'A');
|
|
51
|
+
-- error: UNIQUE
|
|
52
|
+
|
|
53
|
+
-- Update transitioning a row out of scope frees the code
|
|
54
|
+
update p_uniq set status = 'archived' where id = 1;
|
|
55
|
+
insert into p_uniq values (4, 'active', 'A');
|
|
56
|
+
|
|
57
|
+
select id, status, code from p_uniq order by id;
|
|
58
|
+
→ [{"id":1,"status":"archived","code":"A"},{"id":2,"status":"inactive","code":"A"},{"id":4,"status":"active","code":"A"}]
|
|
59
|
+
|
|
60
|
+
drop table p_uniq;
|
|
61
|
+
|
|
62
|
+
-- =====================================================
|
|
63
|
+
-- 3. Partial index with IS NULL / IS NOT NULL predicate
|
|
64
|
+
-- =====================================================
|
|
65
|
+
create table p_null (id integer primary key, name text, deleted_at text null);
|
|
66
|
+
insert into p_null values (1, 'Widget', null);
|
|
67
|
+
insert into p_null values (2, 'Gadget', '2024-06-01');
|
|
68
|
+
insert into p_null values (3, 'Sprocket', null);
|
|
69
|
+
insert into p_null values (4, 'Doohickey', '2025-01-15');
|
|
70
|
+
|
|
71
|
+
create index ix_p_null_active on p_null(name) where deleted_at is null;
|
|
72
|
+
|
|
73
|
+
-- Query inside scope (matches the partial predicate)
|
|
74
|
+
select id from p_null where name = 'Widget' and deleted_at is null;
|
|
75
|
+
→ [{"id":1}]
|
|
76
|
+
|
|
77
|
+
-- Query outside scope (does not match the partial predicate)
|
|
78
|
+
select id from p_null where name = 'Gadget' and deleted_at is not null;
|
|
79
|
+
→ [{"id":2}]
|
|
80
|
+
|
|
81
|
+
-- Listing all "active" rows
|
|
82
|
+
select id, name from p_null where deleted_at is null order by id;
|
|
83
|
+
→ [{"id":1,"name":"Widget"},{"id":3,"name":"Sprocket"}]
|
|
84
|
+
|
|
85
|
+
drop table p_null;
|
|
86
|
+
|
|
87
|
+
-- =====================================================
|
|
88
|
+
-- 4. Partial index with compound WHERE (AND, comparison)
|
|
89
|
+
-- =====================================================
|
|
90
|
+
create table p_cmp (id integer primary key, user_id integer, score real, archived integer);
|
|
91
|
+
insert into p_cmp values (1, 10, 95.5, 0);
|
|
92
|
+
insert into p_cmp values (2, 10, 45.0, 0);
|
|
93
|
+
insert into p_cmp values (3, 20, 88.2, 0);
|
|
94
|
+
insert into p_cmp values (4, 10, 99.0, 1);
|
|
95
|
+
|
|
96
|
+
create index ix_p_cmp_high on p_cmp(user_id) where archived = 0 and score > 80.0;
|
|
97
|
+
|
|
98
|
+
-- Query in scope
|
|
99
|
+
select id from p_cmp where archived = 0 and score > 80.0 and user_id = 10;
|
|
100
|
+
→ [{"id":1}]
|
|
101
|
+
|
|
102
|
+
-- Query that overlaps scope but adds another filter
|
|
103
|
+
select id from p_cmp where user_id = 10 and score > 80.0 order by id;
|
|
104
|
+
→ [{"id":1},{"id":4}]
|
|
105
|
+
|
|
106
|
+
-- Query strictly outside scope
|
|
107
|
+
select id from p_cmp where archived = 1 order by id;
|
|
108
|
+
→ [{"id":4}]
|
|
109
|
+
|
|
110
|
+
drop table p_cmp;
|
|
111
|
+
|
|
112
|
+
-- =====================================================
|
|
113
|
+
-- 5. Partial index updated correctly when a row's WHERE-eligibility changes
|
|
114
|
+
-- =====================================================
|
|
115
|
+
create table p_move (id integer primary key, kind text, label text);
|
|
116
|
+
create index ix_p_move on p_move(label) where kind = 'A';
|
|
117
|
+
|
|
118
|
+
insert into p_move values (1, 'A', 'one');
|
|
119
|
+
insert into p_move values (2, 'B', 'two');
|
|
120
|
+
insert into p_move values (3, 'A', 'three');
|
|
121
|
+
|
|
122
|
+
select id from p_move where kind = 'A' and label = 'one';
|
|
123
|
+
→ [{"id":1}]
|
|
124
|
+
|
|
125
|
+
-- Move id=1 out of scope
|
|
126
|
+
update p_move set kind = 'B' where id = 1;
|
|
127
|
+
|
|
128
|
+
select id from p_move where kind = 'A' and label = 'one';
|
|
129
|
+
→ []
|
|
130
|
+
|
|
131
|
+
-- Move id=2 into scope
|
|
132
|
+
update p_move set kind = 'A' where id = 2;
|
|
133
|
+
|
|
134
|
+
select id from p_move where kind = 'A' order by id;
|
|
135
|
+
→ [{"id":2},{"id":3}]
|
|
136
|
+
|
|
137
|
+
drop table p_move;
|
|
138
|
+
|
|
139
|
+
-- =====================================================
|
|
140
|
+
-- 6. Partial UNIQUE index must NOT register as a relation key
|
|
141
|
+
-- (FD-layer soundness — partial UNIQUE only guarantees uniqueness
|
|
142
|
+
-- inside the WHERE scope, so it cannot be promoted to an
|
|
143
|
+
-- unconditional key. Otherwise the FD layer derives
|
|
144
|
+
-- K → all-other-cols over the whole table and silently breaks
|
|
145
|
+
-- DISTINCT elimination, GROUP BY simplification, ORDER BY pruning,
|
|
146
|
+
-- and FK→PK join elimination.)
|
|
147
|
+
-- =====================================================
|
|
148
|
+
create table p_fdkey (id integer primary key, c text not null, status text not null);
|
|
149
|
+
create unique index ix_p_fdkey on p_fdkey(c) where status = 'active';
|
|
150
|
+
insert into p_fdkey values (1, 'A', 'active');
|
|
151
|
+
insert into p_fdkey values (2, 'A', 'inactive');
|
|
152
|
+
insert into p_fdkey values (3, 'B', 'active');
|
|
153
|
+
|
|
154
|
+
-- DISTINCT must not be eliminated: c is only unique among status='active' rows.
|
|
155
|
+
select c from (select distinct c from p_fdkey) order by c;
|
|
156
|
+
→ [{"c":"A"},{"c":"B"}]
|
|
157
|
+
|
|
158
|
+
-- Same query, count form — must equal the true distinct count across all rows.
|
|
159
|
+
select count(distinct c) as n from p_fdkey;
|
|
160
|
+
→ [{"n":2}]
|
|
161
|
+
|
|
162
|
+
-- LEFT JOIN whose right side is the partial-UNIQUE column: join elimination must
|
|
163
|
+
-- not fire — t.c is not an unconditional key, so the join can change row count
|
|
164
|
+
-- (the driver row 'A' matches two p_fdkey rows, not one).
|
|
165
|
+
create table p_fdkey_drv (x integer primary key, c text);
|
|
166
|
+
insert into p_fdkey_drv values (10, 'A');
|
|
167
|
+
select count(*) as n from p_fdkey_drv d left join p_fdkey t on d.c = t.c;
|
|
168
|
+
→ [{"n":2}]
|
|
169
|
+
|
|
170
|
+
drop table p_fdkey_drv;
|
|
171
|
+
drop table p_fdkey;
|
|
172
|
+
|
|
173
|
+
-- Positive control: a *full* UNIQUE index on a NOT NULL column on the same
|
|
174
|
+
-- shape still registers as a key and DISTINCT/etc. may safely be eliminated.
|
|
175
|
+
create table p_fdkey_full (id integer primary key, c text not null);
|
|
176
|
+
create unique index ix_p_fdkey_full on p_fdkey_full(c);
|
|
177
|
+
insert into p_fdkey_full values (1, 'A');
|
|
178
|
+
insert into p_fdkey_full values (2, 'B');
|
|
179
|
+
select count(*) as n from (select distinct c from p_fdkey_full);
|
|
180
|
+
→ [{"n":2}]
|
|
181
|
+
drop table p_fdkey_full;
|
|
182
|
+
|
|
183
|
+
-- =====================================================
|
|
184
|
+
-- 7. Partial UNIQUE index → guarded FD; correctness across filter shapes.
|
|
185
|
+
--
|
|
186
|
+
-- The producer (partial-unique-extraction) emits a guarded FD `K → others | P`
|
|
187
|
+
-- on the table reference. Filter activation discharges the guard when the
|
|
188
|
+
-- surrounding predicate entails P. Observable plan-shape verification of the
|
|
189
|
+
-- activation happens in unit tests (conditional-fds.spec.ts), which inspect
|
|
190
|
+
-- the FilterNode's physical FDs directly. Here we pin runtime correctness:
|
|
191
|
+
-- queries that *should* be safe against duplicates inside the partial scope
|
|
192
|
+
-- must return the right rows whether or not the optimizer chose to eliminate
|
|
193
|
+
-- DISTINCT / GROUP BY.
|
|
194
|
+
-- =====================================================
|
|
195
|
+
create table p7 (id integer primary key, c text not null, status text not null, region text not null, amt integer not null);
|
|
196
|
+
create unique index ix_p7_active on p7(c) where status = 'active';
|
|
197
|
+
insert into p7 values (1, 'A', 'active', 'us', 10);
|
|
198
|
+
insert into p7 values (2, 'A', 'inactive', 'us', 20);
|
|
199
|
+
insert into p7 values (3, 'B', 'active', 'us', 30);
|
|
200
|
+
insert into p7 values (4, 'C', 'active', 'eu', 40);
|
|
201
|
+
|
|
202
|
+
-- 7a. Direct match: filter exactly equal to the partial predicate.
|
|
203
|
+
select c from p7 where status = 'active' order by c;
|
|
204
|
+
→ [{"c":"A"},{"c":"B"},{"c":"C"}]
|
|
205
|
+
|
|
206
|
+
-- 7b. DISTINCT is correct whether eliminated or not.
|
|
207
|
+
select distinct c from (select c from p7 where status = 'active') order by c;
|
|
208
|
+
→ [{"c":"A"},{"c":"B"},{"c":"C"}]
|
|
209
|
+
|
|
210
|
+
-- 7c. Negative — no filter: DISTINCT must dedupe ('A' appears twice).
|
|
211
|
+
select c from (select distinct c from p7) order by c;
|
|
212
|
+
→ [{"c":"A"},{"c":"B"},{"c":"C"}]
|
|
213
|
+
|
|
214
|
+
-- 7d. Negative — wrong filter: 'A' duplicates outside the partial scope.
|
|
215
|
+
select count(*) as n from (select distinct c from p7 where status = 'inactive');
|
|
216
|
+
→ [{"n":1}]
|
|
217
|
+
|
|
218
|
+
-- 7e. GROUP BY: one row per group regardless of partial-FD discharge.
|
|
219
|
+
select c, max(amt) as max_amt from p7 where status = 'active' group by c order by c;
|
|
220
|
+
→ [{"c":"A","max_amt":10},{"c":"B","max_amt":30},{"c":"C","max_amt":40}]
|
|
221
|
+
|
|
222
|
+
drop table p7;
|
|
223
|
+
|
|
224
|
+
-- 7f. Multi-conjunct partial predicate: correctness when both clauses match,
|
|
225
|
+
-- and when only one does (uniqueness no longer holds).
|
|
226
|
+
create table p7m (id integer primary key, c text not null, status text not null, region text not null);
|
|
227
|
+
create unique index ix_p7m on p7m(c) where status = 'active' and region = 'us';
|
|
228
|
+
insert into p7m values (1, 'A', 'active', 'us');
|
|
229
|
+
insert into p7m values (2, 'A', 'active', 'eu');
|
|
230
|
+
insert into p7m values (3, 'B', 'active', 'us');
|
|
231
|
+
|
|
232
|
+
-- Both conjuncts present: 'A' appears once (only the 'us' row matches).
|
|
233
|
+
select c from p7m where status = 'active' and region = 'us' order by c;
|
|
234
|
+
→ [{"c":"A"},{"c":"B"}]
|
|
235
|
+
|
|
236
|
+
-- Single conjunct: 'A' appears twice (two active rows, different regions).
|
|
237
|
+
-- DISTINCT must deduplicate (the partial UC doesn't cover the broader scope).
|
|
238
|
+
select count(*) as n from (select distinct c from p7m where status = 'active');
|
|
239
|
+
→ [{"n":2}]
|
|
240
|
+
|
|
241
|
+
drop table p7m;
|
|
242
|
+
|
|
243
|
+
-- 7g. Nullable UC column: NOT-NULL gate suppresses the FD entirely. Even
|
|
244
|
+
-- with a perfectly matching filter, the partial UC doesn't give a key —
|
|
245
|
+
-- nullable c admits duplicate NULLs inside the partial scope.
|
|
246
|
+
create table p7n (id integer primary key, c text null, status text not null);
|
|
247
|
+
create unique index ix_p7n on p7n(c) where status = 'active';
|
|
248
|
+
insert into p7n values (1, 'A', 'active');
|
|
249
|
+
insert into p7n values (2, 'B', 'active');
|
|
250
|
+
insert into p7n values (3, null, 'active');
|
|
251
|
+
|
|
252
|
+
select count(*) as n from (select distinct c from p7n where status = 'active');
|
|
253
|
+
→ [{"n":3}]
|
|
254
|
+
|
|
255
|
+
drop table p7n;
|
|
256
|
+
|
|
257
|
+
-- 7h. Nullable UC column with IS NOT NULL guard: the partial predicate itself
|
|
258
|
+
-- forces the column non-NULL inside scope, so the guarded FD is sound and
|
|
259
|
+
-- DISTINCT should be eliminable when the filter discharges it.
|
|
260
|
+
create table p7h (id integer primary key, email text null);
|
|
261
|
+
create unique index ix_p7h on p7h(email) where email is not null;
|
|
262
|
+
insert into p7h values (1, 'a@x');
|
|
263
|
+
insert into p7h values (2, 'b@x');
|
|
264
|
+
insert into p7h values (3, null);
|
|
265
|
+
|
|
266
|
+
-- Inside scope: every email is unique; DISTINCT must yield the same count
|
|
267
|
+
-- as without (correctness must hold whether or not the optimizer eliminated
|
|
268
|
+
-- DISTINCT). Two non-null rows.
|
|
269
|
+
select count(*) as n from (select distinct email from p7h where email is not null);
|
|
270
|
+
→ [{"n":2}]
|
|
271
|
+
|
|
272
|
+
-- Negative: without the IS NOT NULL filter, NULL is part of the result set;
|
|
273
|
+
-- correctness must remain — three distinct values including NULL.
|
|
274
|
+
select count(*) as n from (select distinct email from p7h);
|
|
275
|
+
→ [{"n":3}]
|
|
276
|
+
|
|
277
|
+
drop table p7h;
|
|
278
|
+
|
|
279
|
+
-- =====================================================
|
|
280
|
+
-- 7i. Partial UNIQUE with IN-list predicate: producer recognizes
|
|
281
|
+
-- `col IN (lit, …)` as an `or-of [eq-literal …]` guard; the
|
|
282
|
+
-- consumer discharges it when the filter pins the column to a
|
|
283
|
+
-- subset of the OR-set.
|
|
284
|
+
-- =====================================================
|
|
285
|
+
create table p7i (id integer primary key, c text not null, status text not null);
|
|
286
|
+
create unique index ix_p7i on p7i(c) where status in ('active', 'pending');
|
|
287
|
+
|
|
288
|
+
-- Direct match: c must be unique inside the partial scope.
|
|
289
|
+
insert into p7i values (1, 'A', 'active');
|
|
290
|
+
insert into p7i values (2, 'B', 'pending');
|
|
291
|
+
insert into p7i values (3, 'A', 'inactive');
|
|
292
|
+
-- Different status, same c: allowed (partial UC excludes the row).
|
|
293
|
+
|
|
294
|
+
select id, c, status from p7i order by id;
|
|
295
|
+
→ [{"id":1,"c":"A","status":"active"},{"id":2,"c":"B","status":"pending"},{"id":3,"c":"A","status":"inactive"}]
|
|
296
|
+
|
|
297
|
+
-- Duplicate inside scope: rejected.
|
|
298
|
+
insert into p7i values (4, 'A', 'pending');
|
|
299
|
+
-- error: UNIQUE
|
|
300
|
+
|
|
301
|
+
-- DISTINCT inside scope: c is unique, so the result count equals the
|
|
302
|
+
-- in-scope row count regardless of FD discharge.
|
|
303
|
+
select count(*) as n from (select distinct c from p7i where status in ('active', 'pending'));
|
|
304
|
+
→ [{"n":2}]
|
|
305
|
+
|
|
306
|
+
-- Negative: a filter outside the scope (status not in OR-set) must still
|
|
307
|
+
-- dedupe correctly when c repeats across scopes.
|
|
308
|
+
select count(*) as n from (select distinct c from p7i);
|
|
309
|
+
→ [{"n":2}]
|
|
310
|
+
|
|
311
|
+
drop table p7i;
|
|
312
|
+
|
|
313
|
+
-- =====================================================
|
|
314
|
+
-- 7j. Partial UNIQUE with `NOT col` predicate (declared NOT NULL int):
|
|
315
|
+
-- the producer rewrites `NOT col` to `col = 0` and the consumer
|
|
316
|
+
-- discharges from a filter that pins `col` to 0.
|
|
317
|
+
-- =====================================================
|
|
318
|
+
create table p7j (id integer primary key, c text not null, archived integer not null);
|
|
319
|
+
create unique index ix_p7j on p7j(c) where not archived;
|
|
320
|
+
|
|
321
|
+
insert into p7j values (1, 'A', 0);
|
|
322
|
+
insert into p7j values (2, 'B', 0);
|
|
323
|
+
insert into p7j values (3, 'A', 1); -- archived: outside partial scope, dupes allowed.
|
|
324
|
+
|
|
325
|
+
select id, c, archived from p7j order by id;
|
|
326
|
+
→ [{"id":1,"c":"A","archived":0},{"id":2,"c":"B","archived":0},{"id":3,"c":"A","archived":1}]
|
|
327
|
+
|
|
328
|
+
-- Duplicate inside the scope (archived=0): rejected.
|
|
329
|
+
insert into p7j values (4, 'A', 0);
|
|
330
|
+
-- error: UNIQUE
|
|
331
|
+
|
|
332
|
+
-- Correctness: distinct c across the whole table.
|
|
333
|
+
select count(*) as n from (select distinct c from p7j);
|
|
334
|
+
→ [{"n":2}]
|
|
335
|
+
|
|
336
|
+
-- Inside scope: still distinct (no duplicates among archived=0 rows).
|
|
337
|
+
select count(*) as n from (select distinct c from p7j where archived = 0);
|
|
338
|
+
→ [{"n":2}]
|
|
339
|
+
|
|
340
|
+
drop table p7j;
|
|
341
|
+
|
|
342
|
+
-- =====================================================
|
|
343
|
+
-- 7j-NOT-on-TEXT. Regression: `NOT col` on a TEXT column must NOT
|
|
344
|
+
-- yield a `col = 0` rewrite. SQLite's strict sqlValueEquals treats
|
|
345
|
+
-- TEXT '' as unequal to integer 0; the partial UC predicate
|
|
346
|
+
-- `WHERE NOT val` keeps rows with val='' (falsy text), but those
|
|
347
|
+
-- rows are NOT distinguished by val under the rewritten guard.
|
|
348
|
+
-- Before this fix the planner believed `WHERE NOT val` activated
|
|
349
|
+
-- the partial UC and a FILTER-emitted FD c → {…} fired over rows
|
|
350
|
+
-- that actually share c, producing observably wrong results
|
|
351
|
+
-- (DISTINCT / aggregate-elimination misfire).
|
|
352
|
+
-- =====================================================
|
|
353
|
+
create table p7j_text (id integer primary key, c integer not null, val text not null);
|
|
354
|
+
create unique index ix_p7j_text on p7j_text(c) where val = 0;
|
|
355
|
+
|
|
356
|
+
-- Two rows with identical c and val='' (falsy in SQLite's NOT-truthiness).
|
|
357
|
+
-- The partial UC predicate `val = 0` does not match val='' under strict
|
|
358
|
+
-- equality, so neither row is in the partial scope — duplicates allowed.
|
|
359
|
+
insert into p7j_text values (1, 1, '');
|
|
360
|
+
insert into p7j_text values (2, 1, '');
|
|
361
|
+
|
|
362
|
+
-- `WHERE NOT val` keeps both rows. They share c=1, so any planner-level
|
|
363
|
+
-- claim "c → others" would be unsound. Pin the count.
|
|
364
|
+
select c, count(*) as n from p7j_text where not val group by c order by c;
|
|
365
|
+
→ [{"c":1,"n":2}]
|
|
366
|
+
|
|
367
|
+
drop table p7j_text;
|
|
368
|
+
|
|
369
|
+
-- Mirror: same shape with val INTEGER NOT NULL — `NOT val` correctly
|
|
370
|
+
-- rewrites to `val = 0` and the partial UC still activates. Confirms the
|
|
371
|
+
-- numeric-only gate didn't regress the INT case.
|
|
372
|
+
create table p7j_int (id integer primary key, c integer not null, val integer not null);
|
|
373
|
+
create unique index ix_p7j_int on p7j_int(c) where val = 0;
|
|
374
|
+
|
|
375
|
+
insert into p7j_int values (1, 1, 0);
|
|
376
|
+
-- Duplicate inside scope (val=0): rejected.
|
|
377
|
+
insert into p7j_int values (2, 1, 0);
|
|
378
|
+
-- error: UNIQUE
|
|
379
|
+
|
|
380
|
+
-- Outside scope (val != 0): duplicates allowed.
|
|
381
|
+
insert into p7j_int values (3, 1, 1);
|
|
382
|
+
|
|
383
|
+
select c, count(*) as n from p7j_int where not val group by c order by c;
|
|
384
|
+
→ [{"c":1,"n":1}]
|
|
385
|
+
|
|
386
|
+
drop table p7j_int;
|
|
387
|
+
|
|
388
|
+
-- =====================================================
|
|
389
|
+
-- 7k. Partial UNIQUE with top-level OR predicate: producer recognizes
|
|
390
|
+
-- `a OR b` as an `or-of` guard. Either disjunct in a filter
|
|
391
|
+
-- discharges it; an unrelated filter does not.
|
|
392
|
+
-- =====================================================
|
|
393
|
+
create table p7k (id integer primary key, c text not null, status text not null, deleted_at text null);
|
|
394
|
+
create unique index ix_p7k on p7k(c) where deleted_at is null or status = 'archived';
|
|
395
|
+
|
|
396
|
+
insert into p7k values (1, 'A', 'active', null);
|
|
397
|
+
insert into p7k values (2, 'B', 'archived', '2024-01-01');
|
|
398
|
+
-- Both rows match the partial predicate (different disjuncts) — different c's are fine.
|
|
399
|
+
|
|
400
|
+
-- Duplicate c when both fall under the partial scope (different disjuncts): rejected.
|
|
401
|
+
insert into p7k values (3, 'A', 'archived', '2025-01-01');
|
|
402
|
+
-- error: UNIQUE
|
|
403
|
+
|
|
404
|
+
-- A row that satisfies neither disjunct (deleted_at not null AND status != 'archived')
|
|
405
|
+
-- is outside the partial scope and may dupe.
|
|
406
|
+
insert into p7k values (4, 'A', 'active', '2025-06-01');
|
|
407
|
+
|
|
408
|
+
select id, c, status from p7k order by id;
|
|
409
|
+
→ [{"id":1,"c":"A","status":"active"},{"id":2,"c":"B","status":"archived"},{"id":4,"c":"A","status":"active"}]
|
|
410
|
+
|
|
411
|
+
drop table p7k;
|
|
412
|
+
|
|
413
|
+
-- =====================================================
|
|
414
|
+
-- 8. Bare-value predicate truthiness matches the engine (isTruthy).
|
|
415
|
+
-- A bare-column WHERE uses numeric truthiness, so non-numeric text
|
|
416
|
+
-- ('abc') is FALSE (out of scope) while numeric-nonzero text ('1')
|
|
417
|
+
-- is TRUE (in scope) — the same rule the Filter / runtime path uses.
|
|
418
|
+
-- A prior divergence treated any non-empty string as truthy; this
|
|
419
|
+
-- pins the corrected, engine-aligned semantics.
|
|
420
|
+
-- =====================================================
|
|
421
|
+
create table p_bare (id integer primary key, flag text, code text);
|
|
422
|
+
create unique index ix_p_bare on p_bare(code) where flag;
|
|
423
|
+
|
|
424
|
+
-- 'abc' is non-numeric → predicate FALSE → row is OUT of the partial scope.
|
|
425
|
+
insert into p_bare values (1, 'abc', 'X');
|
|
426
|
+
-- Same code, also out of scope → allowed (would be a UNIQUE error under the old
|
|
427
|
+
-- "any non-empty string is truthy" rule).
|
|
428
|
+
insert into p_bare values (2, 'abc', 'X');
|
|
429
|
+
|
|
430
|
+
-- '1' coerces to 1 → predicate TRUE → row is IN scope and claims code 'Y'.
|
|
431
|
+
insert into p_bare values (3, '1', 'Y');
|
|
432
|
+
-- Same code inside scope → rejected.
|
|
433
|
+
insert into p_bare values (4, '1', 'Y');
|
|
434
|
+
-- error: UNIQUE
|
|
435
|
+
|
|
436
|
+
select id, code from p_bare order by id;
|
|
437
|
+
→ [{"id":1,"code":"X"},{"id":2,"code":"X"},{"id":3,"code":"Y"}]
|
|
438
|
+
|
|
439
|
+
drop table p_bare;
|
|
440
|
+
|
|
441
|
+
-- =====================================================
|
|
442
|
+
-- 9. Bare-value truthiness through the operator-nested predicateTruthy
|
|
443
|
+
-- call sites (compileUnary NOT, compileBinary AND/OR) and the blob
|
|
444
|
+
-- branch of isTruthy. § 8 pins the top-level bare-value path; these
|
|
445
|
+
-- pin the same isTruthy delegation reached *inside* operators, plus
|
|
446
|
+
-- the blobs-are-falsy rule. Each case is an observable partial-UNIQUE
|
|
447
|
+
-- accept/reject, so a truthiness regression fails loudly.
|
|
448
|
+
-- =====================================================
|
|
449
|
+
|
|
450
|
+
-- 9a. NOT of a bare text column. `where not flag`:
|
|
451
|
+
-- flag='abc' → isTruthy false → NOT true → row IN scope
|
|
452
|
+
-- flag='1' → isTruthy true → NOT false → row OUT of scope
|
|
453
|
+
create table p_not (id integer primary key, flag text, code text);
|
|
454
|
+
create unique index ix_p_not on p_not(code) where not flag;
|
|
455
|
+
|
|
456
|
+
-- Two in-scope rows ('abc' is falsy → NOT true) sharing a code: second rejected.
|
|
457
|
+
insert into p_not values (1, 'abc', 'X');
|
|
458
|
+
insert into p_not values (2, 'abc', 'X');
|
|
459
|
+
-- error: UNIQUE
|
|
460
|
+
|
|
461
|
+
-- Two out-of-scope rows ('1' is truthy → NOT false) sharing a code: both allowed.
|
|
462
|
+
insert into p_not values (3, '1', 'Y');
|
|
463
|
+
insert into p_not values (4, '1', 'Y');
|
|
464
|
+
|
|
465
|
+
select id, code from p_not order by id;
|
|
466
|
+
→ [{"id":1,"code":"X"},{"id":3,"code":"Y"},{"id":4,"code":"Y"}]
|
|
467
|
+
|
|
468
|
+
drop table p_not;
|
|
469
|
+
|
|
470
|
+
-- 9b. Bare column as an AND operand. `where flag and othercol > 0`, with
|
|
471
|
+
-- `othercol > 0` held TRUE so the bare-flag truthiness decides scope:
|
|
472
|
+
-- flag='1' (truthy) AND true → row IN scope
|
|
473
|
+
-- flag='abc' (falsy) AND true → row OUT of scope
|
|
474
|
+
create table p_and (id integer primary key, flag text, othercol integer, code text);
|
|
475
|
+
create unique index ix_p_and on p_and(code) where flag and othercol > 0;
|
|
476
|
+
|
|
477
|
+
-- In scope (flag truthy): duplicate code rejected.
|
|
478
|
+
insert into p_and values (1, '1', 5, 'X');
|
|
479
|
+
insert into p_and values (2, '1', 5, 'X');
|
|
480
|
+
-- error: UNIQUE
|
|
481
|
+
|
|
482
|
+
-- Out of scope (flag falsy short-circuits the AND): duplicate code allowed.
|
|
483
|
+
insert into p_and values (3, 'abc', 5, 'Y');
|
|
484
|
+
insert into p_and values (4, 'abc', 5, 'Y');
|
|
485
|
+
|
|
486
|
+
select id, code from p_and order by id;
|
|
487
|
+
→ [{"id":1,"code":"X"},{"id":3,"code":"Y"},{"id":4,"code":"Y"}]
|
|
488
|
+
|
|
489
|
+
drop table p_and;
|
|
490
|
+
|
|
491
|
+
-- 9c. Bare column as an OR operand. `where flag or othercol > 0`, with
|
|
492
|
+
-- `othercol > 0` held FALSE (othercol = 0) so the bare-flag truthiness
|
|
493
|
+
-- decides scope:
|
|
494
|
+
-- flag='1' (truthy) OR false → row IN scope
|
|
495
|
+
-- flag='abc' (falsy) OR false → row OUT of scope
|
|
496
|
+
create table p_or (id integer primary key, flag text, othercol integer, code text);
|
|
497
|
+
create unique index ix_p_or on p_or(code) where flag or othercol > 0;
|
|
498
|
+
|
|
499
|
+
-- In scope (flag truthy): duplicate code rejected.
|
|
500
|
+
insert into p_or values (1, '1', 0, 'X');
|
|
501
|
+
insert into p_or values (2, '1', 0, 'X');
|
|
502
|
+
-- error: UNIQUE
|
|
503
|
+
|
|
504
|
+
-- Out of scope (both disjuncts falsy): duplicate code allowed.
|
|
505
|
+
insert into p_or values (3, 'abc', 0, 'Y');
|
|
506
|
+
insert into p_or values (4, 'abc', 0, 'Y');
|
|
507
|
+
|
|
508
|
+
select id, code from p_or order by id;
|
|
509
|
+
→ [{"id":1,"code":"X"},{"id":3,"code":"Y"},{"id":4,"code":"Y"}]
|
|
510
|
+
|
|
511
|
+
drop table p_or;
|
|
512
|
+
|
|
513
|
+
-- 9d. Bare BLOB value. `where blobcol` with a non-null blob: isTruthy(blob)
|
|
514
|
+
-- is FALSE (util/comparison.ts), so every row is OUT of scope and duplicate
|
|
515
|
+
-- codes are allowed. Under a regression that treated blobs as truthy, these
|
|
516
|
+
-- rows would be IN scope and the second insert would be a UNIQUE error.
|
|
517
|
+
create table p_blob (id integer primary key, blobcol blob, code text);
|
|
518
|
+
create unique index ix_p_blob on p_blob(code) where blobcol;
|
|
519
|
+
|
|
520
|
+
insert into p_blob values (1, x'00', 'X');
|
|
521
|
+
insert into p_blob values (2, x'01ff', 'X');
|
|
522
|
+
|
|
523
|
+
select id, code from p_blob order by id;
|
|
524
|
+
→ [{"id":1,"code":"X"},{"id":2,"code":"X"}]
|
|
525
|
+
|
|
526
|
+
drop table p_blob;
|