@quereus/quereus 4.20.0 → 4.20.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/src/common/types.d.ts +4 -4
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/schema/catalog-rendering.js +13 -1
- package/dist/src/schema/catalog-rendering.js.map +1 -1
- package/dist/src/schema/catalog.d.ts +35 -2
- package/dist/src/schema/catalog.d.ts.map +1 -1
- package/dist/src/schema/catalog.js +42 -33
- package/dist/src/schema/catalog.js.map +1 -1
- package/dist/src/schema/schema-differ.d.ts +1 -1
- package/dist/src/schema/schema-differ.d.ts.map +1 -1
- package/dist/src/schema/schema-differ.js +195 -33
- package/dist/src/schema/schema-differ.js.map +1 -1
- package/dist/src/schema/unique-enforcement.d.ts +23 -1
- package/dist/src/schema/unique-enforcement.d.ts.map +1 -1
- package/dist/src/schema/unique-enforcement.js +43 -1
- package/dist/src/schema/unique-enforcement.js.map +1 -1
- package/dist/src/vtab/memory/layer/manager.d.ts +15 -12
- package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/manager.js +87 -100
- package/dist/src/vtab/memory/layer/manager.js.map +1 -1
- package/package.json +7 -4
- package/test/README.md +173 -0
- package/test/logic/01-basic.sqllogic +39 -0
- package/test/logic/01.1-select-projection-extras.sqllogic +130 -0
- package/test/logic/01.2-strings.sqllogic +43 -0
- package/test/logic/01.5-insert-select.sqllogic +237 -0
- package/test/logic/01.6-update-extras.sqllogic +118 -0
- package/test/logic/01.7-update-from.sqllogic +67 -0
- package/test/logic/01.8-delete-extras.sqllogic +122 -0
- package/test/logic/01.8.1-delete-range-cow.sqllogic +115 -0
- package/test/logic/01.9-query-expr-dml-gates.sqllogic +32 -0
- package/test/logic/01.9-query-expr-dml.sqllogic +171 -0
- package/test/logic/01.9-query-expr-values.sqllogic +111 -0
- package/test/logic/01.9.1-limit-over-dml-subquery.sqllogic +119 -0
- package/test/logic/02-filters.sqllogic +54 -0
- package/test/logic/02-smoke.sqllogic +62 -0
- package/test/logic/02.1-bind-parameters.sqllogic +223 -0
- package/test/logic/03-expressions.sqllogic +190 -0
- package/test/logic/03.1-quoted-identifiers.sqllogic +55 -0
- package/test/logic/03.4-defaults.sqllogic +554 -0
- package/test/logic/03.4.1-default-edge-cases.sqllogic +99 -0
- package/test/logic/03.5-tvf.sqllogic +61 -0
- package/test/logic/03.6-type-system.sqllogic +544 -0
- package/test/logic/03.6.1-numeric-text-comparison-coercion.sqllogic +244 -0
- package/test/logic/03.6.2-value-to-text.sqllogic +224 -0
- package/test/logic/03.7-bigint-mixed-arithmetic.sqllogic +65 -0
- package/test/logic/03.8-not-precedence.sqllogic +255 -0
- package/test/logic/03.9-is-bool-predicate.sqllogic +150 -0
- package/test/logic/03.9.1-is-bool-predicate-partial-index.sqllogic +34 -0
- package/test/logic/04-order-by.sqllogic +38 -0
- package/test/logic/04-transactions.sqllogic +239 -0
- package/test/logic/04a-savepoint-lazy-attach.sqllogic +122 -0
- package/test/logic/05-vtab_memory.sqllogic +50 -0
- package/test/logic/05.0.1-vtab-memory-unique-index-collation.sqllogic +34 -0
- package/test/logic/05.1-composite-pk-range-scan.sqllogic +147 -0
- package/test/logic/05.1.1-secondary-index-range-scan.sqllogic +56 -0
- package/test/logic/05.2-cast-seek-correctness.sqllogic +124 -0
- package/test/logic/06-builtin_functions.sqllogic +149 -0
- package/test/logic/06.1-string-functions.sqllogic +92 -0
- package/test/logic/06.1.3-like-glob-edges.sqllogic +53 -0
- package/test/logic/06.2-math-functions.sqllogic +82 -0
- package/test/logic/06.3-schema.sqllogic +48 -0
- package/test/logic/06.3.1-schema-all-schemas.sqllogic +39 -0
- package/test/logic/06.3.2-schema-foreign-keys.sqllogic +208 -0
- package/test/logic/06.3.3-introspection-tags.sqllogic +202 -0
- package/test/logic/06.3.3.1-introspection-tags-index.sqllogic +74 -0
- package/test/logic/06.3.4-view-info.sqllogic +378 -0
- package/test/logic/06.3.5-column-info.sqllogic +347 -0
- package/test/logic/06.3.6-schema-views.sqllogic +29 -0
- package/test/logic/06.4-schema-search-path.sqllogic +354 -0
- package/test/logic/06.4.1-schema-case-insensitive.sqllogic +83 -0
- package/test/logic/06.4.2-collation-extras.sqllogic +472 -0
- package/test/logic/06.4.2.1-collation-index-access-paths.sqllogic +140 -0
- package/test/logic/06.4.3-write-path-collation.sqllogic +99 -0
- package/test/logic/06.4.4-comparison-collation-precedence.sqllogic +342 -0
- package/test/logic/06.4.5-any-collate-declared-keys.sqllogic +92 -0
- package/test/logic/06.5-polymorphic-types.sqllogic +169 -0
- package/test/logic/06.5.1-conversion-functions.sqllogic +173 -0
- package/test/logic/06.5.2-scalar-minmax.sqllogic +16 -0
- package/test/logic/06.5.3-undeclared-return-type-comparison.sqllogic +244 -0
- package/test/logic/06.5.4-declared-return-type-builtins.sqllogic +288 -0
- package/test/logic/06.6-aggregate-extended.sqllogic +78 -0
- package/test/logic/06.7-json-extended.sqllogic +53 -0
- package/test/logic/06.8-json-path-operators.sqllogic +99 -0
- package/test/logic/06.9-json-canonical-key.sqllogic +65 -0
- package/test/logic/06.9.1-json-coerce-once.sqllogic +417 -0
- package/test/logic/06.9.1.1-json-coerce-once-index.sqllogic +39 -0
- package/test/logic/06.9.2-json-structural-equality.sqllogic +382 -0
- package/test/logic/06.9.2.1-json-structural-equality-index.sqllogic +76 -0
- package/test/logic/06.9.3-json-index-range-seek.sqllogic +205 -0
- package/test/logic/07-aggregates.sqllogic +193 -0
- package/test/logic/07.1-aggregate-filter-clause.sqllogic +12 -0
- package/test/logic/07.2-aggregate-order-by.sqllogic +11 -0
- package/test/logic/07.3-group-by-extras.sqllogic +602 -0
- package/test/logic/07.3.1-group-by-order-by-key.sqllogic +164 -0
- package/test/logic/07.3.2-grouped-select-list-shape.sqllogic +231 -0
- package/test/logic/07.4-group-by-filter-composite-pk.sqllogic +120 -0
- package/test/logic/07.5-sum-mixed-exact-and-float.sqllogic +151 -0
- package/test/logic/07.5-window.sqllogic +1941 -0
- package/test/logic/07.5.1-window-named.sqllogic +13 -0
- package/test/logic/07.5.2-window-nth-value.sqllogic +13 -0
- package/test/logic/07.6-subqueries.sqllogic +78 -0
- package/test/logic/07.6.1-subquery-extras.sqllogic +93 -0
- package/test/logic/07.7-and-or-short-circuit.sqllogic +58 -0
- package/test/logic/07.7-in-subquery-caching.sqllogic +174 -0
- package/test/logic/07.7-scalar-agg-decorrelation.sqllogic +197 -0
- package/test/logic/07.7.1-in-extras.sqllogic +158 -0
- package/test/logic/07.7.1-scalar-agg-decorrelation-filter.sqllogic +105 -0
- package/test/logic/07.7.2-scalar-agg-decorrelation-nested.sqllogic +115 -0
- package/test/logic/07.7.3-exists-in-select-decorrelation.sqllogic +107 -0
- package/test/logic/07.7.4-where-conjunct-ordering.sqllogic +121 -0
- package/test/logic/07.7.5-filter-lost-under-index-order.sqllogic +134 -0
- package/test/logic/07.7.6-correlated-predicate-scope.sqllogic +178 -0
- package/test/logic/07.7.7-join-source-scope-shadowing.sqllogic +137 -0
- package/test/logic/07.7.8-correlated-ref-to-computed-column.sqllogic +165 -0
- package/test/logic/07.7.9-conjunct-monotonicity.sqllogic +200 -0
- package/test/logic/07.8-correlated-subquery-edges.sqllogic +71 -0
- package/test/logic/07.8.1-correlated-in-decorrelation-gates.sqllogic +156 -0
- package/test/logic/07.9-in-value-list.sqllogic +154 -0
- package/test/logic/07.9.1-in-value-list-composite-index.sqllogic +38 -0
- package/test/logic/08-views.sqllogic +64 -0
- package/test/logic/08.1-semi-anti-join.sqllogic +191 -0
- package/test/logic/08.1-view-edge-cases.sqllogic +118 -0
- package/test/logic/08.1.1-uncorrelated-in-semijoin.sqllogic +251 -0
- package/test/logic/08.2-existence-flag-semijoin-recovery.sqllogic +197 -0
- package/test/logic/08.3-existence-flag-inner-recovery.sqllogic +102 -0
- package/test/logic/08.4-key-set-semi-join.sqllogic +447 -0
- package/test/logic/09-set_operations.sqllogic +244 -0
- package/test/logic/09.1-set-op-cross-collation.sqllogic +230 -0
- package/test/logic/10-distinct_datatypes.sqllogic +127 -0
- package/test/logic/10.1-ddl-lifecycle.sqllogic +203 -0
- package/test/logic/10.1.1-create-table-syntax-edges.sqllogic +47 -0
- package/test/logic/10.1.2-ddl-in-transaction.sqllogic +143 -0
- package/test/logic/10.1.2.1-add-constraint-in-transaction.sqllogic +59 -0
- package/test/logic/10.1.3-ddl-drop-in-transaction.sqllogic +187 -0
- package/test/logic/10.1.3.1-drop-constraint-in-transaction.sqllogic +45 -0
- package/test/logic/10.1.4-create-table-duplicate-constraint-names.sqllogic +149 -0
- package/test/logic/10.1.4-ddl-transaction-policy.sqllogic +314 -0
- package/test/logic/10.1.5-alter-add-constraint-minted-name-disambiguation.sqllogic +219 -0
- package/test/logic/10.1.5-create-index-lifecycle.sqllogic +72 -0
- package/test/logic/10.1.6-ddl-transaction-policy-index.sqllogic +143 -0
- package/test/logic/10.1.7-create-table-default-type-check.sqllogic +119 -0
- package/test/logic/10.1.8-alter-add-check-existing-rows.sqllogic +117 -0
- package/test/logic/10.2-column-features.sqllogic +365 -0
- package/test/logic/10.2.1-table-options-rejection.sqllogic +63 -0
- package/test/logic/10.2.2-default-collation-memory.sqllogic +30 -0
- package/test/logic/10.3-function-features.sqllogic +247 -0
- package/test/logic/10.4-schema-scale.sqllogic +168 -0
- package/test/logic/10.4.1-schema-scale-indexes.sqllogic +121 -0
- package/test/logic/10.5-indexes.sqllogic +164 -0
- package/test/logic/10.5.1-partial-indexes.sqllogic +526 -0
- package/test/logic/10.5.2-expression-indexes.sqllogic +34 -0
- package/test/logic/10.5.3-desc-index-ordering.sqllogic +130 -0
- package/test/logic/10.5.4-composite-pk-index-update-phantom.sqllogic +55 -0
- package/test/logic/10.5.5-index-name-uniqueness.sqllogic +76 -0
- package/test/logic/10.5.6-minmax-index-boundary.sqllogic +204 -0
- package/test/logic/10.5.7-implicit-unique-index-lifecycle.sqllogic +1216 -0
- package/test/logic/10.6-distinct-edge-cases.sqllogic +119 -0
- package/test/logic/100-predicate-normalization-edge-cases.sqllogic +238 -0
- package/test/logic/100.1-where-extras.sqllogic +163 -0
- package/test/logic/100.1.1-where-join-on-order-indexed.sqllogic +35 -0
- package/test/logic/101-builtin-mutation-kills.sqllogic +974 -0
- package/test/logic/101-transaction-edge-cases.sqllogic +395 -0
- package/test/logic/102-schema-catalog-edge-cases.sqllogic +252 -0
- package/test/logic/102-unique-constraints.sqllogic +145 -0
- package/test/logic/102.0.1-schema-catalog-indexed-table.sqllogic +32 -0
- package/test/logic/102.1-unique-edge-cases.sqllogic +111 -0
- package/test/logic/102.1.1-unique-index-creation-edge-cases.sqllogic +75 -0
- package/test/logic/102.2-unique-collation.sqllogic +181 -0
- package/test/logic/102.2.1-unique-collation-index-derived.sqllogic +305 -0
- package/test/logic/103-database-options-edge-cases.sqllogic +108 -0
- package/test/logic/103.1-pragma-boolean-values.sqllogic +126 -0
- package/test/logic/104-emit-mutation-kills.sqllogic +236 -0
- package/test/logic/105-vtab-memory-mutation-kills.sqllogic +754 -0
- package/test/logic/105.1-vtab-memory-index-mutation-kills.sqllogic +540 -0
- package/test/logic/106-constraint-extractor-mutation-kills.sqllogic +350 -0
- package/test/logic/107-temporal-arithmetic-mutation-kills.sqllogic +833 -0
- package/test/logic/108-cardinality-estimation.sqllogic +146 -0
- package/test/logic/108.1-analyze-name-resolution.sqllogic +102 -0
- package/test/logic/109-aggregate-physical-selection.sqllogic +103 -0
- package/test/logic/11-joins.sqllogic +86 -0
- package/test/logic/11.1-join-using.sqllogic +267 -0
- package/test/logic/11.2-comma-join.sqllogic +35 -0
- package/test/logic/11.3-index-nested-loop-join.sqllogic +305 -0
- package/test/logic/11.3-mismatched-collation-join.sqllogic +74 -0
- package/test/logic/11.4-hash-join-side-swap.sqllogic +118 -0
- package/test/logic/110-scan-emitter-mutation-kills.sqllogic +121 -0
- package/test/logic/110.1-scan-emitter-index-scan-kills.sqllogic +47 -0
- package/test/logic/12-empty-primary-key.sqllogic +124 -0
- package/test/logic/12-join_padding_order.sqllogic +58 -0
- package/test/logic/12.1-orderby-index-consumption.sqllogic +40 -0
- package/test/logic/13-cte.sqllogic +137 -0
- package/test/logic/13.1-cte-multiple-recursive.sqllogic +104 -0
- package/test/logic/13.10-cte-qualified-name.sqllogic +136 -0
- package/test/logic/13.11-unreferenced-dml-cte.sqllogic +414 -0
- package/test/logic/13.12-nested-dml-cte-rejected.sqllogic +280 -0
- package/test/logic/13.2-cte-bind-params.sqllogic +98 -0
- package/test/logic/13.3-cte-edge-cases.sqllogic +120 -0
- package/test/logic/13.4-cte-extras.sqllogic +98 -0
- package/test/logic/13.5-cte-join-order.sqllogic +166 -0
- package/test/logic/13.6-cte-dml-runs-once.sqllogic +318 -0
- package/test/logic/13.7-cte-sibling-visibility.sqllogic +227 -0
- package/test/logic/13.8-insert-with-clause-visibility.sqllogic +254 -0
- package/test/logic/13.9-schema-authored-cte-isolation.sqllogic +328 -0
- package/test/logic/13.9.1-schema-authored-schema-path-isolation.sqllogic +408 -0
- package/test/logic/14-utilities.sqllogic +168 -0
- package/test/logic/15-timespan.sqllogic +279 -0
- package/test/logic/15.1-semantic-ordering.sqllogic +960 -0
- package/test/logic/15.1.1-json-check-coercion.sqllogic +178 -0
- package/test/logic/15.1.2-semantic-ordering-index.sqllogic +41 -0
- package/test/logic/15.1.3-declared-form-write-contract.sqllogic +519 -0
- package/test/logic/16-epoch.sqllogic +187 -0
- package/test/logic/17-weekday-modifier.sqllogic +78 -0
- package/test/logic/18-json-string-escapes.sqllogic +86 -0
- package/test/logic/18-strftime-extended-formats.sqllogic +68 -0
- package/test/logic/20-empty-single-row.sqllogic +261 -0
- package/test/logic/21-null-edge-cases.sqllogic +227 -0
- package/test/logic/21.1-where-null-comparisons.sqllogic +151 -0
- package/test/logic/21.1.1-where-null-comparisons-secondary-index.sqllogic +35 -0
- package/test/logic/21.2-between-edges.sqllogic +157 -0
- package/test/logic/22-boundary-values.sqllogic +175 -0
- package/test/logic/23-self-joins-duplicates.sqllogic +74 -0
- package/test/logic/24-builtin-branches.sqllogic +611 -0
- package/test/logic/24.1-substr-extras.sqllogic +75 -0
- package/test/logic/24.2-random-extras.sqllogic +39 -0
- package/test/logic/25-aggregate-edge-cases.sqllogic +289 -0
- package/test/logic/25.1-nested-aggregates.sqllogic +74 -0
- package/test/logic/25.2-having-edge-cases.sqllogic +318 -0
- package/test/logic/25.3-aggregate-isnull-empty.sqllogic +16 -0
- package/test/logic/25.4-groupby-fd-constant-empty.sqllogic +55 -0
- package/test/logic/25.5-ungrouped-aggregate-column-free-select-item.sqllogic +196 -0
- package/test/logic/26-join-edge-cases.sqllogic +333 -0
- package/test/logic/26.1-left-join-isnull-on-notnull.sqllogic +26 -0
- package/test/logic/26.2-left-join-on-vs-where.sqllogic +67 -0
- package/test/logic/26.3-join-on-constants.sqllogic +61 -0
- package/test/logic/26.4-join-on-is-null-nullable.sqllogic +44 -0
- package/test/logic/27-window-edge-cases.sqllogic +206 -0
- package/test/logic/27.1-window-groups-frame.sqllogic +13 -0
- package/test/logic/27.2-window-exclude.sqllogic +13 -0
- package/test/logic/27.3-window-json-aggregation.sqllogic +66 -0
- package/test/logic/28-set-ops-sort-edge-cases.sqllogic +444 -0
- package/test/logic/28.1-compound-limit-offset.sqllogic +143 -0
- package/test/logic/28.2-orderby-expression-extras.sqllogic +698 -0
- package/test/logic/28.2-set-op-branch-types.sqllogic +217 -0
- package/test/logic/29-constraint-edge-cases.sqllogic +442 -0
- package/test/logic/29.1-column-level-conflict-clause.sqllogic +171 -0
- package/test/logic/29.2-table-level-pk-conflict-clause.sqllogic +113 -0
- package/test/logic/40-constraints.sqllogic +418 -0
- package/test/logic/40.1-pk-desc-direction.sqllogic +76 -0
- package/test/logic/40.2-check-extras.sqllogic +683 -0
- package/test/logic/41-alter-table.sqllogic +191 -0
- package/test/logic/41-fk-cascade-conflict-and-self-ref.sqllogic +263 -0
- package/test/logic/41-fk-cross-schema.sqllogic +155 -0
- package/test/logic/41-fk-extended-targets.sqllogic +173 -0
- package/test/logic/41-foreign-keys.sqllogic +1001 -0
- package/test/logic/41-generated-column-errors.sqllogic +225 -0
- package/test/logic/41-generated-column-extras.sqllogic +598 -0
- package/test/logic/41-generated-column-scope.sqllogic +329 -0
- package/test/logic/41-generated-columns.sqllogic +361 -0
- package/test/logic/41.1-alter-pk.sqllogic +230 -0
- package/test/logic/41.1-fk-collation-conflict.sqllogic +277 -0
- package/test/logic/41.10-alter-drop-column-foreign-key.sqllogic +274 -0
- package/test/logic/41.10.1-alter-drop-column-unique-index.sqllogic +169 -0
- package/test/logic/41.10.2-alter-drop-column-check-and-assertion.sqllogic +1616 -0
- package/test/logic/41.10.3-alter-drop-column-referencing-fk.sqllogic +292 -0
- package/test/logic/41.10.4-drop-object-expression-dependents.sqllogic +602 -0
- package/test/logic/41.11-deferred-fk-with-rename.sqllogic +232 -0
- package/test/logic/41.12-alter-default-coercion.sqllogic +200 -0
- package/test/logic/41.13-alter-add-column-generated-backfill.sqllogic +566 -0
- package/test/logic/41.14-alter-add-column-subquery-backfill.sqllogic +129 -0
- package/test/logic/41.15-alter-column-default-type-check.sqllogic +178 -0
- package/test/logic/41.16-fk-unenforceable.sqllogic +364 -0
- package/test/logic/41.2-alter-column.sqllogic +382 -0
- package/test/logic/41.2.1-alter-column-retype-deleted-row-memory.sqllogic +32 -0
- package/test/logic/41.2.2-alter-column-retype-index-rebuild.sqllogic +77 -0
- package/test/logic/41.2.3-alter-column-set-not-null-pk-backfill.sqllogic +310 -0
- package/test/logic/41.2.3.1-alter-column-set-not-null-pk-backfill-secondary-index.sqllogic +37 -0
- package/test/logic/41.3-alter-add-column-unique.sqllogic +184 -0
- package/test/logic/41.3-alter-rename-propagation.sqllogic +2352 -0
- package/test/logic/41.3.1-alter-rename-index-propagation.sqllogic +94 -0
- package/test/logic/41.4-alter-add-column-constraints.sqllogic +855 -0
- package/test/logic/41.5-alter-misc.sqllogic +48 -0
- package/test/logic/41.5-cross-schema-foreign-keys.sqllogic +253 -0
- package/test/logic/41.6-alter-drop-rename-constraint.sqllogic +354 -0
- package/test/logic/41.6.1-alter-drop-constraint-index-derived.sqllogic +22 -0
- package/test/logic/41.7-alter-column-collate.sqllogic +105 -0
- package/test/logic/41.7.1-alter-column-collate-unique.sqllogic +45 -0
- package/test/logic/41.7.2-alter-column-collate-unique-store.sqllogic +208 -0
- package/test/logic/41.7.2.1-alter-column-collate-unique-index-store.sqllogic +114 -0
- package/test/logic/41.7.3-alter-column-retype-unique.sqllogic +293 -0
- package/test/logic/41.7.3.1-alter-column-retype-staged-rows-memory.sqllogic +41 -0
- package/test/logic/41.7.3.2-alter-column-retype-unique-index.sqllogic +72 -0
- package/test/logic/41.7.4-alter-column-retype-semantic-memory.sqllogic +445 -0
- package/test/logic/41.7.4.1-alter-column-retype-semantic-index-memory.sqllogic +91 -0
- package/test/logic/41.7.5-alter-column-collate-pk-staged-delete-memory.sqllogic +106 -0
- package/test/logic/41.8-alter-add-constraint-unique-fk.sqllogic +275 -0
- package/test/logic/41.8-alter-savepoint-staged-rows.sqllogic +443 -0
- package/test/logic/41.8.1-alter-rename-savepoint-staged-rows.sqllogic +408 -0
- package/test/logic/41.9-alter-constraint-body-change.sqllogic +180 -0
- package/test/logic/41.9-fk-restrict-batched.sqllogic +290 -0
- package/test/logic/42-committed-snapshot.sqllogic +254 -0
- package/test/logic/42-returning.sqllogic +159 -0
- package/test/logic/42.1-returning-extras.sqllogic +232 -0
- package/test/logic/42.2-returning-stored-row.sqllogic +165 -0
- package/test/logic/43-default-nullability.sqllogic +131 -0
- package/test/logic/43-transition-constraints.sqllogic +341 -0
- package/test/logic/43.1-default-collation.sqllogic +140 -0
- package/test/logic/43.1-notnull-or-conflict.sqllogic +79 -0
- package/test/logic/43.2-deferred-check-new-on-delete.sqllogic +95 -0
- package/test/logic/43.3-nullable-primary-key.sqllogic +587 -0
- package/test/logic/44-determinism-validation.sqllogic +164 -0
- package/test/logic/44-orthogonality.sqllogic +146 -0
- package/test/logic/44.1-nondeterministic-schema.sqllogic +316 -0
- package/test/logic/45-udf-determinism.sqllogic +39 -0
- package/test/logic/46-mutation-context.sqllogic +595 -0
- package/test/logic/47-upsert.sqllogic +255 -0
- package/test/logic/47.1-upsert-conflict-targets.sqllogic +169 -0
- package/test/logic/47.2-replace-and-or-clauses.sqllogic +164 -0
- package/test/logic/47.2.1-pk-replace-secondary-unique.sqllogic +374 -0
- package/test/logic/47.3-engine-or-fail.sqllogic +122 -0
- package/test/logic/47.3-upsert-conflict-target-collation.sqllogic +139 -0
- package/test/logic/47.3.1-upsert-conflict-index-derived-collation.sqllogic +25 -0
- package/test/logic/47.4-upsert-conflict-target-affinity.sqllogic +59 -0
- package/test/logic/47.5-upsert-do-update-constraints.sqllogic +440 -0
- package/test/logic/47.6-upsert-do-update-decomposed.sqllogic +100 -0
- package/test/logic/49-reference-graph.sqllogic +84 -0
- package/test/logic/50-declarative-schema.sqllogic +2550 -0
- package/test/logic/50-metadata-tags.sqllogic +1033 -0
- package/test/logic/50.0.1-metadata-tags-index.sqllogic +141 -0
- package/test/logic/50.1-declare-schema-pk.sqllogic +150 -0
- package/test/logic/50.2-declare-schema-renames.sqllogic +949 -0
- package/test/logic/50.2.1-declare-schema-index-renames.sqllogic +173 -0
- package/test/logic/50.3-declare-schema-duplicate-names.sqllogic +280 -0
- package/test/logic/50.4-declare-schema-apply-restore.sqllogic +192 -0
- package/test/logic/51-lens-foundation.sqllogic +147 -0
- package/test/logic/51-materialized-views.sqllogic +376 -0
- package/test/logic/51.5-materialized-views-coarsened-key.sqllogic +198 -0
- package/test/logic/51.7-maintained-table-attach-detach.sqllogic +468 -0
- package/test/logic/51.8-maintained-table-declared-constraints.sqllogic +440 -0
- package/test/logic/51.85-maintained-table-parent-fk.sqllogic +103 -0
- package/test/logic/51.9-maintained-table-secondary-unique.sqllogic +237 -0
- package/test/logic/51.9.1-maintained-table-partial-unique.sqllogic +36 -0
- package/test/logic/52-lens-overrides.sqllogic +566 -0
- package/test/logic/53-materialized-views-rowtime.sqllogic +1601 -0
- package/test/logic/53-reserved-tags.sqllogic +252 -0
- package/test/logic/53.1-materialized-view-write-through.sqllogic +329 -0
- package/test/logic/53.2-materialized-view-rename-propagation.sqllogic +483 -0
- package/test/logic/53.3-materialized-view-constraint-only-ddl.sqllogic +409 -0
- package/test/logic/53.3.1-materialized-view-index-ddl-irrelevance.sqllogic +29 -0
- package/test/logic/53.4-materialized-view-structural-alter-restore.sqllogic +436 -0
- package/test/logic/54-covering-mv-enforcement.sqllogic +314 -0
- package/test/logic/54.1-covering-mv-partial-enforcement.sqllogic +34 -0
- package/test/logic/55-internal-eviction-reporting.sqllogic +89 -0
- package/test/logic/55-lens-prover.sqllogic +202 -0
- package/test/logic/55.1-eviction-restrict-fk.sqllogic +148 -0
- package/test/logic/55.5-lens-authored-inverse.sqllogic +1468 -0
- package/test/logic/80-grow-retrieve-pass.sqllogic +79 -0
- package/test/logic/81-quickpick.sqllogic +24 -0
- package/test/logic/82-bloom-join.sqllogic +185 -0
- package/test/logic/83-merge-join.sqllogic +280 -0
- package/test/logic/84-asof-scan.sqllogic +238 -0
- package/test/logic/84-key-cardinality.sqllogic +50 -0
- package/test/logic/85-relational-const-folding.sqllogic +51 -0
- package/test/logic/86-scalar-cse.sqllogic +42 -0
- package/test/logic/90-error_paths.sqllogic +114 -0
- package/test/logic/90.1-parse-errors.sqllogic +77 -0
- package/test/logic/90.2-alter-table-errors.sqllogic +53 -0
- package/test/logic/90.2.1-alter-extra-errors.sqllogic +51 -0
- package/test/logic/90.3-expression-errors.sqllogic +43 -0
- package/test/logic/90.4-dml-errors.sqllogic +47 -0
- package/test/logic/90.5-unsupported-join-types.sqllogic +37 -0
- package/test/logic/90.5.1-right-full-join-read.sqllogic +157 -0
- package/test/logic/90.6-select-error-paths.sqllogic +57 -0
- package/test/logic/91-merge-join-edge-cases.sqllogic +159 -0
- package/test/logic/92-hash-aggregate-edge-cases.sqllogic +139 -0
- package/test/logic/93-ddl-view-edge-cases.sqllogic +104 -0
- package/test/logic/93.1-view-error-paths.sqllogic +74 -0
- package/test/logic/93.2-view-mutation-pending.sqllogic +108 -0
- package/test/logic/93.3-view-mutation-or-clause.sqllogic +60 -0
- package/test/logic/93.4-view-mutation.sqllogic +4881 -0
- package/test/logic/93.4.1-view-mutation-partial-unique-cardinality.sqllogic +31 -0
- package/test/logic/93.5-authored-inverse.sqllogic +415 -0
- package/test/logic/93.6-set-op-flagless-write.sqllogic +862 -0
- package/test/logic/94-tvf-edge-cases.sqllogic +58 -0
- package/test/logic/94.1-limit-offset-edge-cases.sqllogic +109 -0
- package/test/logic/94.2-limit-offset-extras.sqllogic +98 -0
- package/test/logic/95-assertions.sqllogic +1417 -0
- package/test/logic/96-subquery-edge-cases.sqllogic +276 -0
- package/test/logic/97-json-function-edge-cases.sqllogic +633 -0
- package/test/logic/97.1-json-blob-and-special-values.sqllogic +92 -0
- package/test/logic/98-temporal-edge-cases.sqllogic +515 -0
- package/test/logic/99-conversion-edge-cases.sqllogic +325 -0
- package/test/logic/99.0.1-schema-index-listing.sqllogic +21 -0
- package/test/logic/99.1-cast-syntax-extras.sqllogic +167 -0
- package/test/logic/drop-unique-index.sqllogic +88 -0
- package/test/logic/pushdown-test.sqllogic +36 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
-- 47-upsert.sqllogic - Testing UPSERT (ON CONFLICT) clauses
|
|
2
|
+
|
|
3
|
+
-- === Setup ===
|
|
4
|
+
|
|
5
|
+
DROP TABLE IF EXISTS upsert_test;
|
|
6
|
+
CREATE TABLE upsert_test (
|
|
7
|
+
id INTEGER PRIMARY KEY,
|
|
8
|
+
name TEXT,
|
|
9
|
+
count INTEGER DEFAULT 1
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
-- === Basic DO NOTHING tests ===
|
|
13
|
+
|
|
14
|
+
-- Insert a row
|
|
15
|
+
INSERT INTO upsert_test (id, name, count) VALUES (1, 'first', 10);
|
|
16
|
+
SELECT * FROM upsert_test;
|
|
17
|
+
→ [{"id":1,"name":"first","count":10}]
|
|
18
|
+
|
|
19
|
+
-- ON CONFLICT DO NOTHING - should silently skip duplicate
|
|
20
|
+
INSERT INTO upsert_test (id, name, count) VALUES (1, 'duplicate', 99)
|
|
21
|
+
ON CONFLICT DO NOTHING;
|
|
22
|
+
SELECT * FROM upsert_test;
|
|
23
|
+
→ [{"id":1,"name":"first","count":10}]
|
|
24
|
+
|
|
25
|
+
-- Insert a new row (no conflict) with ON CONFLICT DO NOTHING
|
|
26
|
+
INSERT INTO upsert_test (id, name, count) VALUES (2, 'second', 20)
|
|
27
|
+
ON CONFLICT DO NOTHING;
|
|
28
|
+
SELECT * FROM upsert_test ORDER BY id;
|
|
29
|
+
→ [{"id":1,"name":"first","count":10},{"id":2,"name":"second","count":20}]
|
|
30
|
+
|
|
31
|
+
-- === Basic DO UPDATE tests ===
|
|
32
|
+
|
|
33
|
+
-- Update on conflict using NEW.* to reference proposed values
|
|
34
|
+
INSERT INTO upsert_test (id, name, count) VALUES (1, 'updated_name', 100)
|
|
35
|
+
ON CONFLICT DO UPDATE SET name = NEW.name, count = NEW.count;
|
|
36
|
+
SELECT * FROM upsert_test ORDER BY id;
|
|
37
|
+
→ [{"id":1,"name":"updated_name","count":100},{"id":2,"name":"second","count":20}]
|
|
38
|
+
|
|
39
|
+
-- Update on conflict using unqualified column (existing value)
|
|
40
|
+
INSERT INTO upsert_test (id, name, count) VALUES (2, 'ignored', 999)
|
|
41
|
+
ON CONFLICT DO UPDATE SET count = count + 1;
|
|
42
|
+
SELECT * FROM upsert_test ORDER BY id;
|
|
43
|
+
→ [{"id":1,"name":"updated_name","count":100},{"id":2,"name":"second","count":21}]
|
|
44
|
+
|
|
45
|
+
-- === Increment pattern ===
|
|
46
|
+
|
|
47
|
+
-- Classic UPSERT increment pattern: increment if exists, insert if not
|
|
48
|
+
INSERT INTO upsert_test (id, name, count) VALUES (3, 'new_entry', 1)
|
|
49
|
+
ON CONFLICT DO UPDATE SET count = count + 1;
|
|
50
|
+
SELECT * FROM upsert_test WHERE id = 3;
|
|
51
|
+
→ [{"id":3,"name":"new_entry","count":1}]
|
|
52
|
+
|
|
53
|
+
-- Now increment the existing row
|
|
54
|
+
INSERT INTO upsert_test (id, name, count) VALUES (3, 'new_entry', 1)
|
|
55
|
+
ON CONFLICT DO UPDATE SET count = count + 1;
|
|
56
|
+
SELECT * FROM upsert_test WHERE id = 3;
|
|
57
|
+
→ [{"id":3,"name":"new_entry","count":2}]
|
|
58
|
+
|
|
59
|
+
-- Another increment
|
|
60
|
+
INSERT INTO upsert_test (id, name, count) VALUES (3, 'ignored', 999)
|
|
61
|
+
ON CONFLICT DO UPDATE SET count = count + 1;
|
|
62
|
+
SELECT * FROM upsert_test WHERE id = 3;
|
|
63
|
+
→ [{"id":3,"name":"new_entry","count":3}]
|
|
64
|
+
|
|
65
|
+
-- === DO UPDATE with excluded.* (PostgreSQL compatibility) ===
|
|
66
|
+
|
|
67
|
+
INSERT INTO upsert_test (id, name, count) VALUES (1, 'via_excluded', 500)
|
|
68
|
+
ON CONFLICT DO UPDATE SET name = excluded.name, count = excluded.count;
|
|
69
|
+
SELECT * FROM upsert_test WHERE id = 1;
|
|
70
|
+
→ [{"id":1,"name":"via_excluded","count":500}]
|
|
71
|
+
|
|
72
|
+
-- === DO UPDATE with mixed references ===
|
|
73
|
+
|
|
74
|
+
-- Combine existing values with proposed values
|
|
75
|
+
INSERT INTO upsert_test (id, name, count) VALUES (2, 'combined', 100)
|
|
76
|
+
ON CONFLICT DO UPDATE SET name = name || '_' || NEW.name, count = count + NEW.count;
|
|
77
|
+
SELECT * FROM upsert_test WHERE id = 2;
|
|
78
|
+
→ [{"id":2,"name":"second_combined","count":121}]
|
|
79
|
+
|
|
80
|
+
-- === DO UPDATE with WHERE condition ===
|
|
81
|
+
|
|
82
|
+
-- Only update if condition is met (condition passes)
|
|
83
|
+
INSERT INTO upsert_test (id, name, count) VALUES (1, 'conditional', 600)
|
|
84
|
+
ON CONFLICT DO UPDATE SET count = NEW.count WHERE count < 600;
|
|
85
|
+
SELECT * FROM upsert_test WHERE id = 1;
|
|
86
|
+
→ [{"id":1,"name":"via_excluded","count":600}]
|
|
87
|
+
|
|
88
|
+
-- Only update if condition is met (condition fails - should skip update)
|
|
89
|
+
INSERT INTO upsert_test (id, name, count) VALUES (1, 'should_skip', 700)
|
|
90
|
+
ON CONFLICT DO UPDATE SET count = NEW.count WHERE count < 100;
|
|
91
|
+
SELECT * FROM upsert_test WHERE id = 1;
|
|
92
|
+
→ [{"id":1,"name":"via_excluded","count":600}]
|
|
93
|
+
|
|
94
|
+
-- === UPSERT with RETURNING ===
|
|
95
|
+
|
|
96
|
+
-- DO NOTHING with RETURNING (returns nothing when conflict is skipped)
|
|
97
|
+
INSERT INTO upsert_test (id, name, count) VALUES (1, 'ignored', 999)
|
|
98
|
+
ON CONFLICT DO NOTHING
|
|
99
|
+
RETURNING id, name, count;
|
|
100
|
+
→ []
|
|
101
|
+
|
|
102
|
+
-- DO UPDATE with RETURNING
|
|
103
|
+
INSERT INTO upsert_test (id, name, count) VALUES (1, 'returned', 700)
|
|
104
|
+
ON CONFLICT DO UPDATE SET name = NEW.name, count = NEW.count
|
|
105
|
+
RETURNING id, name, count;
|
|
106
|
+
→ [{"id":1,"name":"returned","count":700}]
|
|
107
|
+
|
|
108
|
+
-- Verify the update was applied
|
|
109
|
+
SELECT * FROM upsert_test WHERE id = 1;
|
|
110
|
+
→ [{"id":1,"name":"returned","count":700}]
|
|
111
|
+
|
|
112
|
+
-- Insert without conflict with RETURNING
|
|
113
|
+
INSERT INTO upsert_test (id, name, count) VALUES (10, 'new_row', 50)
|
|
114
|
+
ON CONFLICT DO NOTHING
|
|
115
|
+
RETURNING id, name;
|
|
116
|
+
→ [{"id":10,"name":"new_row"}]
|
|
117
|
+
|
|
118
|
+
-- === Multiple rows with UPSERT ===
|
|
119
|
+
|
|
120
|
+
-- Insert multiple rows, some conflict, some don't
|
|
121
|
+
INSERT INTO upsert_test (id, name, count) VALUES
|
|
122
|
+
(10, 'update_existing', 100),
|
|
123
|
+
(11, 'brand_new', 200)
|
|
124
|
+
ON CONFLICT DO UPDATE SET count = NEW.count;
|
|
125
|
+
SELECT * FROM upsert_test WHERE id IN (10, 11) ORDER BY id;
|
|
126
|
+
→ [{"id":10,"name":"new_row","count":100},{"id":11,"name":"brand_new","count":200}]
|
|
127
|
+
|
|
128
|
+
-- === Conflict target specification ===
|
|
129
|
+
|
|
130
|
+
-- Create table with explicit conflict target
|
|
131
|
+
DROP TABLE IF EXISTS upsert_target;
|
|
132
|
+
CREATE TABLE upsert_target (
|
|
133
|
+
id INTEGER PRIMARY KEY,
|
|
134
|
+
email TEXT UNIQUE,
|
|
135
|
+
name TEXT
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
INSERT INTO upsert_target VALUES (1, 'a@test.com', 'Alice');
|
|
139
|
+
SELECT * FROM upsert_target;
|
|
140
|
+
→ [{"id":1,"email":"a@test.com","name":"Alice"}]
|
|
141
|
+
|
|
142
|
+
-- Conflict on primary key (id)
|
|
143
|
+
INSERT INTO upsert_target (id, email, name) VALUES (1, 'new@test.com', 'Updated')
|
|
144
|
+
ON CONFLICT (id) DO UPDATE SET name = NEW.name;
|
|
145
|
+
SELECT * FROM upsert_target;
|
|
146
|
+
→ [{"id":1,"email":"a@test.com","name":"Updated"}]
|
|
147
|
+
|
|
148
|
+
-- === Error cases ===
|
|
149
|
+
|
|
150
|
+
-- Cannot use both OR clause and ON CONFLICT
|
|
151
|
+
INSERT OR REPLACE INTO upsert_target (id, email, name) VALUES (1, 'test@test.com', 'Test')
|
|
152
|
+
ON CONFLICT DO NOTHING;
|
|
153
|
+
-- error: Cannot use both 'INSERT OR ...' and 'ON CONFLICT' in the same statement
|
|
154
|
+
|
|
155
|
+
-- ON CONFLICT DO UPDATE assigning the same column twice is rejected (no silent
|
|
156
|
+
-- last-wins). This path never routes through buildUpdateStmt, so it carries its
|
|
157
|
+
-- own backstop mirroring the UPDATE side. See ticket
|
|
158
|
+
-- insert-family-duplicate-column-targets-silent-last-wins.
|
|
159
|
+
INSERT INTO upsert_target (id, email, name) VALUES (1, 'x@test.com', 'X')
|
|
160
|
+
ON CONFLICT (id) DO UPDATE SET name = 'one', name = 'two';
|
|
161
|
+
-- error: duplicate assignment
|
|
162
|
+
|
|
163
|
+
-- the rejected upsert made no change (name keeps its pre-conflict value, not
|
|
164
|
+
-- last-wins 'two' or 'one').
|
|
165
|
+
SELECT id, name FROM upsert_target;
|
|
166
|
+
→ [{"id":1,"name":"Updated"}]
|
|
167
|
+
|
|
168
|
+
-- The duplicate-target guard is case-insensitive: `name` and `NAME` collide.
|
|
169
|
+
INSERT INTO upsert_target (id, email, name) VALUES (1, 'x@test.com', 'X')
|
|
170
|
+
ON CONFLICT (id) DO UPDATE SET name = 'one', NAME = 'two';
|
|
171
|
+
-- error: duplicate assignment
|
|
172
|
+
|
|
173
|
+
-- A legitimate DO UPDATE assigning two *distinct* columns still works — the
|
|
174
|
+
-- guard keys on exact-name collision, never on distinct columns.
|
|
175
|
+
INSERT INTO upsert_target (id, email, name) VALUES (1, 'x@test.com', 'X')
|
|
176
|
+
ON CONFLICT (id) DO UPDATE SET email = 'multi@test.com', name = 'Multi';
|
|
177
|
+
SELECT id, email, name FROM upsert_target;
|
|
178
|
+
→ [{"id":1,"email":"multi@test.com","name":"Multi"}]
|
|
179
|
+
|
|
180
|
+
-- === UPSERT expressions with subqueries (optimizer must see them as children) ===
|
|
181
|
+
-- `DmlExecutorNode` exposes ON CONFLICT assignment/WHERE expressions as
|
|
182
|
+
-- getChildren() so the optimizer can rewrite subqueries inside them just like any
|
|
183
|
+
-- other plan node. See bug-dml-side-expressions-invisible-to-optimizer.
|
|
184
|
+
|
|
185
|
+
DROP TABLE IF EXISTS upsert_src;
|
|
186
|
+
CREATE TABLE upsert_src (id INTEGER PRIMARY KEY, v TEXT);
|
|
187
|
+
INSERT INTO upsert_src VALUES (1, 'a'), (2, 'b'), (3, 'c');
|
|
188
|
+
|
|
189
|
+
DROP TABLE IF EXISTS upsert_expr;
|
|
190
|
+
CREATE TABLE upsert_expr (id INTEGER PRIMARY KEY, name TEXT, count INTEGER);
|
|
191
|
+
INSERT INTO upsert_expr VALUES (1, 'first', 10);
|
|
192
|
+
|
|
193
|
+
-- subquery in a DO UPDATE SET value
|
|
194
|
+
INSERT INTO upsert_expr (id, name, count) VALUES (1, 'dup', 0)
|
|
195
|
+
ON CONFLICT (id) DO UPDATE SET count = (SELECT COUNT(*) FROM upsert_src);
|
|
196
|
+
SELECT id, count FROM upsert_expr WHERE id = 1;
|
|
197
|
+
→ [{"id":1,"count":3}]
|
|
198
|
+
|
|
199
|
+
-- subquery in the DO UPDATE WHERE clause: condition false leaves the row unchanged
|
|
200
|
+
INSERT INTO upsert_expr (id, name, count) VALUES (1, 'dup2', 999)
|
|
201
|
+
ON CONFLICT (id) DO UPDATE SET count = NEW.count WHERE (SELECT COUNT(*) FROM upsert_src) > 10;
|
|
202
|
+
SELECT id, count FROM upsert_expr WHERE id = 1;
|
|
203
|
+
→ [{"id":1,"count":3}]
|
|
204
|
+
|
|
205
|
+
-- subquery in the DO UPDATE WHERE clause: condition true applies the update
|
|
206
|
+
INSERT INTO upsert_expr (id, name, count) VALUES (1, 'dup3', 999)
|
|
207
|
+
ON CONFLICT (id) DO UPDATE SET count = NEW.count WHERE (SELECT COUNT(*) FROM upsert_src) > 1;
|
|
208
|
+
SELECT id, count FROM upsert_expr WHERE id = 1;
|
|
209
|
+
→ [{"id":1,"count":999}]
|
|
210
|
+
|
|
211
|
+
-- subquery correlated to excluded.<col> (the proposed/rejected row)
|
|
212
|
+
INSERT INTO upsert_expr (id, name, count) VALUES (1, 'corr', 2)
|
|
213
|
+
ON CONFLICT (id) DO UPDATE SET count = (SELECT COUNT(*) FROM upsert_src WHERE id <= excluded.count);
|
|
214
|
+
SELECT id, count FROM upsert_expr WHERE id = 1;
|
|
215
|
+
→ [{"id":1,"count":2}]
|
|
216
|
+
|
|
217
|
+
-- subquery correlated to an unqualified column (the conflicting existing row, not NEW)
|
|
218
|
+
INSERT INTO upsert_expr (id, name, count) VALUES (1, 'corr2', 999)
|
|
219
|
+
ON CONFLICT (id) DO UPDATE SET count = (SELECT COUNT(*) FROM upsert_src WHERE id <= count);
|
|
220
|
+
SELECT id, count FROM upsert_expr WHERE id = 1;
|
|
221
|
+
→ [{"id":1,"count":2}]
|
|
222
|
+
|
|
223
|
+
DROP TABLE upsert_expr;
|
|
224
|
+
|
|
225
|
+
-- multi-clause ON CONFLICT: two conflict targets, each with its own subquery
|
|
226
|
+
-- assignment and WHERE — exercises the child ordering/slicing across clauses.
|
|
227
|
+
DROP TABLE IF EXISTS upsert_multi;
|
|
228
|
+
CREATE TABLE upsert_multi (
|
|
229
|
+
id INTEGER PRIMARY KEY,
|
|
230
|
+
email TEXT UNIQUE,
|
|
231
|
+
tag TEXT
|
|
232
|
+
);
|
|
233
|
+
INSERT INTO upsert_multi VALUES (1, 'a@test.com', 'A'), (2, 'b@test.com', 'B');
|
|
234
|
+
|
|
235
|
+
-- conflict lands on the `id` target — its clause fires, the `email` clause does not
|
|
236
|
+
INSERT INTO upsert_multi (id, email, tag) VALUES (1, 'new@test.com', 'ignored')
|
|
237
|
+
ON CONFLICT (id) DO UPDATE SET tag = (SELECT COUNT(*) FROM upsert_src) WHERE (SELECT COUNT(*) FROM upsert_src) > 0
|
|
238
|
+
ON CONFLICT (email) DO UPDATE SET tag = 'email-match' WHERE (SELECT COUNT(*) FROM upsert_src) > 100;
|
|
239
|
+
SELECT id, tag FROM upsert_multi WHERE id = 1;
|
|
240
|
+
→ [{"id":1,"tag":"3"}]
|
|
241
|
+
|
|
242
|
+
-- conflict lands on the `email` target instead — the `id` clause's WHERE (which
|
|
243
|
+
-- would fail) never runs; the `email` clause fires
|
|
244
|
+
INSERT INTO upsert_multi (id, email, tag) VALUES (99, 'b@test.com', 'ignored')
|
|
245
|
+
ON CONFLICT (id) DO UPDATE SET tag = (SELECT COUNT(*) FROM upsert_src) WHERE (SELECT COUNT(*) FROM upsert_src) > 100
|
|
246
|
+
ON CONFLICT (email) DO UPDATE SET tag = (SELECT COUNT(*) FROM upsert_src) WHERE (SELECT COUNT(*) FROM upsert_src) > 0;
|
|
247
|
+
SELECT id, tag FROM upsert_multi WHERE email = 'b@test.com';
|
|
248
|
+
→ [{"id":2,"tag":"3"}]
|
|
249
|
+
|
|
250
|
+
DROP TABLE upsert_multi;
|
|
251
|
+
DROP TABLE upsert_src;
|
|
252
|
+
|
|
253
|
+
-- Clean up
|
|
254
|
+
DROP TABLE upsert_test;
|
|
255
|
+
DROP TABLE upsert_target;
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
-- adapted from SQLite test/upsert2.test, test/upsert3.test, test/upsert4.test
|
|
2
|
+
-- UPSERT advanced conflict-target scenarios beyond 47-upsert.sqllogic:
|
|
3
|
+
-- composite UNIQUE targets, partial-target rejection, INSERT...AS alias,
|
|
4
|
+
-- column-list assignment in DO UPDATE SET, UPSERT with CTE source.
|
|
5
|
+
|
|
6
|
+
-- ===================================
|
|
7
|
+
-- 1. ON CONFLICT on composite UNIQUE — full match required
|
|
8
|
+
-- ===================================
|
|
9
|
+
|
|
10
|
+
create table comp_u (k integer, v text, payload text, unique (k, v));
|
|
11
|
+
|
|
12
|
+
insert into comp_u values (0, 'abcd', 'first');
|
|
13
|
+
|
|
14
|
+
-- full target columns match — DO NOTHING silently skips duplicate
|
|
15
|
+
insert into comp_u values (0, 'abcd', 'second') on conflict (k, v) do nothing;
|
|
16
|
+
select count(*) as cnt from comp_u;
|
|
17
|
+
→ [{"cnt":1}]
|
|
18
|
+
|
|
19
|
+
-- reversed column order in target also matches the same UNIQUE constraint
|
|
20
|
+
insert into comp_u values (0, 'abcd', 'third') on conflict (v, k) do nothing;
|
|
21
|
+
select count(*) as cnt from comp_u;
|
|
22
|
+
→ [{"cnt":1}]
|
|
23
|
+
|
|
24
|
+
-- Quereus accepts partial conflict targets that match any UNIQUE involving the listed column(s)
|
|
25
|
+
-- so the SQLite-strict "must error" assertions don't apply here; verify the rows are still skipped instead
|
|
26
|
+
insert into comp_u values (0, 'abcd', 'fourth') on conflict (k) do nothing;
|
|
27
|
+
insert into comp_u values (0, 'abcd', 'fifth') on conflict (v) do nothing;
|
|
28
|
+
select count(*) as cnt from comp_u;
|
|
29
|
+
→ [{"cnt":1}]
|
|
30
|
+
|
|
31
|
+
drop table comp_u;
|
|
32
|
+
|
|
33
|
+
-- ===================================
|
|
34
|
+
-- 2. UPSERT DO UPDATE referencing existing vs. proposed value via excluded.col
|
|
35
|
+
-- ===================================
|
|
36
|
+
|
|
37
|
+
create table counter (id integer primary key, n integer);
|
|
38
|
+
insert into counter values (1, 10);
|
|
39
|
+
|
|
40
|
+
-- excluded.* refers to the proposed (rejected) row's values
|
|
41
|
+
insert into counter values (1, 5)
|
|
42
|
+
on conflict (id) do update set n = counter.n + excluded.n;
|
|
43
|
+
|
|
44
|
+
select id, n from counter where id = 1;
|
|
45
|
+
→ [{"id":1,"n":15}]
|
|
46
|
+
|
|
47
|
+
drop table counter;
|
|
48
|
+
|
|
49
|
+
-- ===================================
|
|
50
|
+
-- 3. UPSERT with explicit table alias: INSERT ... AS alias
|
|
51
|
+
-- Alias provides a name for the existing row in DO UPDATE
|
|
52
|
+
-- ===================================
|
|
53
|
+
|
|
54
|
+
create table alias_t (id integer primary key, name text, count integer);
|
|
55
|
+
insert into alias_t values (1, 'alice', 1);
|
|
56
|
+
|
|
57
|
+
-- INSERT ... AS alias is not supported by Quereus's parser
|
|
58
|
+
insert into alias_t as old values (1, 'updated', 100)
|
|
59
|
+
on conflict (id) do update set name = excluded.name, count = old.count + 1;
|
|
60
|
+
-- error: Expected VALUES, SELECT, or DML
|
|
61
|
+
|
|
62
|
+
drop table alias_t;
|
|
63
|
+
|
|
64
|
+
-- ===================================
|
|
65
|
+
-- 4. UPSERT with CTE as source
|
|
66
|
+
-- ===================================
|
|
67
|
+
|
|
68
|
+
create table cte_dst (id integer primary key, val integer);
|
|
69
|
+
|
|
70
|
+
with src(id, val) as (select 1 as id, 100 as val union all select 2, 200)
|
|
71
|
+
insert into cte_dst (id, val) select id, val from src
|
|
72
|
+
on conflict (id) do update set val = excluded.val;
|
|
73
|
+
|
|
74
|
+
select id, val from cte_dst order by id;
|
|
75
|
+
→ [{"id":1,"val":100},{"id":2,"val":200}]
|
|
76
|
+
|
|
77
|
+
-- second pass with CTE — forces conflict and update path
|
|
78
|
+
with src(id, val) as (select 1 as id, 999 as val union all select 3, 300)
|
|
79
|
+
insert into cte_dst (id, val) select id, val from src
|
|
80
|
+
on conflict (id) do update set val = excluded.val;
|
|
81
|
+
|
|
82
|
+
select id, val from cte_dst order by id;
|
|
83
|
+
→ [{"id":1,"val":999},{"id":2,"val":200},{"id":3,"val":300}]
|
|
84
|
+
|
|
85
|
+
drop table cte_dst;
|
|
86
|
+
|
|
87
|
+
-- ===================================
|
|
88
|
+
-- 5. UPSERT DO UPDATE WHERE — condition fails leaves row unchanged
|
|
89
|
+
-- ===================================
|
|
90
|
+
|
|
91
|
+
create table guarded (id integer primary key, n integer);
|
|
92
|
+
insert into guarded values (1, 100);
|
|
93
|
+
|
|
94
|
+
-- condition true: update applies
|
|
95
|
+
insert into guarded values (1, 200) on conflict (id) do update set n = excluded.n where n < 150;
|
|
96
|
+
select n from guarded where id = 1;
|
|
97
|
+
→ [{"n":200}]
|
|
98
|
+
|
|
99
|
+
-- condition false: row unchanged
|
|
100
|
+
insert into guarded values (1, 999) on conflict (id) do update set n = excluded.n where n < 150;
|
|
101
|
+
select n from guarded where id = 1;
|
|
102
|
+
→ [{"n":200}]
|
|
103
|
+
|
|
104
|
+
drop table guarded;
|
|
105
|
+
|
|
106
|
+
-- ===================================
|
|
107
|
+
-- 6. UPSERT DO UPDATE with column-list assignment from subquery
|
|
108
|
+
-- ===================================
|
|
109
|
+
|
|
110
|
+
create table dual_set (id integer primary key, a text, b text);
|
|
111
|
+
insert into dual_set values (1, 'x', 'y');
|
|
112
|
+
|
|
113
|
+
-- column-list SET assignment in DO UPDATE is not supported by the parser
|
|
114
|
+
insert into dual_set values (1, 'ignored_a', 'ignored_b')
|
|
115
|
+
on conflict (id) do update set (a, b) = (select 'new_a', 'new_b');
|
|
116
|
+
-- error: Expected column name
|
|
117
|
+
|
|
118
|
+
drop table dual_set;
|
|
119
|
+
|
|
120
|
+
-- ===================================
|
|
121
|
+
-- 7. UPSERT on multi-row INSERT — mix of conflict and non-conflict rows
|
|
122
|
+
-- ===================================
|
|
123
|
+
|
|
124
|
+
create table multi (id integer primary key, name text, count integer);
|
|
125
|
+
insert into multi values (1, 'first', 10);
|
|
126
|
+
|
|
127
|
+
insert into multi (id, name, count) values
|
|
128
|
+
(1, 'updated_first', 100),
|
|
129
|
+
(2, 'second', 20),
|
|
130
|
+
(3, 'third', 30)
|
|
131
|
+
on conflict (id) do update set count = excluded.count;
|
|
132
|
+
|
|
133
|
+
select id, name, count from multi order by id;
|
|
134
|
+
→ [{"id":1,"name":"first","count":100},{"id":2,"name":"second","count":20},{"id":3,"name":"third","count":30}]
|
|
135
|
+
|
|
136
|
+
drop table multi;
|
|
137
|
+
|
|
138
|
+
-- ===================================
|
|
139
|
+
-- 8. ON CONFLICT (<target>) only suppresses conflicts on <target>
|
|
140
|
+
-- A DO NOTHING clause must NOT swallow a conflict on a *different* unique
|
|
141
|
+
-- constraint. With a PK plus a secondary UNIQUE, a clause targeting one of
|
|
142
|
+
-- them aborts when the actual conflict is on the other.
|
|
143
|
+
-- (ticket seed-secondary-unique-silently-skipped)
|
|
144
|
+
-- ===================================
|
|
145
|
+
|
|
146
|
+
create table scoped (id integer primary key, email text unique);
|
|
147
|
+
insert into scoped values (1, 'a@x');
|
|
148
|
+
|
|
149
|
+
-- Conflict is on the `email` UNIQUE (existing row has a different PK), but the
|
|
150
|
+
-- clause targets `id` — so it must abort, not skip.
|
|
151
|
+
insert into scoped values (2, 'a@x') on conflict (id) do nothing;
|
|
152
|
+
-- error: UNIQUE constraint failed
|
|
153
|
+
|
|
154
|
+
-- Symmetric: conflict is on the PK `id` (existing row has a different email),
|
|
155
|
+
-- but the clause targets `email` — must abort, not skip.
|
|
156
|
+
insert into scoped values (1, 'b@x') on conflict (email) do nothing;
|
|
157
|
+
-- error: UNIQUE constraint failed
|
|
158
|
+
|
|
159
|
+
-- The aborted inserts left no trace: still just the original row.
|
|
160
|
+
select id, email from scoped order by id;
|
|
161
|
+
→ [{"id":1,"email":"a@x"}]
|
|
162
|
+
|
|
163
|
+
-- Idempotency control: a genuine PK conflict (same id, same email) targeting
|
|
164
|
+
-- the PK is skipped silently — the value-comparison match still holds.
|
|
165
|
+
insert into scoped values (1, 'a@x') on conflict (id) do nothing;
|
|
166
|
+
select count(*) as cnt from scoped;
|
|
167
|
+
→ [{"cnt":1}]
|
|
168
|
+
|
|
169
|
+
drop table scoped;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
-- distilled from SQLite test/conflict.test (replace/or-clauses surface);
|
|
2
|
+
-- replace.test does not exist upstream, but the ticket calls out
|
|
3
|
+
-- "INSERT OR REPLACE / OR IGNORE / OR ABORT / OR FAIL / OR ROLLBACK —
|
|
4
|
+
-- Quereus's conflict-resolution surface may differ. Pin it down per clause."
|
|
5
|
+
-- Existing fixtures cover OR IGNORE / OR REPLACE on UNIQUE (102) and NOT NULL (43.1);
|
|
6
|
+
-- this fills in the REPLACE-INTO keyword form, multi-row REPLACE, REPLACE+RETURNING,
|
|
7
|
+
-- UPDATE OR REPLACE on UNIQUE, and OR FAIL / OR ROLLBACK / OR ABORT semantics
|
|
8
|
+
-- with respect to surrounding transactional state.
|
|
9
|
+
|
|
10
|
+
-- ===================================
|
|
11
|
+
-- 1. Bare REPLACE statement is not supported (only INSERT OR REPLACE form)
|
|
12
|
+
-- ===================================
|
|
13
|
+
|
|
14
|
+
create table rk (id integer primary key, email text unique, name text);
|
|
15
|
+
insert into rk values (1, 'a@x', 'Alice'), (2, 'b@x', 'Bob');
|
|
16
|
+
|
|
17
|
+
replace into rk values (1, 'a@x', 'Alice2');
|
|
18
|
+
-- error: Expected statement type
|
|
19
|
+
|
|
20
|
+
drop table rk;
|
|
21
|
+
|
|
22
|
+
-- ===================================
|
|
23
|
+
-- 2. INSERT OR REPLACE multi-row VALUES — atomic per-row conflict resolution
|
|
24
|
+
-- ===================================
|
|
25
|
+
|
|
26
|
+
create table rm (id integer primary key, name text unique);
|
|
27
|
+
insert into rm values (1, 'Alice'), (2, 'Bob');
|
|
28
|
+
|
|
29
|
+
insert or replace into rm values (1, 'Alice-New'), (3, 'Carol');
|
|
30
|
+
|
|
31
|
+
select id, name from rm order by id;
|
|
32
|
+
→ [{"id":1,"name":"Alice-New"},{"id":2,"name":"Bob"},{"id":3,"name":"Carol"}]
|
|
33
|
+
|
|
34
|
+
drop table rm;
|
|
35
|
+
|
|
36
|
+
-- ===================================
|
|
37
|
+
-- 3. REPLACE that resolves multiple existing rows via UNIQUE conflict on different cols
|
|
38
|
+
-- ===================================
|
|
39
|
+
|
|
40
|
+
create table rmm (id integer primary key, email text unique, phone text unique);
|
|
41
|
+
insert into rmm values (1, 'a@x', '111'), (2, 'b@x', '222');
|
|
42
|
+
|
|
43
|
+
-- new row conflicts on email with id=1 and phone with id=2 — both old rows are replaced
|
|
44
|
+
insert or replace into rmm values (3, 'a@x', '222');
|
|
45
|
+
select id from rmm order by id;
|
|
46
|
+
→ [{"id":3}]
|
|
47
|
+
|
|
48
|
+
drop table rmm;
|
|
49
|
+
|
|
50
|
+
-- ===================================
|
|
51
|
+
-- 4. REPLACE INTO with RETURNING
|
|
52
|
+
-- ===================================
|
|
53
|
+
|
|
54
|
+
create table rr (id integer primary key, val text);
|
|
55
|
+
insert into rr values (1, 'old');
|
|
56
|
+
|
|
57
|
+
insert or replace into rr values (1, 'new') returning id, val;
|
|
58
|
+
→ [{"id":1,"val":"new"}]
|
|
59
|
+
|
|
60
|
+
drop table rr;
|
|
61
|
+
|
|
62
|
+
-- ===================================
|
|
63
|
+
-- 5. UPDATE OR <action> is intentionally not supported
|
|
64
|
+
-- ===================================
|
|
65
|
+
-- SQLite-only syntax with no precedent in Postgres / SQL Server / MySQL / Oracle / ANSI.
|
|
66
|
+
-- Per-statement conflict overrides on UPDATE are pinned closed; use schema-level
|
|
67
|
+
-- ON CONFLICT defaults (column / table constraint clauses) or rewrite via
|
|
68
|
+
-- WHERE NOT EXISTS / explicit DELETE+UPDATE in a transaction. See docs/sql.md §11.
|
|
69
|
+
|
|
70
|
+
create table uor (id integer primary key, code text unique);
|
|
71
|
+
insert into uor values (1, 'aaa'), (2, 'bbb');
|
|
72
|
+
|
|
73
|
+
update or replace uor set code = 'aaa' where id = 2;
|
|
74
|
+
-- error: Expected table name
|
|
75
|
+
|
|
76
|
+
drop table uor;
|
|
77
|
+
|
|
78
|
+
-- ===================================
|
|
79
|
+
-- 6. INSERT OR ABORT (default) — violation aborts the statement entirely
|
|
80
|
+
-- ===================================
|
|
81
|
+
|
|
82
|
+
create table ab (id integer primary key, val text);
|
|
83
|
+
insert into ab values (1, 'a');
|
|
84
|
+
|
|
85
|
+
-- bulk insert with a duplicate PK in the middle aborts the entire statement
|
|
86
|
+
insert or abort into ab values (2, 'b'), (1, 'dup'), (3, 'c');
|
|
87
|
+
-- error: UNIQUE constraint failed
|
|
88
|
+
|
|
89
|
+
-- nothing should have been inserted
|
|
90
|
+
select count(*) as cnt from ab;
|
|
91
|
+
→ [{"cnt":1}]
|
|
92
|
+
|
|
93
|
+
drop table ab;
|
|
94
|
+
|
|
95
|
+
-- ===================================
|
|
96
|
+
-- 7. INSERT OR FAIL — earlier rows in the failing statement remain inserted
|
|
97
|
+
-- ===================================
|
|
98
|
+
|
|
99
|
+
create table fl (id integer primary key, val text);
|
|
100
|
+
insert into fl values (5, 'pre');
|
|
101
|
+
|
|
102
|
+
-- FAIL inserts rows that succeed before the violation, then halts
|
|
103
|
+
insert or fail into fl values (1, 'a'), (2, 'b'), (5, 'dup'), (3, 'c');
|
|
104
|
+
-- error: UNIQUE constraint failed
|
|
105
|
+
|
|
106
|
+
-- INSERT OR FAIL leaves previously-successful rows inserted
|
|
107
|
+
select id, val from fl order by id;
|
|
108
|
+
→ [{"id":1,"val":"a"},{"id":2,"val":"b"},{"id":5,"val":"pre"}]
|
|
109
|
+
|
|
110
|
+
drop table fl;
|
|
111
|
+
|
|
112
|
+
-- ===================================
|
|
113
|
+
-- 8. INSERT OR ROLLBACK — violation rolls back the enclosing transaction
|
|
114
|
+
-- ===================================
|
|
115
|
+
|
|
116
|
+
create table rb (id integer primary key, val text);
|
|
117
|
+
insert into rb values (1, 'pre');
|
|
118
|
+
-- run
|
|
119
|
+
|
|
120
|
+
begin;
|
|
121
|
+
insert into rb values (10, 'committed_in_tx');
|
|
122
|
+
insert or rollback into rb values (1, 'dup');
|
|
123
|
+
-- error: UNIQUE constraint failed
|
|
124
|
+
|
|
125
|
+
-- INSERT OR ROLLBACK auto-rolls-back the enclosing transaction; only the
|
|
126
|
+
-- pre-tx insert remains.
|
|
127
|
+
select id, val from rb order by id;
|
|
128
|
+
→ [{"id":1,"val":"pre"}]
|
|
129
|
+
|
|
130
|
+
drop table rb;
|
|
131
|
+
|
|
132
|
+
-- ===================================
|
|
133
|
+
-- 9. INSERT OR IGNORE on CHECK constraint — violating row silently skipped
|
|
134
|
+
-- ===================================
|
|
135
|
+
|
|
136
|
+
create table ck (id integer primary key, n integer check (n > 0));
|
|
137
|
+
insert into ck values (1, 10);
|
|
138
|
+
|
|
139
|
+
insert or ignore into ck values (2, -5);
|
|
140
|
+
select count(*) as cnt from ck;
|
|
141
|
+
→ [{"cnt":1}]
|
|
142
|
+
|
|
143
|
+
-- valid follow-up insert succeeds
|
|
144
|
+
insert or ignore into ck values (3, 30);
|
|
145
|
+
select id, n from ck order by id;
|
|
146
|
+
→ [{"id":1,"n":10},{"id":3,"n":30}]
|
|
147
|
+
|
|
148
|
+
drop table ck;
|
|
149
|
+
|
|
150
|
+
-- ===================================
|
|
151
|
+
-- 10. INSERT OR REPLACE on CHECK — REPLACE does NOT mask CHECK violations
|
|
152
|
+
-- ===================================
|
|
153
|
+
|
|
154
|
+
create table ck2 (id integer primary key, n integer check (n > 0));
|
|
155
|
+
insert into ck2 values (1, 10);
|
|
156
|
+
|
|
157
|
+
-- REPLACE relaxes UNIQUE/PK conflicts but CHECK is always abort-only
|
|
158
|
+
insert or replace into ck2 values (2, -5);
|
|
159
|
+
-- error: CHECK
|
|
160
|
+
|
|
161
|
+
select count(*) as cnt from ck2;
|
|
162
|
+
→ [{"cnt":1}]
|
|
163
|
+
|
|
164
|
+
drop table ck2;
|