@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,255 @@
1
+ -- 47-upsert.sqllogic - Testing UPSERT (ON CONFLICT) clauses
2
+
3
+ -- === Setup ===
4
+
5
+ DROP TABLE IF EXISTS upsert_test;
6
+ CREATE TABLE upsert_test (
7
+ id INTEGER PRIMARY KEY,
8
+ name TEXT,
9
+ count INTEGER DEFAULT 1
10
+ );
11
+
12
+ -- === Basic DO NOTHING tests ===
13
+
14
+ -- Insert a row
15
+ INSERT INTO upsert_test (id, name, count) VALUES (1, 'first', 10);
16
+ SELECT * FROM upsert_test;
17
+ → [{"id":1,"name":"first","count":10}]
18
+
19
+ -- ON CONFLICT DO NOTHING - should silently skip duplicate
20
+ INSERT INTO upsert_test (id, name, count) VALUES (1, 'duplicate', 99)
21
+ ON CONFLICT DO NOTHING;
22
+ SELECT * FROM upsert_test;
23
+ → [{"id":1,"name":"first","count":10}]
24
+
25
+ -- Insert a new row (no conflict) with ON CONFLICT DO NOTHING
26
+ INSERT INTO upsert_test (id, name, count) VALUES (2, 'second', 20)
27
+ ON CONFLICT DO NOTHING;
28
+ SELECT * FROM upsert_test ORDER BY id;
29
+ → [{"id":1,"name":"first","count":10},{"id":2,"name":"second","count":20}]
30
+
31
+ -- === Basic DO UPDATE tests ===
32
+
33
+ -- Update on conflict using NEW.* to reference proposed values
34
+ INSERT INTO upsert_test (id, name, count) VALUES (1, 'updated_name', 100)
35
+ ON CONFLICT DO UPDATE SET name = NEW.name, count = NEW.count;
36
+ SELECT * FROM upsert_test ORDER BY id;
37
+ → [{"id":1,"name":"updated_name","count":100},{"id":2,"name":"second","count":20}]
38
+
39
+ -- Update on conflict using unqualified column (existing value)
40
+ INSERT INTO upsert_test (id, name, count) VALUES (2, 'ignored', 999)
41
+ ON CONFLICT DO UPDATE SET count = count + 1;
42
+ SELECT * FROM upsert_test ORDER BY id;
43
+ → [{"id":1,"name":"updated_name","count":100},{"id":2,"name":"second","count":21}]
44
+
45
+ -- === Increment pattern ===
46
+
47
+ -- Classic UPSERT increment pattern: increment if exists, insert if not
48
+ INSERT INTO upsert_test (id, name, count) VALUES (3, 'new_entry', 1)
49
+ ON CONFLICT DO UPDATE SET count = count + 1;
50
+ SELECT * FROM upsert_test WHERE id = 3;
51
+ → [{"id":3,"name":"new_entry","count":1}]
52
+
53
+ -- Now increment the existing row
54
+ INSERT INTO upsert_test (id, name, count) VALUES (3, 'new_entry', 1)
55
+ ON CONFLICT DO UPDATE SET count = count + 1;
56
+ SELECT * FROM upsert_test WHERE id = 3;
57
+ → [{"id":3,"name":"new_entry","count":2}]
58
+
59
+ -- Another increment
60
+ INSERT INTO upsert_test (id, name, count) VALUES (3, 'ignored', 999)
61
+ ON CONFLICT DO UPDATE SET count = count + 1;
62
+ SELECT * FROM upsert_test WHERE id = 3;
63
+ → [{"id":3,"name":"new_entry","count":3}]
64
+
65
+ -- === DO UPDATE with excluded.* (PostgreSQL compatibility) ===
66
+
67
+ INSERT INTO upsert_test (id, name, count) VALUES (1, 'via_excluded', 500)
68
+ ON CONFLICT DO UPDATE SET name = excluded.name, count = excluded.count;
69
+ SELECT * FROM upsert_test WHERE id = 1;
70
+ → [{"id":1,"name":"via_excluded","count":500}]
71
+
72
+ -- === DO UPDATE with mixed references ===
73
+
74
+ -- Combine existing values with proposed values
75
+ INSERT INTO upsert_test (id, name, count) VALUES (2, 'combined', 100)
76
+ ON CONFLICT DO UPDATE SET name = name || '_' || NEW.name, count = count + NEW.count;
77
+ SELECT * FROM upsert_test WHERE id = 2;
78
+ → [{"id":2,"name":"second_combined","count":121}]
79
+
80
+ -- === DO UPDATE with WHERE condition ===
81
+
82
+ -- Only update if condition is met (condition passes)
83
+ INSERT INTO upsert_test (id, name, count) VALUES (1, 'conditional', 600)
84
+ ON CONFLICT DO UPDATE SET count = NEW.count WHERE count < 600;
85
+ SELECT * FROM upsert_test WHERE id = 1;
86
+ → [{"id":1,"name":"via_excluded","count":600}]
87
+
88
+ -- Only update if condition is met (condition fails - should skip update)
89
+ INSERT INTO upsert_test (id, name, count) VALUES (1, 'should_skip', 700)
90
+ ON CONFLICT DO UPDATE SET count = NEW.count WHERE count < 100;
91
+ SELECT * FROM upsert_test WHERE id = 1;
92
+ → [{"id":1,"name":"via_excluded","count":600}]
93
+
94
+ -- === UPSERT with RETURNING ===
95
+
96
+ -- DO NOTHING with RETURNING (returns nothing when conflict is skipped)
97
+ INSERT INTO upsert_test (id, name, count) VALUES (1, 'ignored', 999)
98
+ ON CONFLICT DO NOTHING
99
+ RETURNING id, name, count;
100
+ → []
101
+
102
+ -- DO UPDATE with RETURNING
103
+ INSERT INTO upsert_test (id, name, count) VALUES (1, 'returned', 700)
104
+ ON CONFLICT DO UPDATE SET name = NEW.name, count = NEW.count
105
+ RETURNING id, name, count;
106
+ → [{"id":1,"name":"returned","count":700}]
107
+
108
+ -- Verify the update was applied
109
+ SELECT * FROM upsert_test WHERE id = 1;
110
+ → [{"id":1,"name":"returned","count":700}]
111
+
112
+ -- Insert without conflict with RETURNING
113
+ INSERT INTO upsert_test (id, name, count) VALUES (10, 'new_row', 50)
114
+ ON CONFLICT DO NOTHING
115
+ RETURNING id, name;
116
+ → [{"id":10,"name":"new_row"}]
117
+
118
+ -- === Multiple rows with UPSERT ===
119
+
120
+ -- Insert multiple rows, some conflict, some don't
121
+ INSERT INTO upsert_test (id, name, count) VALUES
122
+ (10, 'update_existing', 100),
123
+ (11, 'brand_new', 200)
124
+ ON CONFLICT DO UPDATE SET count = NEW.count;
125
+ SELECT * FROM upsert_test WHERE id IN (10, 11) ORDER BY id;
126
+ → [{"id":10,"name":"new_row","count":100},{"id":11,"name":"brand_new","count":200}]
127
+
128
+ -- === Conflict target specification ===
129
+
130
+ -- Create table with explicit conflict target
131
+ DROP TABLE IF EXISTS upsert_target;
132
+ CREATE TABLE upsert_target (
133
+ id INTEGER PRIMARY KEY,
134
+ email TEXT UNIQUE,
135
+ name TEXT
136
+ );
137
+
138
+ INSERT INTO upsert_target VALUES (1, 'a@test.com', 'Alice');
139
+ SELECT * FROM upsert_target;
140
+ → [{"id":1,"email":"a@test.com","name":"Alice"}]
141
+
142
+ -- Conflict on primary key (id)
143
+ INSERT INTO upsert_target (id, email, name) VALUES (1, 'new@test.com', 'Updated')
144
+ ON CONFLICT (id) DO UPDATE SET name = NEW.name;
145
+ SELECT * FROM upsert_target;
146
+ → [{"id":1,"email":"a@test.com","name":"Updated"}]
147
+
148
+ -- === Error cases ===
149
+
150
+ -- Cannot use both OR clause and ON CONFLICT
151
+ INSERT OR REPLACE INTO upsert_target (id, email, name) VALUES (1, 'test@test.com', 'Test')
152
+ ON CONFLICT DO NOTHING;
153
+ -- error: Cannot use both 'INSERT OR ...' and 'ON CONFLICT' in the same statement
154
+
155
+ -- ON CONFLICT DO UPDATE assigning the same column twice is rejected (no silent
156
+ -- last-wins). This path never routes through buildUpdateStmt, so it carries its
157
+ -- own backstop mirroring the UPDATE side. See ticket
158
+ -- insert-family-duplicate-column-targets-silent-last-wins.
159
+ INSERT INTO upsert_target (id, email, name) VALUES (1, 'x@test.com', 'X')
160
+ ON CONFLICT (id) DO UPDATE SET name = 'one', name = 'two';
161
+ -- error: duplicate assignment
162
+
163
+ -- the rejected upsert made no change (name keeps its pre-conflict value, not
164
+ -- last-wins 'two' or 'one').
165
+ SELECT id, name FROM upsert_target;
166
+ → [{"id":1,"name":"Updated"}]
167
+
168
+ -- The duplicate-target guard is case-insensitive: `name` and `NAME` collide.
169
+ INSERT INTO upsert_target (id, email, name) VALUES (1, 'x@test.com', 'X')
170
+ ON CONFLICT (id) DO UPDATE SET name = 'one', NAME = 'two';
171
+ -- error: duplicate assignment
172
+
173
+ -- A legitimate DO UPDATE assigning two *distinct* columns still works — the
174
+ -- guard keys on exact-name collision, never on distinct columns.
175
+ INSERT INTO upsert_target (id, email, name) VALUES (1, 'x@test.com', 'X')
176
+ ON CONFLICT (id) DO UPDATE SET email = 'multi@test.com', name = 'Multi';
177
+ SELECT id, email, name FROM upsert_target;
178
+ → [{"id":1,"email":"multi@test.com","name":"Multi"}]
179
+
180
+ -- === UPSERT expressions with subqueries (optimizer must see them as children) ===
181
+ -- `DmlExecutorNode` exposes ON CONFLICT assignment/WHERE expressions as
182
+ -- getChildren() so the optimizer can rewrite subqueries inside them just like any
183
+ -- other plan node. See bug-dml-side-expressions-invisible-to-optimizer.
184
+
185
+ DROP TABLE IF EXISTS upsert_src;
186
+ CREATE TABLE upsert_src (id INTEGER PRIMARY KEY, v TEXT);
187
+ INSERT INTO upsert_src VALUES (1, 'a'), (2, 'b'), (3, 'c');
188
+
189
+ DROP TABLE IF EXISTS upsert_expr;
190
+ CREATE TABLE upsert_expr (id INTEGER PRIMARY KEY, name TEXT, count INTEGER);
191
+ INSERT INTO upsert_expr VALUES (1, 'first', 10);
192
+
193
+ -- subquery in a DO UPDATE SET value
194
+ INSERT INTO upsert_expr (id, name, count) VALUES (1, 'dup', 0)
195
+ ON CONFLICT (id) DO UPDATE SET count = (SELECT COUNT(*) FROM upsert_src);
196
+ SELECT id, count FROM upsert_expr WHERE id = 1;
197
+ → [{"id":1,"count":3}]
198
+
199
+ -- subquery in the DO UPDATE WHERE clause: condition false leaves the row unchanged
200
+ INSERT INTO upsert_expr (id, name, count) VALUES (1, 'dup2', 999)
201
+ ON CONFLICT (id) DO UPDATE SET count = NEW.count WHERE (SELECT COUNT(*) FROM upsert_src) > 10;
202
+ SELECT id, count FROM upsert_expr WHERE id = 1;
203
+ → [{"id":1,"count":3}]
204
+
205
+ -- subquery in the DO UPDATE WHERE clause: condition true applies the update
206
+ INSERT INTO upsert_expr (id, name, count) VALUES (1, 'dup3', 999)
207
+ ON CONFLICT (id) DO UPDATE SET count = NEW.count WHERE (SELECT COUNT(*) FROM upsert_src) > 1;
208
+ SELECT id, count FROM upsert_expr WHERE id = 1;
209
+ → [{"id":1,"count":999}]
210
+
211
+ -- subquery correlated to excluded.<col> (the proposed/rejected row)
212
+ INSERT INTO upsert_expr (id, name, count) VALUES (1, 'corr', 2)
213
+ ON CONFLICT (id) DO UPDATE SET count = (SELECT COUNT(*) FROM upsert_src WHERE id <= excluded.count);
214
+ SELECT id, count FROM upsert_expr WHERE id = 1;
215
+ → [{"id":1,"count":2}]
216
+
217
+ -- subquery correlated to an unqualified column (the conflicting existing row, not NEW)
218
+ INSERT INTO upsert_expr (id, name, count) VALUES (1, 'corr2', 999)
219
+ ON CONFLICT (id) DO UPDATE SET count = (SELECT COUNT(*) FROM upsert_src WHERE id <= count);
220
+ SELECT id, count FROM upsert_expr WHERE id = 1;
221
+ → [{"id":1,"count":2}]
222
+
223
+ DROP TABLE upsert_expr;
224
+
225
+ -- multi-clause ON CONFLICT: two conflict targets, each with its own subquery
226
+ -- assignment and WHERE — exercises the child ordering/slicing across clauses.
227
+ DROP TABLE IF EXISTS upsert_multi;
228
+ CREATE TABLE upsert_multi (
229
+ id INTEGER PRIMARY KEY,
230
+ email TEXT UNIQUE,
231
+ tag TEXT
232
+ );
233
+ INSERT INTO upsert_multi VALUES (1, 'a@test.com', 'A'), (2, 'b@test.com', 'B');
234
+
235
+ -- conflict lands on the `id` target — its clause fires, the `email` clause does not
236
+ INSERT INTO upsert_multi (id, email, tag) VALUES (1, 'new@test.com', 'ignored')
237
+ ON CONFLICT (id) DO UPDATE SET tag = (SELECT COUNT(*) FROM upsert_src) WHERE (SELECT COUNT(*) FROM upsert_src) > 0
238
+ ON CONFLICT (email) DO UPDATE SET tag = 'email-match' WHERE (SELECT COUNT(*) FROM upsert_src) > 100;
239
+ SELECT id, tag FROM upsert_multi WHERE id = 1;
240
+ → [{"id":1,"tag":"3"}]
241
+
242
+ -- conflict lands on the `email` target instead — the `id` clause's WHERE (which
243
+ -- would fail) never runs; the `email` clause fires
244
+ INSERT INTO upsert_multi (id, email, tag) VALUES (99, 'b@test.com', 'ignored')
245
+ ON CONFLICT (id) DO UPDATE SET tag = (SELECT COUNT(*) FROM upsert_src) WHERE (SELECT COUNT(*) FROM upsert_src) > 100
246
+ ON CONFLICT (email) DO UPDATE SET tag = (SELECT COUNT(*) FROM upsert_src) WHERE (SELECT COUNT(*) FROM upsert_src) > 0;
247
+ SELECT id, tag FROM upsert_multi WHERE email = 'b@test.com';
248
+ → [{"id":2,"tag":"3"}]
249
+
250
+ DROP TABLE upsert_multi;
251
+ DROP TABLE upsert_src;
252
+
253
+ -- Clean up
254
+ DROP TABLE upsert_test;
255
+ DROP TABLE upsert_target;
@@ -0,0 +1,169 @@
1
+ -- adapted from SQLite test/upsert2.test, test/upsert3.test, test/upsert4.test
2
+ -- UPSERT advanced conflict-target scenarios beyond 47-upsert.sqllogic:
3
+ -- composite UNIQUE targets, partial-target rejection, INSERT...AS alias,
4
+ -- column-list assignment in DO UPDATE SET, UPSERT with CTE source.
5
+
6
+ -- ===================================
7
+ -- 1. ON CONFLICT on composite UNIQUE — full match required
8
+ -- ===================================
9
+
10
+ create table comp_u (k integer, v text, payload text, unique (k, v));
11
+
12
+ insert into comp_u values (0, 'abcd', 'first');
13
+
14
+ -- full target columns match — DO NOTHING silently skips duplicate
15
+ insert into comp_u values (0, 'abcd', 'second') on conflict (k, v) do nothing;
16
+ select count(*) as cnt from comp_u;
17
+ → [{"cnt":1}]
18
+
19
+ -- reversed column order in target also matches the same UNIQUE constraint
20
+ insert into comp_u values (0, 'abcd', 'third') on conflict (v, k) do nothing;
21
+ select count(*) as cnt from comp_u;
22
+ → [{"cnt":1}]
23
+
24
+ -- Quereus accepts partial conflict targets that match any UNIQUE involving the listed column(s)
25
+ -- so the SQLite-strict "must error" assertions don't apply here; verify the rows are still skipped instead
26
+ insert into comp_u values (0, 'abcd', 'fourth') on conflict (k) do nothing;
27
+ insert into comp_u values (0, 'abcd', 'fifth') on conflict (v) do nothing;
28
+ select count(*) as cnt from comp_u;
29
+ → [{"cnt":1}]
30
+
31
+ drop table comp_u;
32
+
33
+ -- ===================================
34
+ -- 2. UPSERT DO UPDATE referencing existing vs. proposed value via excluded.col
35
+ -- ===================================
36
+
37
+ create table counter (id integer primary key, n integer);
38
+ insert into counter values (1, 10);
39
+
40
+ -- excluded.* refers to the proposed (rejected) row's values
41
+ insert into counter values (1, 5)
42
+ on conflict (id) do update set n = counter.n + excluded.n;
43
+
44
+ select id, n from counter where id = 1;
45
+ → [{"id":1,"n":15}]
46
+
47
+ drop table counter;
48
+
49
+ -- ===================================
50
+ -- 3. UPSERT with explicit table alias: INSERT ... AS alias
51
+ -- Alias provides a name for the existing row in DO UPDATE
52
+ -- ===================================
53
+
54
+ create table alias_t (id integer primary key, name text, count integer);
55
+ insert into alias_t values (1, 'alice', 1);
56
+
57
+ -- INSERT ... AS alias is not supported by Quereus's parser
58
+ insert into alias_t as old values (1, 'updated', 100)
59
+ on conflict (id) do update set name = excluded.name, count = old.count + 1;
60
+ -- error: Expected VALUES, SELECT, or DML
61
+
62
+ drop table alias_t;
63
+
64
+ -- ===================================
65
+ -- 4. UPSERT with CTE as source
66
+ -- ===================================
67
+
68
+ create table cte_dst (id integer primary key, val integer);
69
+
70
+ with src(id, val) as (select 1 as id, 100 as val union all select 2, 200)
71
+ insert into cte_dst (id, val) select id, val from src
72
+ on conflict (id) do update set val = excluded.val;
73
+
74
+ select id, val from cte_dst order by id;
75
+ → [{"id":1,"val":100},{"id":2,"val":200}]
76
+
77
+ -- second pass with CTE — forces conflict and update path
78
+ with src(id, val) as (select 1 as id, 999 as val union all select 3, 300)
79
+ insert into cte_dst (id, val) select id, val from src
80
+ on conflict (id) do update set val = excluded.val;
81
+
82
+ select id, val from cte_dst order by id;
83
+ → [{"id":1,"val":999},{"id":2,"val":200},{"id":3,"val":300}]
84
+
85
+ drop table cte_dst;
86
+
87
+ -- ===================================
88
+ -- 5. UPSERT DO UPDATE WHERE — condition fails leaves row unchanged
89
+ -- ===================================
90
+
91
+ create table guarded (id integer primary key, n integer);
92
+ insert into guarded values (1, 100);
93
+
94
+ -- condition true: update applies
95
+ insert into guarded values (1, 200) on conflict (id) do update set n = excluded.n where n < 150;
96
+ select n from guarded where id = 1;
97
+ → [{"n":200}]
98
+
99
+ -- condition false: row unchanged
100
+ insert into guarded values (1, 999) on conflict (id) do update set n = excluded.n where n < 150;
101
+ select n from guarded where id = 1;
102
+ → [{"n":200}]
103
+
104
+ drop table guarded;
105
+
106
+ -- ===================================
107
+ -- 6. UPSERT DO UPDATE with column-list assignment from subquery
108
+ -- ===================================
109
+
110
+ create table dual_set (id integer primary key, a text, b text);
111
+ insert into dual_set values (1, 'x', 'y');
112
+
113
+ -- column-list SET assignment in DO UPDATE is not supported by the parser
114
+ insert into dual_set values (1, 'ignored_a', 'ignored_b')
115
+ on conflict (id) do update set (a, b) = (select 'new_a', 'new_b');
116
+ -- error: Expected column name
117
+
118
+ drop table dual_set;
119
+
120
+ -- ===================================
121
+ -- 7. UPSERT on multi-row INSERT — mix of conflict and non-conflict rows
122
+ -- ===================================
123
+
124
+ create table multi (id integer primary key, name text, count integer);
125
+ insert into multi values (1, 'first', 10);
126
+
127
+ insert into multi (id, name, count) values
128
+ (1, 'updated_first', 100),
129
+ (2, 'second', 20),
130
+ (3, 'third', 30)
131
+ on conflict (id) do update set count = excluded.count;
132
+
133
+ select id, name, count from multi order by id;
134
+ → [{"id":1,"name":"first","count":100},{"id":2,"name":"second","count":20},{"id":3,"name":"third","count":30}]
135
+
136
+ drop table multi;
137
+
138
+ -- ===================================
139
+ -- 8. ON CONFLICT (<target>) only suppresses conflicts on <target>
140
+ -- A DO NOTHING clause must NOT swallow a conflict on a *different* unique
141
+ -- constraint. With a PK plus a secondary UNIQUE, a clause targeting one of
142
+ -- them aborts when the actual conflict is on the other.
143
+ -- (ticket seed-secondary-unique-silently-skipped)
144
+ -- ===================================
145
+
146
+ create table scoped (id integer primary key, email text unique);
147
+ insert into scoped values (1, 'a@x');
148
+
149
+ -- Conflict is on the `email` UNIQUE (existing row has a different PK), but the
150
+ -- clause targets `id` — so it must abort, not skip.
151
+ insert into scoped values (2, 'a@x') on conflict (id) do nothing;
152
+ -- error: UNIQUE constraint failed
153
+
154
+ -- Symmetric: conflict is on the PK `id` (existing row has a different email),
155
+ -- but the clause targets `email` — must abort, not skip.
156
+ insert into scoped values (1, 'b@x') on conflict (email) do nothing;
157
+ -- error: UNIQUE constraint failed
158
+
159
+ -- The aborted inserts left no trace: still just the original row.
160
+ select id, email from scoped order by id;
161
+ → [{"id":1,"email":"a@x"}]
162
+
163
+ -- Idempotency control: a genuine PK conflict (same id, same email) targeting
164
+ -- the PK is skipped silently — the value-comparison match still holds.
165
+ insert into scoped values (1, 'a@x') on conflict (id) do nothing;
166
+ select count(*) as cnt from scoped;
167
+ → [{"cnt":1}]
168
+
169
+ drop table scoped;
@@ -0,0 +1,164 @@
1
+ -- distilled from SQLite test/conflict.test (replace/or-clauses surface);
2
+ -- replace.test does not exist upstream, but the ticket calls out
3
+ -- "INSERT OR REPLACE / OR IGNORE / OR ABORT / OR FAIL / OR ROLLBACK —
4
+ -- Quereus's conflict-resolution surface may differ. Pin it down per clause."
5
+ -- Existing fixtures cover OR IGNORE / OR REPLACE on UNIQUE (102) and NOT NULL (43.1);
6
+ -- this fills in the REPLACE-INTO keyword form, multi-row REPLACE, REPLACE+RETURNING,
7
+ -- UPDATE OR REPLACE on UNIQUE, and OR FAIL / OR ROLLBACK / OR ABORT semantics
8
+ -- with respect to surrounding transactional state.
9
+
10
+ -- ===================================
11
+ -- 1. Bare REPLACE statement is not supported (only INSERT OR REPLACE form)
12
+ -- ===================================
13
+
14
+ create table rk (id integer primary key, email text unique, name text);
15
+ insert into rk values (1, 'a@x', 'Alice'), (2, 'b@x', 'Bob');
16
+
17
+ replace into rk values (1, 'a@x', 'Alice2');
18
+ -- error: Expected statement type
19
+
20
+ drop table rk;
21
+
22
+ -- ===================================
23
+ -- 2. INSERT OR REPLACE multi-row VALUES — atomic per-row conflict resolution
24
+ -- ===================================
25
+
26
+ create table rm (id integer primary key, name text unique);
27
+ insert into rm values (1, 'Alice'), (2, 'Bob');
28
+
29
+ insert or replace into rm values (1, 'Alice-New'), (3, 'Carol');
30
+
31
+ select id, name from rm order by id;
32
+ → [{"id":1,"name":"Alice-New"},{"id":2,"name":"Bob"},{"id":3,"name":"Carol"}]
33
+
34
+ drop table rm;
35
+
36
+ -- ===================================
37
+ -- 3. REPLACE that resolves multiple existing rows via UNIQUE conflict on different cols
38
+ -- ===================================
39
+
40
+ create table rmm (id integer primary key, email text unique, phone text unique);
41
+ insert into rmm values (1, 'a@x', '111'), (2, 'b@x', '222');
42
+
43
+ -- new row conflicts on email with id=1 and phone with id=2 — both old rows are replaced
44
+ insert or replace into rmm values (3, 'a@x', '222');
45
+ select id from rmm order by id;
46
+ → [{"id":3}]
47
+
48
+ drop table rmm;
49
+
50
+ -- ===================================
51
+ -- 4. REPLACE INTO with RETURNING
52
+ -- ===================================
53
+
54
+ create table rr (id integer primary key, val text);
55
+ insert into rr values (1, 'old');
56
+
57
+ insert or replace into rr values (1, 'new') returning id, val;
58
+ → [{"id":1,"val":"new"}]
59
+
60
+ drop table rr;
61
+
62
+ -- ===================================
63
+ -- 5. UPDATE OR <action> is intentionally not supported
64
+ -- ===================================
65
+ -- SQLite-only syntax with no precedent in Postgres / SQL Server / MySQL / Oracle / ANSI.
66
+ -- Per-statement conflict overrides on UPDATE are pinned closed; use schema-level
67
+ -- ON CONFLICT defaults (column / table constraint clauses) or rewrite via
68
+ -- WHERE NOT EXISTS / explicit DELETE+UPDATE in a transaction. See docs/sql.md §11.
69
+
70
+ create table uor (id integer primary key, code text unique);
71
+ insert into uor values (1, 'aaa'), (2, 'bbb');
72
+
73
+ update or replace uor set code = 'aaa' where id = 2;
74
+ -- error: Expected table name
75
+
76
+ drop table uor;
77
+
78
+ -- ===================================
79
+ -- 6. INSERT OR ABORT (default) — violation aborts the statement entirely
80
+ -- ===================================
81
+
82
+ create table ab (id integer primary key, val text);
83
+ insert into ab values (1, 'a');
84
+
85
+ -- bulk insert with a duplicate PK in the middle aborts the entire statement
86
+ insert or abort into ab values (2, 'b'), (1, 'dup'), (3, 'c');
87
+ -- error: UNIQUE constraint failed
88
+
89
+ -- nothing should have been inserted
90
+ select count(*) as cnt from ab;
91
+ → [{"cnt":1}]
92
+
93
+ drop table ab;
94
+
95
+ -- ===================================
96
+ -- 7. INSERT OR FAIL — earlier rows in the failing statement remain inserted
97
+ -- ===================================
98
+
99
+ create table fl (id integer primary key, val text);
100
+ insert into fl values (5, 'pre');
101
+
102
+ -- FAIL inserts rows that succeed before the violation, then halts
103
+ insert or fail into fl values (1, 'a'), (2, 'b'), (5, 'dup'), (3, 'c');
104
+ -- error: UNIQUE constraint failed
105
+
106
+ -- INSERT OR FAIL leaves previously-successful rows inserted
107
+ select id, val from fl order by id;
108
+ → [{"id":1,"val":"a"},{"id":2,"val":"b"},{"id":5,"val":"pre"}]
109
+
110
+ drop table fl;
111
+
112
+ -- ===================================
113
+ -- 8. INSERT OR ROLLBACK — violation rolls back the enclosing transaction
114
+ -- ===================================
115
+
116
+ create table rb (id integer primary key, val text);
117
+ insert into rb values (1, 'pre');
118
+ -- run
119
+
120
+ begin;
121
+ insert into rb values (10, 'committed_in_tx');
122
+ insert or rollback into rb values (1, 'dup');
123
+ -- error: UNIQUE constraint failed
124
+
125
+ -- INSERT OR ROLLBACK auto-rolls-back the enclosing transaction; only the
126
+ -- pre-tx insert remains.
127
+ select id, val from rb order by id;
128
+ → [{"id":1,"val":"pre"}]
129
+
130
+ drop table rb;
131
+
132
+ -- ===================================
133
+ -- 9. INSERT OR IGNORE on CHECK constraint — violating row silently skipped
134
+ -- ===================================
135
+
136
+ create table ck (id integer primary key, n integer check (n > 0));
137
+ insert into ck values (1, 10);
138
+
139
+ insert or ignore into ck values (2, -5);
140
+ select count(*) as cnt from ck;
141
+ → [{"cnt":1}]
142
+
143
+ -- valid follow-up insert succeeds
144
+ insert or ignore into ck values (3, 30);
145
+ select id, n from ck order by id;
146
+ → [{"id":1,"n":10},{"id":3,"n":30}]
147
+
148
+ drop table ck;
149
+
150
+ -- ===================================
151
+ -- 10. INSERT OR REPLACE on CHECK — REPLACE does NOT mask CHECK violations
152
+ -- ===================================
153
+
154
+ create table ck2 (id integer primary key, n integer check (n > 0));
155
+ insert into ck2 values (1, 10);
156
+
157
+ -- REPLACE relaxes UNIQUE/PK conflicts but CHECK is always abort-only
158
+ insert or replace into ck2 values (2, -5);
159
+ -- error: CHECK
160
+
161
+ select count(*) as cnt from ck2;
162
+ → [{"cnt":1}]
163
+
164
+ drop table ck2;