@quereus/quereus 4.20.1 → 4.20.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (380) hide show
  1. package/README.md +2 -0
  2. package/dist/src/schema/schema-differ.d.ts.map +1 -1
  3. package/dist/src/schema/schema-differ.js +17 -69
  4. package/dist/src/schema/schema-differ.js.map +1 -1
  5. package/package.json +7 -4
  6. package/test/README.md +173 -0
  7. package/test/logic/01-basic.sqllogic +39 -0
  8. package/test/logic/01.1-select-projection-extras.sqllogic +130 -0
  9. package/test/logic/01.2-strings.sqllogic +43 -0
  10. package/test/logic/01.5-insert-select.sqllogic +237 -0
  11. package/test/logic/01.6-update-extras.sqllogic +118 -0
  12. package/test/logic/01.7-update-from.sqllogic +67 -0
  13. package/test/logic/01.8-delete-extras.sqllogic +122 -0
  14. package/test/logic/01.8.1-delete-range-cow.sqllogic +115 -0
  15. package/test/logic/01.9-query-expr-dml-gates.sqllogic +32 -0
  16. package/test/logic/01.9-query-expr-dml.sqllogic +171 -0
  17. package/test/logic/01.9-query-expr-values.sqllogic +111 -0
  18. package/test/logic/01.9.1-limit-over-dml-subquery.sqllogic +119 -0
  19. package/test/logic/02-filters.sqllogic +54 -0
  20. package/test/logic/02-smoke.sqllogic +62 -0
  21. package/test/logic/02.1-bind-parameters.sqllogic +223 -0
  22. package/test/logic/03-expressions.sqllogic +190 -0
  23. package/test/logic/03.1-quoted-identifiers.sqllogic +55 -0
  24. package/test/logic/03.4-defaults.sqllogic +554 -0
  25. package/test/logic/03.4.1-default-edge-cases.sqllogic +99 -0
  26. package/test/logic/03.5-tvf.sqllogic +61 -0
  27. package/test/logic/03.6-type-system.sqllogic +544 -0
  28. package/test/logic/03.6.1-numeric-text-comparison-coercion.sqllogic +244 -0
  29. package/test/logic/03.6.2-value-to-text.sqllogic +224 -0
  30. package/test/logic/03.7-bigint-mixed-arithmetic.sqllogic +65 -0
  31. package/test/logic/03.8-not-precedence.sqllogic +255 -0
  32. package/test/logic/03.9-is-bool-predicate.sqllogic +150 -0
  33. package/test/logic/03.9.1-is-bool-predicate-partial-index.sqllogic +34 -0
  34. package/test/logic/04-order-by.sqllogic +38 -0
  35. package/test/logic/04-transactions.sqllogic +239 -0
  36. package/test/logic/04a-savepoint-lazy-attach.sqllogic +122 -0
  37. package/test/logic/05-vtab_memory.sqllogic +50 -0
  38. package/test/logic/05.0.1-vtab-memory-unique-index-collation.sqllogic +34 -0
  39. package/test/logic/05.1-composite-pk-range-scan.sqllogic +147 -0
  40. package/test/logic/05.1.1-secondary-index-range-scan.sqllogic +56 -0
  41. package/test/logic/05.2-cast-seek-correctness.sqllogic +124 -0
  42. package/test/logic/06-builtin_functions.sqllogic +149 -0
  43. package/test/logic/06.1-string-functions.sqllogic +92 -0
  44. package/test/logic/06.1.3-like-glob-edges.sqllogic +53 -0
  45. package/test/logic/06.2-math-functions.sqllogic +82 -0
  46. package/test/logic/06.3-schema.sqllogic +48 -0
  47. package/test/logic/06.3.1-schema-all-schemas.sqllogic +39 -0
  48. package/test/logic/06.3.2-schema-foreign-keys.sqllogic +208 -0
  49. package/test/logic/06.3.3-introspection-tags.sqllogic +202 -0
  50. package/test/logic/06.3.3.1-introspection-tags-index.sqllogic +74 -0
  51. package/test/logic/06.3.4-view-info.sqllogic +378 -0
  52. package/test/logic/06.3.5-column-info.sqllogic +347 -0
  53. package/test/logic/06.3.6-schema-views.sqllogic +29 -0
  54. package/test/logic/06.4-schema-search-path.sqllogic +354 -0
  55. package/test/logic/06.4.1-schema-case-insensitive.sqllogic +83 -0
  56. package/test/logic/06.4.2-collation-extras.sqllogic +472 -0
  57. package/test/logic/06.4.2.1-collation-index-access-paths.sqllogic +140 -0
  58. package/test/logic/06.4.3-write-path-collation.sqllogic +99 -0
  59. package/test/logic/06.4.4-comparison-collation-precedence.sqllogic +342 -0
  60. package/test/logic/06.4.5-any-collate-declared-keys.sqllogic +92 -0
  61. package/test/logic/06.5-polymorphic-types.sqllogic +169 -0
  62. package/test/logic/06.5.1-conversion-functions.sqllogic +173 -0
  63. package/test/logic/06.5.2-scalar-minmax.sqllogic +16 -0
  64. package/test/logic/06.5.3-undeclared-return-type-comparison.sqllogic +244 -0
  65. package/test/logic/06.5.4-declared-return-type-builtins.sqllogic +288 -0
  66. package/test/logic/06.6-aggregate-extended.sqllogic +78 -0
  67. package/test/logic/06.7-json-extended.sqllogic +53 -0
  68. package/test/logic/06.8-json-path-operators.sqllogic +99 -0
  69. package/test/logic/06.9-json-canonical-key.sqllogic +65 -0
  70. package/test/logic/06.9.1-json-coerce-once.sqllogic +417 -0
  71. package/test/logic/06.9.1.1-json-coerce-once-index.sqllogic +39 -0
  72. package/test/logic/06.9.2-json-structural-equality.sqllogic +382 -0
  73. package/test/logic/06.9.2.1-json-structural-equality-index.sqllogic +76 -0
  74. package/test/logic/06.9.3-json-index-range-seek.sqllogic +205 -0
  75. package/test/logic/07-aggregates.sqllogic +193 -0
  76. package/test/logic/07.1-aggregate-filter-clause.sqllogic +12 -0
  77. package/test/logic/07.2-aggregate-order-by.sqllogic +11 -0
  78. package/test/logic/07.3-group-by-extras.sqllogic +602 -0
  79. package/test/logic/07.3.1-group-by-order-by-key.sqllogic +164 -0
  80. package/test/logic/07.3.2-grouped-select-list-shape.sqllogic +231 -0
  81. package/test/logic/07.4-group-by-filter-composite-pk.sqllogic +120 -0
  82. package/test/logic/07.5-sum-mixed-exact-and-float.sqllogic +151 -0
  83. package/test/logic/07.5-window.sqllogic +1941 -0
  84. package/test/logic/07.5.1-window-named.sqllogic +13 -0
  85. package/test/logic/07.5.2-window-nth-value.sqllogic +13 -0
  86. package/test/logic/07.6-subqueries.sqllogic +78 -0
  87. package/test/logic/07.6.1-subquery-extras.sqllogic +93 -0
  88. package/test/logic/07.7-and-or-short-circuit.sqllogic +58 -0
  89. package/test/logic/07.7-in-subquery-caching.sqllogic +174 -0
  90. package/test/logic/07.7-scalar-agg-decorrelation.sqllogic +197 -0
  91. package/test/logic/07.7.1-in-extras.sqllogic +158 -0
  92. package/test/logic/07.7.1-scalar-agg-decorrelation-filter.sqllogic +105 -0
  93. package/test/logic/07.7.2-scalar-agg-decorrelation-nested.sqllogic +115 -0
  94. package/test/logic/07.7.3-exists-in-select-decorrelation.sqllogic +107 -0
  95. package/test/logic/07.7.4-where-conjunct-ordering.sqllogic +121 -0
  96. package/test/logic/07.7.5-filter-lost-under-index-order.sqllogic +134 -0
  97. package/test/logic/07.7.6-correlated-predicate-scope.sqllogic +178 -0
  98. package/test/logic/07.7.7-join-source-scope-shadowing.sqllogic +137 -0
  99. package/test/logic/07.7.8-correlated-ref-to-computed-column.sqllogic +165 -0
  100. package/test/logic/07.7.9-conjunct-monotonicity.sqllogic +200 -0
  101. package/test/logic/07.8-correlated-subquery-edges.sqllogic +71 -0
  102. package/test/logic/07.8.1-correlated-in-decorrelation-gates.sqllogic +156 -0
  103. package/test/logic/07.9-in-value-list.sqllogic +154 -0
  104. package/test/logic/07.9.1-in-value-list-composite-index.sqllogic +38 -0
  105. package/test/logic/08-views.sqllogic +64 -0
  106. package/test/logic/08.1-semi-anti-join.sqllogic +191 -0
  107. package/test/logic/08.1-view-edge-cases.sqllogic +118 -0
  108. package/test/logic/08.1.1-uncorrelated-in-semijoin.sqllogic +251 -0
  109. package/test/logic/08.2-existence-flag-semijoin-recovery.sqllogic +197 -0
  110. package/test/logic/08.3-existence-flag-inner-recovery.sqllogic +102 -0
  111. package/test/logic/08.4-key-set-semi-join.sqllogic +447 -0
  112. package/test/logic/09-set_operations.sqllogic +244 -0
  113. package/test/logic/09.1-set-op-cross-collation.sqllogic +230 -0
  114. package/test/logic/10-distinct_datatypes.sqllogic +127 -0
  115. package/test/logic/10.1-ddl-lifecycle.sqllogic +203 -0
  116. package/test/logic/10.1.1-create-table-syntax-edges.sqllogic +47 -0
  117. package/test/logic/10.1.2-ddl-in-transaction.sqllogic +143 -0
  118. package/test/logic/10.1.2.1-add-constraint-in-transaction.sqllogic +59 -0
  119. package/test/logic/10.1.3-ddl-drop-in-transaction.sqllogic +187 -0
  120. package/test/logic/10.1.3.1-drop-constraint-in-transaction.sqllogic +45 -0
  121. package/test/logic/10.1.4-create-table-duplicate-constraint-names.sqllogic +149 -0
  122. package/test/logic/10.1.4-ddl-transaction-policy.sqllogic +314 -0
  123. package/test/logic/10.1.5-alter-add-constraint-minted-name-disambiguation.sqllogic +219 -0
  124. package/test/logic/10.1.5-create-index-lifecycle.sqllogic +72 -0
  125. package/test/logic/10.1.6-ddl-transaction-policy-index.sqllogic +143 -0
  126. package/test/logic/10.1.7-create-table-default-type-check.sqllogic +119 -0
  127. package/test/logic/10.1.8-alter-add-check-existing-rows.sqllogic +117 -0
  128. package/test/logic/10.2-column-features.sqllogic +365 -0
  129. package/test/logic/10.2.1-table-options-rejection.sqllogic +63 -0
  130. package/test/logic/10.2.2-default-collation-memory.sqllogic +30 -0
  131. package/test/logic/10.3-function-features.sqllogic +247 -0
  132. package/test/logic/10.4-schema-scale.sqllogic +168 -0
  133. package/test/logic/10.4.1-schema-scale-indexes.sqllogic +121 -0
  134. package/test/logic/10.5-indexes.sqllogic +164 -0
  135. package/test/logic/10.5.1-partial-indexes.sqllogic +526 -0
  136. package/test/logic/10.5.2-expression-indexes.sqllogic +34 -0
  137. package/test/logic/10.5.3-desc-index-ordering.sqllogic +130 -0
  138. package/test/logic/10.5.4-composite-pk-index-update-phantom.sqllogic +55 -0
  139. package/test/logic/10.5.5-index-name-uniqueness.sqllogic +76 -0
  140. package/test/logic/10.5.6-minmax-index-boundary.sqllogic +204 -0
  141. package/test/logic/10.5.7-implicit-unique-index-lifecycle.sqllogic +1216 -0
  142. package/test/logic/10.6-distinct-edge-cases.sqllogic +119 -0
  143. package/test/logic/100-predicate-normalization-edge-cases.sqllogic +238 -0
  144. package/test/logic/100.1-where-extras.sqllogic +163 -0
  145. package/test/logic/100.1.1-where-join-on-order-indexed.sqllogic +35 -0
  146. package/test/logic/101-builtin-mutation-kills.sqllogic +974 -0
  147. package/test/logic/101-transaction-edge-cases.sqllogic +395 -0
  148. package/test/logic/102-schema-catalog-edge-cases.sqllogic +252 -0
  149. package/test/logic/102-unique-constraints.sqllogic +145 -0
  150. package/test/logic/102.0.1-schema-catalog-indexed-table.sqllogic +32 -0
  151. package/test/logic/102.1-unique-edge-cases.sqllogic +111 -0
  152. package/test/logic/102.1.1-unique-index-creation-edge-cases.sqllogic +75 -0
  153. package/test/logic/102.2-unique-collation.sqllogic +181 -0
  154. package/test/logic/102.2.1-unique-collation-index-derived.sqllogic +305 -0
  155. package/test/logic/103-database-options-edge-cases.sqllogic +108 -0
  156. package/test/logic/103.1-pragma-boolean-values.sqllogic +126 -0
  157. package/test/logic/104-emit-mutation-kills.sqllogic +236 -0
  158. package/test/logic/105-vtab-memory-mutation-kills.sqllogic +754 -0
  159. package/test/logic/105.1-vtab-memory-index-mutation-kills.sqllogic +540 -0
  160. package/test/logic/106-constraint-extractor-mutation-kills.sqllogic +350 -0
  161. package/test/logic/107-temporal-arithmetic-mutation-kills.sqllogic +833 -0
  162. package/test/logic/108-cardinality-estimation.sqllogic +146 -0
  163. package/test/logic/108.1-analyze-name-resolution.sqllogic +102 -0
  164. package/test/logic/109-aggregate-physical-selection.sqllogic +103 -0
  165. package/test/logic/11-joins.sqllogic +86 -0
  166. package/test/logic/11.1-join-using.sqllogic +267 -0
  167. package/test/logic/11.2-comma-join.sqllogic +35 -0
  168. package/test/logic/11.3-index-nested-loop-join.sqllogic +305 -0
  169. package/test/logic/11.3-mismatched-collation-join.sqllogic +74 -0
  170. package/test/logic/11.4-hash-join-side-swap.sqllogic +118 -0
  171. package/test/logic/110-scan-emitter-mutation-kills.sqllogic +121 -0
  172. package/test/logic/110.1-scan-emitter-index-scan-kills.sqllogic +47 -0
  173. package/test/logic/12-empty-primary-key.sqllogic +124 -0
  174. package/test/logic/12-join_padding_order.sqllogic +58 -0
  175. package/test/logic/12.1-orderby-index-consumption.sqllogic +40 -0
  176. package/test/logic/13-cte.sqllogic +137 -0
  177. package/test/logic/13.1-cte-multiple-recursive.sqllogic +104 -0
  178. package/test/logic/13.10-cte-qualified-name.sqllogic +136 -0
  179. package/test/logic/13.11-unreferenced-dml-cte.sqllogic +414 -0
  180. package/test/logic/13.12-nested-dml-cte-rejected.sqllogic +280 -0
  181. package/test/logic/13.2-cte-bind-params.sqllogic +98 -0
  182. package/test/logic/13.3-cte-edge-cases.sqllogic +120 -0
  183. package/test/logic/13.4-cte-extras.sqllogic +98 -0
  184. package/test/logic/13.5-cte-join-order.sqllogic +166 -0
  185. package/test/logic/13.6-cte-dml-runs-once.sqllogic +318 -0
  186. package/test/logic/13.7-cte-sibling-visibility.sqllogic +227 -0
  187. package/test/logic/13.8-insert-with-clause-visibility.sqllogic +254 -0
  188. package/test/logic/13.9-schema-authored-cte-isolation.sqllogic +328 -0
  189. package/test/logic/13.9.1-schema-authored-schema-path-isolation.sqllogic +408 -0
  190. package/test/logic/14-utilities.sqllogic +168 -0
  191. package/test/logic/15-timespan.sqllogic +279 -0
  192. package/test/logic/15.1-semantic-ordering.sqllogic +960 -0
  193. package/test/logic/15.1.1-json-check-coercion.sqllogic +178 -0
  194. package/test/logic/15.1.2-semantic-ordering-index.sqllogic +41 -0
  195. package/test/logic/15.1.3-declared-form-write-contract.sqllogic +519 -0
  196. package/test/logic/16-epoch.sqllogic +187 -0
  197. package/test/logic/17-weekday-modifier.sqllogic +78 -0
  198. package/test/logic/18-json-string-escapes.sqllogic +86 -0
  199. package/test/logic/18-strftime-extended-formats.sqllogic +68 -0
  200. package/test/logic/20-empty-single-row.sqllogic +261 -0
  201. package/test/logic/21-null-edge-cases.sqllogic +227 -0
  202. package/test/logic/21.1-where-null-comparisons.sqllogic +151 -0
  203. package/test/logic/21.1.1-where-null-comparisons-secondary-index.sqllogic +35 -0
  204. package/test/logic/21.2-between-edges.sqllogic +157 -0
  205. package/test/logic/22-boundary-values.sqllogic +175 -0
  206. package/test/logic/23-self-joins-duplicates.sqllogic +74 -0
  207. package/test/logic/24-builtin-branches.sqllogic +611 -0
  208. package/test/logic/24.1-substr-extras.sqllogic +75 -0
  209. package/test/logic/24.2-random-extras.sqllogic +39 -0
  210. package/test/logic/25-aggregate-edge-cases.sqllogic +289 -0
  211. package/test/logic/25.1-nested-aggregates.sqllogic +74 -0
  212. package/test/logic/25.2-having-edge-cases.sqllogic +318 -0
  213. package/test/logic/25.3-aggregate-isnull-empty.sqllogic +16 -0
  214. package/test/logic/25.4-groupby-fd-constant-empty.sqllogic +55 -0
  215. package/test/logic/25.5-ungrouped-aggregate-column-free-select-item.sqllogic +196 -0
  216. package/test/logic/26-join-edge-cases.sqllogic +333 -0
  217. package/test/logic/26.1-left-join-isnull-on-notnull.sqllogic +26 -0
  218. package/test/logic/26.2-left-join-on-vs-where.sqllogic +67 -0
  219. package/test/logic/26.3-join-on-constants.sqllogic +61 -0
  220. package/test/logic/26.4-join-on-is-null-nullable.sqllogic +44 -0
  221. package/test/logic/27-window-edge-cases.sqllogic +206 -0
  222. package/test/logic/27.1-window-groups-frame.sqllogic +13 -0
  223. package/test/logic/27.2-window-exclude.sqllogic +13 -0
  224. package/test/logic/27.3-window-json-aggregation.sqllogic +66 -0
  225. package/test/logic/28-set-ops-sort-edge-cases.sqllogic +444 -0
  226. package/test/logic/28.1-compound-limit-offset.sqllogic +143 -0
  227. package/test/logic/28.2-orderby-expression-extras.sqllogic +698 -0
  228. package/test/logic/28.2-set-op-branch-types.sqllogic +217 -0
  229. package/test/logic/29-constraint-edge-cases.sqllogic +442 -0
  230. package/test/logic/29.1-column-level-conflict-clause.sqllogic +171 -0
  231. package/test/logic/29.2-table-level-pk-conflict-clause.sqllogic +113 -0
  232. package/test/logic/40-constraints.sqllogic +418 -0
  233. package/test/logic/40.1-pk-desc-direction.sqllogic +76 -0
  234. package/test/logic/40.2-check-extras.sqllogic +683 -0
  235. package/test/logic/41-alter-table.sqllogic +191 -0
  236. package/test/logic/41-fk-cascade-conflict-and-self-ref.sqllogic +263 -0
  237. package/test/logic/41-fk-cross-schema.sqllogic +155 -0
  238. package/test/logic/41-fk-extended-targets.sqllogic +173 -0
  239. package/test/logic/41-foreign-keys.sqllogic +1001 -0
  240. package/test/logic/41-generated-column-errors.sqllogic +225 -0
  241. package/test/logic/41-generated-column-extras.sqllogic +598 -0
  242. package/test/logic/41-generated-column-scope.sqllogic +329 -0
  243. package/test/logic/41-generated-columns.sqllogic +361 -0
  244. package/test/logic/41.1-alter-pk.sqllogic +230 -0
  245. package/test/logic/41.1-fk-collation-conflict.sqllogic +277 -0
  246. package/test/logic/41.10-alter-drop-column-foreign-key.sqllogic +274 -0
  247. package/test/logic/41.10.1-alter-drop-column-unique-index.sqllogic +169 -0
  248. package/test/logic/41.10.2-alter-drop-column-check-and-assertion.sqllogic +1616 -0
  249. package/test/logic/41.10.3-alter-drop-column-referencing-fk.sqllogic +292 -0
  250. package/test/logic/41.10.4-drop-object-expression-dependents.sqllogic +602 -0
  251. package/test/logic/41.11-deferred-fk-with-rename.sqllogic +232 -0
  252. package/test/logic/41.12-alter-default-coercion.sqllogic +200 -0
  253. package/test/logic/41.13-alter-add-column-generated-backfill.sqllogic +566 -0
  254. package/test/logic/41.14-alter-add-column-subquery-backfill.sqllogic +129 -0
  255. package/test/logic/41.15-alter-column-default-type-check.sqllogic +178 -0
  256. package/test/logic/41.16-fk-unenforceable.sqllogic +364 -0
  257. package/test/logic/41.2-alter-column.sqllogic +382 -0
  258. package/test/logic/41.2.1-alter-column-retype-deleted-row-memory.sqllogic +32 -0
  259. package/test/logic/41.2.2-alter-column-retype-index-rebuild.sqllogic +77 -0
  260. package/test/logic/41.2.3-alter-column-set-not-null-pk-backfill.sqllogic +310 -0
  261. package/test/logic/41.2.3.1-alter-column-set-not-null-pk-backfill-secondary-index.sqllogic +37 -0
  262. package/test/logic/41.3-alter-add-column-unique.sqllogic +184 -0
  263. package/test/logic/41.3-alter-rename-propagation.sqllogic +2352 -0
  264. package/test/logic/41.3.1-alter-rename-index-propagation.sqllogic +94 -0
  265. package/test/logic/41.4-alter-add-column-constraints.sqllogic +855 -0
  266. package/test/logic/41.5-alter-misc.sqllogic +48 -0
  267. package/test/logic/41.5-cross-schema-foreign-keys.sqllogic +253 -0
  268. package/test/logic/41.6-alter-drop-rename-constraint.sqllogic +354 -0
  269. package/test/logic/41.6.1-alter-drop-constraint-index-derived.sqllogic +22 -0
  270. package/test/logic/41.7-alter-column-collate.sqllogic +105 -0
  271. package/test/logic/41.7.1-alter-column-collate-unique.sqllogic +45 -0
  272. package/test/logic/41.7.2-alter-column-collate-unique-store.sqllogic +208 -0
  273. package/test/logic/41.7.2.1-alter-column-collate-unique-index-store.sqllogic +114 -0
  274. package/test/logic/41.7.3-alter-column-retype-unique.sqllogic +293 -0
  275. package/test/logic/41.7.3.1-alter-column-retype-staged-rows-memory.sqllogic +41 -0
  276. package/test/logic/41.7.3.2-alter-column-retype-unique-index.sqllogic +72 -0
  277. package/test/logic/41.7.4-alter-column-retype-semantic-memory.sqllogic +445 -0
  278. package/test/logic/41.7.4.1-alter-column-retype-semantic-index-memory.sqllogic +91 -0
  279. package/test/logic/41.7.5-alter-column-collate-pk-staged-delete-memory.sqllogic +106 -0
  280. package/test/logic/41.8-alter-add-constraint-unique-fk.sqllogic +275 -0
  281. package/test/logic/41.8-alter-savepoint-staged-rows.sqllogic +443 -0
  282. package/test/logic/41.8.1-alter-rename-savepoint-staged-rows.sqllogic +408 -0
  283. package/test/logic/41.9-alter-constraint-body-change.sqllogic +180 -0
  284. package/test/logic/41.9-fk-restrict-batched.sqllogic +290 -0
  285. package/test/logic/42-committed-snapshot.sqllogic +254 -0
  286. package/test/logic/42-returning.sqllogic +159 -0
  287. package/test/logic/42.1-returning-extras.sqllogic +232 -0
  288. package/test/logic/42.2-returning-stored-row.sqllogic +165 -0
  289. package/test/logic/43-default-nullability.sqllogic +131 -0
  290. package/test/logic/43-transition-constraints.sqllogic +341 -0
  291. package/test/logic/43.1-default-collation.sqllogic +140 -0
  292. package/test/logic/43.1-notnull-or-conflict.sqllogic +79 -0
  293. package/test/logic/43.2-deferred-check-new-on-delete.sqllogic +95 -0
  294. package/test/logic/43.3-nullable-primary-key.sqllogic +587 -0
  295. package/test/logic/44-determinism-validation.sqllogic +164 -0
  296. package/test/logic/44-orthogonality.sqllogic +146 -0
  297. package/test/logic/44.1-nondeterministic-schema.sqllogic +316 -0
  298. package/test/logic/45-udf-determinism.sqllogic +39 -0
  299. package/test/logic/46-mutation-context.sqllogic +595 -0
  300. package/test/logic/47-upsert.sqllogic +255 -0
  301. package/test/logic/47.1-upsert-conflict-targets.sqllogic +169 -0
  302. package/test/logic/47.2-replace-and-or-clauses.sqllogic +164 -0
  303. package/test/logic/47.2.1-pk-replace-secondary-unique.sqllogic +374 -0
  304. package/test/logic/47.3-engine-or-fail.sqllogic +122 -0
  305. package/test/logic/47.3-upsert-conflict-target-collation.sqllogic +139 -0
  306. package/test/logic/47.3.1-upsert-conflict-index-derived-collation.sqllogic +25 -0
  307. package/test/logic/47.4-upsert-conflict-target-affinity.sqllogic +59 -0
  308. package/test/logic/47.5-upsert-do-update-constraints.sqllogic +440 -0
  309. package/test/logic/47.6-upsert-do-update-decomposed.sqllogic +100 -0
  310. package/test/logic/49-reference-graph.sqllogic +84 -0
  311. package/test/logic/50-declarative-schema.sqllogic +2550 -0
  312. package/test/logic/50-metadata-tags.sqllogic +1033 -0
  313. package/test/logic/50.0.1-metadata-tags-index.sqllogic +141 -0
  314. package/test/logic/50.1-declare-schema-pk.sqllogic +150 -0
  315. package/test/logic/50.2-declare-schema-renames.sqllogic +949 -0
  316. package/test/logic/50.2.1-declare-schema-index-renames.sqllogic +210 -0
  317. package/test/logic/50.3-declare-schema-duplicate-names.sqllogic +280 -0
  318. package/test/logic/50.4-declare-schema-apply-restore.sqllogic +192 -0
  319. package/test/logic/51-lens-foundation.sqllogic +147 -0
  320. package/test/logic/51-materialized-views.sqllogic +376 -0
  321. package/test/logic/51.5-materialized-views-coarsened-key.sqllogic +198 -0
  322. package/test/logic/51.7-maintained-table-attach-detach.sqllogic +468 -0
  323. package/test/logic/51.8-maintained-table-declared-constraints.sqllogic +440 -0
  324. package/test/logic/51.85-maintained-table-parent-fk.sqllogic +103 -0
  325. package/test/logic/51.9-maintained-table-secondary-unique.sqllogic +237 -0
  326. package/test/logic/51.9.1-maintained-table-partial-unique.sqllogic +36 -0
  327. package/test/logic/52-lens-overrides.sqllogic +566 -0
  328. package/test/logic/53-materialized-views-rowtime.sqllogic +1601 -0
  329. package/test/logic/53-reserved-tags.sqllogic +252 -0
  330. package/test/logic/53.1-materialized-view-write-through.sqllogic +329 -0
  331. package/test/logic/53.2-materialized-view-rename-propagation.sqllogic +483 -0
  332. package/test/logic/53.3-materialized-view-constraint-only-ddl.sqllogic +409 -0
  333. package/test/logic/53.3.1-materialized-view-index-ddl-irrelevance.sqllogic +29 -0
  334. package/test/logic/53.4-materialized-view-structural-alter-restore.sqllogic +436 -0
  335. package/test/logic/54-covering-mv-enforcement.sqllogic +314 -0
  336. package/test/logic/54.1-covering-mv-partial-enforcement.sqllogic +34 -0
  337. package/test/logic/55-internal-eviction-reporting.sqllogic +89 -0
  338. package/test/logic/55-lens-prover.sqllogic +202 -0
  339. package/test/logic/55.1-eviction-restrict-fk.sqllogic +148 -0
  340. package/test/logic/55.5-lens-authored-inverse.sqllogic +1468 -0
  341. package/test/logic/80-grow-retrieve-pass.sqllogic +79 -0
  342. package/test/logic/81-quickpick.sqllogic +24 -0
  343. package/test/logic/82-bloom-join.sqllogic +185 -0
  344. package/test/logic/83-merge-join.sqllogic +280 -0
  345. package/test/logic/84-asof-scan.sqllogic +238 -0
  346. package/test/logic/84-key-cardinality.sqllogic +50 -0
  347. package/test/logic/85-relational-const-folding.sqllogic +51 -0
  348. package/test/logic/86-scalar-cse.sqllogic +42 -0
  349. package/test/logic/90-error_paths.sqllogic +114 -0
  350. package/test/logic/90.1-parse-errors.sqllogic +77 -0
  351. package/test/logic/90.2-alter-table-errors.sqllogic +53 -0
  352. package/test/logic/90.2.1-alter-extra-errors.sqllogic +51 -0
  353. package/test/logic/90.3-expression-errors.sqllogic +43 -0
  354. package/test/logic/90.4-dml-errors.sqllogic +47 -0
  355. package/test/logic/90.5-unsupported-join-types.sqllogic +37 -0
  356. package/test/logic/90.5.1-right-full-join-read.sqllogic +157 -0
  357. package/test/logic/90.6-select-error-paths.sqllogic +57 -0
  358. package/test/logic/91-merge-join-edge-cases.sqllogic +159 -0
  359. package/test/logic/92-hash-aggregate-edge-cases.sqllogic +139 -0
  360. package/test/logic/93-ddl-view-edge-cases.sqllogic +104 -0
  361. package/test/logic/93.1-view-error-paths.sqllogic +74 -0
  362. package/test/logic/93.2-view-mutation-pending.sqllogic +108 -0
  363. package/test/logic/93.3-view-mutation-or-clause.sqllogic +60 -0
  364. package/test/logic/93.4-view-mutation.sqllogic +4881 -0
  365. package/test/logic/93.4.1-view-mutation-partial-unique-cardinality.sqllogic +31 -0
  366. package/test/logic/93.5-authored-inverse.sqllogic +415 -0
  367. package/test/logic/93.6-set-op-flagless-write.sqllogic +862 -0
  368. package/test/logic/94-tvf-edge-cases.sqllogic +58 -0
  369. package/test/logic/94.1-limit-offset-edge-cases.sqllogic +109 -0
  370. package/test/logic/94.2-limit-offset-extras.sqllogic +98 -0
  371. package/test/logic/95-assertions.sqllogic +1417 -0
  372. package/test/logic/96-subquery-edge-cases.sqllogic +276 -0
  373. package/test/logic/97-json-function-edge-cases.sqllogic +633 -0
  374. package/test/logic/97.1-json-blob-and-special-values.sqllogic +92 -0
  375. package/test/logic/98-temporal-edge-cases.sqllogic +515 -0
  376. package/test/logic/99-conversion-edge-cases.sqllogic +325 -0
  377. package/test/logic/99.0.1-schema-index-listing.sqllogic +21 -0
  378. package/test/logic/99.1-cast-syntax-extras.sqllogic +167 -0
  379. package/test/logic/drop-unique-index.sqllogic +88 -0
  380. package/test/logic/pushdown-test.sqllogic +36 -0
