@quereus/quereus 4.20.1 → 4.20.3
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/schema/schema-differ.d.ts.map +1 -1
- package/dist/src/schema/schema-differ.js +17 -69
- package/dist/src/schema/schema-differ.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 +210 -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,1033 @@
|
|
|
1
|
+
-- metadata-tags.sqllogic - Testing WITH TAGS metadata on schema objects
|
|
2
|
+
|
|
3
|
+
-- ===================================================================
|
|
4
|
+
-- Phase 1: Table-level tags
|
|
5
|
+
-- ===================================================================
|
|
6
|
+
|
|
7
|
+
-- Table with tags
|
|
8
|
+
CREATE TABLE Orders (
|
|
9
|
+
id INTEGER PRIMARY KEY,
|
|
10
|
+
name TEXT NOT NULL
|
|
11
|
+
) WITH TAGS (display_name = 'Customer Orders', audit = true);
|
|
12
|
+
|
|
13
|
+
-- Verify the table works normally with tags
|
|
14
|
+
INSERT INTO Orders VALUES (1, 'Order A'), (2, 'Order B');
|
|
15
|
+
SELECT * FROM Orders ORDER BY id;
|
|
16
|
+
→ [{"id":1,"name":"Order A"},{"id":2,"name":"Order B"}]
|
|
17
|
+
|
|
18
|
+
-- Round-trip: tags surface through schema() introspection
|
|
19
|
+
SELECT json_extract(tags, '$.display_name') AS display_name,
|
|
20
|
+
json_extract(tags, '$.audit') AS audit
|
|
21
|
+
FROM schema() WHERE type = 'table' AND name = 'Orders';
|
|
22
|
+
→ [{"display_name":"Customer Orders","audit":true}]
|
|
23
|
+
|
|
24
|
+
-- ===================================================================
|
|
25
|
+
-- Phase 2: Column-level tags
|
|
26
|
+
-- ===================================================================
|
|
27
|
+
|
|
28
|
+
CREATE TABLE Products (
|
|
29
|
+
id INTEGER PRIMARY KEY WITH TAGS (display_name = 'Product ID'),
|
|
30
|
+
name TEXT NOT NULL WITH TAGS (searchable = true, display_name = 'Product Name'),
|
|
31
|
+
price REAL NOT NULL
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
INSERT INTO Products VALUES (1, 'Widget', 9.99), (2, 'Gadget', 19.99);
|
|
35
|
+
SELECT name, price FROM Products ORDER BY name;
|
|
36
|
+
→ [{"name":"Gadget","price":19.99},{"name":"Widget","price":9.99}]
|
|
37
|
+
|
|
38
|
+
-- Round-trip: column tags via table_info()
|
|
39
|
+
SELECT name, json_extract(tags, '$.display_name') AS display_name,
|
|
40
|
+
json_extract(tags, '$.searchable') AS searchable
|
|
41
|
+
FROM table_info('Products') WHERE cid IN (0, 1) ORDER BY cid;
|
|
42
|
+
→ [{"name":"id","display_name":"Product ID","searchable":null},{"name":"name","display_name":"Product Name","searchable":true}]
|
|
43
|
+
|
|
44
|
+
-- ===================================================================
|
|
45
|
+
-- Phase 3: Constraint-level tags
|
|
46
|
+
-- ===================================================================
|
|
47
|
+
|
|
48
|
+
-- CHECK constraint with tags
|
|
49
|
+
CREATE TABLE Items (
|
|
50
|
+
id INTEGER PRIMARY KEY,
|
|
51
|
+
quantity INTEGER NOT NULL CHECK (quantity > 0) WITH TAGS (error_message = 'Quantity must be positive')
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
INSERT INTO Items VALUES (1, 5);
|
|
55
|
+
SELECT * FROM Items;
|
|
56
|
+
→ [{"id":1,"quantity":5}]
|
|
57
|
+
|
|
58
|
+
-- Verify CHECK still works
|
|
59
|
+
INSERT INTO Items VALUES (2, -1);
|
|
60
|
+
-- error: CHECK constraint failed
|
|
61
|
+
|
|
62
|
+
-- UNIQUE constraint with tags (table-level)
|
|
63
|
+
CREATE TABLE Employees (
|
|
64
|
+
id INTEGER PRIMARY KEY,
|
|
65
|
+
email TEXT NOT NULL,
|
|
66
|
+
CONSTRAINT uq_email UNIQUE (email) WITH TAGS (error_message = 'Email must be unique')
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
INSERT INTO Employees VALUES (1, 'alice@test.com'), (2, 'bob@test.com');
|
|
70
|
+
SELECT * FROM Employees ORDER BY id;
|
|
71
|
+
→ [{"id":1,"email":"alice@test.com"},{"id":2,"email":"bob@test.com"}]
|
|
72
|
+
|
|
73
|
+
-- Round-trip: named UNIQUE constraint tags via unique_constraint_info()
|
|
74
|
+
SELECT name, json_extract(tags, '$.error_message') AS msg
|
|
75
|
+
FROM unique_constraint_info('Employees') WHERE name = 'uq_email';
|
|
76
|
+
→ [{"name":"uq_email","msg":"Email must be unique"}]
|
|
77
|
+
|
|
78
|
+
-- ===================================================================
|
|
79
|
+
-- Phase 4: View-level tags
|
|
80
|
+
-- ===================================================================
|
|
81
|
+
|
|
82
|
+
CREATE VIEW ActiveOrders AS SELECT * FROM Orders WHERE id > 0
|
|
83
|
+
WITH TAGS (cacheable = true, purpose = 'active orders filter');
|
|
84
|
+
|
|
85
|
+
SELECT * FROM ActiveOrders ORDER BY id;
|
|
86
|
+
→ [{"id":1,"name":"Order A"},{"id":2,"name":"Order B"}]
|
|
87
|
+
|
|
88
|
+
-- Round-trip: view tags via schema()
|
|
89
|
+
SELECT json_extract(tags, '$.cacheable') AS cacheable,
|
|
90
|
+
json_extract(tags, '$.purpose') AS purpose
|
|
91
|
+
FROM schema() WHERE type = 'view' AND name = 'ActiveOrders';
|
|
92
|
+
→ [{"cacheable":true,"purpose":"active orders filter"}]
|
|
93
|
+
|
|
94
|
+
-- ===================================================================
|
|
95
|
+
-- Phase 5: Index-level tags
|
|
96
|
+
-- ===================================================================
|
|
97
|
+
-- Lives in 50.0.1-metadata-tags-index (it needs standalone CREATE INDEX).
|
|
98
|
+
|
|
99
|
+
-- ===================================================================
|
|
100
|
+
-- Phase 6: Tag value types
|
|
101
|
+
-- ===================================================================
|
|
102
|
+
|
|
103
|
+
CREATE TABLE TagTypes (
|
|
104
|
+
id INTEGER PRIMARY KEY WITH TAGS (
|
|
105
|
+
str_tag = 'hello',
|
|
106
|
+
num_tag = 42,
|
|
107
|
+
float_tag = 3.14,
|
|
108
|
+
bool_true = true,
|
|
109
|
+
bool_false = false,
|
|
110
|
+
null_tag = null,
|
|
111
|
+
negative = -10
|
|
112
|
+
)
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
INSERT INTO TagTypes VALUES (1);
|
|
116
|
+
SELECT * FROM TagTypes;
|
|
117
|
+
→ [{"id":1}]
|
|
118
|
+
|
|
119
|
+
-- ===================================================================
|
|
120
|
+
-- Phase 7: Combined WITH TAGS and WITH CONTEXT
|
|
121
|
+
-- ===================================================================
|
|
122
|
+
|
|
123
|
+
-- Tags combined with context in any order
|
|
124
|
+
CREATE TABLE AuditLog (
|
|
125
|
+
id INTEGER PRIMARY KEY,
|
|
126
|
+
message TEXT NOT NULL
|
|
127
|
+
) WITH CONTEXT (user_name TEXT) WITH TAGS (audit = true, display_name = 'Audit Log');
|
|
128
|
+
|
|
129
|
+
INSERT INTO AuditLog VALUES (1, 'action') WITH CONTEXT user_name = 'admin';
|
|
130
|
+
SELECT * FROM AuditLog;
|
|
131
|
+
→ [{"id":1,"message":"action"}]
|
|
132
|
+
|
|
133
|
+
-- Tags before context
|
|
134
|
+
CREATE TABLE AuditLog2 (
|
|
135
|
+
id INTEGER PRIMARY KEY,
|
|
136
|
+
message TEXT NOT NULL
|
|
137
|
+
) WITH TAGS (audit = true) WITH CONTEXT (user_name TEXT);
|
|
138
|
+
|
|
139
|
+
INSERT INTO AuditLog2 VALUES (1, 'action') WITH CONTEXT user_name = 'admin';
|
|
140
|
+
SELECT * FROM AuditLog2;
|
|
141
|
+
→ [{"id":1,"message":"action"}]
|
|
142
|
+
|
|
143
|
+
-- ===================================================================
|
|
144
|
+
-- Phase 8: TAGS as a regular identifier (contextual keyword test)
|
|
145
|
+
-- ===================================================================
|
|
146
|
+
|
|
147
|
+
CREATE TABLE TagsTable (
|
|
148
|
+
tags TEXT PRIMARY KEY
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
INSERT INTO TagsTable VALUES ('test');
|
|
152
|
+
SELECT tags FROM TagsTable;
|
|
153
|
+
→ [{"tags":"test"}]
|
|
154
|
+
|
|
155
|
+
-- ===================================================================
|
|
156
|
+
-- Phase 9: Empty tags (edge case)
|
|
157
|
+
-- ===================================================================
|
|
158
|
+
|
|
159
|
+
-- Table with single tag
|
|
160
|
+
CREATE TABLE SingleTag (
|
|
161
|
+
id INTEGER PRIMARY KEY
|
|
162
|
+
) WITH TAGS (label = 'solo');
|
|
163
|
+
|
|
164
|
+
INSERT INTO SingleTag VALUES (1);
|
|
165
|
+
SELECT * FROM SingleTag;
|
|
166
|
+
→ [{"id":1}]
|
|
167
|
+
|
|
168
|
+
-- ===================================================================
|
|
169
|
+
-- Phase 10: Tags with special string values
|
|
170
|
+
-- ===================================================================
|
|
171
|
+
|
|
172
|
+
CREATE TABLE SpecialTags (
|
|
173
|
+
id INTEGER PRIMARY KEY
|
|
174
|
+
) WITH TAGS (description = 'it''s a "test"', empty = '');
|
|
175
|
+
|
|
176
|
+
INSERT INTO SpecialTags VALUES (1);
|
|
177
|
+
SELECT * FROM SpecialTags;
|
|
178
|
+
→ [{"id":1}]
|
|
179
|
+
|
|
180
|
+
-- ===================================================================
|
|
181
|
+
-- Phase 11: ALTER TABLE ... SET TAGS (table-level, whole-set replace + clear)
|
|
182
|
+
-- ===================================================================
|
|
183
|
+
|
|
184
|
+
CREATE TABLE Alterable (
|
|
185
|
+
id INTEGER PRIMARY KEY,
|
|
186
|
+
name TEXT NOT NULL
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
-- No tags yet → tags IS NULL
|
|
190
|
+
SELECT tags FROM schema() WHERE type = 'table' AND name = 'Alterable';
|
|
191
|
+
→ [{"tags":null}]
|
|
192
|
+
|
|
193
|
+
-- Set table tags
|
|
194
|
+
ALTER TABLE Alterable SET TAGS (display_name = 'Alterable Table', audit = true);
|
|
195
|
+
SELECT json_extract(tags, '$.display_name') AS dn, json_extract(tags, '$.audit') AS audit
|
|
196
|
+
FROM schema() WHERE type = 'table' AND name = 'Alterable';
|
|
197
|
+
→ [{"dn":"Alterable Table","audit":true}]
|
|
198
|
+
|
|
199
|
+
-- Whole-set replace: the previous keys are gone, only the new one remains
|
|
200
|
+
ALTER TABLE Alterable SET TAGS (display_name = 'Renamed');
|
|
201
|
+
SELECT json_extract(tags, '$.display_name') AS dn, json_extract(tags, '$.audit') AS audit
|
|
202
|
+
FROM schema() WHERE type = 'table' AND name = 'Alterable';
|
|
203
|
+
→ [{"dn":"Renamed","audit":null}]
|
|
204
|
+
|
|
205
|
+
-- Clear all tags → tags IS NULL
|
|
206
|
+
ALTER TABLE Alterable SET TAGS ();
|
|
207
|
+
SELECT tags FROM schema() WHERE type = 'table' AND name = 'Alterable';
|
|
208
|
+
→ [{"tags":null}]
|
|
209
|
+
|
|
210
|
+
-- The table still works after tag mutations
|
|
211
|
+
INSERT INTO Alterable VALUES (1, 'row');
|
|
212
|
+
SELECT * FROM Alterable;
|
|
213
|
+
→ [{"id":1,"name":"row"}]
|
|
214
|
+
|
|
215
|
+
-- ===================================================================
|
|
216
|
+
-- Phase 12: ALTER TABLE ... ALTER COLUMN ... SET TAGS
|
|
217
|
+
-- ===================================================================
|
|
218
|
+
|
|
219
|
+
ALTER TABLE Alterable ALTER COLUMN name SET TAGS (searchable = true, display_name = 'Name');
|
|
220
|
+
SELECT name, json_extract(tags, '$.searchable') AS searchable, json_extract(tags, '$.display_name') AS dn
|
|
221
|
+
FROM table_info('Alterable') WHERE name = 'name';
|
|
222
|
+
→ [{"name":"name","searchable":true,"dn":"Name"}]
|
|
223
|
+
|
|
224
|
+
-- Column attributes (NOT NULL, type) are untouched by SET TAGS
|
|
225
|
+
SELECT name, type, notnull FROM table_info('Alterable') WHERE name = 'name';
|
|
226
|
+
→ [{"name":"name","type":"TEXT","notnull":1}]
|
|
227
|
+
|
|
228
|
+
-- Clear column tags
|
|
229
|
+
ALTER TABLE Alterable ALTER COLUMN name SET TAGS ();
|
|
230
|
+
SELECT tags FROM table_info('Alterable') WHERE name = 'name';
|
|
231
|
+
→ [{"tags":null}]
|
|
232
|
+
|
|
233
|
+
-- ===================================================================
|
|
234
|
+
-- Phase 13: ALTER TABLE ... ALTER CONSTRAINT ... SET TAGS (named constraint)
|
|
235
|
+
-- ===================================================================
|
|
236
|
+
|
|
237
|
+
CREATE TABLE Staff (
|
|
238
|
+
id INTEGER PRIMARY KEY,
|
|
239
|
+
email TEXT NOT NULL,
|
|
240
|
+
CONSTRAINT uq_staff_email UNIQUE (email)
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
ALTER TABLE Staff ALTER CONSTRAINT uq_staff_email SET TAGS (error_message = 'Email must be unique');
|
|
244
|
+
SELECT name, json_extract(tags, '$.error_message') AS msg
|
|
245
|
+
FROM unique_constraint_info('Staff') WHERE name = 'uq_staff_email';
|
|
246
|
+
→ [{"name":"uq_staff_email","msg":"Email must be unique"}]
|
|
247
|
+
|
|
248
|
+
-- The UNIQUE constraint still enforces after the tag mutation
|
|
249
|
+
INSERT INTO Staff VALUES (1, 'a@x'), (2, 'b@x');
|
|
250
|
+
SELECT count(*) AS n FROM Staff;
|
|
251
|
+
→ [{"n":2}]
|
|
252
|
+
|
|
253
|
+
INSERT INTO Staff VALUES (3, 'a@x');
|
|
254
|
+
-- error: constraint
|
|
255
|
+
|
|
256
|
+
-- ===================================================================
|
|
257
|
+
-- Phase 14: reserved-tag typo rejection on the ALTER path
|
|
258
|
+
-- ===================================================================
|
|
259
|
+
|
|
260
|
+
-- A misspelled reserved key is rejected loudly (not silently stored)
|
|
261
|
+
ALTER TABLE Alterable SET TAGS ("quereus.update.taget" = 1);
|
|
262
|
+
-- error: reserved tag
|
|
263
|
+
|
|
264
|
+
ALTER TABLE Alterable ALTER COLUMN name SET TAGS ("quereus.bogus" = 1);
|
|
265
|
+
-- error: reserved tag
|
|
266
|
+
|
|
267
|
+
-- ===================================================================
|
|
268
|
+
-- Phase 15: NOTFOUND for unknown column / constraint
|
|
269
|
+
-- ===================================================================
|
|
270
|
+
|
|
271
|
+
ALTER TABLE Alterable ALTER COLUMN nope SET TAGS (a = 1);
|
|
272
|
+
-- error: not found
|
|
273
|
+
|
|
274
|
+
ALTER TABLE Alterable ALTER CONSTRAINT nope SET TAGS (a = 1);
|
|
275
|
+
-- error: not found
|
|
276
|
+
|
|
277
|
+
-- ===================================================================
|
|
278
|
+
-- Phase 16: ambiguous constraint name (same name across constraint classes)
|
|
279
|
+
-- ===================================================================
|
|
280
|
+
|
|
281
|
+
-- A name shared by a UNIQUE and a CHECK constraint is constructible (no
|
|
282
|
+
-- create-time dedup across classes), so ALTER CONSTRAINT ... SET TAGS on it
|
|
283
|
+
-- must reject the request as ambiguous rather than silently picking one.
|
|
284
|
+
CREATE TABLE AmbiguousCon (
|
|
285
|
+
id INTEGER PRIMARY KEY,
|
|
286
|
+
x INTEGER,
|
|
287
|
+
CONSTRAINT dup UNIQUE (x),
|
|
288
|
+
CONSTRAINT dup CHECK (x > 0)
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
ALTER TABLE AmbiguousCon ALTER CONSTRAINT dup SET TAGS (m = 'x');
|
|
292
|
+
-- error: ambiguous
|
|
293
|
+
|
|
294
|
+
-- ===================================================================
|
|
295
|
+
-- Phase 17: ALTER VIEW ... SET TAGS (whole-set replace + clear)
|
|
296
|
+
-- ===================================================================
|
|
297
|
+
|
|
298
|
+
-- ActiveOrders (Phase 4) was created with cacheable/purpose tags.
|
|
299
|
+
SELECT json_extract(tags, '$.cacheable') AS cacheable, json_extract(tags, '$.purpose') AS purpose
|
|
300
|
+
FROM schema() WHERE type = 'view' AND name = 'ActiveOrders';
|
|
301
|
+
→ [{"cacheable":true,"purpose":"active orders filter"}]
|
|
302
|
+
|
|
303
|
+
-- Whole-set replace: previous keys are gone, only the new ones remain.
|
|
304
|
+
ALTER VIEW ActiveOrders SET TAGS (owner = 'team-x', cacheable = false);
|
|
305
|
+
SELECT json_extract(tags, '$.owner') AS owner, json_extract(tags, '$.cacheable') AS cacheable,
|
|
306
|
+
json_extract(tags, '$.purpose') AS purpose
|
|
307
|
+
FROM schema() WHERE type = 'view' AND name = 'ActiveOrders';
|
|
308
|
+
→ [{"owner":"team-x","cacheable":false,"purpose":null}]
|
|
309
|
+
|
|
310
|
+
-- The view still resolves and returns rows after the tag mutation.
|
|
311
|
+
SELECT * FROM ActiveOrders ORDER BY id;
|
|
312
|
+
→ [{"id":1,"name":"Order A"},{"id":2,"name":"Order B"}]
|
|
313
|
+
|
|
314
|
+
-- Clear all tags → tags IS NULL.
|
|
315
|
+
ALTER VIEW ActiveOrders SET TAGS ();
|
|
316
|
+
SELECT tags FROM schema() WHERE type = 'view' AND name = 'ActiveOrders';
|
|
317
|
+
→ [{"tags":null}]
|
|
318
|
+
|
|
319
|
+
-- ===================================================================
|
|
320
|
+
-- Phase 18: ALTER INDEX ... SET TAGS (whole-set replace + clear)
|
|
321
|
+
-- ===================================================================
|
|
322
|
+
-- Lives in 50.0.1-metadata-tags-index (it needs standalone CREATE INDEX).
|
|
323
|
+
|
|
324
|
+
-- ===================================================================
|
|
325
|
+
-- Phase 19: ALTER MATERIALIZED VIEW ... SET TAGS (no re-materialization)
|
|
326
|
+
-- ===================================================================
|
|
327
|
+
|
|
328
|
+
CREATE MATERIALIZED VIEW mv_orders AS SELECT id, name FROM Orders;
|
|
329
|
+
|
|
330
|
+
-- The MV is materialized from Orders (rows inserted in Phase 1).
|
|
331
|
+
SELECT id, name FROM mv_orders ORDER BY id;
|
|
332
|
+
→ [{"id":1,"name":"Order A"},{"id":2,"name":"Order B"}]
|
|
333
|
+
|
|
334
|
+
-- Tag mutation executes as a catalog-only change.
|
|
335
|
+
ALTER MATERIALIZED VIEW mv_orders SET TAGS (owner = 'analytics');
|
|
336
|
+
|
|
337
|
+
-- The materialized data is unchanged by the tag mutation (no rebuild).
|
|
338
|
+
SELECT id, name FROM mv_orders ORDER BY id;
|
|
339
|
+
→ [{"id":1,"name":"Order A"},{"id":2,"name":"Order B"}]
|
|
340
|
+
|
|
341
|
+
-- Replace then clear still leave the data intact.
|
|
342
|
+
ALTER MATERIALIZED VIEW mv_orders SET TAGS (owner = 'platform', tier = 'gold');
|
|
343
|
+
ALTER MATERIALIZED VIEW mv_orders SET TAGS ();
|
|
344
|
+
SELECT id, name FROM mv_orders ORDER BY id;
|
|
345
|
+
→ [{"id":1,"name":"Order A"},{"id":2,"name":"Order B"}]
|
|
346
|
+
|
|
347
|
+
-- ===================================================================
|
|
348
|
+
-- Phase 20: NOTFOUND for unknown view / index / materialized view
|
|
349
|
+
-- ===================================================================
|
|
350
|
+
|
|
351
|
+
ALTER VIEW NoSuchView SET TAGS (a = 1);
|
|
352
|
+
-- error: not found
|
|
353
|
+
|
|
354
|
+
ALTER INDEX NoSuchIndex SET TAGS (a = 1);
|
|
355
|
+
-- error: not found
|
|
356
|
+
|
|
357
|
+
ALTER MATERIALIZED VIEW NoSuchMv SET TAGS (a = 1);
|
|
358
|
+
-- error: not found
|
|
359
|
+
|
|
360
|
+
-- ===================================================================
|
|
361
|
+
-- Phase 21: reserved-tag typo rejection on the view / index ALTER paths
|
|
362
|
+
-- ===================================================================
|
|
363
|
+
|
|
364
|
+
-- A misspelled reserved key is rejected loudly (view-ddl site).
|
|
365
|
+
ALTER VIEW ActiveOrders SET TAGS ("quereus.update.taget" = 1);
|
|
366
|
+
-- error: reserved tag
|
|
367
|
+
|
|
368
|
+
-- The physical-index site of the same rejection is in 50.0.1-metadata-tags-index.
|
|
369
|
+
|
|
370
|
+
-- ===================================================================
|
|
371
|
+
-- Phase 22: hidden implicit covering index is not addressable (NOTFOUND)
|
|
372
|
+
-- ===================================================================
|
|
373
|
+
|
|
374
|
+
-- Employees (Phase 3) has a named UNIQUE constraint uq_email whose implicit
|
|
375
|
+
-- covering structure is hidden — ALTER INDEX must treat it as NOTFOUND (its
|
|
376
|
+
-- tags live on the constraint, set via ALTER TABLE ... ALTER CONSTRAINT).
|
|
377
|
+
ALTER INDEX uq_email SET TAGS (a = 1);
|
|
378
|
+
-- error: not found
|
|
379
|
+
|
|
380
|
+
-- ===================================================================
|
|
381
|
+
-- Phase 23: reserved-tag validation on the direct CREATE TABLE path
|
|
382
|
+
-- ===================================================================
|
|
383
|
+
|
|
384
|
+
-- The direct CREATE path now validates reserved `quereus.*` tags at plan-build,
|
|
385
|
+
-- mirroring ALTER ... SET TAGS (Phase 14/21) and the declarative differ, so a
|
|
386
|
+
-- typo / mis-site fails loudly here instead of being silently stored.
|
|
387
|
+
|
|
388
|
+
-- Table-level unknown reserved key rejected (physical-table site).
|
|
389
|
+
CREATE TABLE RsvBadTbl (id INTEGER PRIMARY KEY) WITH TAGS ("quereus.bogus" = 1);
|
|
390
|
+
-- error: reserved tag
|
|
391
|
+
|
|
392
|
+
-- Column-level unknown reserved key rejected (physical-column site).
|
|
393
|
+
CREATE TABLE RsvBadCol (id INTEGER PRIMARY KEY, x INTEGER WITH TAGS ("quereus.bogus" = 1));
|
|
394
|
+
-- error: reserved tag
|
|
395
|
+
|
|
396
|
+
-- Table-level NAMED-constraint unknown reserved key rejected (physical-constraint site).
|
|
397
|
+
CREATE TABLE RsvBadCon (
|
|
398
|
+
id INTEGER PRIMARY KEY,
|
|
399
|
+
x INTEGER,
|
|
400
|
+
CONSTRAINT c CHECK (x > 0) WITH TAGS ("quereus.bogus" = 1)
|
|
401
|
+
);
|
|
402
|
+
-- error: reserved tag
|
|
403
|
+
|
|
404
|
+
-- Mis-sited but otherwise-valid key rejected: quereus.lens.access.<col> is legal
|
|
405
|
+
-- only on a logical table, not on a physical CREATE TABLE ⇒ tag-not-allowed-here.
|
|
406
|
+
CREATE TABLE RsvMissite (id INTEGER PRIMARY KEY) WITH TAGS ("quereus.lens.access.id" = 'eq');
|
|
407
|
+
-- error: not allowed
|
|
408
|
+
|
|
409
|
+
-- The CREATE INDEX form of this rejection is in 50.0.1-metadata-tags-index.
|
|
410
|
+
|
|
411
|
+
-- Multiple offending tags in one statement: diagnostics accumulate table → column,
|
|
412
|
+
-- and the first error (the table-level one) is raised — deterministic ordering.
|
|
413
|
+
CREATE TABLE RsvMulti (
|
|
414
|
+
id INTEGER PRIMARY KEY,
|
|
415
|
+
x INTEGER WITH TAGS ("quereus.also_bogus" = 1)
|
|
416
|
+
) WITH TAGS ("quereus.bogus" = 1);
|
|
417
|
+
-- error: reserved tag
|
|
418
|
+
|
|
419
|
+
-- IF NOT EXISTS still validates at build time: Orders (Phase 1) already exists, so
|
|
420
|
+
-- the create would be skipped at runtime, but the malformed reserved tag is rejected
|
|
421
|
+
-- at plan-build regardless (matches ALTER's build-time semantics).
|
|
422
|
+
CREATE TABLE IF NOT EXISTS Orders (id INTEGER PRIMARY KEY) WITH TAGS ("quereus.bogus" = 1);
|
|
423
|
+
-- error: reserved tag
|
|
424
|
+
|
|
425
|
+
-- Valid rename hint quereus.id accepted on a table and round-trips through schema().
|
|
426
|
+
CREATE TABLE RsvOkTbl (id INTEGER PRIMARY KEY) WITH TAGS ("quereus.id" = 'tbl-thing');
|
|
427
|
+
SELECT json_extract(tags, '$."quereus.id"') AS qid
|
|
428
|
+
FROM schema() WHERE type = 'table' AND name = 'RsvOkTbl';
|
|
429
|
+
→ [{"qid":"tbl-thing"}]
|
|
430
|
+
|
|
431
|
+
-- Valid quereus.id accepted on a column and round-trips through table_info().
|
|
432
|
+
CREATE TABLE RsvOkCol (id INTEGER PRIMARY KEY WITH TAGS ("quereus.id" = 'col-pk'), x INTEGER);
|
|
433
|
+
SELECT name, json_extract(tags, '$."quereus.id"') AS qid
|
|
434
|
+
FROM table_info('RsvOkCol') WHERE name = 'id';
|
|
435
|
+
→ [{"name":"id","qid":"col-pk"}]
|
|
436
|
+
|
|
437
|
+
-- Valid quereus.id accepted on a table-level NAMED constraint and round-trips
|
|
438
|
+
-- through unique_constraint_info() (the physical-constraint surface accepts the hint).
|
|
439
|
+
CREATE TABLE RsvOkConTbl (
|
|
440
|
+
id INTEGER PRIMARY KEY,
|
|
441
|
+
email TEXT NOT NULL,
|
|
442
|
+
CONSTRAINT uq_rsv UNIQUE (email) WITH TAGS ("quereus.id" = 'con-uq')
|
|
443
|
+
);
|
|
444
|
+
SELECT name, json_extract(tags, '$."quereus.id"') AS qid
|
|
445
|
+
FROM unique_constraint_info('RsvOkConTbl') WHERE name = 'uq_rsv';
|
|
446
|
+
→ [{"name":"uq_rsv","qid":"con-uq"}]
|
|
447
|
+
|
|
448
|
+
-- -------------------------------------------------------------------
|
|
449
|
+
-- Inline NAMED column-constraint reserved-tag validation
|
|
450
|
+
-- (ColumnDef.constraints[].tags). The parser lifts a trailing WITH TAGS onto an
|
|
451
|
+
-- inline constraint only when it is NAMED; the direct CREATE path validates it at
|
|
452
|
+
-- the same physical-constraint site as a table-level constraint (mirrors the
|
|
453
|
+
-- differ — see 50.2-declare-schema-renames.sqllogic § 10).
|
|
454
|
+
-- -------------------------------------------------------------------
|
|
455
|
+
|
|
456
|
+
-- Typo'd reserved key on an inline NAMED CHECK constraint rejected
|
|
457
|
+
-- (physical-constraint site) — the core gap this change closes.
|
|
458
|
+
CREATE TABLE RsvInlineBadCon (
|
|
459
|
+
id INTEGER PRIMARY KEY,
|
|
460
|
+
qty INTEGER CONSTRAINT chk_qty CHECK (qty > 0) WITH TAGS ("quereus.bogus" = 1)
|
|
461
|
+
);
|
|
462
|
+
-- error: reserved tag
|
|
463
|
+
|
|
464
|
+
-- Mis-sited but otherwise-valid key on an inline named constraint rejected:
|
|
465
|
+
-- quereus.lens.writable is logical-column only ⇒ tag-not-allowed-here at the
|
|
466
|
+
-- physical-constraint site.
|
|
467
|
+
CREATE TABLE RsvInlineMissite (
|
|
468
|
+
id INTEGER PRIMARY KEY,
|
|
469
|
+
qty INTEGER CONSTRAINT chk_qty2 CHECK (qty > 0) WITH TAGS ("quereus.lens.writable" = true)
|
|
470
|
+
);
|
|
471
|
+
-- error: not allowed
|
|
472
|
+
|
|
473
|
+
-- The retired quereus.update.default_for.<col> key (replaced by the view-level
|
|
474
|
+
-- `with defaults (…)` clause) is unknown — still rejected, different reason.
|
|
475
|
+
CREATE TABLE RsvInlineRetired (
|
|
476
|
+
id INTEGER PRIMARY KEY,
|
|
477
|
+
qty INTEGER CONSTRAINT chk_qty3 CHECK (qty > 0) WITH TAGS ("quereus.update.default_for.qty" = '0')
|
|
478
|
+
);
|
|
479
|
+
-- error: unknown reserved tag
|
|
480
|
+
|
|
481
|
+
-- Valid functional tag quereus.expose_implicit_index accepted on an inline NAMED
|
|
482
|
+
-- UNIQUE constraint and round-trips through unique_constraint_info (the same tag
|
|
483
|
+
-- catalog.ts reads to surface the implicit covering structure).
|
|
484
|
+
CREATE TABLE RsvInlineUq (
|
|
485
|
+
id INTEGER PRIMARY KEY,
|
|
486
|
+
vin TEXT CONSTRAINT uq_vin UNIQUE WITH TAGS ("quereus.expose_implicit_index" = true)
|
|
487
|
+
);
|
|
488
|
+
SELECT name, json_extract(tags, '$."quereus.expose_implicit_index"') AS exposed
|
|
489
|
+
FROM unique_constraint_info('RsvInlineUq') WHERE name = 'uq_vin';
|
|
490
|
+
→ [{"name":"uq_vin","exposed":true}]
|
|
491
|
+
|
|
492
|
+
-- Valid rename hint quereus.id accepted on an inline named UNIQUE constraint and
|
|
493
|
+
-- round-trips (mirrors the table-level RsvOkConTbl case above).
|
|
494
|
+
CREATE TABLE RsvInlineId (
|
|
495
|
+
id INTEGER PRIMARY KEY,
|
|
496
|
+
email TEXT CONSTRAINT uq_email_inline UNIQUE WITH TAGS ("quereus.id" = 'con-inline')
|
|
497
|
+
);
|
|
498
|
+
SELECT name, json_extract(tags, '$."quereus.id"') AS qid
|
|
499
|
+
FROM unique_constraint_info('RsvInlineId') WHERE name = 'uq_email_inline';
|
|
500
|
+
→ [{"name":"uq_email_inline","qid":"con-inline"}]
|
|
501
|
+
|
|
502
|
+
-- Unnamed inline constraint with trailing WITH TAGS: the parser defers the tag to
|
|
503
|
+
-- the COLUMN (physical-column site), so it validates/stores there and round-trips
|
|
504
|
+
-- on the column via table_info — NOT on the constraint (no regression, no double
|
|
505
|
+
-- error). quereus.id is legal at physical-column, so this is accepted.
|
|
506
|
+
CREATE TABLE RsvInlineUnnamed (
|
|
507
|
+
id INTEGER PRIMARY KEY,
|
|
508
|
+
x INTEGER CHECK (x > 0) WITH TAGS ("quereus.id" = 'col-x-tag')
|
|
509
|
+
);
|
|
510
|
+
SELECT name, json_extract(tags, '$."quereus.id"') AS qid
|
|
511
|
+
FROM table_info('RsvInlineUnnamed') WHERE name = 'x';
|
|
512
|
+
→ [{"name":"x","qid":"col-x-tag"}]
|
|
513
|
+
|
|
514
|
+
-- The same quereus.id round-trip on an INDEX is in 50.0.1-metadata-tags-index.
|
|
515
|
+
|
|
516
|
+
-- Free-form (non-quereus.*) tags are unaffected and still create cleanly
|
|
517
|
+
-- (guard against over-rejection — validateReservedTags skips non-reserved keys).
|
|
518
|
+
CREATE TABLE RsvFreeform (id INTEGER PRIMARY KEY) WITH TAGS (display_name = 'x', audit = true);
|
|
519
|
+
INSERT INTO RsvFreeform VALUES (1);
|
|
520
|
+
SELECT * FROM RsvFreeform;
|
|
521
|
+
→ [{"id":1}]
|
|
522
|
+
|
|
523
|
+
-- ===================================================================
|
|
524
|
+
-- Phase 24: reserved-tag validation on the ALTER ... ADD CONSTRAINT /
|
|
525
|
+
-- ADD COLUMN paths
|
|
526
|
+
-- ===================================================================
|
|
527
|
+
|
|
528
|
+
-- The two imperative ALTER ... ADD arms now validate reserved `quereus.*` tags at
|
|
529
|
+
-- plan-build, mirroring CREATE TABLE (Phase 23) and ALTER ... SET TAGS (Phase 14):
|
|
530
|
+
-- ADD CONSTRAINT ... WITH TAGS -> physical-constraint
|
|
531
|
+
-- ADD COLUMN ... WITH TAGS -> physical-column (column) +
|
|
532
|
+
-- physical-constraint (each inline named constraint)
|
|
533
|
+
-- so a typo / mis-site fails loudly here instead of being silently stored.
|
|
534
|
+
|
|
535
|
+
CREATE TABLE AddCon (id INTEGER PRIMARY KEY, email TEXT NOT NULL, code TEXT);
|
|
536
|
+
CREATE TABLE AddCol (id INTEGER PRIMARY KEY);
|
|
537
|
+
|
|
538
|
+
-- -------------------------------------------------------------------
|
|
539
|
+
-- ADD CONSTRAINT ... WITH TAGS (physical-constraint site)
|
|
540
|
+
-- -------------------------------------------------------------------
|
|
541
|
+
|
|
542
|
+
-- Typo'd reserved key on ADD CONSTRAINT CHECK rejected (the validation fires at
|
|
543
|
+
-- plan-build, before any runtime ADD CONSTRAINT machinery).
|
|
544
|
+
ALTER TABLE AddCon ADD CONSTRAINT c_chk CHECK (id > 0) WITH TAGS ("quereus.bogus" = 1);
|
|
545
|
+
-- error: reserved tag
|
|
546
|
+
|
|
547
|
+
-- Mis-sited but otherwise-valid key on ADD CONSTRAINT rejected:
|
|
548
|
+
-- quereus.lens.writable is logical-column only ⇒ tag-not-allowed-here at the
|
|
549
|
+
-- physical-constraint site.
|
|
550
|
+
ALTER TABLE AddCon ADD CONSTRAINT c_chk2 CHECK (id > 0) WITH TAGS ("quereus.lens.writable" = true);
|
|
551
|
+
-- error: not allowed
|
|
552
|
+
|
|
553
|
+
-- The retired quereus.update.default_for.<col> key (replaced by the view-level
|
|
554
|
+
-- `with defaults (…)` clause) is unknown — still rejected, different reason.
|
|
555
|
+
ALTER TABLE AddCon ADD CONSTRAINT c_chk3 CHECK (id > 0) WITH TAGS ("quereus.update.default_for.id" = '0');
|
|
556
|
+
-- error: unknown reserved tag
|
|
557
|
+
|
|
558
|
+
-- Valid functional tag quereus.expose_implicit_index accepted on an ADD CONSTRAINT
|
|
559
|
+
-- UNIQUE and round-trips through unique_constraint_info (the same tag catalog.ts
|
|
560
|
+
-- reads to surface the implicit covering structure).
|
|
561
|
+
ALTER TABLE AddCon ADD CONSTRAINT uq_code UNIQUE (code) WITH TAGS ("quereus.expose_implicit_index" = true);
|
|
562
|
+
SELECT name, json_extract(tags, '$."quereus.expose_implicit_index"') AS exposed
|
|
563
|
+
FROM unique_constraint_info('AddCon') WHERE name = 'uq_code';
|
|
564
|
+
→ [{"name":"uq_code","exposed":true}]
|
|
565
|
+
|
|
566
|
+
-- Guard against over-rejection: a free-form (non-quereus.*) tag on ADD CONSTRAINT
|
|
567
|
+
-- still applies cleanly and round-trips.
|
|
568
|
+
ALTER TABLE AddCon ADD CONSTRAINT uq_email UNIQUE (email) WITH TAGS (error_message = 'Email must be unique');
|
|
569
|
+
SELECT name, json_extract(tags, '$.error_message') AS msg
|
|
570
|
+
FROM unique_constraint_info('AddCon') WHERE name = 'uq_email';
|
|
571
|
+
→ [{"name":"uq_email","msg":"Email must be unique"}]
|
|
572
|
+
|
|
573
|
+
-- -------------------------------------------------------------------
|
|
574
|
+
-- ADD COLUMN ... WITH TAGS (physical-column + inline physical-constraint sites)
|
|
575
|
+
-- -------------------------------------------------------------------
|
|
576
|
+
|
|
577
|
+
-- Typo'd reserved key on an ADD COLUMN column tag rejected (physical-column site).
|
|
578
|
+
ALTER TABLE AddCol ADD COLUMN y INT WITH TAGS ("quereus.bogus" = 1);
|
|
579
|
+
-- error: reserved tag
|
|
580
|
+
|
|
581
|
+
-- Typo'd reserved key on an ADD COLUMN inline NAMED constraint tag rejected
|
|
582
|
+
-- (physical-constraint site) — the parser lifts the trailing WITH TAGS onto the
|
|
583
|
+
-- named constraint, and the shared columnTagDiagnostics validates it there.
|
|
584
|
+
ALTER TABLE AddCol ADD COLUMN z INT CONSTRAINT cz CHECK (z > 0) WITH TAGS ("quereus.bogus" = 1);
|
|
585
|
+
-- error: reserved tag
|
|
586
|
+
|
|
587
|
+
-- Valid quereus.id accepted on an ADD COLUMN column tag and round-trips via table_info.
|
|
588
|
+
ALTER TABLE AddCol ADD COLUMN c1 INT WITH TAGS ("quereus.id" = 'col-c1');
|
|
589
|
+
SELECT name, json_extract(tags, '$."quereus.id"') AS qid
|
|
590
|
+
FROM table_info('AddCol') WHERE name = 'c1';
|
|
591
|
+
→ [{"name":"c1","qid":"col-c1"}]
|
|
592
|
+
|
|
593
|
+
-- Valid quereus.id accepted on an ADD COLUMN inline NAMED constraint: the tag
|
|
594
|
+
-- validates at the physical-constraint site (quereus.id is legal there), so the
|
|
595
|
+
-- statement is admitted and the column is added. An inline CHECK becomes an
|
|
596
|
+
-- engine-side row-constraint (surfaced via check_constraint_info, not
|
|
597
|
+
-- unique_constraint_info); the c2 case only proves acceptance (no over-rejection).
|
|
598
|
+
-- The inline-UNIQUE constraint-tag round-trip is asserted by the c5 case below
|
|
599
|
+
-- (inline UNIQUE on ADD COLUMN is now materialized via the module's addConstraint
|
|
600
|
+
-- path), and table-level ADD CONSTRAINT by the uq_code case above.
|
|
601
|
+
ALTER TABLE AddCol ADD COLUMN c2 INT CONSTRAINT ck_c2 CHECK (c2 > 0) WITH TAGS ("quereus.id" = 'con-c2');
|
|
602
|
+
SELECT name FROM table_info('AddCol') WHERE name = 'c2';
|
|
603
|
+
→ [{"name":"c2"}]
|
|
604
|
+
|
|
605
|
+
-- Inline UNIQUE on ADD COLUMN is materialized + enforced (routed through the same
|
|
606
|
+
-- module addConstraint UNIQUE path as ALTER … ADD CONSTRAINT … UNIQUE), so a named
|
|
607
|
+
-- inline UNIQUE round-trips its name AND its constraint tag via unique_constraint_info
|
|
608
|
+
-- — closing the prior gap where the inline UNIQUE was silently dropped on this path.
|
|
609
|
+
ALTER TABLE AddCol ADD COLUMN c5 INT CONSTRAINT uq_c5 UNIQUE WITH TAGS ("quereus.id" = 'con-c5');
|
|
610
|
+
SELECT name, json_extract(tags, '$."quereus.id"') AS qid
|
|
611
|
+
FROM unique_constraint_info('AddCol') WHERE name = 'uq_c5';
|
|
612
|
+
→ [{"name":"uq_c5","qid":"con-c5"}]
|
|
613
|
+
|
|
614
|
+
-- Unnamed inline constraint on ADD COLUMN with a trailing WITH TAGS: the parser
|
|
615
|
+
-- defers the tag to the COLUMN (physical-column site), so it validates/stores there
|
|
616
|
+
-- and round-trips on the column via table_info — NOT on the constraint (no double
|
|
617
|
+
-- validation). quereus.id is legal at physical-column, so this is accepted.
|
|
618
|
+
ALTER TABLE AddCol ADD COLUMN c3 INT CHECK (c3 > 0) WITH TAGS ("quereus.id" = 'col-c3');
|
|
619
|
+
SELECT name, json_extract(tags, '$."quereus.id"') AS qid
|
|
620
|
+
FROM table_info('AddCol') WHERE name = 'c3';
|
|
621
|
+
→ [{"name":"c3","qid":"col-c3"}]
|
|
622
|
+
|
|
623
|
+
-- Guard against over-rejection: free-form (non-quereus.*) tags on ADD COLUMN still
|
|
624
|
+
-- apply cleanly and round-trip via table_info.
|
|
625
|
+
ALTER TABLE AddCol ADD COLUMN c4 INT WITH TAGS (display_name = 'C4', searchable = true);
|
|
626
|
+
SELECT name, json_extract(tags, '$.display_name') AS dn, json_extract(tags, '$.searchable') AS searchable
|
|
627
|
+
FROM table_info('AddCol') WHERE name = 'c4';
|
|
628
|
+
→ [{"name":"c4","dn":"C4","searchable":true}]
|
|
629
|
+
|
|
630
|
+
-- -------------------------------------------------------------------
|
|
631
|
+
-- Adversarial coverage: named-ness does not gate ADD CONSTRAINT validation,
|
|
632
|
+
-- and every constraint kind is covered (not just check/unique).
|
|
633
|
+
-- -------------------------------------------------------------------
|
|
634
|
+
|
|
635
|
+
-- Validation fires on an *unnamed* ADD CONSTRAINT too (the tag lives on the
|
|
636
|
+
-- table-level constraint regardless of the optional CONSTRAINT <name> prefix), and
|
|
637
|
+
-- it fires at plan-build *before* any constraint machinery — so the bad tag is the
|
|
638
|
+
-- error, not e.g. a duplicate-constraint complaint.
|
|
639
|
+
ALTER TABLE AddCon ADD CHECK (id < 1000) WITH TAGS ("quereus.bogus" = 1);
|
|
640
|
+
-- error: reserved tag
|
|
641
|
+
|
|
642
|
+
-- A bad tag on an ADD CONSTRAINT FOREIGN KEY is rejected too (the leg iterates every
|
|
643
|
+
-- constraint kind, not just check/unique).
|
|
644
|
+
ALTER TABLE AddCon ADD CONSTRAINT fk_self FOREIGN KEY (code) REFERENCES AddCon (id) WITH TAGS ("quereus.bogus" = 1);
|
|
645
|
+
-- error: reserved tag
|
|
646
|
+
|
|
647
|
+
-- ===================================================================
|
|
648
|
+
-- Phase 25: ALTER TABLE ... ADD TAGS (per-key merge at the table level)
|
|
649
|
+
-- ===================================================================
|
|
650
|
+
|
|
651
|
+
CREATE TABLE Mergeable (
|
|
652
|
+
id INTEGER PRIMARY KEY,
|
|
653
|
+
name TEXT NOT NULL
|
|
654
|
+
);
|
|
655
|
+
|
|
656
|
+
-- ADD onto a target with no tags creates the set.
|
|
657
|
+
ALTER TABLE Mergeable ADD TAGS (audit = true);
|
|
658
|
+
SELECT json_extract(tags, '$.audit') AS audit FROM schema() WHERE type = 'table' AND name = 'Mergeable';
|
|
659
|
+
→ [{"audit":true}]
|
|
660
|
+
|
|
661
|
+
-- ADD overwrites the listed key and keeps the rest (merge, not replace).
|
|
662
|
+
ALTER TABLE Mergeable ADD TAGS (display_name = 'M', audit = false);
|
|
663
|
+
SELECT json_extract(tags, '$.display_name') AS dn, json_extract(tags, '$.audit') AS audit
|
|
664
|
+
FROM schema() WHERE type = 'table' AND name = 'Mergeable';
|
|
665
|
+
→ [{"dn":"M","audit":false}]
|
|
666
|
+
|
|
667
|
+
-- Back-to-back ADD composes onto the prior result (live read at execution time).
|
|
668
|
+
ALTER TABLE Mergeable ADD TAGS (extra = 1);
|
|
669
|
+
SELECT json_extract(tags, '$.display_name') AS dn, json_extract(tags, '$.audit') AS audit,
|
|
670
|
+
json_extract(tags, '$.extra') AS extra
|
|
671
|
+
FROM schema() WHERE type = 'table' AND name = 'Mergeable';
|
|
672
|
+
→ [{"dn":"M","audit":false,"extra":1}]
|
|
673
|
+
|
|
674
|
+
-- ADD with a null value stores the key PRESENT with null (json_type reports 'null'),
|
|
675
|
+
-- distinct from dropping it. Other keys are untouched.
|
|
676
|
+
ALTER TABLE Mergeable ADD TAGS (display_name = null);
|
|
677
|
+
SELECT json_type(tags, '$.display_name') AS dn_type, json_extract(tags, '$.extra') AS extra
|
|
678
|
+
FROM schema() WHERE type = 'table' AND name = 'Mergeable';
|
|
679
|
+
→ [{"dn_type":"null","extra":1}]
|
|
680
|
+
|
|
681
|
+
-- ADD TAGS () is a no-op (does NOT clear) — distinct from SET TAGS ().
|
|
682
|
+
ALTER TABLE Mergeable ADD TAGS ();
|
|
683
|
+
SELECT json_extract(tags, '$.extra') AS extra FROM schema() WHERE type = 'table' AND name = 'Mergeable';
|
|
684
|
+
→ [{"extra":1}]
|
|
685
|
+
|
|
686
|
+
-- ===================================================================
|
|
687
|
+
-- Phase 26: ALTER TABLE ... DROP TAGS (per-key delete at the table level)
|
|
688
|
+
-- ===================================================================
|
|
689
|
+
|
|
690
|
+
-- Current keys: audit=false, display_name=null, extra=1. Drop one, keep the rest.
|
|
691
|
+
ALTER TABLE Mergeable DROP TAGS (extra);
|
|
692
|
+
SELECT json_type(tags, '$.extra') AS extra_type, json_extract(tags, '$.audit') AS audit
|
|
693
|
+
FROM schema() WHERE type = 'table' AND name = 'Mergeable';
|
|
694
|
+
→ [{"extra_type":null,"audit":false}]
|
|
695
|
+
|
|
696
|
+
-- DROP of an absent key fails (NOTFOUND) and drops NOTHING (atomic): audit survives.
|
|
697
|
+
ALTER TABLE Mergeable DROP TAGS (audit, nonexistent);
|
|
698
|
+
-- error: not found
|
|
699
|
+
|
|
700
|
+
SELECT json_extract(tags, '$.audit') AS audit FROM schema() WHERE type = 'table' AND name = 'Mergeable';
|
|
701
|
+
→ [{"audit":false}]
|
|
702
|
+
|
|
703
|
+
-- DROP TAGS () is a no-op.
|
|
704
|
+
ALTER TABLE Mergeable DROP TAGS ();
|
|
705
|
+
SELECT json_extract(tags, '$.audit') AS audit FROM schema() WHERE type = 'table' AND name = 'Mergeable';
|
|
706
|
+
→ [{"audit":false}]
|
|
707
|
+
|
|
708
|
+
-- Drop all remaining keys → tags IS NULL (same end-state as SET TAGS ()).
|
|
709
|
+
ALTER TABLE Mergeable DROP TAGS (audit, display_name);
|
|
710
|
+
SELECT tags FROM schema() WHERE type = 'table' AND name = 'Mergeable';
|
|
711
|
+
→ [{"tags":null}]
|
|
712
|
+
|
|
713
|
+
-- The table still works after the tag churn.
|
|
714
|
+
INSERT INTO Mergeable VALUES (1, 'row');
|
|
715
|
+
SELECT * FROM Mergeable;
|
|
716
|
+
→ [{"id":1,"name":"row"}]
|
|
717
|
+
|
|
718
|
+
-- ===================================================================
|
|
719
|
+
-- Phase 27: ALTER COLUMN ... ADD / DROP TAGS
|
|
720
|
+
-- ===================================================================
|
|
721
|
+
|
|
722
|
+
ALTER TABLE Mergeable ALTER COLUMN name ADD TAGS (searchable = true);
|
|
723
|
+
ALTER TABLE Mergeable ALTER COLUMN name ADD TAGS (display_name = 'Name');
|
|
724
|
+
SELECT json_extract(tags, '$.searchable') AS s, json_extract(tags, '$.display_name') AS dn
|
|
725
|
+
FROM table_info('Mergeable') WHERE name = 'name';
|
|
726
|
+
→ [{"s":true,"dn":"Name"}]
|
|
727
|
+
|
|
728
|
+
-- Column attributes (NOT NULL, type) are untouched by the tag merge.
|
|
729
|
+
SELECT name, type, notnull FROM table_info('Mergeable') WHERE name = 'name';
|
|
730
|
+
→ [{"name":"name","type":"TEXT","notnull":1}]
|
|
731
|
+
|
|
732
|
+
-- DROP one column key, keep the rest.
|
|
733
|
+
ALTER TABLE Mergeable ALTER COLUMN name DROP TAGS (searchable);
|
|
734
|
+
SELECT json_type(tags, '$.searchable') AS s_type, json_extract(tags, '$.display_name') AS dn
|
|
735
|
+
FROM table_info('Mergeable') WHERE name = 'name';
|
|
736
|
+
→ [{"s_type":null,"dn":"Name"}]
|
|
737
|
+
|
|
738
|
+
-- DROP of an absent column key → NOTFOUND (atomic).
|
|
739
|
+
ALTER TABLE Mergeable ALTER COLUMN name DROP TAGS (nope);
|
|
740
|
+
-- error: not found
|
|
741
|
+
|
|
742
|
+
-- DROP the last column key → tags IS NULL.
|
|
743
|
+
ALTER TABLE Mergeable ALTER COLUMN name DROP TAGS (display_name);
|
|
744
|
+
SELECT tags FROM table_info('Mergeable') WHERE name = 'name';
|
|
745
|
+
→ [{"tags":null}]
|
|
746
|
+
|
|
747
|
+
-- ===================================================================
|
|
748
|
+
-- Phase 28: ALTER CONSTRAINT ... ADD / DROP TAGS (named constraint)
|
|
749
|
+
-- ===================================================================
|
|
750
|
+
|
|
751
|
+
CREATE TABLE MergeCon (
|
|
752
|
+
id INTEGER PRIMARY KEY,
|
|
753
|
+
email TEXT NOT NULL,
|
|
754
|
+
CONSTRAINT uq_mc UNIQUE (email)
|
|
755
|
+
);
|
|
756
|
+
|
|
757
|
+
ALTER TABLE MergeCon ALTER CONSTRAINT uq_mc ADD TAGS (msg = 'dup');
|
|
758
|
+
ALTER TABLE MergeCon ALTER CONSTRAINT uq_mc ADD TAGS (sev = 'high');
|
|
759
|
+
SELECT json_extract(tags, '$.msg') AS msg, json_extract(tags, '$.sev') AS sev
|
|
760
|
+
FROM unique_constraint_info('MergeCon') WHERE name = 'uq_mc';
|
|
761
|
+
→ [{"msg":"dup","sev":"high"}]
|
|
762
|
+
|
|
763
|
+
-- The UNIQUE constraint still enforces after the tag churn.
|
|
764
|
+
INSERT INTO MergeCon VALUES (1, 'a@x'), (2, 'b@x');
|
|
765
|
+
INSERT INTO MergeCon VALUES (3, 'a@x');
|
|
766
|
+
-- error: constraint
|
|
767
|
+
|
|
768
|
+
ALTER TABLE MergeCon ALTER CONSTRAINT uq_mc DROP TAGS (msg);
|
|
769
|
+
SELECT json_type(tags, '$.msg') AS msg_type, json_extract(tags, '$.sev') AS sev
|
|
770
|
+
FROM unique_constraint_info('MergeCon') WHERE name = 'uq_mc';
|
|
771
|
+
→ [{"msg_type":null,"sev":"high"}]
|
|
772
|
+
|
|
773
|
+
-- DROP of an absent constraint key → NOTFOUND.
|
|
774
|
+
ALTER TABLE MergeCon ALTER CONSTRAINT uq_mc DROP TAGS (nope);
|
|
775
|
+
-- error: not found
|
|
776
|
+
|
|
777
|
+
-- ===================================================================
|
|
778
|
+
-- Phase 29: ADD validates reserved keys; DROP does not (drop reserved succeeds)
|
|
779
|
+
-- ===================================================================
|
|
780
|
+
|
|
781
|
+
-- ADD validates reserved `quereus.*` keys at plan-build, same as SET TAGS: a typo
|
|
782
|
+
-- fails loudly rather than being stored.
|
|
783
|
+
ALTER TABLE Mergeable ADD TAGS ("quereus.update.taget" = 1);
|
|
784
|
+
-- error: reserved tag
|
|
785
|
+
|
|
786
|
+
-- A valid reserved key at the right site is stored by ADD.
|
|
787
|
+
ALTER TABLE Mergeable ADD TAGS ("quereus.id" = 'tbl-id');
|
|
788
|
+
SELECT json_extract(tags, '$."quereus.id"') AS qid FROM schema() WHERE type = 'table' AND name = 'Mergeable';
|
|
789
|
+
→ [{"qid":"tbl-id"}]
|
|
790
|
+
|
|
791
|
+
-- DROP does no value validation — dropping a reserved key is legitimate and succeeds.
|
|
792
|
+
ALTER TABLE Mergeable DROP TAGS ("quereus.id");
|
|
793
|
+
SELECT tags FROM schema() WHERE type = 'table' AND name = 'Mergeable';
|
|
794
|
+
→ [{"tags":null}]
|
|
795
|
+
|
|
796
|
+
-- ===================================================================
|
|
797
|
+
-- Phase 30: column-named-`tags` disambiguation at the table level
|
|
798
|
+
-- ===================================================================
|
|
799
|
+
|
|
800
|
+
-- Only `ADD TAGS (` / `DROP TAGS (` (TAGS immediately followed by '(') routes to a
|
|
801
|
+
-- tag mutation; `ADD tags <type>` and `DROP [COLUMN] tags` still operate on a column
|
|
802
|
+
-- literally named `tags`.
|
|
803
|
+
|
|
804
|
+
CREATE TABLE DropColTags (id INTEGER PRIMARY KEY, tags TEXT);
|
|
805
|
+
-- `DROP TAGS` with no parens drops the COLUMN named `tags`.
|
|
806
|
+
ALTER TABLE DropColTags DROP TAGS;
|
|
807
|
+
SELECT name FROM table_info('DropColTags') ORDER BY cid;
|
|
808
|
+
→ [{"name":"id"}]
|
|
809
|
+
|
|
810
|
+
CREATE TABLE AddColTags (id INTEGER PRIMARY KEY);
|
|
811
|
+
-- `ADD tags <type>` adds a COLUMN named `tags`.
|
|
812
|
+
ALTER TABLE AddColTags ADD tags integer;
|
|
813
|
+
SELECT name FROM table_info('AddColTags') ORDER BY cid;
|
|
814
|
+
→ [{"name":"id"},{"name":"tags"}]
|
|
815
|
+
|
|
816
|
+
-- Schema-hash neutrality of ADD/DROP TAGS rides the same tag-exclusion path as
|
|
817
|
+
-- SET TAGS; the declarative tag-value-hash-neutral cases live in
|
|
818
|
+
-- test/schema-manager.spec.ts (§ "Schema hashing with tags").
|
|
819
|
+
|
|
820
|
+
-- ===================================================================
|
|
821
|
+
-- Phase 31: adversarial edge cases (ambiguous constraint, dup key, mix)
|
|
822
|
+
-- ===================================================================
|
|
823
|
+
|
|
824
|
+
-- ADD / DROP TAGS share resolveNamedConstraintClass with SET TAGS, so an
|
|
825
|
+
-- ambiguous name (AmbiguousCon from Phase 16 has a UNIQUE and a CHECK both
|
|
826
|
+
-- named `dup`) is rejected identically — not just on SET.
|
|
827
|
+
ALTER TABLE AmbiguousCon ALTER CONSTRAINT dup ADD TAGS (m = 'x');
|
|
828
|
+
-- error: ambiguous
|
|
829
|
+
|
|
830
|
+
ALTER TABLE AmbiguousCon ALTER CONSTRAINT dup DROP TAGS (m);
|
|
831
|
+
-- error: ambiguous
|
|
832
|
+
|
|
833
|
+
-- Dropping the SAME key twice in one list is harmless — the key is present once,
|
|
834
|
+
-- so the presence check passes and the key is removed (the second delete is a
|
|
835
|
+
-- no-op), leaving the rest intact rather than erroring.
|
|
836
|
+
CREATE TABLE DupDropKey (id INTEGER PRIMARY KEY) WITH TAGS (a = 1, b = 2);
|
|
837
|
+
ALTER TABLE DupDropKey DROP TAGS (a, a);
|
|
838
|
+
SELECT json_type(tags, '$.a') AS a_type, json_extract(tags, '$.b') AS b
|
|
839
|
+
FROM schema() WHERE type = 'table' AND name = 'DupDropKey';
|
|
840
|
+
→ [{"a_type":null,"b":2}]
|
|
841
|
+
|
|
842
|
+
-- merge-then-drop across separate statements composes on the live tag set:
|
|
843
|
+
-- the drop sees the merged key and removes it, leaving the survivor.
|
|
844
|
+
CREATE TABLE MixMergeDrop (id INTEGER PRIMARY KEY) WITH TAGS (keep = 1);
|
|
845
|
+
ALTER TABLE MixMergeDrop ADD TAGS (scratch = 2);
|
|
846
|
+
ALTER TABLE MixMergeDrop DROP TAGS (scratch);
|
|
847
|
+
SELECT json_extract(tags, '$.keep') AS keep, json_type(tags, '$.scratch') AS scratch_type
|
|
848
|
+
FROM schema() WHERE type = 'table' AND name = 'MixMergeDrop';
|
|
849
|
+
→ [{"keep":1,"scratch_type":null}]
|
|
850
|
+
|
|
851
|
+
-- ===================================================================
|
|
852
|
+
-- Phase 32: ALTER VIEW ... ADD / DROP TAGS (per-key merge + delete)
|
|
853
|
+
-- ===================================================================
|
|
854
|
+
|
|
855
|
+
CREATE TABLE VBase (id INTEGER PRIMARY KEY, name TEXT);
|
|
856
|
+
INSERT INTO VBase VALUES (1, 'a'), (2, 'b');
|
|
857
|
+
CREATE VIEW VTagged AS SELECT id, name FROM VBase WITH TAGS (a = 1, b = 2);
|
|
858
|
+
|
|
859
|
+
-- ADD merges: overwrite b, keep a, add c (merge, not replace).
|
|
860
|
+
ALTER VIEW VTagged ADD TAGS (b = 99, c = 3);
|
|
861
|
+
SELECT json_extract(tags, '$.a') AS a, json_extract(tags, '$.b') AS b, json_extract(tags, '$.c') AS c
|
|
862
|
+
FROM schema() WHERE type = 'view' AND name = 'VTagged';
|
|
863
|
+
→ [{"a":1,"b":99,"c":3}]
|
|
864
|
+
|
|
865
|
+
-- ADD TAGS () is a no-op (keeps existing) — distinct from SET TAGS ().
|
|
866
|
+
ALTER VIEW VTagged ADD TAGS ();
|
|
867
|
+
SELECT json_extract(tags, '$.a') AS a FROM schema() WHERE type = 'view' AND name = 'VTagged';
|
|
868
|
+
→ [{"a":1}]
|
|
869
|
+
|
|
870
|
+
-- DROP one key, keep the rest.
|
|
871
|
+
ALTER VIEW VTagged DROP TAGS (b);
|
|
872
|
+
SELECT json_type(tags, '$.b') AS b_type, json_extract(tags, '$.a') AS a
|
|
873
|
+
FROM schema() WHERE type = 'view' AND name = 'VTagged';
|
|
874
|
+
→ [{"b_type":null,"a":1}]
|
|
875
|
+
|
|
876
|
+
-- DROP of an absent key → NOTFOUND, atomic (a, c survive).
|
|
877
|
+
ALTER VIEW VTagged DROP TAGS (a, nope);
|
|
878
|
+
-- error: not found
|
|
879
|
+
|
|
880
|
+
SELECT json_extract(tags, '$.a') AS a, json_extract(tags, '$.c') AS c
|
|
881
|
+
FROM schema() WHERE type = 'view' AND name = 'VTagged';
|
|
882
|
+
→ [{"a":1,"c":3}]
|
|
883
|
+
|
|
884
|
+
-- DROP TAGS () is a no-op.
|
|
885
|
+
ALTER VIEW VTagged DROP TAGS ();
|
|
886
|
+
SELECT json_extract(tags, '$.a') AS a FROM schema() WHERE type = 'view' AND name = 'VTagged';
|
|
887
|
+
→ [{"a":1}]
|
|
888
|
+
|
|
889
|
+
-- Drop all remaining keys → tags IS NULL (same end-state as SET TAGS ()).
|
|
890
|
+
ALTER VIEW VTagged DROP TAGS (a, c);
|
|
891
|
+
SELECT tags FROM schema() WHERE type = 'view' AND name = 'VTagged';
|
|
892
|
+
→ [{"tags":null}]
|
|
893
|
+
|
|
894
|
+
-- The view still resolves and returns rows after the tag churn.
|
|
895
|
+
SELECT * FROM VTagged ORDER BY id;
|
|
896
|
+
→ [{"id":1,"name":"a"},{"id":2,"name":"b"}]
|
|
897
|
+
|
|
898
|
+
-- ===================================================================
|
|
899
|
+
-- Phase 33: ALTER INDEX ... ADD / DROP TAGS (per-key merge + delete)
|
|
900
|
+
-- ===================================================================
|
|
901
|
+
-- Lives in 50.0.1-metadata-tags-index (it needs standalone CREATE INDEX).
|
|
902
|
+
|
|
903
|
+
-- ===================================================================
|
|
904
|
+
-- Phase 34: ALTER MATERIALIZED VIEW ... ADD / DROP TAGS (no re-materialization)
|
|
905
|
+
-- ===================================================================
|
|
906
|
+
|
|
907
|
+
CREATE TABLE MTbl (id INTEGER PRIMARY KEY, name TEXT);
|
|
908
|
+
INSERT INTO MTbl VALUES (1, 'M-A'), (2, 'M-B');
|
|
909
|
+
CREATE MATERIALIZED VIEW mv_tagged AS SELECT id, name FROM MTbl WITH TAGS (owner = 'analytics');
|
|
910
|
+
|
|
911
|
+
SELECT id, name FROM mv_tagged ORDER BY id;
|
|
912
|
+
→ [{"id":1,"name":"M-A"},{"id":2,"name":"M-B"}]
|
|
913
|
+
|
|
914
|
+
-- ADD merges as a catalog-only change — the backing data is not rebuilt.
|
|
915
|
+
ALTER MATERIALIZED VIEW mv_tagged ADD TAGS (tier = 'gold');
|
|
916
|
+
SELECT id, name FROM mv_tagged ORDER BY id;
|
|
917
|
+
→ [{"id":1,"name":"M-A"},{"id":2,"name":"M-B"}]
|
|
918
|
+
|
|
919
|
+
-- DROP is catalog-only too — still no rebuild.
|
|
920
|
+
ALTER MATERIALIZED VIEW mv_tagged DROP TAGS (owner);
|
|
921
|
+
SELECT id, name FROM mv_tagged ORDER BY id;
|
|
922
|
+
→ [{"id":1,"name":"M-A"},{"id":2,"name":"M-B"}]
|
|
923
|
+
|
|
924
|
+
-- DROP of an absent key → NOTFOUND (atomic; tier survives).
|
|
925
|
+
ALTER MATERIALIZED VIEW mv_tagged DROP TAGS (nope);
|
|
926
|
+
-- error: not found
|
|
927
|
+
|
|
928
|
+
-- Drop the last key → still no rebuild, data intact.
|
|
929
|
+
ALTER MATERIALIZED VIEW mv_tagged DROP TAGS (tier);
|
|
930
|
+
SELECT id, name FROM mv_tagged ORDER BY id;
|
|
931
|
+
→ [{"id":1,"name":"M-A"},{"id":2,"name":"M-B"}]
|
|
932
|
+
|
|
933
|
+
-- ===================================================================
|
|
934
|
+
-- Phase 35: empty-list distinction for ADD / SET / DROP (view kind)
|
|
935
|
+
-- ===================================================================
|
|
936
|
+
|
|
937
|
+
CREATE TABLE EBase (id INTEGER PRIMARY KEY);
|
|
938
|
+
CREATE VIEW EView AS SELECT id FROM EBase WITH TAGS (k = 1);
|
|
939
|
+
|
|
940
|
+
-- ADD TAGS () keeps the existing set.
|
|
941
|
+
ALTER VIEW EView ADD TAGS ();
|
|
942
|
+
SELECT json_extract(tags, '$.k') AS k FROM schema() WHERE type = 'view' AND name = 'EView';
|
|
943
|
+
→ [{"k":1}]
|
|
944
|
+
|
|
945
|
+
-- DROP TAGS () keeps the existing set.
|
|
946
|
+
ALTER VIEW EView DROP TAGS ();
|
|
947
|
+
SELECT json_extract(tags, '$.k') AS k FROM schema() WHERE type = 'view' AND name = 'EView';
|
|
948
|
+
→ [{"k":1}]
|
|
949
|
+
|
|
950
|
+
-- SET TAGS () clears — the distinguishing case.
|
|
951
|
+
ALTER VIEW EView SET TAGS ();
|
|
952
|
+
SELECT tags FROM schema() WHERE type = 'view' AND name = 'EView';
|
|
953
|
+
→ [{"tags":null}]
|
|
954
|
+
|
|
955
|
+
-- ===================================================================
|
|
956
|
+
-- Phase 36: ADD validates reserved keys; DROP does not (view)
|
|
957
|
+
-- ===================================================================
|
|
958
|
+
|
|
959
|
+
-- ADD rejects an unknown reserved key at the view-ddl site (same as SET TAGS).
|
|
960
|
+
ALTER VIEW VTagged ADD TAGS ("quereus.bogus" = 1);
|
|
961
|
+
-- error: reserved tag
|
|
962
|
+
|
|
963
|
+
-- The physical-index site of the same ADD rejection is in 50.0.1-metadata-tags-index.
|
|
964
|
+
|
|
965
|
+
-- A valid reserved key at the right site is stored by ADD (quereus.id is legal at
|
|
966
|
+
-- view-ddl), then DROP removes it without value validation — dropping a reserved
|
|
967
|
+
-- key is legitimate.
|
|
968
|
+
ALTER VIEW VTagged ADD TAGS ("quereus.id" = 'view-thing');
|
|
969
|
+
SELECT json_extract(tags, '$."quereus.id"') AS qid FROM schema() WHERE type = 'view' AND name = 'VTagged';
|
|
970
|
+
→ [{"qid":"view-thing"}]
|
|
971
|
+
ALTER VIEW VTagged DROP TAGS ("quereus.id");
|
|
972
|
+
SELECT tags FROM schema() WHERE type = 'view' AND name = 'VTagged';
|
|
973
|
+
→ [{"tags":null}]
|
|
974
|
+
|
|
975
|
+
-- The index equivalent (quereus.id added then dropped) is in 50.0.1-metadata-tags-index.
|
|
976
|
+
|
|
977
|
+
-- ===================================================================
|
|
978
|
+
-- Phase 37: hidden implicit covering index is not addressable for ADD / DROP
|
|
979
|
+
-- ===================================================================
|
|
980
|
+
|
|
981
|
+
-- Employees (Phase 3) has a named UNIQUE constraint uq_email whose implicit
|
|
982
|
+
-- covering structure is hidden — ADD / DROP TAGS must treat it as NOTFOUND
|
|
983
|
+
-- (its tags live on the constraint), mirroring SET TAGS (Phase 22).
|
|
984
|
+
ALTER INDEX uq_email ADD TAGS (a = 1);
|
|
985
|
+
-- error: not found
|
|
986
|
+
|
|
987
|
+
ALTER INDEX uq_email DROP TAGS (a);
|
|
988
|
+
-- error: not found
|
|
989
|
+
|
|
990
|
+
-- ===================================================================
|
|
991
|
+
-- Phase 38: exposed implicit covering index becomes addressable for ADD / DROP
|
|
992
|
+
-- ===================================================================
|
|
993
|
+
|
|
994
|
+
CREATE TABLE ExpoTbl (
|
|
995
|
+
id INTEGER PRIMARY KEY,
|
|
996
|
+
vin TEXT,
|
|
997
|
+
CONSTRAINT uq_expo_vin UNIQUE (vin) WITH TAGS ("quereus.expose_implicit_index" = true)
|
|
998
|
+
);
|
|
999
|
+
|
|
1000
|
+
-- The exposed implicit index is user-addressable: ADD merges onto its tags.
|
|
1001
|
+
ALTER INDEX uq_expo_vin ADD TAGS (purpose = 'lookup');
|
|
1002
|
+
SELECT json_extract(tags, '$.purpose') AS purpose
|
|
1003
|
+
FROM schema() WHERE type = 'index' AND name = 'uq_expo_vin';
|
|
1004
|
+
→ [{"purpose":"lookup"}]
|
|
1005
|
+
|
|
1006
|
+
-- DROP removes the key (visibility is governed by the constraint, so the index
|
|
1007
|
+
-- stays addressable).
|
|
1008
|
+
ALTER INDEX uq_expo_vin DROP TAGS (purpose);
|
|
1009
|
+
SELECT json_type(tags, '$.purpose') AS purpose_type
|
|
1010
|
+
FROM schema() WHERE type = 'index' AND name = 'uq_expo_vin';
|
|
1011
|
+
→ [{"purpose_type":null}]
|
|
1012
|
+
|
|
1013
|
+
-- ===================================================================
|
|
1014
|
+
-- Phase 39: NOTFOUND object for ADD / DROP (view, materialized view, index)
|
|
1015
|
+
-- ===================================================================
|
|
1016
|
+
|
|
1017
|
+
ALTER VIEW NoSuchV ADD TAGS (a = 1);
|
|
1018
|
+
-- error: not found
|
|
1019
|
+
|
|
1020
|
+
ALTER VIEW NoSuchV DROP TAGS (a);
|
|
1021
|
+
-- error: not found
|
|
1022
|
+
|
|
1023
|
+
ALTER MATERIALIZED VIEW NoSuchMv ADD TAGS (a = 1);
|
|
1024
|
+
-- error: not found
|
|
1025
|
+
|
|
1026
|
+
ALTER MATERIALIZED VIEW NoSuchMv DROP TAGS (a);
|
|
1027
|
+
-- error: not found
|
|
1028
|
+
|
|
1029
|
+
ALTER INDEX NoSuchIx ADD TAGS (a = 1);
|
|
1030
|
+
-- error: not found
|
|
1031
|
+
|
|
1032
|
+
ALTER INDEX NoSuchIx DROP TAGS (a);
|
|
1033
|
+
-- error: not found
|