@quereus/quereus 4.20.1 → 4.20.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/package.json +7 -4
- package/test/README.md +173 -0
- package/test/logic/01-basic.sqllogic +39 -0
- package/test/logic/01.1-select-projection-extras.sqllogic +130 -0
- package/test/logic/01.2-strings.sqllogic +43 -0
- package/test/logic/01.5-insert-select.sqllogic +237 -0
- package/test/logic/01.6-update-extras.sqllogic +118 -0
- package/test/logic/01.7-update-from.sqllogic +67 -0
- package/test/logic/01.8-delete-extras.sqllogic +122 -0
- package/test/logic/01.8.1-delete-range-cow.sqllogic +115 -0
- package/test/logic/01.9-query-expr-dml-gates.sqllogic +32 -0
- package/test/logic/01.9-query-expr-dml.sqllogic +171 -0
- package/test/logic/01.9-query-expr-values.sqllogic +111 -0
- package/test/logic/01.9.1-limit-over-dml-subquery.sqllogic +119 -0
- package/test/logic/02-filters.sqllogic +54 -0
- package/test/logic/02-smoke.sqllogic +62 -0
- package/test/logic/02.1-bind-parameters.sqllogic +223 -0
- package/test/logic/03-expressions.sqllogic +190 -0
- package/test/logic/03.1-quoted-identifiers.sqllogic +55 -0
- package/test/logic/03.4-defaults.sqllogic +554 -0
- package/test/logic/03.4.1-default-edge-cases.sqllogic +99 -0
- package/test/logic/03.5-tvf.sqllogic +61 -0
- package/test/logic/03.6-type-system.sqllogic +544 -0
- package/test/logic/03.6.1-numeric-text-comparison-coercion.sqllogic +244 -0
- package/test/logic/03.6.2-value-to-text.sqllogic +224 -0
- package/test/logic/03.7-bigint-mixed-arithmetic.sqllogic +65 -0
- package/test/logic/03.8-not-precedence.sqllogic +255 -0
- package/test/logic/03.9-is-bool-predicate.sqllogic +150 -0
- package/test/logic/03.9.1-is-bool-predicate-partial-index.sqllogic +34 -0
- package/test/logic/04-order-by.sqllogic +38 -0
- package/test/logic/04-transactions.sqllogic +239 -0
- package/test/logic/04a-savepoint-lazy-attach.sqllogic +122 -0
- package/test/logic/05-vtab_memory.sqllogic +50 -0
- package/test/logic/05.0.1-vtab-memory-unique-index-collation.sqllogic +34 -0
- package/test/logic/05.1-composite-pk-range-scan.sqllogic +147 -0
- package/test/logic/05.1.1-secondary-index-range-scan.sqllogic +56 -0
- package/test/logic/05.2-cast-seek-correctness.sqllogic +124 -0
- package/test/logic/06-builtin_functions.sqllogic +149 -0
- package/test/logic/06.1-string-functions.sqllogic +92 -0
- package/test/logic/06.1.3-like-glob-edges.sqllogic +53 -0
- package/test/logic/06.2-math-functions.sqllogic +82 -0
- package/test/logic/06.3-schema.sqllogic +48 -0
- package/test/logic/06.3.1-schema-all-schemas.sqllogic +39 -0
- package/test/logic/06.3.2-schema-foreign-keys.sqllogic +208 -0
- package/test/logic/06.3.3-introspection-tags.sqllogic +202 -0
- package/test/logic/06.3.3.1-introspection-tags-index.sqllogic +74 -0
- package/test/logic/06.3.4-view-info.sqllogic +378 -0
- package/test/logic/06.3.5-column-info.sqllogic +347 -0
- package/test/logic/06.3.6-schema-views.sqllogic +29 -0
- package/test/logic/06.4-schema-search-path.sqllogic +354 -0
- package/test/logic/06.4.1-schema-case-insensitive.sqllogic +83 -0
- package/test/logic/06.4.2-collation-extras.sqllogic +472 -0
- package/test/logic/06.4.2.1-collation-index-access-paths.sqllogic +140 -0
- package/test/logic/06.4.3-write-path-collation.sqllogic +99 -0
- package/test/logic/06.4.4-comparison-collation-precedence.sqllogic +342 -0
- package/test/logic/06.4.5-any-collate-declared-keys.sqllogic +92 -0
- package/test/logic/06.5-polymorphic-types.sqllogic +169 -0
- package/test/logic/06.5.1-conversion-functions.sqllogic +173 -0
- package/test/logic/06.5.2-scalar-minmax.sqllogic +16 -0
- package/test/logic/06.5.3-undeclared-return-type-comparison.sqllogic +244 -0
- package/test/logic/06.5.4-declared-return-type-builtins.sqllogic +288 -0
- package/test/logic/06.6-aggregate-extended.sqllogic +78 -0
- package/test/logic/06.7-json-extended.sqllogic +53 -0
- package/test/logic/06.8-json-path-operators.sqllogic +99 -0
- package/test/logic/06.9-json-canonical-key.sqllogic +65 -0
- package/test/logic/06.9.1-json-coerce-once.sqllogic +417 -0
- package/test/logic/06.9.1.1-json-coerce-once-index.sqllogic +39 -0
- package/test/logic/06.9.2-json-structural-equality.sqllogic +382 -0
- package/test/logic/06.9.2.1-json-structural-equality-index.sqllogic +76 -0
- package/test/logic/06.9.3-json-index-range-seek.sqllogic +205 -0
- package/test/logic/07-aggregates.sqllogic +193 -0
- package/test/logic/07.1-aggregate-filter-clause.sqllogic +12 -0
- package/test/logic/07.2-aggregate-order-by.sqllogic +11 -0
- package/test/logic/07.3-group-by-extras.sqllogic +602 -0
- package/test/logic/07.3.1-group-by-order-by-key.sqllogic +164 -0
- package/test/logic/07.3.2-grouped-select-list-shape.sqllogic +231 -0
- package/test/logic/07.4-group-by-filter-composite-pk.sqllogic +120 -0
- package/test/logic/07.5-sum-mixed-exact-and-float.sqllogic +151 -0
- package/test/logic/07.5-window.sqllogic +1941 -0
- package/test/logic/07.5.1-window-named.sqllogic +13 -0
- package/test/logic/07.5.2-window-nth-value.sqllogic +13 -0
- package/test/logic/07.6-subqueries.sqllogic +78 -0
- package/test/logic/07.6.1-subquery-extras.sqllogic +93 -0
- package/test/logic/07.7-and-or-short-circuit.sqllogic +58 -0
- package/test/logic/07.7-in-subquery-caching.sqllogic +174 -0
- package/test/logic/07.7-scalar-agg-decorrelation.sqllogic +197 -0
- package/test/logic/07.7.1-in-extras.sqllogic +158 -0
- package/test/logic/07.7.1-scalar-agg-decorrelation-filter.sqllogic +105 -0
- package/test/logic/07.7.2-scalar-agg-decorrelation-nested.sqllogic +115 -0
- package/test/logic/07.7.3-exists-in-select-decorrelation.sqllogic +107 -0
- package/test/logic/07.7.4-where-conjunct-ordering.sqllogic +121 -0
- package/test/logic/07.7.5-filter-lost-under-index-order.sqllogic +134 -0
- package/test/logic/07.7.6-correlated-predicate-scope.sqllogic +178 -0
- package/test/logic/07.7.7-join-source-scope-shadowing.sqllogic +137 -0
- package/test/logic/07.7.8-correlated-ref-to-computed-column.sqllogic +165 -0
- package/test/logic/07.7.9-conjunct-monotonicity.sqllogic +200 -0
- package/test/logic/07.8-correlated-subquery-edges.sqllogic +71 -0
- package/test/logic/07.8.1-correlated-in-decorrelation-gates.sqllogic +156 -0
- package/test/logic/07.9-in-value-list.sqllogic +154 -0
- package/test/logic/07.9.1-in-value-list-composite-index.sqllogic +38 -0
- package/test/logic/08-views.sqllogic +64 -0
- package/test/logic/08.1-semi-anti-join.sqllogic +191 -0
- package/test/logic/08.1-view-edge-cases.sqllogic +118 -0
- package/test/logic/08.1.1-uncorrelated-in-semijoin.sqllogic +251 -0
- package/test/logic/08.2-existence-flag-semijoin-recovery.sqllogic +197 -0
- package/test/logic/08.3-existence-flag-inner-recovery.sqllogic +102 -0
- package/test/logic/08.4-key-set-semi-join.sqllogic +447 -0
- package/test/logic/09-set_operations.sqllogic +244 -0
- package/test/logic/09.1-set-op-cross-collation.sqllogic +230 -0
- package/test/logic/10-distinct_datatypes.sqllogic +127 -0
- package/test/logic/10.1-ddl-lifecycle.sqllogic +203 -0
- package/test/logic/10.1.1-create-table-syntax-edges.sqllogic +47 -0
- package/test/logic/10.1.2-ddl-in-transaction.sqllogic +143 -0
- package/test/logic/10.1.2.1-add-constraint-in-transaction.sqllogic +59 -0
- package/test/logic/10.1.3-ddl-drop-in-transaction.sqllogic +187 -0
- package/test/logic/10.1.3.1-drop-constraint-in-transaction.sqllogic +45 -0
- package/test/logic/10.1.4-create-table-duplicate-constraint-names.sqllogic +149 -0
- package/test/logic/10.1.4-ddl-transaction-policy.sqllogic +314 -0
- package/test/logic/10.1.5-alter-add-constraint-minted-name-disambiguation.sqllogic +219 -0
- package/test/logic/10.1.5-create-index-lifecycle.sqllogic +72 -0
- package/test/logic/10.1.6-ddl-transaction-policy-index.sqllogic +143 -0
- package/test/logic/10.1.7-create-table-default-type-check.sqllogic +119 -0
- package/test/logic/10.1.8-alter-add-check-existing-rows.sqllogic +117 -0
- package/test/logic/10.2-column-features.sqllogic +365 -0
- package/test/logic/10.2.1-table-options-rejection.sqllogic +63 -0
- package/test/logic/10.2.2-default-collation-memory.sqllogic +30 -0
- package/test/logic/10.3-function-features.sqllogic +247 -0
- package/test/logic/10.4-schema-scale.sqllogic +168 -0
- package/test/logic/10.4.1-schema-scale-indexes.sqllogic +121 -0
- package/test/logic/10.5-indexes.sqllogic +164 -0
- package/test/logic/10.5.1-partial-indexes.sqllogic +526 -0
- package/test/logic/10.5.2-expression-indexes.sqllogic +34 -0
- package/test/logic/10.5.3-desc-index-ordering.sqllogic +130 -0
- package/test/logic/10.5.4-composite-pk-index-update-phantom.sqllogic +55 -0
- package/test/logic/10.5.5-index-name-uniqueness.sqllogic +76 -0
- package/test/logic/10.5.6-minmax-index-boundary.sqllogic +204 -0
- package/test/logic/10.5.7-implicit-unique-index-lifecycle.sqllogic +1216 -0
- package/test/logic/10.6-distinct-edge-cases.sqllogic +119 -0
- package/test/logic/100-predicate-normalization-edge-cases.sqllogic +238 -0
- package/test/logic/100.1-where-extras.sqllogic +163 -0
- package/test/logic/100.1.1-where-join-on-order-indexed.sqllogic +35 -0
- package/test/logic/101-builtin-mutation-kills.sqllogic +974 -0
- package/test/logic/101-transaction-edge-cases.sqllogic +395 -0
- package/test/logic/102-schema-catalog-edge-cases.sqllogic +252 -0
- package/test/logic/102-unique-constraints.sqllogic +145 -0
- package/test/logic/102.0.1-schema-catalog-indexed-table.sqllogic +32 -0
- package/test/logic/102.1-unique-edge-cases.sqllogic +111 -0
- package/test/logic/102.1.1-unique-index-creation-edge-cases.sqllogic +75 -0
- package/test/logic/102.2-unique-collation.sqllogic +181 -0
- package/test/logic/102.2.1-unique-collation-index-derived.sqllogic +305 -0
- package/test/logic/103-database-options-edge-cases.sqllogic +108 -0
- package/test/logic/103.1-pragma-boolean-values.sqllogic +126 -0
- package/test/logic/104-emit-mutation-kills.sqllogic +236 -0
- package/test/logic/105-vtab-memory-mutation-kills.sqllogic +754 -0
- package/test/logic/105.1-vtab-memory-index-mutation-kills.sqllogic +540 -0
- package/test/logic/106-constraint-extractor-mutation-kills.sqllogic +350 -0
- package/test/logic/107-temporal-arithmetic-mutation-kills.sqllogic +833 -0
- package/test/logic/108-cardinality-estimation.sqllogic +146 -0
- package/test/logic/108.1-analyze-name-resolution.sqllogic +102 -0
- package/test/logic/109-aggregate-physical-selection.sqllogic +103 -0
- package/test/logic/11-joins.sqllogic +86 -0
- package/test/logic/11.1-join-using.sqllogic +267 -0
- package/test/logic/11.2-comma-join.sqllogic +35 -0
- package/test/logic/11.3-index-nested-loop-join.sqllogic +305 -0
- package/test/logic/11.3-mismatched-collation-join.sqllogic +74 -0
- package/test/logic/11.4-hash-join-side-swap.sqllogic +118 -0
- package/test/logic/110-scan-emitter-mutation-kills.sqllogic +121 -0
- package/test/logic/110.1-scan-emitter-index-scan-kills.sqllogic +47 -0
- package/test/logic/12-empty-primary-key.sqllogic +124 -0
- package/test/logic/12-join_padding_order.sqllogic +58 -0
- package/test/logic/12.1-orderby-index-consumption.sqllogic +40 -0
- package/test/logic/13-cte.sqllogic +137 -0
- package/test/logic/13.1-cte-multiple-recursive.sqllogic +104 -0
- package/test/logic/13.10-cte-qualified-name.sqllogic +136 -0
- package/test/logic/13.11-unreferenced-dml-cte.sqllogic +414 -0
- package/test/logic/13.12-nested-dml-cte-rejected.sqllogic +280 -0
- package/test/logic/13.2-cte-bind-params.sqllogic +98 -0
- package/test/logic/13.3-cte-edge-cases.sqllogic +120 -0
- package/test/logic/13.4-cte-extras.sqllogic +98 -0
- package/test/logic/13.5-cte-join-order.sqllogic +166 -0
- package/test/logic/13.6-cte-dml-runs-once.sqllogic +318 -0
- package/test/logic/13.7-cte-sibling-visibility.sqllogic +227 -0
- package/test/logic/13.8-insert-with-clause-visibility.sqllogic +254 -0
- package/test/logic/13.9-schema-authored-cte-isolation.sqllogic +328 -0
- package/test/logic/13.9.1-schema-authored-schema-path-isolation.sqllogic +408 -0
- package/test/logic/14-utilities.sqllogic +168 -0
- package/test/logic/15-timespan.sqllogic +279 -0
- package/test/logic/15.1-semantic-ordering.sqllogic +960 -0
- package/test/logic/15.1.1-json-check-coercion.sqllogic +178 -0
- package/test/logic/15.1.2-semantic-ordering-index.sqllogic +41 -0
- package/test/logic/15.1.3-declared-form-write-contract.sqllogic +519 -0
- package/test/logic/16-epoch.sqllogic +187 -0
- package/test/logic/17-weekday-modifier.sqllogic +78 -0
- package/test/logic/18-json-string-escapes.sqllogic +86 -0
- package/test/logic/18-strftime-extended-formats.sqllogic +68 -0
- package/test/logic/20-empty-single-row.sqllogic +261 -0
- package/test/logic/21-null-edge-cases.sqllogic +227 -0
- package/test/logic/21.1-where-null-comparisons.sqllogic +151 -0
- package/test/logic/21.1.1-where-null-comparisons-secondary-index.sqllogic +35 -0
- package/test/logic/21.2-between-edges.sqllogic +157 -0
- package/test/logic/22-boundary-values.sqllogic +175 -0
- package/test/logic/23-self-joins-duplicates.sqllogic +74 -0
- package/test/logic/24-builtin-branches.sqllogic +611 -0
- package/test/logic/24.1-substr-extras.sqllogic +75 -0
- package/test/logic/24.2-random-extras.sqllogic +39 -0
- package/test/logic/25-aggregate-edge-cases.sqllogic +289 -0
- package/test/logic/25.1-nested-aggregates.sqllogic +74 -0
- package/test/logic/25.2-having-edge-cases.sqllogic +318 -0
- package/test/logic/25.3-aggregate-isnull-empty.sqllogic +16 -0
- package/test/logic/25.4-groupby-fd-constant-empty.sqllogic +55 -0
- package/test/logic/25.5-ungrouped-aggregate-column-free-select-item.sqllogic +196 -0
- package/test/logic/26-join-edge-cases.sqllogic +333 -0
- package/test/logic/26.1-left-join-isnull-on-notnull.sqllogic +26 -0
- package/test/logic/26.2-left-join-on-vs-where.sqllogic +67 -0
- package/test/logic/26.3-join-on-constants.sqllogic +61 -0
- package/test/logic/26.4-join-on-is-null-nullable.sqllogic +44 -0
- package/test/logic/27-window-edge-cases.sqllogic +206 -0
- package/test/logic/27.1-window-groups-frame.sqllogic +13 -0
- package/test/logic/27.2-window-exclude.sqllogic +13 -0
- package/test/logic/27.3-window-json-aggregation.sqllogic +66 -0
- package/test/logic/28-set-ops-sort-edge-cases.sqllogic +444 -0
- package/test/logic/28.1-compound-limit-offset.sqllogic +143 -0
- package/test/logic/28.2-orderby-expression-extras.sqllogic +698 -0
- package/test/logic/28.2-set-op-branch-types.sqllogic +217 -0
- package/test/logic/29-constraint-edge-cases.sqllogic +442 -0
- package/test/logic/29.1-column-level-conflict-clause.sqllogic +171 -0
- package/test/logic/29.2-table-level-pk-conflict-clause.sqllogic +113 -0
- package/test/logic/40-constraints.sqllogic +418 -0
- package/test/logic/40.1-pk-desc-direction.sqllogic +76 -0
- package/test/logic/40.2-check-extras.sqllogic +683 -0
- package/test/logic/41-alter-table.sqllogic +191 -0
- package/test/logic/41-fk-cascade-conflict-and-self-ref.sqllogic +263 -0
- package/test/logic/41-fk-cross-schema.sqllogic +155 -0
- package/test/logic/41-fk-extended-targets.sqllogic +173 -0
- package/test/logic/41-foreign-keys.sqllogic +1001 -0
- package/test/logic/41-generated-column-errors.sqllogic +225 -0
- package/test/logic/41-generated-column-extras.sqllogic +598 -0
- package/test/logic/41-generated-column-scope.sqllogic +329 -0
- package/test/logic/41-generated-columns.sqllogic +361 -0
- package/test/logic/41.1-alter-pk.sqllogic +230 -0
- package/test/logic/41.1-fk-collation-conflict.sqllogic +277 -0
- package/test/logic/41.10-alter-drop-column-foreign-key.sqllogic +274 -0
- package/test/logic/41.10.1-alter-drop-column-unique-index.sqllogic +169 -0
- package/test/logic/41.10.2-alter-drop-column-check-and-assertion.sqllogic +1616 -0
- package/test/logic/41.10.3-alter-drop-column-referencing-fk.sqllogic +292 -0
- package/test/logic/41.10.4-drop-object-expression-dependents.sqllogic +602 -0
- package/test/logic/41.11-deferred-fk-with-rename.sqllogic +232 -0
- package/test/logic/41.12-alter-default-coercion.sqllogic +200 -0
- package/test/logic/41.13-alter-add-column-generated-backfill.sqllogic +566 -0
- package/test/logic/41.14-alter-add-column-subquery-backfill.sqllogic +129 -0
- package/test/logic/41.15-alter-column-default-type-check.sqllogic +178 -0
- package/test/logic/41.16-fk-unenforceable.sqllogic +364 -0
- package/test/logic/41.2-alter-column.sqllogic +382 -0
- package/test/logic/41.2.1-alter-column-retype-deleted-row-memory.sqllogic +32 -0
- package/test/logic/41.2.2-alter-column-retype-index-rebuild.sqllogic +77 -0
- package/test/logic/41.2.3-alter-column-set-not-null-pk-backfill.sqllogic +310 -0
- package/test/logic/41.2.3.1-alter-column-set-not-null-pk-backfill-secondary-index.sqllogic +37 -0
- package/test/logic/41.3-alter-add-column-unique.sqllogic +184 -0
- package/test/logic/41.3-alter-rename-propagation.sqllogic +2352 -0
- package/test/logic/41.3.1-alter-rename-index-propagation.sqllogic +94 -0
- package/test/logic/41.4-alter-add-column-constraints.sqllogic +855 -0
- package/test/logic/41.5-alter-misc.sqllogic +48 -0
- package/test/logic/41.5-cross-schema-foreign-keys.sqllogic +253 -0
- package/test/logic/41.6-alter-drop-rename-constraint.sqllogic +354 -0
- package/test/logic/41.6.1-alter-drop-constraint-index-derived.sqllogic +22 -0
- package/test/logic/41.7-alter-column-collate.sqllogic +105 -0
- package/test/logic/41.7.1-alter-column-collate-unique.sqllogic +45 -0
- package/test/logic/41.7.2-alter-column-collate-unique-store.sqllogic +208 -0
- package/test/logic/41.7.2.1-alter-column-collate-unique-index-store.sqllogic +114 -0
- package/test/logic/41.7.3-alter-column-retype-unique.sqllogic +293 -0
- package/test/logic/41.7.3.1-alter-column-retype-staged-rows-memory.sqllogic +41 -0
- package/test/logic/41.7.3.2-alter-column-retype-unique-index.sqllogic +72 -0
- package/test/logic/41.7.4-alter-column-retype-semantic-memory.sqllogic +445 -0
- package/test/logic/41.7.4.1-alter-column-retype-semantic-index-memory.sqllogic +91 -0
- package/test/logic/41.7.5-alter-column-collate-pk-staged-delete-memory.sqllogic +106 -0
- package/test/logic/41.8-alter-add-constraint-unique-fk.sqllogic +275 -0
- package/test/logic/41.8-alter-savepoint-staged-rows.sqllogic +443 -0
- package/test/logic/41.8.1-alter-rename-savepoint-staged-rows.sqllogic +408 -0
- package/test/logic/41.9-alter-constraint-body-change.sqllogic +180 -0
- package/test/logic/41.9-fk-restrict-batched.sqllogic +290 -0
- package/test/logic/42-committed-snapshot.sqllogic +254 -0
- package/test/logic/42-returning.sqllogic +159 -0
- package/test/logic/42.1-returning-extras.sqllogic +232 -0
- package/test/logic/42.2-returning-stored-row.sqllogic +165 -0
- package/test/logic/43-default-nullability.sqllogic +131 -0
- package/test/logic/43-transition-constraints.sqllogic +341 -0
- package/test/logic/43.1-default-collation.sqllogic +140 -0
- package/test/logic/43.1-notnull-or-conflict.sqllogic +79 -0
- package/test/logic/43.2-deferred-check-new-on-delete.sqllogic +95 -0
- package/test/logic/43.3-nullable-primary-key.sqllogic +587 -0
- package/test/logic/44-determinism-validation.sqllogic +164 -0
- package/test/logic/44-orthogonality.sqllogic +146 -0
- package/test/logic/44.1-nondeterministic-schema.sqllogic +316 -0
- package/test/logic/45-udf-determinism.sqllogic +39 -0
- package/test/logic/46-mutation-context.sqllogic +595 -0
- package/test/logic/47-upsert.sqllogic +255 -0
- package/test/logic/47.1-upsert-conflict-targets.sqllogic +169 -0
- package/test/logic/47.2-replace-and-or-clauses.sqllogic +164 -0
- package/test/logic/47.2.1-pk-replace-secondary-unique.sqllogic +374 -0
- package/test/logic/47.3-engine-or-fail.sqllogic +122 -0
- package/test/logic/47.3-upsert-conflict-target-collation.sqllogic +139 -0
- package/test/logic/47.3.1-upsert-conflict-index-derived-collation.sqllogic +25 -0
- package/test/logic/47.4-upsert-conflict-target-affinity.sqllogic +59 -0
- package/test/logic/47.5-upsert-do-update-constraints.sqllogic +440 -0
- package/test/logic/47.6-upsert-do-update-decomposed.sqllogic +100 -0
- package/test/logic/49-reference-graph.sqllogic +84 -0
- package/test/logic/50-declarative-schema.sqllogic +2550 -0
- package/test/logic/50-metadata-tags.sqllogic +1033 -0
- package/test/logic/50.0.1-metadata-tags-index.sqllogic +141 -0
- package/test/logic/50.1-declare-schema-pk.sqllogic +150 -0
- package/test/logic/50.2-declare-schema-renames.sqllogic +949 -0
- package/test/logic/50.2.1-declare-schema-index-renames.sqllogic +173 -0
- package/test/logic/50.3-declare-schema-duplicate-names.sqllogic +280 -0
- package/test/logic/50.4-declare-schema-apply-restore.sqllogic +192 -0
- package/test/logic/51-lens-foundation.sqllogic +147 -0
- package/test/logic/51-materialized-views.sqllogic +376 -0
- package/test/logic/51.5-materialized-views-coarsened-key.sqllogic +198 -0
- package/test/logic/51.7-maintained-table-attach-detach.sqllogic +468 -0
- package/test/logic/51.8-maintained-table-declared-constraints.sqllogic +440 -0
- package/test/logic/51.85-maintained-table-parent-fk.sqllogic +103 -0
- package/test/logic/51.9-maintained-table-secondary-unique.sqllogic +237 -0
- package/test/logic/51.9.1-maintained-table-partial-unique.sqllogic +36 -0
- package/test/logic/52-lens-overrides.sqllogic +566 -0
- package/test/logic/53-materialized-views-rowtime.sqllogic +1601 -0
- package/test/logic/53-reserved-tags.sqllogic +252 -0
- package/test/logic/53.1-materialized-view-write-through.sqllogic +329 -0
- package/test/logic/53.2-materialized-view-rename-propagation.sqllogic +483 -0
- package/test/logic/53.3-materialized-view-constraint-only-ddl.sqllogic +409 -0
- package/test/logic/53.3.1-materialized-view-index-ddl-irrelevance.sqllogic +29 -0
- package/test/logic/53.4-materialized-view-structural-alter-restore.sqllogic +436 -0
- package/test/logic/54-covering-mv-enforcement.sqllogic +314 -0
- package/test/logic/54.1-covering-mv-partial-enforcement.sqllogic +34 -0
- package/test/logic/55-internal-eviction-reporting.sqllogic +89 -0
- package/test/logic/55-lens-prover.sqllogic +202 -0
- package/test/logic/55.1-eviction-restrict-fk.sqllogic +148 -0
- package/test/logic/55.5-lens-authored-inverse.sqllogic +1468 -0
- package/test/logic/80-grow-retrieve-pass.sqllogic +79 -0
- package/test/logic/81-quickpick.sqllogic +24 -0
- package/test/logic/82-bloom-join.sqllogic +185 -0
- package/test/logic/83-merge-join.sqllogic +280 -0
- package/test/logic/84-asof-scan.sqllogic +238 -0
- package/test/logic/84-key-cardinality.sqllogic +50 -0
- package/test/logic/85-relational-const-folding.sqllogic +51 -0
- package/test/logic/86-scalar-cse.sqllogic +42 -0
- package/test/logic/90-error_paths.sqllogic +114 -0
- package/test/logic/90.1-parse-errors.sqllogic +77 -0
- package/test/logic/90.2-alter-table-errors.sqllogic +53 -0
- package/test/logic/90.2.1-alter-extra-errors.sqllogic +51 -0
- package/test/logic/90.3-expression-errors.sqllogic +43 -0
- package/test/logic/90.4-dml-errors.sqllogic +47 -0
- package/test/logic/90.5-unsupported-join-types.sqllogic +37 -0
- package/test/logic/90.5.1-right-full-join-read.sqllogic +157 -0
- package/test/logic/90.6-select-error-paths.sqllogic +57 -0
- package/test/logic/91-merge-join-edge-cases.sqllogic +159 -0
- package/test/logic/92-hash-aggregate-edge-cases.sqllogic +139 -0
- package/test/logic/93-ddl-view-edge-cases.sqllogic +104 -0
- package/test/logic/93.1-view-error-paths.sqllogic +74 -0
- package/test/logic/93.2-view-mutation-pending.sqllogic +108 -0
- package/test/logic/93.3-view-mutation-or-clause.sqllogic +60 -0
- package/test/logic/93.4-view-mutation.sqllogic +4881 -0
- package/test/logic/93.4.1-view-mutation-partial-unique-cardinality.sqllogic +31 -0
- package/test/logic/93.5-authored-inverse.sqllogic +415 -0
- package/test/logic/93.6-set-op-flagless-write.sqllogic +862 -0
- package/test/logic/94-tvf-edge-cases.sqllogic +58 -0
- package/test/logic/94.1-limit-offset-edge-cases.sqllogic +109 -0
- package/test/logic/94.2-limit-offset-extras.sqllogic +98 -0
- package/test/logic/95-assertions.sqllogic +1417 -0
- package/test/logic/96-subquery-edge-cases.sqllogic +276 -0
- package/test/logic/97-json-function-edge-cases.sqllogic +633 -0
- package/test/logic/97.1-json-blob-and-special-values.sqllogic +92 -0
- package/test/logic/98-temporal-edge-cases.sqllogic +515 -0
- package/test/logic/99-conversion-edge-cases.sqllogic +325 -0
- package/test/logic/99.0.1-schema-index-listing.sqllogic +21 -0
- package/test/logic/99.1-cast-syntax-extras.sqllogic +167 -0
- package/test/logic/drop-unique-index.sqllogic +88 -0
- package/test/logic/pushdown-test.sqllogic +36 -0
|
@@ -0,0 +1,833 @@
|
|
|
1
|
+
-- 107-temporal-arithmetic-mutation-kills.sqllogic
|
|
2
|
+
-- Mutation-killing tests for temporal arithmetic and comparison paths in
|
|
3
|
+
-- binary.ts and temporal-arithmetic.ts.
|
|
4
|
+
|
|
5
|
+
-- ============================================================
|
|
6
|
+
-- DATE + TIMESPAN arithmetic
|
|
7
|
+
-- ============================================================
|
|
8
|
+
|
|
9
|
+
-- Basic addition
|
|
10
|
+
SELECT date('2024-01-15') + timespan('P10D') as result;
|
|
11
|
+
→ [{"result":"2024-01-25"}]
|
|
12
|
+
|
|
13
|
+
-- Month addition
|
|
14
|
+
SELECT date('2024-01-15') + timespan('P3M') as result;
|
|
15
|
+
→ [{"result":"2024-04-15"}]
|
|
16
|
+
|
|
17
|
+
-- Year addition
|
|
18
|
+
SELECT date('2024-01-15') + timespan('P1Y') as result;
|
|
19
|
+
→ [{"result":"2025-01-15"}]
|
|
20
|
+
|
|
21
|
+
-- Month rollover: Jan 31 + 1 month (leap year)
|
|
22
|
+
SELECT date('2024-01-31') + timespan('P1M') as result;
|
|
23
|
+
→ [{"result":"2024-02-29"}]
|
|
24
|
+
|
|
25
|
+
-- Month rollover: Jan 31 + 1 month (non-leap year)
|
|
26
|
+
SELECT date('2023-01-31') + timespan('P1M') as result;
|
|
27
|
+
→ [{"result":"2023-02-28"}]
|
|
28
|
+
|
|
29
|
+
-- Leap year: Feb 29 + 1 year
|
|
30
|
+
SELECT date('2024-02-29') + timespan('P1Y') as result;
|
|
31
|
+
→ [{"result":"2025-02-28"}]
|
|
32
|
+
|
|
33
|
+
-- Negative timespan
|
|
34
|
+
SELECT date('2024-03-15') + timespan('-P10D') as result;
|
|
35
|
+
→ [{"result":"2024-03-05"}]
|
|
36
|
+
|
|
37
|
+
-- Zero timespan is identity
|
|
38
|
+
SELECT date('2024-06-15') + timespan('PT0S') as result;
|
|
39
|
+
→ [{"result":"2024-06-15"}]
|
|
40
|
+
|
|
41
|
+
-- ============================================================
|
|
42
|
+
-- TIMESPAN + DATE (commutative)
|
|
43
|
+
-- ============================================================
|
|
44
|
+
|
|
45
|
+
SELECT timespan('P10D') + date('2024-01-15') as result;
|
|
46
|
+
→ [{"result":"2024-01-25"}]
|
|
47
|
+
|
|
48
|
+
SELECT timespan('P2M') + date('2024-01-31') as result;
|
|
49
|
+
→ [{"result":"2024-03-31"}]
|
|
50
|
+
|
|
51
|
+
-- ============================================================
|
|
52
|
+
-- DATE - TIMESPAN
|
|
53
|
+
-- ============================================================
|
|
54
|
+
|
|
55
|
+
SELECT date('2024-01-25') - timespan('P10D') as result;
|
|
56
|
+
→ [{"result":"2024-01-15"}]
|
|
57
|
+
|
|
58
|
+
SELECT date('2024-03-31') - timespan('P1M') as result;
|
|
59
|
+
→ [{"result":"2024-02-29"}]
|
|
60
|
+
|
|
61
|
+
-- Subtracting negative timespan (effectively adds)
|
|
62
|
+
SELECT date('2024-01-15') - timespan('-P10D') as result;
|
|
63
|
+
→ [{"result":"2024-01-25"}]
|
|
64
|
+
|
|
65
|
+
-- ============================================================
|
|
66
|
+
-- DATE - DATE → TIMESPAN
|
|
67
|
+
-- ============================================================
|
|
68
|
+
|
|
69
|
+
-- Same date → zero
|
|
70
|
+
SELECT date('2024-01-15') - date('2024-01-15') as result;
|
|
71
|
+
→ [{"result":"PT0S"}]
|
|
72
|
+
|
|
73
|
+
-- Later - earlier
|
|
74
|
+
SELECT date('2024-01-25') - date('2024-01-15') as result;
|
|
75
|
+
→ [{"result":"P10D"}]
|
|
76
|
+
|
|
77
|
+
-- Earlier - later → negative
|
|
78
|
+
SELECT date('2024-01-15') - date('2024-01-25') as result;
|
|
79
|
+
→ [{"result":"-P10D"}]
|
|
80
|
+
|
|
81
|
+
-- ============================================================
|
|
82
|
+
-- DATETIME + TIMESPAN
|
|
83
|
+
-- ============================================================
|
|
84
|
+
|
|
85
|
+
SELECT datetime('2024-01-15T10:00:00') + timespan('PT2H') as result;
|
|
86
|
+
→ [{"result":"2024-01-15T12:00:00"}]
|
|
87
|
+
|
|
88
|
+
-- Crossing midnight
|
|
89
|
+
SELECT datetime('2024-01-15T23:00:00') + timespan('PT2H') as result;
|
|
90
|
+
→ [{"result":"2024-01-16T01:00:00"}]
|
|
91
|
+
|
|
92
|
+
-- Month rollover in datetime
|
|
93
|
+
SELECT datetime('2024-01-31T12:00:00') + timespan('P1M') as result;
|
|
94
|
+
→ [{"result":"2024-02-29T12:00:00"}]
|
|
95
|
+
|
|
96
|
+
-- Negative timespan on datetime
|
|
97
|
+
SELECT datetime('2024-01-15T12:00:00') + timespan('-PT3H') as result;
|
|
98
|
+
→ [{"result":"2024-01-15T09:00:00"}]
|
|
99
|
+
|
|
100
|
+
-- ============================================================
|
|
101
|
+
-- TIMESPAN + DATETIME (commutative)
|
|
102
|
+
-- ============================================================
|
|
103
|
+
|
|
104
|
+
SELECT timespan('PT2H') + datetime('2024-01-15T10:00:00') as result;
|
|
105
|
+
→ [{"result":"2024-01-15T12:00:00"}]
|
|
106
|
+
|
|
107
|
+
-- ============================================================
|
|
108
|
+
-- DATETIME - TIMESPAN
|
|
109
|
+
-- ============================================================
|
|
110
|
+
|
|
111
|
+
SELECT datetime('2024-01-15T12:00:00') - timespan('PT2H') as result;
|
|
112
|
+
→ [{"result":"2024-01-15T10:00:00"}]
|
|
113
|
+
|
|
114
|
+
-- Across day boundary
|
|
115
|
+
SELECT datetime('2024-01-16T01:00:00') - timespan('PT2H') as result;
|
|
116
|
+
→ [{"result":"2024-01-15T23:00:00"}]
|
|
117
|
+
|
|
118
|
+
-- ============================================================
|
|
119
|
+
-- DATETIME - DATETIME → TIMESPAN
|
|
120
|
+
-- ============================================================
|
|
121
|
+
|
|
122
|
+
SELECT datetime('2024-01-15T12:00:00') - datetime('2024-01-15T12:00:00') as result;
|
|
123
|
+
→ [{"result":"PT0S"}]
|
|
124
|
+
|
|
125
|
+
SELECT datetime('2024-01-25T00:00:00') - datetime('2024-01-15T00:00:00') as result;
|
|
126
|
+
→ [{"result":"P10D"}]
|
|
127
|
+
|
|
128
|
+
-- ============================================================
|
|
129
|
+
-- Mixed DATE/DATETIME subtraction
|
|
130
|
+
-- ============================================================
|
|
131
|
+
|
|
132
|
+
-- A DATE facing a DATETIME is read as that date at midnight
|
|
133
|
+
SELECT date('2024-01-25') - datetime('2024-01-15T10:00:00') as result;
|
|
134
|
+
→ [{"result":"P9DT14H"}]
|
|
135
|
+
|
|
136
|
+
SELECT datetime('2024-01-25T10:00:00') - date('2024-01-15') as result;
|
|
137
|
+
→ [{"result":"P10DT10H"}]
|
|
138
|
+
|
|
139
|
+
SELECT date('2024-01-25') - date('2024-01-15') as result;
|
|
140
|
+
→ [{"result":"P10D"}]
|
|
141
|
+
|
|
142
|
+
-- ============================================================
|
|
143
|
+
-- TIME + TIMESPAN
|
|
144
|
+
-- ============================================================
|
|
145
|
+
|
|
146
|
+
SELECT time('10:00:00') + timespan('PT2H') as result;
|
|
147
|
+
→ [{"result":"12:00:00"}]
|
|
148
|
+
|
|
149
|
+
SELECT time('10:00:00') + timespan('PT30M') as result;
|
|
150
|
+
→ [{"result":"10:30:00"}]
|
|
151
|
+
|
|
152
|
+
-- Wrap around midnight
|
|
153
|
+
SELECT time('23:00:00') + timespan('PT2H') as result;
|
|
154
|
+
→ [{"result":"01:00:00"}]
|
|
155
|
+
|
|
156
|
+
-- ============================================================
|
|
157
|
+
-- TIMESPAN + TIME (commutative)
|
|
158
|
+
-- ============================================================
|
|
159
|
+
|
|
160
|
+
SELECT timespan('PT2H') + time('10:00:00') as result;
|
|
161
|
+
→ [{"result":"12:00:00"}]
|
|
162
|
+
|
|
163
|
+
-- ============================================================
|
|
164
|
+
-- TIME - TIMESPAN
|
|
165
|
+
-- ============================================================
|
|
166
|
+
|
|
167
|
+
SELECT time('12:00:00') - timespan('PT2H') as result;
|
|
168
|
+
→ [{"result":"10:00:00"}]
|
|
169
|
+
|
|
170
|
+
-- Wrap before midnight
|
|
171
|
+
SELECT time('01:00:00') - timespan('PT2H') as result;
|
|
172
|
+
→ [{"result":"23:00:00"}]
|
|
173
|
+
|
|
174
|
+
-- ============================================================
|
|
175
|
+
-- TIME - TIME → TIMESPAN
|
|
176
|
+
-- ============================================================
|
|
177
|
+
|
|
178
|
+
SELECT time('12:00:00') - time('12:00:00') as result;
|
|
179
|
+
→ [{"result":"PT0S"}]
|
|
180
|
+
|
|
181
|
+
SELECT time('14:00:00') - time('12:00:00') as result;
|
|
182
|
+
→ [{"result":"PT2H"}]
|
|
183
|
+
|
|
184
|
+
SELECT time('10:00:00') - time('12:00:00') as result;
|
|
185
|
+
→ [{"result":"-PT2H"}]
|
|
186
|
+
|
|
187
|
+
-- ============================================================
|
|
188
|
+
-- TIMESPAN + TIMESPAN
|
|
189
|
+
-- ============================================================
|
|
190
|
+
|
|
191
|
+
SELECT timespan('PT1H') + timespan('PT30M') as result;
|
|
192
|
+
→ [{"result":"PT1H30M"}]
|
|
193
|
+
|
|
194
|
+
SELECT timespan('P1D') + timespan('PT12H') as result;
|
|
195
|
+
→ [{"result":"P1DT12H"}]
|
|
196
|
+
|
|
197
|
+
-- Adding zero
|
|
198
|
+
SELECT timespan('PT1H') + timespan('PT0S') as result;
|
|
199
|
+
→ [{"result":"PT1H"}]
|
|
200
|
+
|
|
201
|
+
-- ============================================================
|
|
202
|
+
-- TIMESPAN - TIMESPAN
|
|
203
|
+
-- ============================================================
|
|
204
|
+
|
|
205
|
+
SELECT timespan('PT2H') - timespan('PT30M') as result;
|
|
206
|
+
→ [{"result":"PT1H30M"}]
|
|
207
|
+
|
|
208
|
+
-- Subtracting equal → zero
|
|
209
|
+
SELECT timespan('PT1H') - timespan('PT1H') as result;
|
|
210
|
+
→ [{"result":"PT0S"}]
|
|
211
|
+
|
|
212
|
+
-- Subtracting larger → negative
|
|
213
|
+
SELECT timespan('PT30M') - timespan('PT1H') as result;
|
|
214
|
+
→ [{"result":"-PT30M"}]
|
|
215
|
+
|
|
216
|
+
-- ============================================================
|
|
217
|
+
-- TIMESPAN * NUMBER
|
|
218
|
+
-- ============================================================
|
|
219
|
+
|
|
220
|
+
SELECT timespan('PT1H') * 2 as result;
|
|
221
|
+
→ [{"result":"PT7200S"}]
|
|
222
|
+
|
|
223
|
+
SELECT timespan('PT1H') * 0.5 as result;
|
|
224
|
+
→ [{"result":"PT1800S"}]
|
|
225
|
+
|
|
226
|
+
-- Times zero
|
|
227
|
+
SELECT timespan('PT1H') * 0 as result;
|
|
228
|
+
→ [{"result":"PT0S"}]
|
|
229
|
+
|
|
230
|
+
-- Calendar-unit scaling
|
|
231
|
+
SELECT timespan('P1Y') * 2 as result;
|
|
232
|
+
→ [{"result":"P2Y"}]
|
|
233
|
+
|
|
234
|
+
-- ============================================================
|
|
235
|
+
-- NUMBER * TIMESPAN (commutative)
|
|
236
|
+
-- ============================================================
|
|
237
|
+
|
|
238
|
+
SELECT 2 * timespan('PT1H') as result;
|
|
239
|
+
→ [{"result":"PT7200S"}]
|
|
240
|
+
|
|
241
|
+
SELECT 3 * timespan('P1M') as result;
|
|
242
|
+
→ [{"result":"P3M"}]
|
|
243
|
+
|
|
244
|
+
-- ============================================================
|
|
245
|
+
-- TIMESPAN / NUMBER
|
|
246
|
+
-- ============================================================
|
|
247
|
+
|
|
248
|
+
SELECT timespan('PT2H') / 2 as result;
|
|
249
|
+
→ [{"result":"PT3600S"}]
|
|
250
|
+
|
|
251
|
+
-- Divide by zero returns null
|
|
252
|
+
SELECT timespan('PT1H') / 0 as result;
|
|
253
|
+
→ [{"result":null}]
|
|
254
|
+
|
|
255
|
+
-- Calendar-unit division
|
|
256
|
+
SELECT timespan('P6M') / 2 as result;
|
|
257
|
+
→ [{"result":"P3M"}]
|
|
258
|
+
|
|
259
|
+
-- ============================================================
|
|
260
|
+
-- TIMESPAN / TIMESPAN → NUMBER
|
|
261
|
+
-- ============================================================
|
|
262
|
+
|
|
263
|
+
SELECT timespan('PT2H') / timespan('PT1H') as result;
|
|
264
|
+
→ [{"result":2}]
|
|
265
|
+
|
|
266
|
+
SELECT timespan('PT30M') / timespan('PT1H') as result;
|
|
267
|
+
→ [{"result":0.5}]
|
|
268
|
+
|
|
269
|
+
-- Divide by zero timespan → null
|
|
270
|
+
SELECT timespan('PT1H') / timespan('PT0S') as result;
|
|
271
|
+
→ [{"result":null}]
|
|
272
|
+
|
|
273
|
+
-- Calendar unit ratio → null
|
|
274
|
+
SELECT timespan('P1Y') / timespan('P1M') as result;
|
|
275
|
+
→ [{"result":null}]
|
|
276
|
+
|
|
277
|
+
-- ============================================================
|
|
278
|
+
-- NULL propagation — temporal operand with NULL
|
|
279
|
+
-- ============================================================
|
|
280
|
+
|
|
281
|
+
SELECT date('2024-01-15') + null as result;
|
|
282
|
+
→ [{"result":null}]
|
|
283
|
+
|
|
284
|
+
SELECT null + date('2024-01-15') as result;
|
|
285
|
+
→ [{"result":null}]
|
|
286
|
+
|
|
287
|
+
SELECT null - date('2024-01-15') as result;
|
|
288
|
+
→ [{"result":null}]
|
|
289
|
+
|
|
290
|
+
SELECT datetime('2024-01-15T12:00:00') + null as result;
|
|
291
|
+
→ [{"result":null}]
|
|
292
|
+
|
|
293
|
+
SELECT null + timespan('PT1H') as result;
|
|
294
|
+
→ [{"result":null}]
|
|
295
|
+
|
|
296
|
+
SELECT timespan('PT1H') * null as result;
|
|
297
|
+
→ [{"result":null}]
|
|
298
|
+
|
|
299
|
+
SELECT timespan('PT1H') / null as result;
|
|
300
|
+
→ [{"result":null}]
|
|
301
|
+
|
|
302
|
+
SELECT null * timespan('PT1H') as result;
|
|
303
|
+
→ [{"result":null}]
|
|
304
|
+
|
|
305
|
+
SELECT timespan('PT1H') - null as result;
|
|
306
|
+
→ [{"result":null}]
|
|
307
|
+
|
|
308
|
+
SELECT null / timespan('PT1H') as result;
|
|
309
|
+
→ [{"result":null}]
|
|
310
|
+
|
|
311
|
+
SELECT time('10:00:00') - null as result;
|
|
312
|
+
→ [{"result":null}]
|
|
313
|
+
|
|
314
|
+
-- ============================================================
|
|
315
|
+
-- Chained temporal arithmetic
|
|
316
|
+
--
|
|
317
|
+
-- The declared result type of the inner expression is what the outer operator
|
|
318
|
+
-- specializes on (types/temporal-ops.ts). Before that table existed the planner
|
|
319
|
+
-- announced the LEFT operand's type for every temporal pair, so the inner
|
|
320
|
+
-- `date - date` claimed DATE while holding a duration string.
|
|
321
|
+
-- ============================================================
|
|
322
|
+
|
|
323
|
+
-- (DATE - DATE) is a TIMESPAN, so the outer + is TIMESPAN + TIMESPAN
|
|
324
|
+
SELECT (date('2024-01-20') - date('2024-01-15')) + timespan('P1D') as result;
|
|
325
|
+
→ [{"result":"P6D"}]
|
|
326
|
+
|
|
327
|
+
-- (DATE + TIMESPAN) is a DATE, so the outer - is DATE - DATE → a TIMESPAN
|
|
328
|
+
SELECT (date('2024-01-20') + timespan('P1D')) - date('2024-01-15') as result;
|
|
329
|
+
→ [{"result":"P6D"}]
|
|
330
|
+
|
|
331
|
+
-- (TIMESPAN / TIMESPAN) is a REAL, so the outer + is plain numeric arithmetic
|
|
332
|
+
SELECT (timespan('PT2H') / timespan('PT1H')) + 1 as result;
|
|
333
|
+
→ [{"result":3}]
|
|
334
|
+
|
|
335
|
+
-- (TIMESPAN - TIMESPAN) is a TIMESPAN
|
|
336
|
+
SELECT (timespan('PT2H') - timespan('PT30M')) + timespan('PT30M') as result;
|
|
337
|
+
→ [{"result":"PT2H"}]
|
|
338
|
+
|
|
339
|
+
-- (NUMBER * TIMESPAN) is a TIMESPAN, so the outer + finds no NUMBER case.
|
|
340
|
+
-- Returned null before the result type was fixed: the inner expression was
|
|
341
|
+
-- announced INTEGER, the outer + took the numeric fast path, and `'PT7200S' + 3`
|
|
342
|
+
-- produced a non-finite value. An error is the honest answer.
|
|
343
|
+
SELECT (2 * timespan('PT1H')) + 3 as result;
|
|
344
|
+
-- error: Unsupported temporal operation
|
|
345
|
+
|
|
346
|
+
-- ============================================================
|
|
347
|
+
-- Unsupported combinations still raise, byte for byte
|
|
348
|
+
-- ============================================================
|
|
349
|
+
|
|
350
|
+
SELECT date('2024-01-15') + date('2024-01-16') as result;
|
|
351
|
+
-- error: Unsupported temporal operation
|
|
352
|
+
|
|
353
|
+
SELECT date('2024-01-15') * 2 as result;
|
|
354
|
+
-- error: Unsupported temporal operation
|
|
355
|
+
|
|
356
|
+
SELECT time('10:00:00') - date('2024-01-15') as result;
|
|
357
|
+
-- error: Unsupported temporal operation
|
|
358
|
+
|
|
359
|
+
SELECT timespan('PT1H') % timespan('PT1H') as result;
|
|
360
|
+
-- error: Unsupported temporal operation
|
|
361
|
+
|
|
362
|
+
SELECT date('2024-01-15') - 5 as result;
|
|
363
|
+
-- error: Unsupported temporal operation
|
|
364
|
+
|
|
365
|
+
-- A number past 2^53 is a bigint, which the `*` / `/` number cases reject.
|
|
366
|
+
-- Preserved as found — see the NOTE on scaleTimespan in types/temporal-ops.ts.
|
|
367
|
+
SELECT timespan('PT1H') * 9007199254740993 as result;
|
|
368
|
+
-- error: Unsupported temporal operation
|
|
369
|
+
|
|
370
|
+
-- ============================================================
|
|
371
|
+
-- Operands whose declared type settles nothing keep sniffing values at runtime
|
|
372
|
+
-- ============================================================
|
|
373
|
+
|
|
374
|
+
-- TEXT operand: no plan-time kind, so the pair falls back to runtime shape probes,
|
|
375
|
+
-- which find no (undefined, date) case.
|
|
376
|
+
SELECT 'not-a-date' - date('2024-01-15') as result;
|
|
377
|
+
-- error: Unsupported temporal operation
|
|
378
|
+
|
|
379
|
+
-- ...and the same fallback still succeeds when the TEXT value does look temporal
|
|
380
|
+
SELECT timespan('PT1H') + 'PT1H' as result;
|
|
381
|
+
→ [{"result":"PT2H"}]
|
|
382
|
+
|
|
383
|
+
-- ============================================================
|
|
384
|
+
-- TIMESTAMP is deliberately outside the table
|
|
385
|
+
--
|
|
386
|
+
-- It is an integer instant, not a string temporal, and appears in no case — so
|
|
387
|
+
-- `ts + 1` keeps taking the runtime-sniffed path (both values look numeric, so
|
|
388
|
+
-- nothing temporal matches) and plain numeric arithmetic answers.
|
|
389
|
+
-- ============================================================
|
|
390
|
+
|
|
391
|
+
CREATE TABLE ts_int (id INTEGER PRIMARY KEY, t TIMESTAMP);
|
|
392
|
+
INSERT INTO ts_int VALUES (1, 1705276800000);
|
|
393
|
+
-- run
|
|
394
|
+
|
|
395
|
+
SELECT t + 1 as result FROM ts_int;
|
|
396
|
+
→ [{"result":1705276800001}]
|
|
397
|
+
|
|
398
|
+
SELECT t - t as result FROM ts_int;
|
|
399
|
+
→ [{"result":0}]
|
|
400
|
+
|
|
401
|
+
DROP TABLE ts_int;
|
|
402
|
+
|
|
403
|
+
-- ============================================================
|
|
404
|
+
-- DATETIME - DATETIME keeps the time of day
|
|
405
|
+
--
|
|
406
|
+
-- The difference is the full elapsed gap — days plus the time-of-day remainder —
|
|
407
|
+
-- never whole calendar days. The largest unit stays `day`.
|
|
408
|
+
-- ============================================================
|
|
409
|
+
|
|
410
|
+
SELECT datetime('2024-01-20T10:00:00') - datetime('2024-01-15T08:00:00') as result;
|
|
411
|
+
→ [{"result":"P5DT2H"}]
|
|
412
|
+
|
|
413
|
+
-- Negative mirror
|
|
414
|
+
SELECT datetime('2024-01-15T08:00:00') - datetime('2024-01-20T10:00:00') as result;
|
|
415
|
+
→ [{"result":"-P5DT2H"}]
|
|
416
|
+
|
|
417
|
+
-- Under a day apart but across midnight: two hours, not a calendar day
|
|
418
|
+
SELECT datetime('2024-01-16T01:00:00') - datetime('2024-01-15T23:00:00') as result;
|
|
419
|
+
→ [{"result":"PT2H"}]
|
|
420
|
+
|
|
421
|
+
-- Sub-second gap
|
|
422
|
+
SELECT datetime('2024-01-15T00:00:00.500') - datetime('2024-01-15T00:00:00') as result;
|
|
423
|
+
→ [{"result":"PT0.5S"}]
|
|
424
|
+
|
|
425
|
+
-- Over a year apart: still days, never years/months/weeks. Load-bearing, not cosmetic —
|
|
426
|
+
-- `TIMESPAN / TIMESPAN` returns NULL once either side carries calendar units, so a
|
|
427
|
+
-- years-shaped difference would silently break division on long gaps.
|
|
428
|
+
SELECT datetime('2025-03-01T10:00:00') - datetime('2024-01-15T08:00:00') as result;
|
|
429
|
+
→ [{"result":"P411DT2H"}]
|
|
430
|
+
|
|
431
|
+
SELECT (datetime('2025-03-01T10:00:00') - datetime('2024-01-15T08:00:00')) / timespan('PT1H') as result;
|
|
432
|
+
→ [{"result":9866}]
|
|
433
|
+
|
|
434
|
+
-- ============================================================
|
|
435
|
+
-- TIMESPAN comparisons (semantic, not lexicographic)
|
|
436
|
+
-- ============================================================
|
|
437
|
+
|
|
438
|
+
-- Create table with timespan column for comparison tests
|
|
439
|
+
CREATE TABLE ts_test (id INTEGER PRIMARY KEY, dur TIMESPAN);
|
|
440
|
+
INSERT INTO ts_test VALUES (1, 'PT30M'), (2, 'PT1H'), (3, 'PT2H'), (4, 'P1D'), (5, 'PT0S');
|
|
441
|
+
-- run
|
|
442
|
+
|
|
443
|
+
-- Equality with equivalent representations
|
|
444
|
+
SELECT id FROM ts_test WHERE dur = 'PT60M';
|
|
445
|
+
→ [{"id":2}]
|
|
446
|
+
|
|
447
|
+
-- Less-than
|
|
448
|
+
SELECT id FROM ts_test WHERE dur < 'PT1H' ORDER BY id;
|
|
449
|
+
→ [{"id":1},{"id":5}]
|
|
450
|
+
|
|
451
|
+
-- Greater-than
|
|
452
|
+
SELECT id FROM ts_test WHERE dur > 'PT1H' ORDER BY id;
|
|
453
|
+
→ [{"id":3},{"id":4}]
|
|
454
|
+
|
|
455
|
+
-- Less-than-or-equal
|
|
456
|
+
SELECT id FROM ts_test WHERE dur <= 'PT1H' ORDER BY id;
|
|
457
|
+
→ [{"id":1},{"id":2},{"id":5}]
|
|
458
|
+
|
|
459
|
+
-- Greater-than-or-equal
|
|
460
|
+
SELECT id FROM ts_test WHERE dur >= 'PT1H' ORDER BY id;
|
|
461
|
+
→ [{"id":2},{"id":3},{"id":4}]
|
|
462
|
+
|
|
463
|
+
-- Not-equal
|
|
464
|
+
SELECT id FROM ts_test WHERE dur != 'PT1H' ORDER BY id;
|
|
465
|
+
→ [{"id":1},{"id":3},{"id":4},{"id":5}]
|
|
466
|
+
|
|
467
|
+
-- ORDER BY with timespans: semantic (elapsed-time) order, matching `<`/`>` above
|
|
468
|
+
-- (see docs/types.md "Semantic ordering"; was lexicographic before that ruling)
|
|
469
|
+
SELECT id, dur FROM ts_test ORDER BY dur;
|
|
470
|
+
→ [{"id":5,"dur":"PT0S"},{"id":1,"dur":"PT30M"},{"id":2,"dur":"PT1H"},{"id":3,"dur":"PT2H"},{"id":4,"dur":"P1D"}]
|
|
471
|
+
|
|
472
|
+
-- MIN / MAX aggregation ranks by elapsed time, same as ORDER BY / `<` above
|
|
473
|
+
-- (the aggregate binds to the argument's TIMESPAN type at emit — docs/types.md
|
|
474
|
+
-- "Semantic ordering"). Text order would report mn=P1D, mx=PT30M.
|
|
475
|
+
SELECT min(dur) as mn, max(dur) as mx FROM ts_test;
|
|
476
|
+
→ [{"mn":"PT0S","mx":"P1D"}]
|
|
477
|
+
|
|
478
|
+
-- min/max agree with the ordering sites: order by … limit 1 (asc and desc)
|
|
479
|
+
SELECT (min(dur) = (SELECT dur FROM ts_test ORDER BY dur LIMIT 1)) as min_agrees,
|
|
480
|
+
(max(dur) = (SELECT dur FROM ts_test ORDER BY dur DESC LIMIT 1)) as max_agrees
|
|
481
|
+
FROM ts_test;
|
|
482
|
+
→ [{"min_agrees":true,"max_agrees":true}]
|
|
483
|
+
|
|
484
|
+
-- DISTINCT dedup is already semantic; the DISTINCT form must match the plain form
|
|
485
|
+
SELECT min(distinct dur) as mn, max(distinct dur) as mx FROM ts_test;
|
|
486
|
+
→ [{"mn":"PT0S","mx":"P1D"}]
|
|
487
|
+
|
|
488
|
+
DROP TABLE ts_test;
|
|
489
|
+
|
|
490
|
+
-- GROUP BY shape (hash aggregate): the bound comparator must reach the grouped
|
|
491
|
+
-- path too, not just the single-group stream aggregate.
|
|
492
|
+
CREATE TABLE ts_grp (id INTEGER PRIMARY KEY, g INTEGER, dur TIMESPAN);
|
|
493
|
+
INSERT INTO ts_grp VALUES
|
|
494
|
+
(1, 1, 'PT30M'), (2, 1, 'PT2H'), (3, 1, 'PT90M'),
|
|
495
|
+
(4, 2, 'P1D'), (5, 2, 'PT10M');
|
|
496
|
+
-- run
|
|
497
|
+
|
|
498
|
+
SELECT g, min(dur) as mn, max(dur) as mx FROM ts_grp GROUP BY g ORDER BY g;
|
|
499
|
+
→ [{"g":1,"mn":"PT30M","mx":"PT2H"},{"g":2,"mn":"PT10M","mx":"P1D"}]
|
|
500
|
+
|
|
501
|
+
DROP TABLE ts_grp;
|
|
502
|
+
|
|
503
|
+
-- Materialized view over TIMESPAN min/max: store-maintained values must rank by
|
|
504
|
+
-- the same semantic comparator as direct evaluation, through BOTH maintenance
|
|
505
|
+
-- arms — the delta merge on insert and the tighten residual fallback on a
|
|
506
|
+
-- delete of the extreme.
|
|
507
|
+
CREATE TABLE ts_src (id INTEGER PRIMARY KEY, g INTEGER, dur TIMESPAN);
|
|
508
|
+
INSERT INTO ts_src VALUES (1, 1, 'PT30M'), (2, 1, 'PT2H'), (3, 1, 'PT90M');
|
|
509
|
+
CREATE MATERIALIZED VIEW ts_mv AS
|
|
510
|
+
SELECT g, count(*) AS c, min(dur) AS mn, max(dur) AS mx FROM ts_src GROUP BY g;
|
|
511
|
+
-- run
|
|
512
|
+
|
|
513
|
+
-- (a) create-fill: stored equals the directly-evaluated body (text order would
|
|
514
|
+
-- store mn=PT2H, mx=PT90M).
|
|
515
|
+
SELECT g, c, mn, mx FROM ts_mv ORDER BY g;
|
|
516
|
+
→ [{"g":1,"c":3,"mn":"PT30M","mx":"PT2H"}]
|
|
517
|
+
|
|
518
|
+
-- (b) an insert exercises the delta merge path. 'P1D' is chosen because its text
|
|
519
|
+
-- and elapsed-time orders disagree against BOTH stored extrema: it sorts before
|
|
520
|
+
-- 'PT30M' textually (a text merge would wrongly drop mn to P1D) yet is the longest
|
|
521
|
+
-- duration here (a text merge would wrongly leave mx at PT2H).
|
|
522
|
+
INSERT INTO ts_src VALUES (4, 1, 'P1D');
|
|
523
|
+
SELECT g, c, mn, mx FROM ts_mv ORDER BY g;
|
|
524
|
+
→ [{"g":1,"c":4,"mn":"PT30M","mx":"P1D"}]
|
|
525
|
+
|
|
526
|
+
-- stored and direct agree after the delta merge
|
|
527
|
+
SELECT g, count(*) AS c, min(dur) AS mn, max(dur) AS mx FROM ts_src GROUP BY g ORDER BY g;
|
|
528
|
+
→ [{"g":1,"c":4,"mn":"PT30M","mx":"P1D"}]
|
|
529
|
+
|
|
530
|
+
-- (c) a delete of the extreme exercises the tighten residual fallback (min/max
|
|
531
|
+
-- cannot retract arithmetically — the group re-derives from live source state).
|
|
532
|
+
DELETE FROM ts_src WHERE id = 4;
|
|
533
|
+
SELECT g, c, mn, mx FROM ts_mv ORDER BY g;
|
|
534
|
+
→ [{"g":1,"c":3,"mn":"PT30M","mx":"PT2H"}]
|
|
535
|
+
|
|
536
|
+
DROP MATERIALIZED VIEW ts_mv;
|
|
537
|
+
DROP TABLE ts_src;
|
|
538
|
+
|
|
539
|
+
-- ============================================================
|
|
540
|
+
-- Semantic ordering reaches a COMPUTED difference, not just a declared column
|
|
541
|
+
--
|
|
542
|
+
-- Everything above orders a column DECLARED timespan. `date - date` produces the
|
|
543
|
+
-- same duration strings, and until the operation table (types/temporal-ops.ts)
|
|
544
|
+
-- gave it a TIMESPAN result type the planner announced DATE — so every ordering
|
|
545
|
+
-- site fell back to text order and disagreed with the `<`/`>` results above.
|
|
546
|
+
-- Each expectation below is a value the old announcement got wrong: text order
|
|
547
|
+
-- ranks 'P15D' before 'P1D' before 'P9D'.
|
|
548
|
+
-- ============================================================
|
|
549
|
+
|
|
550
|
+
CREATE TABLE spans (id INTEGER PRIMARY KEY, a DATE NOT NULL, b DATE NOT NULL);
|
|
551
|
+
INSERT INTO spans VALUES
|
|
552
|
+
(1, '2024-01-20', '2024-01-05'),
|
|
553
|
+
(2, '2024-01-20', '2024-01-11'),
|
|
554
|
+
(3, '2024-01-20', '2024-01-19');
|
|
555
|
+
-- run
|
|
556
|
+
|
|
557
|
+
SELECT id, a - b AS g FROM spans ORDER BY (a - b);
|
|
558
|
+
→ [{"id":3,"g":"P1D"},{"id":2,"g":"P9D"},{"id":1,"g":"P15D"}]
|
|
559
|
+
|
|
560
|
+
SELECT min(a - b) AS mn, max(a - b) AS mx FROM spans;
|
|
561
|
+
→ [{"mn":"P1D","mx":"P15D"}]
|
|
562
|
+
|
|
563
|
+
SELECT DISTINCT (a - b) AS g FROM spans ORDER BY 1;
|
|
564
|
+
→ [{"g":"P1D"},{"g":"P9D"},{"g":"P15D"}]
|
|
565
|
+
|
|
566
|
+
-- the computed difference and a declared TIMESPAN literal rank against each other
|
|
567
|
+
SELECT id FROM spans WHERE (a - b) > timespan('P8D') ORDER BY id;
|
|
568
|
+
→ [{"id":1},{"id":2}]
|
|
569
|
+
|
|
570
|
+
-- a materialized view over the computed difference stores and orders it the same way
|
|
571
|
+
CREATE MATERIALIZED VIEW spans_mv AS SELECT id, (a - b) AS g FROM spans;
|
|
572
|
+
-- run
|
|
573
|
+
|
|
574
|
+
SELECT id, g FROM spans_mv ORDER BY g;
|
|
575
|
+
→ [{"id":3,"g":"P1D"},{"id":2,"g":"P9D"},{"id":1,"g":"P15D"}]
|
|
576
|
+
|
|
577
|
+
DROP MATERIALIZED VIEW spans_mv;
|
|
578
|
+
DROP TABLE spans;
|
|
579
|
+
|
|
580
|
+
-- ============================================================
|
|
581
|
+
-- Dividing a calendar duration truncates the sub-month remainder
|
|
582
|
+
--
|
|
583
|
+
-- months have no fixed day count, so the remainder cannot cascade to days.
|
|
584
|
+
-- See the NOTE on divideDuration in src/types/temporal-ops.ts.
|
|
585
|
+
-- ============================================================
|
|
586
|
+
|
|
587
|
+
SELECT timespan('P1Y2M') / 2 AS result;
|
|
588
|
+
→ [{"result":"P7M"}]
|
|
589
|
+
|
|
590
|
+
SELECT timespan('P1M') / 2 AS result;
|
|
591
|
+
→ [{"result":"PT0S"}]
|
|
592
|
+
|
|
593
|
+
-- ============================================================
|
|
594
|
+
-- The three emit-time arms, over COLUMNS
|
|
595
|
+
--
|
|
596
|
+
-- Every case above operates on literals, which constant-fold before a row is ever
|
|
597
|
+
-- scanned. These run the same shapes per row instead, so each of the three arms of
|
|
598
|
+
-- the temporal branch in runtime/emit/binary.ts is exercised where it matters:
|
|
599
|
+
-- arm 1 both declared kinds resolve and the operation table has a case
|
|
600
|
+
-- arm 2 both resolve and the table has NO case (a constant-throw body)
|
|
601
|
+
-- arm 3 a declared type settles nothing, so runtime value sniffing decides
|
|
602
|
+
-- The emitted note for each is asserted in test/runtime/scalar-op-spec.spec.ts.
|
|
603
|
+
-- ============================================================
|
|
604
|
+
|
|
605
|
+
CREATE TABLE arms (
|
|
606
|
+
id INTEGER PRIMARY KEY,
|
|
607
|
+
dt DATE, dt2 DATE,
|
|
608
|
+
sp TIMESPAN, sp2 TIMESPAN,
|
|
609
|
+
txt TEXT,
|
|
610
|
+
n INTEGER
|
|
611
|
+
);
|
|
612
|
+
INSERT INTO arms VALUES
|
|
613
|
+
(1, '2024-01-20', '2024-01-15', 'P1D', 'PT12H', 'PT1H', 2),
|
|
614
|
+
(2, '2024-03-01', '2024-02-01', 'P2D', 'PT6H', 'P3D', 3);
|
|
615
|
+
-- run
|
|
616
|
+
|
|
617
|
+
-- arm 1: DATE + TIMESPAN, case fixed at emit
|
|
618
|
+
SELECT id, dt + sp AS r FROM arms ORDER BY id;
|
|
619
|
+
→ [{"id":1,"r":"2024-01-21"},{"id":2,"r":"2024-03-03"}]
|
|
620
|
+
|
|
621
|
+
-- arm 1: DATE - DATE announces TIMESPAN, and the value agrees
|
|
622
|
+
SELECT id, dt - dt2 AS r FROM arms ORDER BY id;
|
|
623
|
+
→ [{"id":1,"r":"P5D"},{"id":2,"r":"P29D"}]
|
|
624
|
+
|
|
625
|
+
-- arm 1: TIMESPAN * NUMBER
|
|
626
|
+
SELECT id, sp2 * n AS r FROM arms ORDER BY id;
|
|
627
|
+
→ [{"id":1,"r":"PT86400S"},{"id":2,"r":"PT64800S"}]
|
|
628
|
+
|
|
629
|
+
-- arm 3: a TEXT operand settles nothing at emit, so the value decides — and this
|
|
630
|
+
-- value does look like a duration, so the (timespan, timespan) case still applies
|
|
631
|
+
SELECT id, txt + sp AS r FROM arms ORDER BY id;
|
|
632
|
+
→ [{"id":1,"r":"P1DT1H"},{"id":2,"r":"P5D"}]
|
|
633
|
+
|
|
634
|
+
-- Deep chain: every level specializes on the level below's announced type.
|
|
635
|
+
-- (dt + sp) is a DATE, minus dt2 is a TIMESPAN, plus sp2 is a TIMESPAN.
|
|
636
|
+
SELECT id, dt + sp - dt2 + sp2 AS r FROM arms ORDER BY id;
|
|
637
|
+
→ [{"id":1,"r":"P6DT12H"},{"id":2,"r":"P31DT6H"}]
|
|
638
|
+
|
|
639
|
+
-- ============================================================
|
|
640
|
+
-- arm 1, the rest of the operation table, over COLUMNS
|
|
641
|
+
--
|
|
642
|
+
-- The cases above reach four of the table's entries. The remainder — TIME and
|
|
643
|
+
-- DATETIME shifts, the commuted TIMESPAN-first forms, mixed DATE/DATETIME
|
|
644
|
+
-- differences, and the two division cases — are otherwise pinned only by literal
|
|
645
|
+
-- expressions, which constant-fold before a row is scanned. These run them per row,
|
|
646
|
+
-- so a wrong entry in the emit-time lookup cannot hide behind the folder.
|
|
647
|
+
-- ============================================================
|
|
648
|
+
|
|
649
|
+
CREATE TABLE arms2 (
|
|
650
|
+
id INTEGER PRIMARY KEY,
|
|
651
|
+
dt DATE,
|
|
652
|
+
dtm DATETIME, dtm2 DATETIME,
|
|
653
|
+
tm TIME, tm2 TIME,
|
|
654
|
+
sp TIMESPAN, sp2 TIMESPAN,
|
|
655
|
+
n INTEGER
|
|
656
|
+
);
|
|
657
|
+
INSERT INTO arms2 VALUES
|
|
658
|
+
(1, '2024-01-15', '2024-01-20T08:15:00', '2024-01-10T06:00:00', '10:30:00', '08:00:00', 'PT1H30M', 'PT30M', 3);
|
|
659
|
+
-- run
|
|
660
|
+
|
|
661
|
+
-- TIME ± TIMESPAN, and the commuted TIMESPAN + TIME
|
|
662
|
+
SELECT tm + sp AS a, tm - sp AS b, sp + tm AS c FROM arms2;
|
|
663
|
+
→ [{"a":"12:00:00","b":"09:00:00","c":"12:00:00"}]
|
|
664
|
+
|
|
665
|
+
-- DATETIME ± TIMESPAN, and the commuted TIMESPAN + DATETIME
|
|
666
|
+
SELECT dtm + sp AS a, dtm - sp AS b, sp + dtm AS c FROM arms2;
|
|
667
|
+
→ [{"a":"2024-01-20T09:45:00","b":"2024-01-20T06:45:00","c":"2024-01-20T09:45:00"}]
|
|
668
|
+
|
|
669
|
+
-- the commuted TIMESPAN + DATE. PT30M carries no whole days, and a DATE has no time
|
|
670
|
+
-- of day to carry them into, so the date is unchanged — the same sub-day truncation
|
|
671
|
+
-- `date('2024-01-15') + timespan('PT30M')` shows as a literal.
|
|
672
|
+
SELECT sp2 + dt AS r FROM arms2;
|
|
673
|
+
→ [{"r":"2024-01-15"}]
|
|
674
|
+
|
|
675
|
+
-- TIME - TIME
|
|
676
|
+
SELECT tm - tm2 AS r FROM arms2;
|
|
677
|
+
→ [{"r":"PT2H30M"}]
|
|
678
|
+
|
|
679
|
+
-- the three mixed DATE/DATETIME differences, each the full elapsed gap (a DATE reads as midnight)
|
|
680
|
+
SELECT dtm - dtm2 AS a, dtm - dt AS b, dt - dtm2 AS c FROM arms2;
|
|
681
|
+
→ [{"a":"P10DT2H15M","b":"P5DT8H15M","c":"P4DT18H"}]
|
|
682
|
+
|
|
683
|
+
-- TIMESPAN ± TIMESPAN
|
|
684
|
+
SELECT sp + sp2 AS a, sp - sp2 AS b FROM arms2;
|
|
685
|
+
→ [{"a":"PT2H","b":"PT1H"}]
|
|
686
|
+
|
|
687
|
+
-- TIMESPAN / TIMESPAN announces REAL, TIMESPAN / NUMBER announces TIMESPAN,
|
|
688
|
+
-- and NUMBER * TIMESPAN is the commuted scale case
|
|
689
|
+
SELECT sp / sp2 AS a, sp / n AS b, n * sp AS c FROM arms2;
|
|
690
|
+
→ [{"a":3,"b":"PT1800S","c":"PT16200S"}]
|
|
691
|
+
|
|
692
|
+
-- A view body is emitted like any other scalar op, so the specialized arm applies there too
|
|
693
|
+
CREATE VIEW arms2_v AS SELECT id, dtm + sp AS shifted FROM arms2;
|
|
694
|
+
-- run
|
|
695
|
+
SELECT shifted FROM arms2_v;
|
|
696
|
+
→ [{"shifted":"2024-01-20T09:45:00"}]
|
|
697
|
+
DROP VIEW arms2_v;
|
|
698
|
+
|
|
699
|
+
DROP TABLE arms2;
|
|
700
|
+
|
|
701
|
+
-- A CHECK constraint is another scalar-op site: the specialized body decides the verdict
|
|
702
|
+
CREATE TABLE arm_check (
|
|
703
|
+
id INTEGER PRIMARY KEY,
|
|
704
|
+
dt DATE,
|
|
705
|
+
sp TIMESPAN,
|
|
706
|
+
CHECK (dt + sp > dt)
|
|
707
|
+
);
|
|
708
|
+
-- run
|
|
709
|
+
INSERT INTO arm_check VALUES (1, '2024-01-15', 'P1D');
|
|
710
|
+
-- run
|
|
711
|
+
SELECT dt + sp AS r FROM arm_check;
|
|
712
|
+
→ [{"r":"2024-01-16"}]
|
|
713
|
+
|
|
714
|
+
-- a negative shift moves the date backwards, so the constraint rejects the row
|
|
715
|
+
INSERT INTO arm_check VALUES (2, '2024-01-15', '-P1D');
|
|
716
|
+
-- error: CHECK constraint
|
|
717
|
+
|
|
718
|
+
DROP TABLE arm_check;
|
|
719
|
+
|
|
720
|
+
-- arm 2: no case for DATE + DATE. The throw is per row, not at emit — so a query
|
|
721
|
+
-- that never evaluates the expression still succeeds (next three).
|
|
722
|
+
SELECT id, dt + dt2 AS r FROM arms ORDER BY id;
|
|
723
|
+
-- error: Unsupported temporal operation
|
|
724
|
+
|
|
725
|
+
-- ...guarded by a CASE that never selects it
|
|
726
|
+
SELECT id, CASE WHEN 0 THEN dt + dt2 ELSE 'skipped' END AS r FROM arms ORDER BY id;
|
|
727
|
+
→ [{"id":1,"r":"skipped"},{"id":2,"r":"skipped"}]
|
|
728
|
+
|
|
729
|
+
-- ...filtered out before evaluation
|
|
730
|
+
SELECT dt + dt2 AS r FROM arms WHERE 1 = 0;
|
|
731
|
+
→ []
|
|
732
|
+
|
|
733
|
+
-- ...or over no rows at all
|
|
734
|
+
CREATE TABLE arms_empty (id INTEGER PRIMARY KEY, dt DATE, dt2 DATE);
|
|
735
|
+
-- run
|
|
736
|
+
SELECT dt + dt2 AS r FROM arms_empty;
|
|
737
|
+
→ []
|
|
738
|
+
DROP TABLE arms_empty;
|
|
739
|
+
|
|
740
|
+
-- ============================================================
|
|
741
|
+
-- NULL short-circuits ahead of the arm choice, on all three arms
|
|
742
|
+
--
|
|
743
|
+
-- All three bodies null-check before doing anything else, so a NULL operand is
|
|
744
|
+
-- NULL rather than an error — including on arm 2, where a non-NULL pair throws.
|
|
745
|
+
-- ============================================================
|
|
746
|
+
|
|
747
|
+
CREATE TABLE arm_nulls (id INTEGER PRIMARY KEY, dt DATE NULL, dt2 DATE NULL, sp TIMESPAN NULL, txt TEXT NULL, n INTEGER NULL);
|
|
748
|
+
INSERT INTO arm_nulls VALUES (1, null, null, null, null, null);
|
|
749
|
+
-- run
|
|
750
|
+
|
|
751
|
+
-- arm 1 (date, timespan) with a NULL operand
|
|
752
|
+
SELECT dt + sp AS r FROM arm_nulls;
|
|
753
|
+
→ [{"r":null}]
|
|
754
|
+
|
|
755
|
+
-- arm 1 (timespan, number) with a NULL operand
|
|
756
|
+
SELECT sp * n AS r FROM arm_nulls;
|
|
757
|
+
→ [{"r":null}]
|
|
758
|
+
|
|
759
|
+
-- arm 2 (date, date) — no case exists, yet NULL still wins over the throw
|
|
760
|
+
SELECT dt + dt2 AS r FROM arm_nulls;
|
|
761
|
+
→ [{"r":null}]
|
|
762
|
+
|
|
763
|
+
-- arm 3 (text, date)
|
|
764
|
+
SELECT txt - dt AS r FROM arm_nulls;
|
|
765
|
+
→ [{"r":null}]
|
|
766
|
+
|
|
767
|
+
DROP TABLE arm_nulls;
|
|
768
|
+
|
|
769
|
+
-- ============================================================
|
|
770
|
+
-- A bigint on the NUMBER side of `*` / `/`
|
|
771
|
+
--
|
|
772
|
+
-- `sp * big` resolves to the (timespan, number) case at emit, and the case's own
|
|
773
|
+
-- `typeof n === 'number'` guard then rejects the bigint — the same error the
|
|
774
|
+
-- value-sniffed path produced, reached by a different route. This is the one place
|
|
775
|
+
-- that guard is reachable (see the NOTE on scaleTimespan in types/temporal-ops.ts).
|
|
776
|
+
-- ============================================================
|
|
777
|
+
|
|
778
|
+
CREATE TABLE bigmul (id INTEGER PRIMARY KEY, sp TIMESPAN, big INTEGER);
|
|
779
|
+
INSERT INTO bigmul VALUES (1, 'PT1H', 9007199254740993);
|
|
780
|
+
-- run
|
|
781
|
+
|
|
782
|
+
SELECT sp * big AS r FROM bigmul;
|
|
783
|
+
-- error: Unsupported temporal operation
|
|
784
|
+
|
|
785
|
+
SELECT sp / big AS r FROM bigmul;
|
|
786
|
+
-- error: Unsupported temporal operation
|
|
787
|
+
|
|
788
|
+
DROP TABLE bigmul;
|
|
789
|
+
|
|
790
|
+
-- ============================================================
|
|
791
|
+
-- A DATE-declared column cannot hold a value that is not a DATE
|
|
792
|
+
--
|
|
793
|
+
-- The specialized arm trusts the declared type: a DATE-typed operand holding a
|
|
794
|
+
-- non-parseable string would return null where value sniffing raised
|
|
795
|
+
-- `Unsupported temporal operation`. These pin the two ways a caller might try to
|
|
796
|
+
-- manufacture such a value — write-side coercion rejects the insert outright, and a
|
|
797
|
+
-- failed CAST yields NULL rather than the garbage string — so the divergence is not
|
|
798
|
+
-- reachable through SQL. Only a misbehaving virtual table could produce one.
|
|
799
|
+
-- ============================================================
|
|
800
|
+
|
|
801
|
+
CREATE TABLE trust (id INTEGER PRIMARY KEY, dt DATE, sp TIMESPAN);
|
|
802
|
+
-- run
|
|
803
|
+
|
|
804
|
+
INSERT INTO trust VALUES (1, 'garbage', 'PT1H');
|
|
805
|
+
-- error: Cannot convert 'garbage' to DATE
|
|
806
|
+
|
|
807
|
+
INSERT INTO trust VALUES (2, '2024-01-15', 'PT1H');
|
|
808
|
+
-- run
|
|
809
|
+
|
|
810
|
+
-- a failed cast is NULL, so the null check answers before the declared type matters
|
|
811
|
+
SELECT cast('garbage' as DATE) + sp AS r FROM trust;
|
|
812
|
+
→ [{"r":null}]
|
|
813
|
+
|
|
814
|
+
DROP TABLE trust;
|
|
815
|
+
|
|
816
|
+
DROP TABLE arms;
|
|
817
|
+
|
|
818
|
+
-- ============================================================
|
|
819
|
+
-- Temporal arithmetic in WHERE clause (ensures dispatch path is exercised)
|
|
820
|
+
-- ============================================================
|
|
821
|
+
|
|
822
|
+
CREATE TABLE events (id INTEGER PRIMARY KEY, dt DATE);
|
|
823
|
+
INSERT INTO events VALUES (1, '2024-01-10'), (2, '2024-01-20'), (3, '2024-02-15');
|
|
824
|
+
-- run
|
|
825
|
+
|
|
826
|
+
-- Filter using date arithmetic
|
|
827
|
+
SELECT id FROM events WHERE dt + timespan('P10D') > date('2024-01-25') ORDER BY id;
|
|
828
|
+
→ [{"id":2},{"id":3}]
|
|
829
|
+
|
|
830
|
+
SELECT id FROM events WHERE dt - timespan('P5D') < date('2024-01-10') ORDER BY id;
|
|
831
|
+
→ [{"id":1}]
|
|
832
|
+
|
|
833
|
+
DROP TABLE events;
|