@quereus/quereus 4.20.0 → 4.20.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (400) hide show
  1. package/README.md +2 -0
  2. package/dist/src/common/types.d.ts +4 -4
  3. package/dist/src/index.d.ts +1 -1
  4. package/dist/src/index.d.ts.map +1 -1
  5. package/dist/src/index.js +3 -2
  6. package/dist/src/index.js.map +1 -1
  7. package/dist/src/schema/catalog-rendering.js +13 -1
  8. package/dist/src/schema/catalog-rendering.js.map +1 -1
  9. package/dist/src/schema/catalog.d.ts +35 -2
  10. package/dist/src/schema/catalog.d.ts.map +1 -1
  11. package/dist/src/schema/catalog.js +42 -33
  12. package/dist/src/schema/catalog.js.map +1 -1
  13. package/dist/src/schema/schema-differ.d.ts +1 -1
  14. package/dist/src/schema/schema-differ.d.ts.map +1 -1
  15. package/dist/src/schema/schema-differ.js +195 -33
  16. package/dist/src/schema/schema-differ.js.map +1 -1
  17. package/dist/src/schema/unique-enforcement.d.ts +23 -1
  18. package/dist/src/schema/unique-enforcement.d.ts.map +1 -1
  19. package/dist/src/schema/unique-enforcement.js +43 -1
  20. package/dist/src/schema/unique-enforcement.js.map +1 -1
  21. package/dist/src/vtab/memory/layer/manager.d.ts +15 -12
  22. package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
  23. package/dist/src/vtab/memory/layer/manager.js +87 -100
  24. package/dist/src/vtab/memory/layer/manager.js.map +1 -1
  25. package/package.json +7 -4
  26. package/test/README.md +173 -0
  27. package/test/logic/01-basic.sqllogic +39 -0
  28. package/test/logic/01.1-select-projection-extras.sqllogic +130 -0
  29. package/test/logic/01.2-strings.sqllogic +43 -0
  30. package/test/logic/01.5-insert-select.sqllogic +237 -0
  31. package/test/logic/01.6-update-extras.sqllogic +118 -0
  32. package/test/logic/01.7-update-from.sqllogic +67 -0
  33. package/test/logic/01.8-delete-extras.sqllogic +122 -0
  34. package/test/logic/01.8.1-delete-range-cow.sqllogic +115 -0
  35. package/test/logic/01.9-query-expr-dml-gates.sqllogic +32 -0
  36. package/test/logic/01.9-query-expr-dml.sqllogic +171 -0
  37. package/test/logic/01.9-query-expr-values.sqllogic +111 -0
  38. package/test/logic/01.9.1-limit-over-dml-subquery.sqllogic +119 -0
  39. package/test/logic/02-filters.sqllogic +54 -0
  40. package/test/logic/02-smoke.sqllogic +62 -0
  41. package/test/logic/02.1-bind-parameters.sqllogic +223 -0
  42. package/test/logic/03-expressions.sqllogic +190 -0
  43. package/test/logic/03.1-quoted-identifiers.sqllogic +55 -0
  44. package/test/logic/03.4-defaults.sqllogic +554 -0
  45. package/test/logic/03.4.1-default-edge-cases.sqllogic +99 -0
  46. package/test/logic/03.5-tvf.sqllogic +61 -0
  47. package/test/logic/03.6-type-system.sqllogic +544 -0
  48. package/test/logic/03.6.1-numeric-text-comparison-coercion.sqllogic +244 -0
  49. package/test/logic/03.6.2-value-to-text.sqllogic +224 -0
  50. package/test/logic/03.7-bigint-mixed-arithmetic.sqllogic +65 -0
  51. package/test/logic/03.8-not-precedence.sqllogic +255 -0
  52. package/test/logic/03.9-is-bool-predicate.sqllogic +150 -0
  53. package/test/logic/03.9.1-is-bool-predicate-partial-index.sqllogic +34 -0
  54. package/test/logic/04-order-by.sqllogic +38 -0
  55. package/test/logic/04-transactions.sqllogic +239 -0
  56. package/test/logic/04a-savepoint-lazy-attach.sqllogic +122 -0
  57. package/test/logic/05-vtab_memory.sqllogic +50 -0
  58. package/test/logic/05.0.1-vtab-memory-unique-index-collation.sqllogic +34 -0
  59. package/test/logic/05.1-composite-pk-range-scan.sqllogic +147 -0
  60. package/test/logic/05.1.1-secondary-index-range-scan.sqllogic +56 -0
  61. package/test/logic/05.2-cast-seek-correctness.sqllogic +124 -0
  62. package/test/logic/06-builtin_functions.sqllogic +149 -0
  63. package/test/logic/06.1-string-functions.sqllogic +92 -0
  64. package/test/logic/06.1.3-like-glob-edges.sqllogic +53 -0
  65. package/test/logic/06.2-math-functions.sqllogic +82 -0
  66. package/test/logic/06.3-schema.sqllogic +48 -0
  67. package/test/logic/06.3.1-schema-all-schemas.sqllogic +39 -0
  68. package/test/logic/06.3.2-schema-foreign-keys.sqllogic +208 -0
  69. package/test/logic/06.3.3-introspection-tags.sqllogic +202 -0
  70. package/test/logic/06.3.3.1-introspection-tags-index.sqllogic +74 -0
  71. package/test/logic/06.3.4-view-info.sqllogic +378 -0
  72. package/test/logic/06.3.5-column-info.sqllogic +347 -0
  73. package/test/logic/06.3.6-schema-views.sqllogic +29 -0
  74. package/test/logic/06.4-schema-search-path.sqllogic +354 -0
  75. package/test/logic/06.4.1-schema-case-insensitive.sqllogic +83 -0
  76. package/test/logic/06.4.2-collation-extras.sqllogic +472 -0
  77. package/test/logic/06.4.2.1-collation-index-access-paths.sqllogic +140 -0
  78. package/test/logic/06.4.3-write-path-collation.sqllogic +99 -0
  79. package/test/logic/06.4.4-comparison-collation-precedence.sqllogic +342 -0
  80. package/test/logic/06.4.5-any-collate-declared-keys.sqllogic +92 -0
  81. package/test/logic/06.5-polymorphic-types.sqllogic +169 -0
  82. package/test/logic/06.5.1-conversion-functions.sqllogic +173 -0
  83. package/test/logic/06.5.2-scalar-minmax.sqllogic +16 -0
  84. package/test/logic/06.5.3-undeclared-return-type-comparison.sqllogic +244 -0
  85. package/test/logic/06.5.4-declared-return-type-builtins.sqllogic +288 -0
  86. package/test/logic/06.6-aggregate-extended.sqllogic +78 -0
  87. package/test/logic/06.7-json-extended.sqllogic +53 -0
  88. package/test/logic/06.8-json-path-operators.sqllogic +99 -0
  89. package/test/logic/06.9-json-canonical-key.sqllogic +65 -0
  90. package/test/logic/06.9.1-json-coerce-once.sqllogic +417 -0
  91. package/test/logic/06.9.1.1-json-coerce-once-index.sqllogic +39 -0
  92. package/test/logic/06.9.2-json-structural-equality.sqllogic +382 -0
  93. package/test/logic/06.9.2.1-json-structural-equality-index.sqllogic +76 -0
  94. package/test/logic/06.9.3-json-index-range-seek.sqllogic +205 -0
  95. package/test/logic/07-aggregates.sqllogic +193 -0
  96. package/test/logic/07.1-aggregate-filter-clause.sqllogic +12 -0
  97. package/test/logic/07.2-aggregate-order-by.sqllogic +11 -0
  98. package/test/logic/07.3-group-by-extras.sqllogic +602 -0
  99. package/test/logic/07.3.1-group-by-order-by-key.sqllogic +164 -0
  100. package/test/logic/07.3.2-grouped-select-list-shape.sqllogic +231 -0
  101. package/test/logic/07.4-group-by-filter-composite-pk.sqllogic +120 -0
  102. package/test/logic/07.5-sum-mixed-exact-and-float.sqllogic +151 -0
  103. package/test/logic/07.5-window.sqllogic +1941 -0
  104. package/test/logic/07.5.1-window-named.sqllogic +13 -0
  105. package/test/logic/07.5.2-window-nth-value.sqllogic +13 -0
  106. package/test/logic/07.6-subqueries.sqllogic +78 -0
  107. package/test/logic/07.6.1-subquery-extras.sqllogic +93 -0
  108. package/test/logic/07.7-and-or-short-circuit.sqllogic +58 -0
  109. package/test/logic/07.7-in-subquery-caching.sqllogic +174 -0
  110. package/test/logic/07.7-scalar-agg-decorrelation.sqllogic +197 -0
  111. package/test/logic/07.7.1-in-extras.sqllogic +158 -0
  112. package/test/logic/07.7.1-scalar-agg-decorrelation-filter.sqllogic +105 -0
  113. package/test/logic/07.7.2-scalar-agg-decorrelation-nested.sqllogic +115 -0
  114. package/test/logic/07.7.3-exists-in-select-decorrelation.sqllogic +107 -0
  115. package/test/logic/07.7.4-where-conjunct-ordering.sqllogic +121 -0
  116. package/test/logic/07.7.5-filter-lost-under-index-order.sqllogic +134 -0
  117. package/test/logic/07.7.6-correlated-predicate-scope.sqllogic +178 -0
  118. package/test/logic/07.7.7-join-source-scope-shadowing.sqllogic +137 -0
  119. package/test/logic/07.7.8-correlated-ref-to-computed-column.sqllogic +165 -0
  120. package/test/logic/07.7.9-conjunct-monotonicity.sqllogic +200 -0
  121. package/test/logic/07.8-correlated-subquery-edges.sqllogic +71 -0
  122. package/test/logic/07.8.1-correlated-in-decorrelation-gates.sqllogic +156 -0
  123. package/test/logic/07.9-in-value-list.sqllogic +154 -0
  124. package/test/logic/07.9.1-in-value-list-composite-index.sqllogic +38 -0
  125. package/test/logic/08-views.sqllogic +64 -0
  126. package/test/logic/08.1-semi-anti-join.sqllogic +191 -0
  127. package/test/logic/08.1-view-edge-cases.sqllogic +118 -0
  128. package/test/logic/08.1.1-uncorrelated-in-semijoin.sqllogic +251 -0
  129. package/test/logic/08.2-existence-flag-semijoin-recovery.sqllogic +197 -0
  130. package/test/logic/08.3-existence-flag-inner-recovery.sqllogic +102 -0
  131. package/test/logic/08.4-key-set-semi-join.sqllogic +447 -0
  132. package/test/logic/09-set_operations.sqllogic +244 -0
  133. package/test/logic/09.1-set-op-cross-collation.sqllogic +230 -0
  134. package/test/logic/10-distinct_datatypes.sqllogic +127 -0
  135. package/test/logic/10.1-ddl-lifecycle.sqllogic +203 -0
  136. package/test/logic/10.1.1-create-table-syntax-edges.sqllogic +47 -0
  137. package/test/logic/10.1.2-ddl-in-transaction.sqllogic +143 -0
  138. package/test/logic/10.1.2.1-add-constraint-in-transaction.sqllogic +59 -0
  139. package/test/logic/10.1.3-ddl-drop-in-transaction.sqllogic +187 -0
  140. package/test/logic/10.1.3.1-drop-constraint-in-transaction.sqllogic +45 -0
  141. package/test/logic/10.1.4-create-table-duplicate-constraint-names.sqllogic +149 -0
  142. package/test/logic/10.1.4-ddl-transaction-policy.sqllogic +314 -0
  143. package/test/logic/10.1.5-alter-add-constraint-minted-name-disambiguation.sqllogic +219 -0
  144. package/test/logic/10.1.5-create-index-lifecycle.sqllogic +72 -0
  145. package/test/logic/10.1.6-ddl-transaction-policy-index.sqllogic +143 -0
  146. package/test/logic/10.1.7-create-table-default-type-check.sqllogic +119 -0
  147. package/test/logic/10.1.8-alter-add-check-existing-rows.sqllogic +117 -0
  148. package/test/logic/10.2-column-features.sqllogic +365 -0
  149. package/test/logic/10.2.1-table-options-rejection.sqllogic +63 -0
  150. package/test/logic/10.2.2-default-collation-memory.sqllogic +30 -0
  151. package/test/logic/10.3-function-features.sqllogic +247 -0
  152. package/test/logic/10.4-schema-scale.sqllogic +168 -0
  153. package/test/logic/10.4.1-schema-scale-indexes.sqllogic +121 -0
  154. package/test/logic/10.5-indexes.sqllogic +164 -0
  155. package/test/logic/10.5.1-partial-indexes.sqllogic +526 -0
  156. package/test/logic/10.5.2-expression-indexes.sqllogic +34 -0
  157. package/test/logic/10.5.3-desc-index-ordering.sqllogic +130 -0
  158. package/test/logic/10.5.4-composite-pk-index-update-phantom.sqllogic +55 -0
  159. package/test/logic/10.5.5-index-name-uniqueness.sqllogic +76 -0
  160. package/test/logic/10.5.6-minmax-index-boundary.sqllogic +204 -0
  161. package/test/logic/10.5.7-implicit-unique-index-lifecycle.sqllogic +1216 -0
  162. package/test/logic/10.6-distinct-edge-cases.sqllogic +119 -0
  163. package/test/logic/100-predicate-normalization-edge-cases.sqllogic +238 -0
  164. package/test/logic/100.1-where-extras.sqllogic +163 -0
  165. package/test/logic/100.1.1-where-join-on-order-indexed.sqllogic +35 -0
  166. package/test/logic/101-builtin-mutation-kills.sqllogic +974 -0
  167. package/test/logic/101-transaction-edge-cases.sqllogic +395 -0
  168. package/test/logic/102-schema-catalog-edge-cases.sqllogic +252 -0
  169. package/test/logic/102-unique-constraints.sqllogic +145 -0
  170. package/test/logic/102.0.1-schema-catalog-indexed-table.sqllogic +32 -0
  171. package/test/logic/102.1-unique-edge-cases.sqllogic +111 -0
  172. package/test/logic/102.1.1-unique-index-creation-edge-cases.sqllogic +75 -0
  173. package/test/logic/102.2-unique-collation.sqllogic +181 -0
  174. package/test/logic/102.2.1-unique-collation-index-derived.sqllogic +305 -0
  175. package/test/logic/103-database-options-edge-cases.sqllogic +108 -0
  176. package/test/logic/103.1-pragma-boolean-values.sqllogic +126 -0
  177. package/test/logic/104-emit-mutation-kills.sqllogic +236 -0
  178. package/test/logic/105-vtab-memory-mutation-kills.sqllogic +754 -0
  179. package/test/logic/105.1-vtab-memory-index-mutation-kills.sqllogic +540 -0
  180. package/test/logic/106-constraint-extractor-mutation-kills.sqllogic +350 -0
  181. package/test/logic/107-temporal-arithmetic-mutation-kills.sqllogic +833 -0
  182. package/test/logic/108-cardinality-estimation.sqllogic +146 -0
  183. package/test/logic/108.1-analyze-name-resolution.sqllogic +102 -0
  184. package/test/logic/109-aggregate-physical-selection.sqllogic +103 -0
  185. package/test/logic/11-joins.sqllogic +86 -0
  186. package/test/logic/11.1-join-using.sqllogic +267 -0
  187. package/test/logic/11.2-comma-join.sqllogic +35 -0
  188. package/test/logic/11.3-index-nested-loop-join.sqllogic +305 -0
  189. package/test/logic/11.3-mismatched-collation-join.sqllogic +74 -0
  190. package/test/logic/11.4-hash-join-side-swap.sqllogic +118 -0
  191. package/test/logic/110-scan-emitter-mutation-kills.sqllogic +121 -0
  192. package/test/logic/110.1-scan-emitter-index-scan-kills.sqllogic +47 -0
  193. package/test/logic/12-empty-primary-key.sqllogic +124 -0
  194. package/test/logic/12-join_padding_order.sqllogic +58 -0
  195. package/test/logic/12.1-orderby-index-consumption.sqllogic +40 -0
  196. package/test/logic/13-cte.sqllogic +137 -0
  197. package/test/logic/13.1-cte-multiple-recursive.sqllogic +104 -0
  198. package/test/logic/13.10-cte-qualified-name.sqllogic +136 -0
  199. package/test/logic/13.11-unreferenced-dml-cte.sqllogic +414 -0
  200. package/test/logic/13.12-nested-dml-cte-rejected.sqllogic +280 -0
  201. package/test/logic/13.2-cte-bind-params.sqllogic +98 -0
  202. package/test/logic/13.3-cte-edge-cases.sqllogic +120 -0
  203. package/test/logic/13.4-cte-extras.sqllogic +98 -0
  204. package/test/logic/13.5-cte-join-order.sqllogic +166 -0
  205. package/test/logic/13.6-cte-dml-runs-once.sqllogic +318 -0
  206. package/test/logic/13.7-cte-sibling-visibility.sqllogic +227 -0
  207. package/test/logic/13.8-insert-with-clause-visibility.sqllogic +254 -0
  208. package/test/logic/13.9-schema-authored-cte-isolation.sqllogic +328 -0
  209. package/test/logic/13.9.1-schema-authored-schema-path-isolation.sqllogic +408 -0
  210. package/test/logic/14-utilities.sqllogic +168 -0
  211. package/test/logic/15-timespan.sqllogic +279 -0
  212. package/test/logic/15.1-semantic-ordering.sqllogic +960 -0
  213. package/test/logic/15.1.1-json-check-coercion.sqllogic +178 -0
  214. package/test/logic/15.1.2-semantic-ordering-index.sqllogic +41 -0
  215. package/test/logic/15.1.3-declared-form-write-contract.sqllogic +519 -0
  216. package/test/logic/16-epoch.sqllogic +187 -0
  217. package/test/logic/17-weekday-modifier.sqllogic +78 -0
  218. package/test/logic/18-json-string-escapes.sqllogic +86 -0
  219. package/test/logic/18-strftime-extended-formats.sqllogic +68 -0
  220. package/test/logic/20-empty-single-row.sqllogic +261 -0
  221. package/test/logic/21-null-edge-cases.sqllogic +227 -0
  222. package/test/logic/21.1-where-null-comparisons.sqllogic +151 -0
  223. package/test/logic/21.1.1-where-null-comparisons-secondary-index.sqllogic +35 -0
  224. package/test/logic/21.2-between-edges.sqllogic +157 -0
  225. package/test/logic/22-boundary-values.sqllogic +175 -0
  226. package/test/logic/23-self-joins-duplicates.sqllogic +74 -0
  227. package/test/logic/24-builtin-branches.sqllogic +611 -0
  228. package/test/logic/24.1-substr-extras.sqllogic +75 -0
  229. package/test/logic/24.2-random-extras.sqllogic +39 -0
  230. package/test/logic/25-aggregate-edge-cases.sqllogic +289 -0
  231. package/test/logic/25.1-nested-aggregates.sqllogic +74 -0
  232. package/test/logic/25.2-having-edge-cases.sqllogic +318 -0
  233. package/test/logic/25.3-aggregate-isnull-empty.sqllogic +16 -0
  234. package/test/logic/25.4-groupby-fd-constant-empty.sqllogic +55 -0
  235. package/test/logic/25.5-ungrouped-aggregate-column-free-select-item.sqllogic +196 -0
  236. package/test/logic/26-join-edge-cases.sqllogic +333 -0
  237. package/test/logic/26.1-left-join-isnull-on-notnull.sqllogic +26 -0
  238. package/test/logic/26.2-left-join-on-vs-where.sqllogic +67 -0
  239. package/test/logic/26.3-join-on-constants.sqllogic +61 -0
  240. package/test/logic/26.4-join-on-is-null-nullable.sqllogic +44 -0
  241. package/test/logic/27-window-edge-cases.sqllogic +206 -0
  242. package/test/logic/27.1-window-groups-frame.sqllogic +13 -0
  243. package/test/logic/27.2-window-exclude.sqllogic +13 -0
  244. package/test/logic/27.3-window-json-aggregation.sqllogic +66 -0
  245. package/test/logic/28-set-ops-sort-edge-cases.sqllogic +444 -0
  246. package/test/logic/28.1-compound-limit-offset.sqllogic +143 -0
  247. package/test/logic/28.2-orderby-expression-extras.sqllogic +698 -0
  248. package/test/logic/28.2-set-op-branch-types.sqllogic +217 -0
  249. package/test/logic/29-constraint-edge-cases.sqllogic +442 -0
  250. package/test/logic/29.1-column-level-conflict-clause.sqllogic +171 -0
  251. package/test/logic/29.2-table-level-pk-conflict-clause.sqllogic +113 -0
  252. package/test/logic/40-constraints.sqllogic +418 -0
  253. package/test/logic/40.1-pk-desc-direction.sqllogic +76 -0
  254. package/test/logic/40.2-check-extras.sqllogic +683 -0
  255. package/test/logic/41-alter-table.sqllogic +191 -0
  256. package/test/logic/41-fk-cascade-conflict-and-self-ref.sqllogic +263 -0
  257. package/test/logic/41-fk-cross-schema.sqllogic +155 -0
  258. package/test/logic/41-fk-extended-targets.sqllogic +173 -0
  259. package/test/logic/41-foreign-keys.sqllogic +1001 -0
  260. package/test/logic/41-generated-column-errors.sqllogic +225 -0
  261. package/test/logic/41-generated-column-extras.sqllogic +598 -0
  262. package/test/logic/41-generated-column-scope.sqllogic +329 -0
  263. package/test/logic/41-generated-columns.sqllogic +361 -0
  264. package/test/logic/41.1-alter-pk.sqllogic +230 -0
  265. package/test/logic/41.1-fk-collation-conflict.sqllogic +277 -0
  266. package/test/logic/41.10-alter-drop-column-foreign-key.sqllogic +274 -0
  267. package/test/logic/41.10.1-alter-drop-column-unique-index.sqllogic +169 -0
  268. package/test/logic/41.10.2-alter-drop-column-check-and-assertion.sqllogic +1616 -0
  269. package/test/logic/41.10.3-alter-drop-column-referencing-fk.sqllogic +292 -0
  270. package/test/logic/41.10.4-drop-object-expression-dependents.sqllogic +602 -0
  271. package/test/logic/41.11-deferred-fk-with-rename.sqllogic +232 -0
  272. package/test/logic/41.12-alter-default-coercion.sqllogic +200 -0
  273. package/test/logic/41.13-alter-add-column-generated-backfill.sqllogic +566 -0
  274. package/test/logic/41.14-alter-add-column-subquery-backfill.sqllogic +129 -0
  275. package/test/logic/41.15-alter-column-default-type-check.sqllogic +178 -0
  276. package/test/logic/41.16-fk-unenforceable.sqllogic +364 -0
  277. package/test/logic/41.2-alter-column.sqllogic +382 -0
  278. package/test/logic/41.2.1-alter-column-retype-deleted-row-memory.sqllogic +32 -0
  279. package/test/logic/41.2.2-alter-column-retype-index-rebuild.sqllogic +77 -0
  280. package/test/logic/41.2.3-alter-column-set-not-null-pk-backfill.sqllogic +310 -0
  281. package/test/logic/41.2.3.1-alter-column-set-not-null-pk-backfill-secondary-index.sqllogic +37 -0
  282. package/test/logic/41.3-alter-add-column-unique.sqllogic +184 -0
  283. package/test/logic/41.3-alter-rename-propagation.sqllogic +2352 -0
  284. package/test/logic/41.3.1-alter-rename-index-propagation.sqllogic +94 -0
  285. package/test/logic/41.4-alter-add-column-constraints.sqllogic +855 -0
  286. package/test/logic/41.5-alter-misc.sqllogic +48 -0
  287. package/test/logic/41.5-cross-schema-foreign-keys.sqllogic +253 -0
  288. package/test/logic/41.6-alter-drop-rename-constraint.sqllogic +354 -0
  289. package/test/logic/41.6.1-alter-drop-constraint-index-derived.sqllogic +22 -0
  290. package/test/logic/41.7-alter-column-collate.sqllogic +105 -0
  291. package/test/logic/41.7.1-alter-column-collate-unique.sqllogic +45 -0
  292. package/test/logic/41.7.2-alter-column-collate-unique-store.sqllogic +208 -0
  293. package/test/logic/41.7.2.1-alter-column-collate-unique-index-store.sqllogic +114 -0
  294. package/test/logic/41.7.3-alter-column-retype-unique.sqllogic +293 -0
  295. package/test/logic/41.7.3.1-alter-column-retype-staged-rows-memory.sqllogic +41 -0
  296. package/test/logic/41.7.3.2-alter-column-retype-unique-index.sqllogic +72 -0
  297. package/test/logic/41.7.4-alter-column-retype-semantic-memory.sqllogic +445 -0
  298. package/test/logic/41.7.4.1-alter-column-retype-semantic-index-memory.sqllogic +91 -0
  299. package/test/logic/41.7.5-alter-column-collate-pk-staged-delete-memory.sqllogic +106 -0
  300. package/test/logic/41.8-alter-add-constraint-unique-fk.sqllogic +275 -0
  301. package/test/logic/41.8-alter-savepoint-staged-rows.sqllogic +443 -0
  302. package/test/logic/41.8.1-alter-rename-savepoint-staged-rows.sqllogic +408 -0
  303. package/test/logic/41.9-alter-constraint-body-change.sqllogic +180 -0
  304. package/test/logic/41.9-fk-restrict-batched.sqllogic +290 -0
  305. package/test/logic/42-committed-snapshot.sqllogic +254 -0
  306. package/test/logic/42-returning.sqllogic +159 -0
  307. package/test/logic/42.1-returning-extras.sqllogic +232 -0
  308. package/test/logic/42.2-returning-stored-row.sqllogic +165 -0
  309. package/test/logic/43-default-nullability.sqllogic +131 -0
  310. package/test/logic/43-transition-constraints.sqllogic +341 -0
  311. package/test/logic/43.1-default-collation.sqllogic +140 -0
  312. package/test/logic/43.1-notnull-or-conflict.sqllogic +79 -0
  313. package/test/logic/43.2-deferred-check-new-on-delete.sqllogic +95 -0
  314. package/test/logic/43.3-nullable-primary-key.sqllogic +587 -0
  315. package/test/logic/44-determinism-validation.sqllogic +164 -0
  316. package/test/logic/44-orthogonality.sqllogic +146 -0
  317. package/test/logic/44.1-nondeterministic-schema.sqllogic +316 -0
  318. package/test/logic/45-udf-determinism.sqllogic +39 -0
  319. package/test/logic/46-mutation-context.sqllogic +595 -0
  320. package/test/logic/47-upsert.sqllogic +255 -0
  321. package/test/logic/47.1-upsert-conflict-targets.sqllogic +169 -0
  322. package/test/logic/47.2-replace-and-or-clauses.sqllogic +164 -0
  323. package/test/logic/47.2.1-pk-replace-secondary-unique.sqllogic +374 -0
  324. package/test/logic/47.3-engine-or-fail.sqllogic +122 -0
  325. package/test/logic/47.3-upsert-conflict-target-collation.sqllogic +139 -0
  326. package/test/logic/47.3.1-upsert-conflict-index-derived-collation.sqllogic +25 -0
  327. package/test/logic/47.4-upsert-conflict-target-affinity.sqllogic +59 -0
  328. package/test/logic/47.5-upsert-do-update-constraints.sqllogic +440 -0
  329. package/test/logic/47.6-upsert-do-update-decomposed.sqllogic +100 -0
  330. package/test/logic/49-reference-graph.sqllogic +84 -0
  331. package/test/logic/50-declarative-schema.sqllogic +2550 -0
  332. package/test/logic/50-metadata-tags.sqllogic +1033 -0
  333. package/test/logic/50.0.1-metadata-tags-index.sqllogic +141 -0
  334. package/test/logic/50.1-declare-schema-pk.sqllogic +150 -0
  335. package/test/logic/50.2-declare-schema-renames.sqllogic +949 -0
  336. package/test/logic/50.2.1-declare-schema-index-renames.sqllogic +173 -0
  337. package/test/logic/50.3-declare-schema-duplicate-names.sqllogic +280 -0
  338. package/test/logic/50.4-declare-schema-apply-restore.sqllogic +192 -0
  339. package/test/logic/51-lens-foundation.sqllogic +147 -0
  340. package/test/logic/51-materialized-views.sqllogic +376 -0
  341. package/test/logic/51.5-materialized-views-coarsened-key.sqllogic +198 -0
  342. package/test/logic/51.7-maintained-table-attach-detach.sqllogic +468 -0
  343. package/test/logic/51.8-maintained-table-declared-constraints.sqllogic +440 -0
  344. package/test/logic/51.85-maintained-table-parent-fk.sqllogic +103 -0
  345. package/test/logic/51.9-maintained-table-secondary-unique.sqllogic +237 -0
  346. package/test/logic/51.9.1-maintained-table-partial-unique.sqllogic +36 -0
  347. package/test/logic/52-lens-overrides.sqllogic +566 -0
  348. package/test/logic/53-materialized-views-rowtime.sqllogic +1601 -0
  349. package/test/logic/53-reserved-tags.sqllogic +252 -0
  350. package/test/logic/53.1-materialized-view-write-through.sqllogic +329 -0
  351. package/test/logic/53.2-materialized-view-rename-propagation.sqllogic +483 -0
  352. package/test/logic/53.3-materialized-view-constraint-only-ddl.sqllogic +409 -0
  353. package/test/logic/53.3.1-materialized-view-index-ddl-irrelevance.sqllogic +29 -0
  354. package/test/logic/53.4-materialized-view-structural-alter-restore.sqllogic +436 -0
  355. package/test/logic/54-covering-mv-enforcement.sqllogic +314 -0
  356. package/test/logic/54.1-covering-mv-partial-enforcement.sqllogic +34 -0
  357. package/test/logic/55-internal-eviction-reporting.sqllogic +89 -0
  358. package/test/logic/55-lens-prover.sqllogic +202 -0
  359. package/test/logic/55.1-eviction-restrict-fk.sqllogic +148 -0
  360. package/test/logic/55.5-lens-authored-inverse.sqllogic +1468 -0
  361. package/test/logic/80-grow-retrieve-pass.sqllogic +79 -0
  362. package/test/logic/81-quickpick.sqllogic +24 -0
  363. package/test/logic/82-bloom-join.sqllogic +185 -0
  364. package/test/logic/83-merge-join.sqllogic +280 -0
  365. package/test/logic/84-asof-scan.sqllogic +238 -0
  366. package/test/logic/84-key-cardinality.sqllogic +50 -0
  367. package/test/logic/85-relational-const-folding.sqllogic +51 -0
  368. package/test/logic/86-scalar-cse.sqllogic +42 -0
  369. package/test/logic/90-error_paths.sqllogic +114 -0
  370. package/test/logic/90.1-parse-errors.sqllogic +77 -0
  371. package/test/logic/90.2-alter-table-errors.sqllogic +53 -0
  372. package/test/logic/90.2.1-alter-extra-errors.sqllogic +51 -0
  373. package/test/logic/90.3-expression-errors.sqllogic +43 -0
  374. package/test/logic/90.4-dml-errors.sqllogic +47 -0
  375. package/test/logic/90.5-unsupported-join-types.sqllogic +37 -0
  376. package/test/logic/90.5.1-right-full-join-read.sqllogic +157 -0
  377. package/test/logic/90.6-select-error-paths.sqllogic +57 -0
  378. package/test/logic/91-merge-join-edge-cases.sqllogic +159 -0
  379. package/test/logic/92-hash-aggregate-edge-cases.sqllogic +139 -0
  380. package/test/logic/93-ddl-view-edge-cases.sqllogic +104 -0
  381. package/test/logic/93.1-view-error-paths.sqllogic +74 -0
  382. package/test/logic/93.2-view-mutation-pending.sqllogic +108 -0
  383. package/test/logic/93.3-view-mutation-or-clause.sqllogic +60 -0
  384. package/test/logic/93.4-view-mutation.sqllogic +4881 -0
  385. package/test/logic/93.4.1-view-mutation-partial-unique-cardinality.sqllogic +31 -0
  386. package/test/logic/93.5-authored-inverse.sqllogic +415 -0
  387. package/test/logic/93.6-set-op-flagless-write.sqllogic +862 -0
  388. package/test/logic/94-tvf-edge-cases.sqllogic +58 -0
  389. package/test/logic/94.1-limit-offset-edge-cases.sqllogic +109 -0
  390. package/test/logic/94.2-limit-offset-extras.sqllogic +98 -0
  391. package/test/logic/95-assertions.sqllogic +1417 -0
  392. package/test/logic/96-subquery-edge-cases.sqllogic +276 -0
  393. package/test/logic/97-json-function-edge-cases.sqllogic +633 -0
  394. package/test/logic/97.1-json-blob-and-special-values.sqllogic +92 -0
  395. package/test/logic/98-temporal-edge-cases.sqllogic +515 -0
  396. package/test/logic/99-conversion-edge-cases.sqllogic +325 -0
  397. package/test/logic/99.0.1-schema-index-listing.sqllogic +21 -0
  398. package/test/logic/99.1-cast-syntax-extras.sqllogic +167 -0
  399. package/test/logic/drop-unique-index.sqllogic +88 -0
  400. package/test/logic/pushdown-test.sqllogic +36 -0