@@ -0,0 +1,164 @@
1
+ -- indexes.sqllogic - Testing index creation and usage
2
+ --
3
+ -- requires-capability: standalone-index-ddl
4
+
5
+ -- Setup base table for index testing
6
+ CREATE TABLE idx_test (
7
+ id INTEGER PRIMARY KEY,
8
+ name TEXT,
9
+ age INTEGER,
10
+ city TEXT,
11
+ score REAL,
12
+ active INTEGER
13
+ );
14
+
15
+ INSERT INTO idx_test VALUES
16
+ (1, 'Alice', 30, 'New York', 95.5, 1),
17
+ (2, 'Bob', 25, 'London', 87.2, 1),
18
+ (3, 'Charlie', 35, 'New York', 92.1, 0),
19
+ (4, 'David', 30, 'Paris', 89.8, 1),
20
+ (5, 'Eve', 28, 'London', 96.3, 1);
21
+
22
+ -- Basic CREATE INDEX
23
+ CREATE INDEX idx_name ON idx_test (name);
24
+
25
+ -- Verify table still works after index creation
26
+ SELECT name FROM idx_test WHERE name = 'Alice';
27
+ → [{"name":"Alice"}]
28
+
29
+ -- CREATE INDEX with IF NOT EXISTS
30
+ CREATE INDEX IF NOT EXISTS idx_age ON idx_test (age);
31
+
32
+ -- Try to create same index again (should succeed with IF NOT EXISTS)
33
+ CREATE INDEX IF NOT EXISTS idx_age ON idx_test (age);
34
+
35
+ -- Multi-column index
36
+ CREATE INDEX idx_city_age ON idx_test (city, age);
37
+
38
+ -- Index with DESC ordering
39
+ CREATE INDEX idx_score_desc ON idx_test (score DESC);
40
+
41
+ -- Index on different data types
42
+ CREATE INDEX idx_active ON idx_test (active);
43
+
44
+ -- Verify queries still work with indexes
45
+ SELECT id, name FROM idx_test WHERE age = 30 ORDER BY name;
46
+ → [{"id":1,"name":"Alice"},{"id":4,"name":"David"}]
47
+
48
+ SELECT name FROM idx_test WHERE city = 'London' ORDER BY age;
49
+ → [{"name":"Bob"},{"name":"Eve"}]
50
+
51
+ SELECT name, score FROM idx_test WHERE score > 90 ORDER BY score DESC;
52
+ → [{"name":"Eve","score":96.3},{"name":"Alice","score":95.5},{"name":"Charlie","score":92.1}]
53
+
54
+ -- Test UNIQUE index
55
+ CREATE TABLE unique_test (id INTEGER PRIMARY KEY, email TEXT);
56
+ INSERT INTO unique_test VALUES (1, 'alice@example.com'), (2, 'bob@example.com');
57
+
58
+ CREATE UNIQUE INDEX idx_email_unique ON unique_test (email);
59
+
60
+ -- Query with unique index
61
+ SELECT id FROM unique_test WHERE email = 'alice@example.com';
62
+ → [{"id":1}]
63
+
64
+ -- Test index on NULL values
65
+ CREATE TABLE null_test (id INTEGER PRIMARY KEY, optional_field TEXT NULL);
66
+ INSERT INTO null_test VALUES (1, 'value1'), (2, NULL), (3, 'value3'), (4, NULL);
67
+
68
+ CREATE INDEX idx_optional ON null_test (optional_field);
69
+
70
+ -- Query with NULL values
71
+ SELECT id FROM null_test WHERE optional_field IS NULL ORDER BY id;
72
+ → [{"id":2},{"id":4}]
73
+
74
+ SELECT id FROM null_test WHERE optional_field = 'value1';
75
+ → [{"id":1}]
76
+
77
+ -- Test complex WHERE clauses with indexed columns
78
+ SELECT name, age FROM idx_test WHERE city = 'New York' AND age > 30 ORDER BY name;
79
+ → [{"name":"Charlie","age":35}]
80
+
81
+ -- Test JOIN with indexed columns
82
+ CREATE TABLE departments (id INTEGER PRIMARY KEY, name TEXT, city TEXT);
83
+ INSERT INTO departments VALUES (1, 'Engineering', 'New York'), (2, 'Sales', 'London'), (3, 'Marketing', 'Paris');
84
+
85
+ CREATE INDEX idx_dept_city ON departments (city);
86
+
87
+ SELECT i.name, d.name as dept FROM idx_test i
88
+ JOIN departments d ON i.city = d.city
89
+ WHERE i.active = 1
90
+ ORDER BY i.name;
91
+ → [{"name":"Alice","dept":"Engineering"},{"name":"Bob","dept":"Sales"},{"name":"David","dept":"Marketing"},{"name":"Eve","dept":"Sales"}]
92
+
93
+ -- Test ORDER BY with indexed columns (should be optimized)
94
+ SELECT name FROM idx_test ORDER BY name;
95
+ → [{"name":"Alice"},{"name":"Bob"},{"name":"Charlie"},{"name":"David"},{"name":"Eve"}]
96
+
97
+ SELECT name FROM idx_test ORDER BY age, name;
98
+ → [{"name":"Bob"},{"name":"Eve"},{"name":"Alice"},{"name":"David"},{"name":"Charlie"}]
99
+
100
+ -- Test range queries on indexed columns
101
+ SELECT name FROM idx_test WHERE age BETWEEN 25 AND 30 ORDER BY age, name;
102
+ → [{"name":"Bob"},{"name":"Eve"},{"name":"Alice"},{"name":"David"}]
103
+
104
+ -- Error cases
105
+
106
+ -- Try to create index on non-existent table
107
+ CREATE INDEX idx_bad_table ON non_existent_table (col);
108
+ -- error: no such table
109
+
110
+ -- Try to create index on non-existent column
111
+ CREATE INDEX idx_bad_col ON idx_test (non_existent_column);
112
+ -- error: Column 'non_existent_column' not found in table 'idx_test'
113
+
114
+ -- Try to create duplicate index without IF NOT EXISTS
115
+ CREATE INDEX idx_name ON idx_test (name);
116
+ -- error: Index idx_name already exists
117
+
118
+ -- ========================================
119
+ -- DROP INDEX tests
120
+ -- ========================================
121
+
122
+ -- DROP INDEX: basic drop
123
+ CREATE TABLE drop_idx_test (id INTEGER PRIMARY KEY, name TEXT, age INTEGER);
124
+ INSERT INTO drop_idx_test VALUES (1, 'Alice', 30), (2, 'Bob', 25);
125
+
126
+ CREATE INDEX idx_drop_name ON drop_idx_test (name);
127
+
128
+ -- Verify index works
129
+ SELECT name FROM drop_idx_test WHERE name = 'Alice';
130
+ → [{"name":"Alice"}]
131
+
132
+ -- Drop the index
133
+ DROP INDEX idx_drop_name;
134
+
135
+ -- Queries should still work after dropping index
136
+ SELECT name FROM drop_idx_test WHERE name = 'Alice';
137
+ → [{"name":"Alice"}]
138
+
139
+ -- Re-creating the same index should succeed after drop
140
+ CREATE INDEX idx_drop_name ON drop_idx_test (name);
141
+ DROP INDEX idx_drop_name;
142
+
143
+ -- DROP INDEX IF EXISTS: index exists
144
+ CREATE INDEX idx_drop_age ON drop_idx_test (age);
145
+ DROP INDEX IF EXISTS idx_drop_age;
146
+
147
+ -- DROP INDEX IF EXISTS: index does not exist (should be no-op)
148
+ DROP INDEX IF EXISTS idx_nonexistent;
149
+
150
+ -- DROP INDEX: error when index does not exist (no IF EXISTS)
151
+ DROP INDEX idx_nonexistent;
152
+ -- error: no such index
153
+
154
+ -- DROP TRIGGER: parser rejects (not a supported object type)
155
+ DROP TRIGGER some_trigger;
156
+ -- error: Expected TABLE, VIEW, MATERIALIZED VIEW, INDEX, or ASSERTION after DROP
157
+
158
+ DROP TABLE drop_idx_test;
159
+
160
+ -- Clean up
161
+ DROP TABLE departments;
162
+ DROP TABLE null_test;
163
+ DROP TABLE unique_test;
164
+ DROP TABLE idx_test;
@@ -0,0 +1,526 @@
1
+ -- adapted from SQLite test/index6.test, test/index7.test
2
+ -- partial indexes (CREATE INDEX ... WHERE expr) — both regular and UNIQUE.
3
+ -- Quereus's parser accepts partial indexes; this fixture pins the runtime semantics:
4
+ -- only rows matching the WHERE clause participate in the index, but query results must
5
+ -- remain correct regardless of which rows the index covers.
6
+ --
7
+ -- requires-capability: standalone-index-ddl
8
+
9
+ -- =====================================================
10
+ -- 1. Basic partial index — rows outside WHERE still queryable
11
+ -- =====================================================
12
+ create table p_basic (id integer primary key, status text, val integer);
13
+ insert into p_basic values (1, 'active', 10);
14
+ insert into p_basic values (2, 'inactive', 20);
15
+ insert into p_basic values (3, 'active', 30);
16
+ insert into p_basic values (4, 'inactive', 5);
17
+
18
+ create index ix_p_basic_active on p_basic(val) where status = 'active';
19
+
20
+ -- Query inside the partial scope
21
+ select id from p_basic where status = 'active' order by id;
22
+ → [{"id":1},{"id":3}]
23
+
24
+ -- Query outside the partial scope still returns correct rows (index need not apply)
25
+ select id from p_basic where status = 'inactive' order by id;
26
+ → [{"id":2},{"id":4}]
27
+
28
+ -- Combined predicate using the partial scope
29
+ select id from p_basic where status = 'active' and val > 15;
30
+ → [{"id":3}]
31
+
32
+ drop table p_basic;
33
+
34
+ -- =====================================================
35
+ -- 2. Partial UNIQUE index — uniqueness limited to WHERE scope
36
+ -- =====================================================
37
+ create table p_uniq (id integer primary key, status text, code text);
38
+ create unique index ix_p_uniq_active_code on p_uniq(code) where status = 'active';
39
+
40
+ -- First active row claims code 'A'
41
+ insert into p_uniq values (1, 'active', 'A');
42
+
43
+ -- Same code outside scope: allowed (partial UNIQUE excludes inactive rows)
44
+ insert into p_uniq values (2, 'inactive', 'A');
45
+
46
+ select id, status, code from p_uniq order by id;
47
+ → [{"id":1,"status":"active","code":"A"},{"id":2,"status":"inactive","code":"A"}]
48
+
49
+ -- Same code inside scope: rejected
50
+ insert into p_uniq values (3, 'active', 'A');
51
+ -- error: UNIQUE
52
+
53
+ -- Update transitioning a row out of scope frees the code
54
+ update p_uniq set status = 'archived' where id = 1;
55
+ insert into p_uniq values (4, 'active', 'A');
56
+
57
+ select id, status, code from p_uniq order by id;
58
+ → [{"id":1,"status":"archived","code":"A"},{"id":2,"status":"inactive","code":"A"},{"id":4,"status":"active","code":"A"}]
59
+
60
+ drop table p_uniq;
61
+
62
+ -- =====================================================
63
+ -- 3. Partial index with IS NULL / IS NOT NULL predicate
64
+ -- =====================================================
65
+ create table p_null (id integer primary key, name text, deleted_at text null);
66
+ insert into p_null values (1, 'Widget', null);
67
+ insert into p_null values (2, 'Gadget', '2024-06-01');
68
+ insert into p_null values (3, 'Sprocket', null);
69
+ insert into p_null values (4, 'Doohickey', '2025-01-15');
70
+
71
+ create index ix_p_null_active on p_null(name) where deleted_at is null;
72
+
73
+ -- Query inside scope (matches the partial predicate)
74
+ select id from p_null where name = 'Widget' and deleted_at is null;
75
+ → [{"id":1}]
76
+
77
+ -- Query outside scope (does not match the partial predicate)
78
+ select id from p_null where name = 'Gadget' and deleted_at is not null;
79
+ → [{"id":2}]
80
+
81
+ -- Listing all "active" rows
82
+ select id, name from p_null where deleted_at is null order by id;
83
+ → [{"id":1,"name":"Widget"},{"id":3,"name":"Sprocket"}]
84
+
85
+ drop table p_null;
86
+
87
+ -- =====================================================
88
+ -- 4. Partial index with compound WHERE (AND, comparison)
89
+ -- =====================================================
90
+ create table p_cmp (id integer primary key, user_id integer, score real, archived integer);
91
+ insert into p_cmp values (1, 10, 95.5, 0);
92
+ insert into p_cmp values (2, 10, 45.0, 0);
93
+ insert into p_cmp values (3, 20, 88.2, 0);
94
+ insert into p_cmp values (4, 10, 99.0, 1);
95
+
96
+ create index ix_p_cmp_high on p_cmp(user_id) where archived = 0 and score > 80.0;
97
+
98
+ -- Query in scope
99
+ select id from p_cmp where archived = 0 and score > 80.0 and user_id = 10;
100
+ → [{"id":1}]
101
+
102
+ -- Query that overlaps scope but adds another filter
103
+ select id from p_cmp where user_id = 10 and score > 80.0 order by id;
104
+ → [{"id":1},{"id":4}]
105
+
106
+ -- Query strictly outside scope
107
+ select id from p_cmp where archived = 1 order by id;
108
+ → [{"id":4}]
109
+
110
+ drop table p_cmp;
111
+
112
+ -- =====================================================
113
+ -- 5. Partial index updated correctly when a row's WHERE-eligibility changes
114
+ -- =====================================================
115
+ create table p_move (id integer primary key, kind text, label text);
116
+ create index ix_p_move on p_move(label) where kind = 'A';
117
+
118
+ insert into p_move values (1, 'A', 'one');
119
+ insert into p_move values (2, 'B', 'two');
120
+ insert into p_move values (3, 'A', 'three');
121
+
122
+ select id from p_move where kind = 'A' and label = 'one';
123
+ → [{"id":1}]
124
+
125
+ -- Move id=1 out of scope
126
+ update p_move set kind = 'B' where id = 1;
127
+
128
+ select id from p_move where kind = 'A' and label = 'one';
129
+ → []
130
+
131
+ -- Move id=2 into scope
132
+ update p_move set kind = 'A' where id = 2;
133
+
134
+ select id from p_move where kind = 'A' order by id;
135
+ → [{"id":2},{"id":3}]
136
+
137
+ drop table p_move;
138
+
139
+ -- =====================================================
140
+ -- 6. Partial UNIQUE index must NOT register as a relation key
141
+ -- (FD-layer soundness — partial UNIQUE only guarantees uniqueness
142
+ -- inside the WHERE scope, so it cannot be promoted to an
143
+ -- unconditional key. Otherwise the FD layer derives
144
+ -- K → all-other-cols over the whole table and silently breaks
145
+ -- DISTINCT elimination, GROUP BY simplification, ORDER BY pruning,
146
+ -- and FK→PK join elimination.)
147
+ -- =====================================================
148
+ create table p_fdkey (id integer primary key, c text not null, status text not null);
149
+ create unique index ix_p_fdkey on p_fdkey(c) where status = 'active';
150
+ insert into p_fdkey values (1, 'A', 'active');
151
+ insert into p_fdkey values (2, 'A', 'inactive');
152
+ insert into p_fdkey values (3, 'B', 'active');
153
+
154
+ -- DISTINCT must not be eliminated: c is only unique among status='active' rows.
155
+ select c from (select distinct c from p_fdkey) order by c;
156
+ → [{"c":"A"},{"c":"B"}]
157
+
158
+ -- Same query, count form — must equal the true distinct count across all rows.
159
+ select count(distinct c) as n from p_fdkey;
160
+ → [{"n":2}]
161
+
162
+ -- LEFT JOIN whose right side is the partial-UNIQUE column: join elimination must
163
+ -- not fire — t.c is not an unconditional key, so the join can change row count
164
+ -- (the driver row 'A' matches two p_fdkey rows, not one).
165
+ create table p_fdkey_drv (x integer primary key, c text);
166
+ insert into p_fdkey_drv values (10, 'A');
167
+ select count(*) as n from p_fdkey_drv d left join p_fdkey t on d.c = t.c;
168
+ → [{"n":2}]
169
+
170
+ drop table p_fdkey_drv;
171
+ drop table p_fdkey;
172
+
173
+ -- Positive control: a *full* UNIQUE index on a NOT NULL column on the same
174
+ -- shape still registers as a key and DISTINCT/etc. may safely be eliminated.
175
+ create table p_fdkey_full (id integer primary key, c text not null);
176
+ create unique index ix_p_fdkey_full on p_fdkey_full(c);
177
+ insert into p_fdkey_full values (1, 'A');
178
+ insert into p_fdkey_full values (2, 'B');
179
+ select count(*) as n from (select distinct c from p_fdkey_full);
180
+ → [{"n":2}]
181
+ drop table p_fdkey_full;
182
+
183
+ -- =====================================================
184
+ -- 7. Partial UNIQUE index → guarded FD; correctness across filter shapes.
185
+ --
186
+ -- The producer (partial-unique-extraction) emits a guarded FD `K → others | P`
187
+ -- on the table reference. Filter activation discharges the guard when the
188
+ -- surrounding predicate entails P. Observable plan-shape verification of the
189
+ -- activation happens in unit tests (conditional-fds.spec.ts), which inspect
190
+ -- the FilterNode's physical FDs directly. Here we pin runtime correctness:
191
+ -- queries that *should* be safe against duplicates inside the partial scope
192
+ -- must return the right rows whether or not the optimizer chose to eliminate
193
+ -- DISTINCT / GROUP BY.
194
+ -- =====================================================
195
+ create table p7 (id integer primary key, c text not null, status text not null, region text not null, amt integer not null);
196
+ create unique index ix_p7_active on p7(c) where status = 'active';
197
+ insert into p7 values (1, 'A', 'active', 'us', 10);
198
+ insert into p7 values (2, 'A', 'inactive', 'us', 20);
199
+ insert into p7 values (3, 'B', 'active', 'us', 30);
200
+ insert into p7 values (4, 'C', 'active', 'eu', 40);
201
+
202
+ -- 7a. Direct match: filter exactly equal to the partial predicate.
203
+ select c from p7 where status = 'active' order by c;
204
+ → [{"c":"A"},{"c":"B"},{"c":"C"}]
205
+
206
+ -- 7b. DISTINCT is correct whether eliminated or not.
207
+ select distinct c from (select c from p7 where status = 'active') order by c;
208
+ → [{"c":"A"},{"c":"B"},{"c":"C"}]
209
+
210
+ -- 7c. Negative — no filter: DISTINCT must dedupe ('A' appears twice).
211
+ select c from (select distinct c from p7) order by c;
212
+ → [{"c":"A"},{"c":"B"},{"c":"C"}]
213
+
214
+ -- 7d. Negative — wrong filter: 'A' duplicates outside the partial scope.
215
+ select count(*) as n from (select distinct c from p7 where status = 'inactive');
216
+ → [{"n":1}]
217
+
218
+ -- 7e. GROUP BY: one row per group regardless of partial-FD discharge.
219
+ select c, max(amt) as max_amt from p7 where status = 'active' group by c order by c;
220
+ → [{"c":"A","max_amt":10},{"c":"B","max_amt":30},{"c":"C","max_amt":40}]
221
+
222
+ drop table p7;
223
+
224
+ -- 7f. Multi-conjunct partial predicate: correctness when both clauses match,
225
+ -- and when only one does (uniqueness no longer holds).
226
+ create table p7m (id integer primary key, c text not null, status text not null, region text not null);
227
+ create unique index ix_p7m on p7m(c) where status = 'active' and region = 'us';
228
+ insert into p7m values (1, 'A', 'active', 'us');
229
+ insert into p7m values (2, 'A', 'active', 'eu');
230
+ insert into p7m values (3, 'B', 'active', 'us');
231
+
232
+ -- Both conjuncts present: 'A' appears once (only the 'us' row matches).
233
+ select c from p7m where status = 'active' and region = 'us' order by c;
234
+ → [{"c":"A"},{"c":"B"}]
235
+
236
+ -- Single conjunct: 'A' appears twice (two active rows, different regions).
237
+ -- DISTINCT must deduplicate (the partial UC doesn't cover the broader scope).
238
+ select count(*) as n from (select distinct c from p7m where status = 'active');
239
+ → [{"n":2}]
240
+
241
+ drop table p7m;
242
+
243
+ -- 7g. Nullable UC column: NOT-NULL gate suppresses the FD entirely. Even
244
+ -- with a perfectly matching filter, the partial UC doesn't give a key —
245
+ -- nullable c admits duplicate NULLs inside the partial scope.
246
+ create table p7n (id integer primary key, c text null, status text not null);
247
+ create unique index ix_p7n on p7n(c) where status = 'active';
248
+ insert into p7n values (1, 'A', 'active');
249
+ insert into p7n values (2, 'B', 'active');
250
+ insert into p7n values (3, null, 'active');
251
+
252
+ select count(*) as n from (select distinct c from p7n where status = 'active');
253
+ → [{"n":3}]
254
+
255
+ drop table p7n;
256
+
257
+ -- 7h. Nullable UC column with IS NOT NULL guard: the partial predicate itself
258
+ -- forces the column non-NULL inside scope, so the guarded FD is sound and
259
+ -- DISTINCT should be eliminable when the filter discharges it.
260
+ create table p7h (id integer primary key, email text null);
261
+ create unique index ix_p7h on p7h(email) where email is not null;
262
+ insert into p7h values (1, 'a@x');
263
+ insert into p7h values (2, 'b@x');
264
+ insert into p7h values (3, null);
265
+
266
+ -- Inside scope: every email is unique; DISTINCT must yield the same count
267
+ -- as without (correctness must hold whether or not the optimizer eliminated
268
+ -- DISTINCT). Two non-null rows.
269
+ select count(*) as n from (select distinct email from p7h where email is not null);
270
+ → [{"n":2}]
271
+
272
+ -- Negative: without the IS NOT NULL filter, NULL is part of the result set;
273
+ -- correctness must remain — three distinct values including NULL.
274
+ select count(*) as n from (select distinct email from p7h);
275
+ → [{"n":3}]
276
+
277
+ drop table p7h;
278
+
279
+ -- =====================================================
280
+ -- 7i. Partial UNIQUE with IN-list predicate: producer recognizes
281
+ -- `col IN (lit, …)` as an `or-of [eq-literal …]` guard; the
282
+ -- consumer discharges it when the filter pins the column to a
283
+ -- subset of the OR-set.
284
+ -- =====================================================
285
+ create table p7i (id integer primary key, c text not null, status text not null);
286
+ create unique index ix_p7i on p7i(c) where status in ('active', 'pending');
287
+
288
+ -- Direct match: c must be unique inside the partial scope.
289
+ insert into p7i values (1, 'A', 'active');
290
+ insert into p7i values (2, 'B', 'pending');
291
+ insert into p7i values (3, 'A', 'inactive');
292
+ -- Different status, same c: allowed (partial UC excludes the row).
293
+
294
+ select id, c, status from p7i order by id;
295
+ → [{"id":1,"c":"A","status":"active"},{"id":2,"c":"B","status":"pending"},{"id":3,"c":"A","status":"inactive"}]
296
+
297
+ -- Duplicate inside scope: rejected.
298
+ insert into p7i values (4, 'A', 'pending');
299
+ -- error: UNIQUE
300
+
301
+ -- DISTINCT inside scope: c is unique, so the result count equals the
302
+ -- in-scope row count regardless of FD discharge.
303
+ select count(*) as n from (select distinct c from p7i where status in ('active', 'pending'));
304
+ → [{"n":2}]
305
+
306
+ -- Negative: a filter outside the scope (status not in OR-set) must still
307
+ -- dedupe correctly when c repeats across scopes.
308
+ select count(*) as n from (select distinct c from p7i);
309
+ → [{"n":2}]
310
+
311
+ drop table p7i;
312
+
313
+ -- =====================================================
314
+ -- 7j. Partial UNIQUE with `NOT col` predicate (declared NOT NULL int):
315
+ -- the producer rewrites `NOT col` to `col = 0` and the consumer
316
+ -- discharges from a filter that pins `col` to 0.
317
+ -- =====================================================
318
+ create table p7j (id integer primary key, c text not null, archived integer not null);
319
+ create unique index ix_p7j on p7j(c) where not archived;
320
+
321
+ insert into p7j values (1, 'A', 0);
322
+ insert into p7j values (2, 'B', 0);
323
+ insert into p7j values (3, 'A', 1); -- archived: outside partial scope, dupes allowed.
324
+
325
+ select id, c, archived from p7j order by id;
326
+ → [{"id":1,"c":"A","archived":0},{"id":2,"c":"B","archived":0},{"id":3,"c":"A","archived":1}]
327
+
328
+ -- Duplicate inside the scope (archived=0): rejected.
329
+ insert into p7j values (4, 'A', 0);
330
+ -- error: UNIQUE
331
+
332
+ -- Correctness: distinct c across the whole table.
333
+ select count(*) as n from (select distinct c from p7j);
334
+ → [{"n":2}]
335
+
336
+ -- Inside scope: still distinct (no duplicates among archived=0 rows).
337
+ select count(*) as n from (select distinct c from p7j where archived = 0);
338
+ → [{"n":2}]
339
+
340
+ drop table p7j;
341
+
342
+ -- =====================================================
343
+ -- 7j-NOT-on-TEXT. Regression: `NOT col` on a TEXT column must NOT
344
+ -- yield a `col = 0` rewrite. SQLite's strict sqlValueEquals treats
345
+ -- TEXT '' as unequal to integer 0; the partial UC predicate
346
+ -- `WHERE NOT val` keeps rows with val='' (falsy text), but those
347
+ -- rows are NOT distinguished by val under the rewritten guard.
348
+ -- Before this fix the planner believed `WHERE NOT val` activated
349
+ -- the partial UC and a FILTER-emitted FD c → {…} fired over rows
350
+ -- that actually share c, producing observably wrong results
351
+ -- (DISTINCT / aggregate-elimination misfire).
352
+ -- =====================================================
353
+ create table p7j_text (id integer primary key, c integer not null, val text not null);
354
+ create unique index ix_p7j_text on p7j_text(c) where val = 0;
355
+
356
+ -- Two rows with identical c and val='' (falsy in SQLite's NOT-truthiness).
357
+ -- The partial UC predicate `val = 0` does not match val='' under strict
358
+ -- equality, so neither row is in the partial scope — duplicates allowed.
359
+ insert into p7j_text values (1, 1, '');
360
+ insert into p7j_text values (2, 1, '');
361
+
362
+ -- `WHERE NOT val` keeps both rows. They share c=1, so any planner-level
363
+ -- claim "c → others" would be unsound. Pin the count.
364
+ select c, count(*) as n from p7j_text where not val group by c order by c;
365
+ → [{"c":1,"n":2}]
366
+
367
+ drop table p7j_text;
368
+
369
+ -- Mirror: same shape with val INTEGER NOT NULL — `NOT val` correctly
370
+ -- rewrites to `val = 0` and the partial UC still activates. Confirms the
371
+ -- numeric-only gate didn't regress the INT case.
372
+ create table p7j_int (id integer primary key, c integer not null, val integer not null);
373
+ create unique index ix_p7j_int on p7j_int(c) where val = 0;
374
+
375
+ insert into p7j_int values (1, 1, 0);
376
+ -- Duplicate inside scope (val=0): rejected.
377
+ insert into p7j_int values (2, 1, 0);
378
+ -- error: UNIQUE
379
+
380
+ -- Outside scope (val != 0): duplicates allowed.
381
+ insert into p7j_int values (3, 1, 1);
382
+
383
+ select c, count(*) as n from p7j_int where not val group by c order by c;
384
+ → [{"c":1,"n":1}]
385
+
386
+ drop table p7j_int;
387
+
388
+ -- =====================================================
389
+ -- 7k. Partial UNIQUE with top-level OR predicate: producer recognizes
390
+ -- `a OR b` as an `or-of` guard. Either disjunct in a filter
391
+ -- discharges it; an unrelated filter does not.
392
+ -- =====================================================
393
+ create table p7k (id integer primary key, c text not null, status text not null, deleted_at text null);
394
+ create unique index ix_p7k on p7k(c) where deleted_at is null or status = 'archived';
395
+
396
+ insert into p7k values (1, 'A', 'active', null);
397
+ insert into p7k values (2, 'B', 'archived', '2024-01-01');
398
+ -- Both rows match the partial predicate (different disjuncts) — different c's are fine.
399
+
400
+ -- Duplicate c when both fall under the partial scope (different disjuncts): rejected.
401
+ insert into p7k values (3, 'A', 'archived', '2025-01-01');
402
+ -- error: UNIQUE
403
+
404
+ -- A row that satisfies neither disjunct (deleted_at not null AND status != 'archived')
405
+ -- is outside the partial scope and may dupe.
406
+ insert into p7k values (4, 'A', 'active', '2025-06-01');
407
+
408
+ select id, c, status from p7k order by id;
409
+ → [{"id":1,"c":"A","status":"active"},{"id":2,"c":"B","status":"archived"},{"id":4,"c":"A","status":"active"}]
410
+
411
+ drop table p7k;
412
+
413
+ -- =====================================================
414
+ -- 8. Bare-value predicate truthiness matches the engine (isTruthy).
415
+ -- A bare-column WHERE uses numeric truthiness, so non-numeric text
416
+ -- ('abc') is FALSE (out of scope) while numeric-nonzero text ('1')
417
+ -- is TRUE (in scope) — the same rule the Filter / runtime path uses.
418
+ -- A prior divergence treated any non-empty string as truthy; this
419
+ -- pins the corrected, engine-aligned semantics.
420
+ -- =====================================================
421
+ create table p_bare (id integer primary key, flag text, code text);
422
+ create unique index ix_p_bare on p_bare(code) where flag;
423
+
424
+ -- 'abc' is non-numeric → predicate FALSE → row is OUT of the partial scope.
425
+ insert into p_bare values (1, 'abc', 'X');
426
+ -- Same code, also out of scope → allowed (would be a UNIQUE error under the old
427
+ -- "any non-empty string is truthy" rule).
428
+ insert into p_bare values (2, 'abc', 'X');
429
+
430
+ -- '1' coerces to 1 → predicate TRUE → row is IN scope and claims code 'Y'.
431
+ insert into p_bare values (3, '1', 'Y');
432
+ -- Same code inside scope → rejected.
433
+ insert into p_bare values (4, '1', 'Y');
434
+ -- error: UNIQUE
435
+
436
+ select id, code from p_bare order by id;
437
+ → [{"id":1,"code":"X"},{"id":2,"code":"X"},{"id":3,"code":"Y"}]
438
+
439
+ drop table p_bare;
440
+
441
+ -- =====================================================
442
+ -- 9. Bare-value truthiness through the operator-nested predicateTruthy
443
+ -- call sites (compileUnary NOT, compileBinary AND/OR) and the blob
444
+ -- branch of isTruthy. § 8 pins the top-level bare-value path; these
445
+ -- pin the same isTruthy delegation reached *inside* operators, plus
446
+ -- the blobs-are-falsy rule. Each case is an observable partial-UNIQUE
447
+ -- accept/reject, so a truthiness regression fails loudly.
448
+ -- =====================================================
449
+
450
+ -- 9a. NOT of a bare text column. `where not flag`:
451
+ -- flag='abc' → isTruthy false → NOT true → row IN scope
452
+ -- flag='1' → isTruthy true → NOT false → row OUT of scope
453
+ create table p_not (id integer primary key, flag text, code text);
454
+ create unique index ix_p_not on p_not(code) where not flag;
455
+
456
+ -- Two in-scope rows ('abc' is falsy → NOT true) sharing a code: second rejected.
457
+ insert into p_not values (1, 'abc', 'X');
458
+ insert into p_not values (2, 'abc', 'X');
459
+ -- error: UNIQUE
460
+
461
+ -- Two out-of-scope rows ('1' is truthy → NOT false) sharing a code: both allowed.
462
+ insert into p_not values (3, '1', 'Y');
463
+ insert into p_not values (4, '1', 'Y');
464
+
465
+ select id, code from p_not order by id;
466
+ → [{"id":1,"code":"X"},{"id":3,"code":"Y"},{"id":4,"code":"Y"}]
467
+
468
+ drop table p_not;
469
+
470
+ -- 9b. Bare column as an AND operand. `where flag and othercol > 0`, with
471
+ -- `othercol > 0` held TRUE so the bare-flag truthiness decides scope:
472
+ -- flag='1' (truthy) AND true → row IN scope
473
+ -- flag='abc' (falsy) AND true → row OUT of scope
474
+ create table p_and (id integer primary key, flag text, othercol integer, code text);
475
+ create unique index ix_p_and on p_and(code) where flag and othercol > 0;
476
+
477
+ -- In scope (flag truthy): duplicate code rejected.
478
+ insert into p_and values (1, '1', 5, 'X');
479
+ insert into p_and values (2, '1', 5, 'X');
480
+ -- error: UNIQUE
481
+
482
+ -- Out of scope (flag falsy short-circuits the AND): duplicate code allowed.
483
+ insert into p_and values (3, 'abc', 5, 'Y');
484
+ insert into p_and values (4, 'abc', 5, 'Y');
485
+
486
+ select id, code from p_and order by id;
487
+ → [{"id":1,"code":"X"},{"id":3,"code":"Y"},{"id":4,"code":"Y"}]
488
+
489
+ drop table p_and;
490
+
491
+ -- 9c. Bare column as an OR operand. `where flag or othercol > 0`, with
492
+ -- `othercol > 0` held FALSE (othercol = 0) so the bare-flag truthiness
493
+ -- decides scope:
494
+ -- flag='1' (truthy) OR false → row IN scope
495
+ -- flag='abc' (falsy) OR false → row OUT of scope
496
+ create table p_or (id integer primary key, flag text, othercol integer, code text);
497
+ create unique index ix_p_or on p_or(code) where flag or othercol > 0;
498
+
499
+ -- In scope (flag truthy): duplicate code rejected.
500
+ insert into p_or values (1, '1', 0, 'X');
501
+ insert into p_or values (2, '1', 0, 'X');
502
+ -- error: UNIQUE
503
+
504
+ -- Out of scope (both disjuncts falsy): duplicate code allowed.
505
+ insert into p_or values (3, 'abc', 0, 'Y');
506
+ insert into p_or values (4, 'abc', 0, 'Y');
507
+
508
+ select id, code from p_or order by id;
509
+ → [{"id":1,"code":"X"},{"id":3,"code":"Y"},{"id":4,"code":"Y"}]
510
+
511
+ drop table p_or;
512
+
513
+ -- 9d. Bare BLOB value. `where blobcol` with a non-null blob: isTruthy(blob)
514
+ -- is FALSE (util/comparison.ts), so every row is OUT of scope and duplicate
515
+ -- codes are allowed. Under a regression that treated blobs as truthy, these
516
+ -- rows would be IN scope and the second insert would be a UNIQUE error.
517
+ create table p_blob (id integer primary key, blobcol blob, code text);
518
+ create unique index ix_p_blob on p_blob(code) where blobcol;
519
+
520
+ insert into p_blob values (1, x'00', 'X');
521
+ insert into p_blob values (2, x'01ff', 'X');
522
+
523
+ select id, code from p_blob order by id;
524
+ → [{"id":1,"code":"X"},{"id":2,"code":"X"}]
525
+
526
+ drop table p_blob;