@@ -0,0 +1,519 @@
1
+ -- 15.1.3-declared-form-write-contract.sqllogic
2
+ --
3
+ -- THE CONTRACT: every expression evaluated against a row being written sees that
4
+ -- row in its columns' DECLARED form — the values that will be stored — never the
5
+ -- form the statement spelled. That covers CHECK (immediate and deferred), DEFAULT
6
+ -- (including one reading a sibling through `new.<column>`), and GENERATED ALWAYS
7
+ -- AS, at every write site: INSERT, UPDATE, `ON CONFLICT ... DO UPDATE`, and the
8
+ -- `ALTER TABLE ... ADD COLUMN` backfill.
9
+ --
10
+ -- Why it needs pinning: each of those sites converts the row at a different place
11
+ -- in its own pipeline (docs/types.md § Where coercion happens (and why exactly
12
+ -- once) enumerates them), and they are easy to drift apart. INSERT used to
13
+ -- evaluate DEFAULT and GENERATED expressions against the UNCONVERTED row while
14
+ -- UPDATE evaluated them against the converted one, so the same value produced two
15
+ -- different computed results depending on which statement wrote it. The
16
+ -- `-- agreement` sections below are the assertions that caught that.
17
+ --
18
+ -- DATETIME is the witness because the split is visible in one character:
19
+ -- '2099-01-01T00:00:00.000Z' is accepted, canonicalized through UTC, and STORED
20
+ -- as '2099-01-01T00:00:00'. Any expression that still sees the trailing `Z` (or
21
+ -- the `.000` fraction) is reading the written form and is wrong.
22
+ --
23
+ -- Scope note: whether a DATETIME column should preserve a `Z` suffix at all is a
24
+ -- separate question, tracked as bug-datetime-literal-with-timezone-never-matches.
25
+ -- This file pins only that every write-path expression agrees with storage on
26
+ -- whatever the declared form turns out to be.
27
+ --
28
+ -- The same contract for JSON — where the split is between raw JSON text and the
29
+ -- parsed document — lives in 15.1.1-json-check-coercion.sqllogic, and
30
+ -- 06.9.1-json-coerce-once.sqllogic pins that the conversion happens exactly once.
31
+ -- Do not duplicate those here.
32
+ --
33
+ -- Runs under both the memory module (`yarn test`) and the store module
34
+ -- (`yarn test:store`).
35
+ --
36
+ -- NOTE: the witness here is DATETIME only, and JSON's is in 15.1.1 — DATE, TIME
37
+ -- and TIMESPAN also rewrite a value on the way in but have no contract coverage,
38
+ -- and nothing forces a new logical type whose `parse` rewrites values to acquire
39
+ -- any. Fine while the write sites share `buildCellCoercion`, since one witness
40
+ -- exercises the shared path. If a type ever converts through its own route, add a
41
+ -- section here for it rather than trusting the DATETIME case to cover it.
42
+
43
+ -- ============================================================
44
+ -- 1. Baseline: what the declared form of a DATETIME actually is
45
+ --
46
+ -- Everything below compares against this one value. If this section changes,
47
+ -- every expectation in the file changes with it.
48
+ -- ============================================================
49
+
50
+ create table wf_base (id integer primary key, d datetime null);
51
+ -- run
52
+
53
+ insert into wf_base values (1, '2099-01-01T00:00:00.000Z');
54
+ -- run
55
+
56
+ -- The written form is NOT what is stored.
57
+ select d from wf_base;
58
+ → [{"d":"2099-01-01T00:00:00"}]
59
+
60
+ drop table wf_base;
61
+ -- run
62
+
63
+ -- ============================================================
64
+ -- 2. An immediate CHECK sees the declared form
65
+ --
66
+ -- A CHECK with no subquery evaluates inline, during the writing statement.
67
+ -- ============================================================
68
+
69
+ create table wf_chk (id integer primary key, d datetime null, check (d = '2099-01-01T00:00:00'));
70
+ -- run
71
+
72
+ -- The CHECK compares against the DECLARED spelling and admits the row, even
73
+ -- though the INSERT spelled the value differently.
74
+ insert into wf_chk values (1, '2099-01-01T00:00:00.000Z');
75
+ -- run
76
+
77
+ select d from wf_chk;
78
+ → [{"d":"2099-01-01T00:00:00"}]
79
+
80
+ -- The read path agrees with the CHECK that admitted the row.
81
+ select count(*) as c from wf_chk where d = '2099-01-01T00:00:00';
82
+ → [{"c":1}]
83
+
84
+ -- UPDATE goes through the same coerced NEW section: the CHECK is not vacuous.
85
+ update wf_chk set d = '2098-01-01T00:00:00' where id = 1;
86
+ -- error: CHECK
87
+
88
+ select d from wf_chk;
89
+ → [{"d":"2099-01-01T00:00:00"}]
90
+
91
+ -- An UPDATE that re-supplies the WRITTEN form still satisfies the CHECK, because
92
+ -- the CHECK sees the converted value.
93
+ update wf_chk set d = '2099-01-01T00:00:00.000Z' where id = 1;
94
+ -- run
95
+
96
+ select d from wf_chk;
97
+ → [{"d":"2099-01-01T00:00:00"}]
98
+
99
+ drop table wf_chk;
100
+ -- run
101
+
102
+ -- Control: a CHECK written against the WRITTEN form matches nothing. This is the
103
+ -- sharp end of the contract — if the CHECK saw the raw statement text this row
104
+ -- would be admitted.
105
+ create table wf_chk_raw (id integer primary key, d datetime null, check (d = '2099-01-01T00:00:00.000Z'));
106
+ -- run
107
+
108
+ insert into wf_chk_raw values (1, '2099-01-01T00:00:00.000Z');
109
+ -- error: CHECK
110
+
111
+ select count(*) as c from wf_chk_raw;
112
+ → [{"c":0}]
113
+
114
+ drop table wf_chk_raw;
115
+ -- run
116
+
117
+ -- ============================================================
118
+ -- 3. A deferred (subquery-bearing) CHECK reaches the same verdict
119
+ --
120
+ -- A CHECK containing a subquery auto-defers to the DeferredConstraintQueue, which
121
+ -- is handed the same coerced row. Same comparison, same accept/reject decisions.
122
+ -- ============================================================
123
+
124
+ create table wf_def (id integer primary key, d datetime null, check ((select d = '2099-01-01T00:00:00')));
125
+ -- run
126
+
127
+ insert into wf_def values (1, '2099-01-01T00:00:00.000Z');
128
+ -- run
129
+
130
+ select d from wf_def;
131
+ → [{"d":"2099-01-01T00:00:00"}]
132
+
133
+ drop table wf_def;
134
+ -- run
135
+
136
+ create table wf_def_raw (id integer primary key, d datetime null, check ((select d = '2099-01-01T00:00:00.000Z')));
137
+ -- run
138
+
139
+ insert into wf_def_raw values (1, '2099-01-01T00:00:00.000Z');
140
+ -- error: CHECK
141
+
142
+ select count(*) as c from wf_def_raw;
143
+ → [{"c":0}]
144
+
145
+ drop table wf_def_raw;
146
+ -- run
147
+
148
+ -- The shape that motivated the contract: a deferred CHECK whose subquery compares
149
+ -- `new.<column>` against a value ALREADY STORED in another table — i.e. already in
150
+ -- declared form. If the CHECK saw the unconverted `new.d` the two would never
151
+ -- compare equal and a perfectly valid row would be rejected.
152
+ create table wf_seen (k integer primary key, d datetime null);
153
+ -- run
154
+
155
+ insert into wf_seen values (1, '2099-01-01T00:00:00.000Z');
156
+ -- run
157
+
158
+ create table wf_ref (id integer primary key, d datetime null, check ((select count(*) from wf_seen where wf_seen.d = new.d) = 1));
159
+ -- run
160
+
161
+ insert into wf_ref values (1, '2099-01-01T00:00:00.000Z');
162
+ -- run
163
+
164
+ select d from wf_ref;
165
+ → [{"d":"2099-01-01T00:00:00"}]
166
+
167
+ -- UPDATE re-supplies the written form and must still match the stored row.
168
+ update wf_ref set d = '2099-01-01T00:00:00.000Z' where id = 1;
169
+ -- run
170
+
171
+ select d from wf_ref;
172
+ → [{"d":"2099-01-01T00:00:00"}]
173
+
174
+ -- Not vacuous: a value with no counterpart in wf_seen is rejected.
175
+ insert into wf_ref values (2, '2050-06-15T12:00:00');
176
+ -- error: CHECK
177
+
178
+ drop table wf_ref;
179
+ -- run
180
+
181
+ drop table wf_seen;
182
+ -- run
183
+
184
+ -- ============================================================
185
+ -- 4. A DEFAULT reading a sibling through `new.<column>` sees the declared form
186
+ --
187
+ -- The DEFAULT lands in a TEXT column, so whatever it read is visible verbatim.
188
+ -- ============================================================
189
+
190
+ create table wf_dflt (id integer primary key, d datetime null, c text null default ('<' || new.d || '>'));
191
+ -- run
192
+
193
+ insert into wf_dflt (id, d) values (1, '2099-01-01T00:00:00.000Z');
194
+ -- run
195
+
196
+ select d, c from wf_dflt;
197
+ → [{"d":"2099-01-01T00:00:00","c":"<2099-01-01T00:00:00>"}]
198
+
199
+ drop table wf_dflt;
200
+ -- run
201
+
202
+ -- A DEFAULT that is itself a literal in the written form converts too, and a
203
+ -- generated column reading that column sees the converted result.
204
+ create table wf_dflt_lit (id integer primary key, d datetime null default ('2099-01-01T00:00:00.000Z'), g text null generated always as ('<' || d || '>'));
205
+ -- run
206
+
207
+ insert into wf_dflt_lit (id) values (1);
208
+ -- run
209
+
210
+ select d, g from wf_dflt_lit;
211
+ → [{"d":"2099-01-01T00:00:00","g":"<2099-01-01T00:00:00>"}]
212
+
213
+ drop table wf_dflt_lit;
214
+ -- run
215
+
216
+ -- ============================================================
217
+ -- 5. A GENERATED ALWAYS AS expression sees the declared form
218
+ -- ============================================================
219
+
220
+ create table wf_gen (id integer primary key, d datetime null, g text null generated always as ('<' || d || '>'));
221
+ -- run
222
+
223
+ insert into wf_gen (id, d) values (1, '2099-01-01T00:00:00.000Z');
224
+ -- run
225
+
226
+ select d, g from wf_gen;
227
+ → [{"d":"2099-01-01T00:00:00","g":"<2099-01-01T00:00:00>"}]
228
+
229
+ drop table wf_gen;
230
+ -- run
231
+
232
+ -- ============================================================
233
+ -- 6. agreement — INSERT and UPDATE compute the same value
234
+ --
235
+ -- This is the assertion that caught the divergence: INSERT evaluated the
236
+ -- generated expression against the unconverted row, UPDATE against the converted
237
+ -- one, so the same value written two ways produced two different `g` values.
238
+ -- Stated as `count(distinct g)` so the test names the property, not the value.
239
+ -- ============================================================
240
+
241
+ create table wf_agree (id integer primary key, d datetime null, g text null generated always as ('<' || d || '>'));
242
+ -- run
243
+
244
+ -- Row 1 gets the value through INSERT.
245
+ insert into wf_agree (id, d) values (1, '2099-01-01T00:00:00.000Z');
246
+ -- run
247
+
248
+ -- Row 2 arrives holding something else, then gets the same value through UPDATE.
249
+ insert into wf_agree (id, d) values (2, '1970-01-01T00:00:00');
250
+ -- run
251
+
252
+ update wf_agree set d = '2099-01-01T00:00:00.000Z' where id = 2;
253
+ -- run
254
+
255
+ -- One value written two ways ⇒ one computed result.
256
+ select count(distinct g) as c from wf_agree;
257
+ → [{"c":1}]
258
+
259
+ select id, d, g from wf_agree order by id;
260
+ → [{"id":1,"d":"2099-01-01T00:00:00","g":"<2099-01-01T00:00:00>"},{"id":2,"d":"2099-01-01T00:00:00","g":"<2099-01-01T00:00:00>"}]
261
+
262
+ drop table wf_agree;
263
+ -- run
264
+
265
+ -- ============================================================
266
+ -- 7. agreement — touching an unrelated column does not move a computed column
267
+ --
268
+ -- UPDATE carries the untouched `d` over from storage, where it is already in
269
+ -- declared form. Re-converting it (or evaluating against a stale written form)
270
+ -- would show up here as `g` changing under a write that never mentioned `d`.
271
+ -- ============================================================
272
+
273
+ create table wf_touch (id integer primary key, d datetime null, other integer null, g text null generated always as ('<' || d || '>'));
274
+ -- run
275
+
276
+ insert into wf_touch (id, d, other) values (1, '2099-01-01T00:00:00.000Z', 1);
277
+ -- run
278
+
279
+ select d, other, g from wf_touch;
280
+ → [{"d":"2099-01-01T00:00:00","other":1,"g":"<2099-01-01T00:00:00>"}]
281
+
282
+ update wf_touch set other = 2 where id = 1;
283
+ -- run
284
+
285
+ select d, other, g from wf_touch;
286
+ → [{"d":"2099-01-01T00:00:00","other":2,"g":"<2099-01-01T00:00:00>"}]
287
+
288
+ drop table wf_touch;
289
+ -- run
290
+
291
+ -- ============================================================
292
+ -- 8. agreement — `add column ... generated` backfill equals a later INSERT
293
+ --
294
+ -- The backfill evaluates the generated expression per existing row, through a
295
+ -- different code path than INSERT. Both must land on the same value. (The
296
+ -- backfill's own mechanics — every spelling, constant expressions, chained
297
+ -- generated columns — are covered by 41.13-alter-add-column-generated-backfill;
298
+ -- what is pinned here is only that it agrees with INSERT on the declared form.)
299
+ -- ============================================================
300
+
301
+ create table wf_bf_gen (id integer primary key, d datetime null);
302
+ -- run
303
+
304
+ insert into wf_bf_gen values (1, '2099-01-01T00:00:00.000Z');
305
+ -- run
306
+
307
+ alter table wf_bf_gen add column g text null generated always as ('<' || d || '>');
308
+ -- run
309
+
310
+ -- Row 2 arrives AFTER the ALTER, through the ordinary INSERT path.
311
+ insert into wf_bf_gen (id, d) values (2, '2099-01-01T00:00:00.000Z');
312
+ -- run
313
+
314
+ select count(distinct g) as c from wf_bf_gen;
315
+ → [{"c":1}]
316
+
317
+ select id, d, g from wf_bf_gen order by id;
318
+ → [{"id":1,"d":"2099-01-01T00:00:00","g":"<2099-01-01T00:00:00>"},{"id":2,"d":"2099-01-01T00:00:00","g":"<2099-01-01T00:00:00>"}]
319
+
320
+ drop table wf_bf_gen;
321
+ -- run
322
+
323
+ -- ============================================================
324
+ -- 9. agreement — `add column ... default (new.<col>)` backfill equals a later INSERT
325
+ --
326
+ -- This is the parity claim docs/sql-alter.md § ADD COLUMN makes: "a backfilled row
327
+ -- and a row inserted afterwards under the same DEFAULT hold the same value".
328
+ -- ============================================================
329
+
330
+ create table wf_bf_dflt (id integer primary key, d datetime null);
331
+ -- run
332
+
333
+ insert into wf_bf_dflt values (1, '2099-01-01T00:00:00.000Z');
334
+ -- run
335
+
336
+ alter table wf_bf_dflt add column c text null default ('<' || new.d || '>');
337
+ -- run
338
+
339
+ insert into wf_bf_dflt (id, d) values (2, '2099-01-01T00:00:00.000Z');
340
+ -- run
341
+
342
+ select count(distinct c) as c from wf_bf_dflt;
343
+ → [{"c":1}]
344
+
345
+ select id, d, c from wf_bf_dflt order by id;
346
+ → [{"id":1,"d":"2099-01-01T00:00:00","c":"<2099-01-01T00:00:00>"},{"id":2,"d":"2099-01-01T00:00:00","c":"<2099-01-01T00:00:00>"}]
347
+
348
+ drop table wf_bf_dflt;
349
+ -- run
350
+
351
+ -- ============================================================
352
+ -- 10. agreement — `on conflict ... do update` recompute equals a plain UPDATE
353
+ --
354
+ -- The DO UPDATE arm assigns its cells AFTER the emitters' conversion pass and
355
+ -- converts each one itself (docs/types.md, the two single-cell injectors), so it
356
+ -- is a genuinely separate path from both INSERT and UPDATE.
357
+ -- ============================================================
358
+
359
+ create table wf_upsert (id integer primary key, d datetime null, g text null generated always as ('<' || d || '>'));
360
+ -- run
361
+
362
+ insert into wf_upsert (id, d) values (1, '1970-01-01T00:00:00');
363
+ -- run
364
+
365
+ insert into wf_upsert (id, d) values (2, '1970-01-01T00:00:00');
366
+ -- run
367
+
368
+ -- Row 1: the value arrives through a DO UPDATE assignment of a written-form literal.
369
+ insert into wf_upsert (id, d) values (1, '2000-01-01T00:00:00') on conflict (id) do update set d = '2099-01-01T00:00:00.000Z';
370
+ -- run
371
+
372
+ -- Row 2: the same value through a plain UPDATE.
373
+ update wf_upsert set d = '2099-01-01T00:00:00.000Z' where id = 2;
374
+ -- run
375
+
376
+ select count(distinct g) as c from wf_upsert;
377
+ → [{"c":1}]
378
+
379
+ select id, d, g from wf_upsert order by id;
380
+ → [{"id":1,"d":"2099-01-01T00:00:00","g":"<2099-01-01T00:00:00>"},{"id":2,"d":"2099-01-01T00:00:00","g":"<2099-01-01T00:00:00>"}]
381
+
382
+ drop table wf_upsert;
383
+ -- run
384
+
385
+ -- `excluded.<col>` reaches the DO UPDATE arm already converted too, so routing the
386
+ -- proposed value through it lands on the same computed result.
387
+ create table wf_excluded (id integer primary key, d datetime null, g text null generated always as ('<' || d || '>'));
388
+ -- run
389
+
390
+ insert into wf_excluded (id, d) values (1, '1970-01-01T00:00:00');
391
+ -- run
392
+
393
+ insert into wf_excluded (id, d) values (1, '2099-01-01T00:00:00.000Z') on conflict (id) do update set d = excluded.d;
394
+ -- run
395
+
396
+ select id, d, g from wf_excluded;
397
+ → [{"id":1,"d":"2099-01-01T00:00:00","g":"<2099-01-01T00:00:00>"}]
398
+
399
+ drop table wf_excluded;
400
+ -- run
401
+
402
+ -- ============================================================
403
+ -- 11. The `OR REPLACE` NOT NULL DEFAULT substitution is not an exception
404
+ --
405
+ -- This is the last write-path expression, and the most out-of-band one: it fires
406
+ -- during constraint checking, after the emitters' conversion pass, when NOT NULL
407
+ -- catches a NULL and the column has a DEFAULT to substitute. It reads the row it
408
+ -- is handed — which is the converted one — and converts its own injected cell
409
+ -- separately. So it agrees with every site above.
410
+ --
411
+ -- (15.1.1-json-check-coercion covers why that separate conversion of its OWN cell
412
+ -- must not double-apply for JSON. Here the point is only which form it READS.)
413
+ -- ============================================================
414
+
415
+ create table wf_repl (id integer primary key, d datetime null, c text not null default ('<' || new.d || '>'));
416
+ -- run
417
+
418
+ insert or replace into wf_repl values (1, '2099-01-01T00:00:00.000Z', null);
419
+ -- run
420
+
421
+ select id, d, c from wf_repl;
422
+ → [{"id":1,"d":"2099-01-01T00:00:00","c":"<2099-01-01T00:00:00>"}]
423
+
424
+ -- A second row, this one conflicting with nothing — the OR REPLACE resolves the
425
+ -- NOT NULL violation, not a key collision — takes the same substitution and agrees.
426
+ insert or replace into wf_repl values (2, '2099-01-01T00:00:00.000Z', null);
427
+ -- run
428
+
429
+ select count(distinct c) as c from wf_repl;
430
+ → [{"c":1}]
431
+
432
+ -- Without REPLACE the substitution never fires at all; NOT NULL simply rejects the
433
+ -- row. The contract is about which form the DEFAULT reads, not about when it runs.
434
+ insert into wf_repl values (3, '2099-01-01T00:00:00.000Z', null);
435
+ -- error: NOT NULL constraint failed: wf_repl.c
436
+
437
+ drop table wf_repl;
438
+ -- run
439
+
440
+ -- ============================================================
441
+ -- 12. agreement — a multi-row `insert ... select` agrees with `values`
442
+ --
443
+ -- Sections 1-11 all write through `values`, which is the row-expansion path.
444
+ -- A relational source reaches the same expansion, but when its static type is
445
+ -- ALREADY the declared type the per-cell conversion is provably inert and
446
+ -- `coerceToDeclared` skips the wrap, leaving `emitInsert`'s pass as a bare
447
+ -- conformance probe. Both source spellings must land on the stored form.
448
+ -- ============================================================
449
+
450
+ create table wf_sel_dt (id integer primary key, d datetime null);
451
+ -- run
452
+
453
+ create table wf_sel_txt (id integer primary key, d text null);
454
+ -- run
455
+
456
+ -- Source A is already DATETIME: it holds the declared form, and the conversion on
457
+ -- the way into wf_sel_tgt is the skipped one.
458
+ insert into wf_sel_dt values (1, '2099-01-01T00:00:00.000Z'), (2, '2099-01-01T00:00:00.000Z');
459
+ -- run
460
+
461
+ -- Source B is TEXT holding the WRITTEN form: the conversion is live.
462
+ insert into wf_sel_txt values (3, '2099-01-01T00:00:00.000Z');
463
+ -- run
464
+
465
+ create table wf_sel_tgt (id integer primary key, d datetime null, g text null generated always as ('<' || d || '>'), check (d = '2099-01-01T00:00:00'));
466
+ -- run
467
+
468
+ insert into wf_sel_tgt (id, d) select id, d from wf_sel_dt;
469
+ -- run
470
+
471
+ insert into wf_sel_tgt (id, d) select id, d from wf_sel_txt;
472
+ -- run
473
+
474
+ -- Row 4 through the ordinary `values` path, for comparison.
475
+ insert into wf_sel_tgt (id, d) values (4, '2099-01-01T00:00:00.000Z');
476
+ -- run
477
+
478
+ -- Four rows, three source spellings ⇒ one computed result.
479
+ select count(distinct g) as c from wf_sel_tgt;
480
+ → [{"c":1}]
481
+
482
+ select id, d, g from wf_sel_tgt order by id;
483
+ → [{"id":1,"d":"2099-01-01T00:00:00","g":"<2099-01-01T00:00:00>"},{"id":2,"d":"2099-01-01T00:00:00","g":"<2099-01-01T00:00:00>"},{"id":3,"d":"2099-01-01T00:00:00","g":"<2099-01-01T00:00:00>"},{"id":4,"d":"2099-01-01T00:00:00","g":"<2099-01-01T00:00:00>"}]
484
+
485
+ drop table wf_sel_tgt;
486
+ -- run
487
+
488
+ drop table wf_sel_txt;
489
+ -- run
490
+
491
+ drop table wf_sel_dt;
492
+ -- run
493
+
494
+ -- ============================================================
495
+ -- 13. RETURNING hands back the same declared form the row was written in
496
+ --
497
+ -- RETURNING reads the written row rather than re-evaluating anything, so it is
498
+ -- the observable end of the contract: what the caller is handed must match what a
499
+ -- later SELECT finds, at every write site that can carry a RETURNING clause.
500
+ -- ============================================================
501
+
502
+ create table wf_ret (id integer primary key, d datetime null, g text null generated always as ('<' || d || '>'));
503
+ -- run
504
+
505
+ insert into wf_ret (id, d) values (1, '2099-01-01T00:00:00.000Z') returning d, g;
506
+ → [{"d":"2099-01-01T00:00:00","g":"<2099-01-01T00:00:00>"}]
507
+
508
+ update wf_ret set d = '2099-01-01T00:00:00.000Z' where id = 1 returning d, g;
509
+ → [{"d":"2099-01-01T00:00:00","g":"<2099-01-01T00:00:00>"}]
510
+
511
+ insert into wf_ret (id, d) values (1, '2099-01-01T00:00:00.000Z') on conflict (id) do update set d = excluded.d returning d, g;
512
+ → [{"d":"2099-01-01T00:00:00","g":"<2099-01-01T00:00:00>"}]
513
+
514
+ -- A later read agrees with every RETURNING above.
515
+ select d, g from wf_ret;
516
+ → [{"d":"2099-01-01T00:00:00","g":"<2099-01-01T00:00:00>"}]
517
+
518
+ drop table wf_ret;
519
+ -- run
@@ -0,0 +1,187 @@
1
+ -- Epoch functions: epoch_s, epoch_ms, epoch_s_frac
2
+ -- Tests cover known-value conversions, round-trips, modifiers, strict parsing,
3
+ -- subsec modifier on datetime/time, and strftime epoch specifiers.
4
+
5
+ -- ============================================================
6
+ -- epoch_s: known conversions
7
+ -- ============================================================
8
+
9
+ SELECT epoch_s('1970-01-01 00:00:00');
10
+ → [0]
11
+
12
+ SELECT epoch_s('1970-01-01T00:00:00');
13
+ → [0]
14
+
15
+ SELECT epoch_s('2000-01-01 00:00:00');
16
+ → [946684800]
17
+
18
+ SELECT epoch_s('2024-07-26 12:30:45');
19
+ → [1721997045]
20
+
21
+ -- Date-only input (time defaults to 00:00:00)
22
+ SELECT epoch_s('2024-01-01');
23
+ → [1704067200]
24
+
25
+ -- With timezone offset in the string
26
+ SELECT epoch_s('2024-01-01T00:00:00Z');
27
+ → [1704067200]
28
+
29
+ SELECT epoch_s('2024-01-01T01:00:00+01:00');
30
+ → [1704067200]
31
+
32
+ -- ============================================================
33
+ -- epoch_ms: known conversions
34
+ -- ============================================================
35
+
36
+ SELECT epoch_ms('1970-01-01 00:00:00');
37
+ → [0]
38
+
39
+ SELECT epoch_ms('2024-01-01 00:00:00');
40
+ → [1704067200000]
41
+
42
+ SELECT epoch_ms('2024-07-26 12:30:45.123');
43
+ → [1721997045123]
44
+
45
+ -- Sub-second precision preserved
46
+ SELECT epoch_ms('2024-07-26 12:30:45.999');
47
+ → [1721997045999]
48
+
49
+ -- ============================================================
50
+ -- epoch_s_frac: fractional seconds
51
+ -- ============================================================
52
+
53
+ SELECT epoch_s_frac('1970-01-01 00:00:00');
54
+ → [0]
55
+
56
+ SELECT epoch_s_frac('2024-07-26 12:30:45.5');
57
+ → [1721997045.5]
58
+
59
+ SELECT epoch_s_frac('2024-07-26 12:30:45.123');
60
+ → [1721997045.123]
61
+
62
+ -- ============================================================
63
+ -- epoch_s with modifiers
64
+ -- ============================================================
65
+
66
+ SELECT epoch_s('2024-01-01', '+1 day');
67
+ → [1704153600]
68
+
69
+ SELECT epoch_s('2024-01-15', 'start of month');
70
+ → [1704067200]
71
+
72
+ SELECT epoch_s('2024-06-15 12:00:00', 'start of day');
73
+ → [1718409600]
74
+
75
+ -- ============================================================
76
+ -- Strict parsing: bare numbers are rejected
77
+ -- ============================================================
78
+
79
+ SELECT epoch_s(1704067200);
80
+ → [null]
81
+
82
+ SELECT epoch_ms(1704067200000);
83
+ → [null]
84
+
85
+ SELECT epoch_s_frac(1704067200.5);
86
+ → [null]
87
+
88
+ -- Time-only strings are rejected
89
+ SELECT epoch_s('12:30:45');
90
+ → [null]
91
+
92
+ -- YYYYMMDD format is rejected (not strict ISO)
93
+ SELECT epoch_s('20240101');
94
+ → [null]
95
+
96
+ -- NULL input
97
+ SELECT epoch_s(NULL);
98
+ → [null]
99
+
100
+ -- ============================================================
101
+ -- 'now' returns non-null values
102
+ -- ============================================================
103
+
104
+ SELECT epoch_s('now') IS NOT NULL;
105
+ → [true]
106
+
107
+ SELECT epoch_ms('now') IS NOT NULL;
108
+ → [true]
109
+
110
+ SELECT epoch_s_frac('now') IS NOT NULL;
111
+ → [true]
112
+
113
+ -- ============================================================
114
+ -- Round-trip: epoch_s → datetime via unixepoch modifier
115
+ -- ============================================================
116
+
117
+ SELECT datetime(epoch_s('2024-07-26 12:30:45'), 'unixepoch');
118
+ → ["2024-07-26 12:30:45"]
119
+
120
+ SELECT date(epoch_s('2024-01-15 08:00:00'), 'unixepoch');
121
+ → ["2024-01-15"]
122
+
123
+ -- ============================================================
124
+ -- Relationship between epoch_s and epoch_ms
125
+ -- ============================================================
126
+
127
+ -- epoch_ms / 1000 equals epoch_s for whole-second datetimes
128
+ SELECT epoch_ms('2024-01-01 00:00:00') - epoch_s('2024-01-01 00:00:00') * 1000;
129
+ → [0]
130
+
131
+ -- Milliseconds capture sub-second precision that seconds truncate
132
+ SELECT epoch_ms('2024-07-26 12:30:45.500') - epoch_s('2024-07-26 12:30:45.500') * 1000;
133
+ → [500]
134
+
135
+ -- ============================================================
136
+ -- subsec modifier on datetime/time
137
+ -- ============================================================
138
+
139
+ SELECT datetime('2024-07-26 12:30:45.123', 'subsec');
140
+ → ["2024-07-26 12:30:45.123"]
141
+
142
+ SELECT time('12:30:45.456', 'subsec');
143
+ → ["12:30:45.456"]
144
+
145
+ -- Without subsec, fractional seconds are truncated (2+ args to use datetime.ts path)
146
+ SELECT datetime('2024-07-26 12:30:45.999', '+0 seconds');
147
+ → ["2024-07-26 12:30:45"]
148
+
149
+ SELECT time('12:30:45.999', '+0 seconds');
150
+ → ["12:30:45"]
151
+
152
+ -- subsec with unixepoch
153
+ SELECT datetime(1721997045.123, 'unixepoch', 'subsec');
154
+ → ["2024-07-26 12:30:45.123"]
155
+
156
+ -- subsec with arithmetic modifiers
157
+ SELECT datetime('2024-07-26 12:30:45.500', '+1 second', 'subsec');
158
+ → ["2024-07-26 12:30:46.500"]
159
+
160
+ -- ============================================================
161
+ -- strftime epoch specifiers: %E (seconds) and %Q (milliseconds)
162
+ -- ============================================================
163
+
164
+ SELECT strftime('%E', '2024-01-01 00:00:00');
165
+ → ["1704067200"]
166
+
167
+ SELECT strftime('%Q', '2024-01-01 00:00:00');
168
+ → ["1704067200000"]
169
+
170
+ SELECT strftime('%Q', '2024-07-26 12:30:45.123');
171
+ → ["1721997045123"]
172
+
173
+ -- Epoch specifiers work with modifiers
174
+ SELECT strftime('%E', '2024-01-01', '+1 day');
175
+ → ["1704153600"]
176
+
177
+ -- ============================================================
178
+ -- Arithmetic with epoch values
179
+ -- ============================================================
180
+
181
+ -- Difference in seconds between two datetimes
182
+ SELECT epoch_s('2024-01-02 00:00:00') - epoch_s('2024-01-01 00:00:00');
183
+ → [86400]
184
+
185
+ -- Difference in milliseconds
186
+ SELECT epoch_ms('2024-01-02 00:00:00') - epoch_ms('2024-01-01 00:00:00');
187
+ → [86400000]