@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,378 @@
1
+ -- 06.3.4-view-info.sqllogic — view_info() per-view updateability surface.
2
+ -- The engine-idiomatic realization of docs/view-updateability.md
3
+ -- § Information Schema Surface (information_schema.views → view_info() TVF).
4
+ -- Columns: schema, name, is_insertable_into, is_updatable, is_deletable,
5
+ -- effective_targets (JSON array of base-table names). Values are 'YES'/'NO'.
6
+
7
+ -- ===================================================================
8
+ -- Identity single-source view: every column projected → fully mutable.
9
+ -- ===================================================================
10
+
11
+ create table t (id integer primary key, name text);
12
+ create view v_identity as select id, name from t;
13
+
14
+ select schema, name from view_info('v_identity');
15
+ → [{"schema":"main","name":"v_identity"}]
16
+
17
+ select is_insertable_into, is_updatable, is_deletable, effective_targets from view_info('v_identity');
18
+ → [{"is_insertable_into":"YES","is_updatable":"YES","is_deletable":"YES","effective_targets":"[\"t\"]"}]
19
+
20
+ -- ===================================================================
21
+ -- Rename projection: base lineage survives the alias rename.
22
+ -- ===================================================================
23
+
24
+ create view v_rename as select id as user_id, name as full_name from t;
25
+ select is_insertable_into, is_updatable, is_deletable, effective_targets from view_info('v_rename');
26
+ → [{"is_insertable_into":"YES","is_updatable":"YES","is_deletable":"YES","effective_targets":"[\"t\"]"}]
27
+
28
+ -- ===================================================================
29
+ -- Projected-away PK: still updatable, but not deletable (no row identity)
30
+ -- and not insertable (the not-null PK has no recoverable value).
31
+ -- ===================================================================
32
+
33
+ create view v_no_pk as select name from t;
34
+ select is_insertable_into, is_updatable, is_deletable, effective_targets from view_info('v_no_pk');
35
+ → [{"is_insertable_into":"NO","is_updatable":"YES","is_deletable":"NO","effective_targets":"[\"t\"]"}]
36
+
37
+ -- ===================================================================
38
+ -- Constant-FD default for a PROJECTED-AWAY column: `country` is dropped by
39
+ -- the projection but pinned to 'US' by the selection predicate, so an insert
40
+ -- can recover it → insertable even though it is omitted.
41
+ -- ===================================================================
42
+
43
+ create table adults (name text primary key, age integer, country text);
44
+ create view adults_bare as select name, age from adults where country = 'US';
45
+ select is_insertable_into, is_updatable, is_deletable, effective_targets from view_info('adults_bare');
46
+ → [{"is_insertable_into":"YES","is_updatable":"YES","is_deletable":"YES","effective_targets":"[\"adults\"]"}]
47
+
48
+ -- The crux, load-bearing: the projected-away pinned column is NOT NULL with no
49
+ -- declared default, so insertability hinges ENTIRELY on the whole-spine
50
+ -- constant-FD recovery (the pin lives on the Filter, below the projection that
51
+ -- drops the column). Without it, this would be 'NO' — contrast nn_unpinned below.
52
+ create table nn_adults (name text primary key, age integer, country text not null);
53
+ create view nn_pinned as select name, age from nn_adults where country = 'US';
54
+ select is_insertable_into, is_deletable, effective_targets from view_info('nn_pinned');
55
+ → [{"is_insertable_into":"YES","is_deletable":"YES","effective_targets":"[\"nn_adults\"]"}]
56
+
57
+ -- Negative control: same not-null projected-away column, but UNPINNED (no
58
+ -- predicate) → no recoverable value → not insertable. Isolates the pin as the
59
+ -- sole cause of the 'YES' above.
60
+ create view nn_unpinned as select name, age from nn_adults;
61
+ select is_insertable_into, is_deletable, effective_targets from view_info('nn_unpinned');
62
+ → [{"is_insertable_into":"NO","is_deletable":"YES","effective_targets":"[\"nn_adults\"]"}]
63
+
64
+ -- ===================================================================
65
+ -- Constant-FD default with `select *` (the column survives the projection).
66
+ -- ===================================================================
67
+
68
+ create table men (name text primary key, color text);
69
+ create view greenmen as select * from men where color = 'green';
70
+ select is_insertable_into, is_updatable, is_deletable, effective_targets from view_info('greenmen');
71
+ → [{"is_insertable_into":"YES","is_updatable":"YES","is_deletable":"YES","effective_targets":"[\"men\"]"}]
72
+
73
+ -- ===================================================================
74
+ -- Declared base-column default survives projection: the omitted `name`
75
+ -- column has a DEFAULT, so it is not a not-null-without-default worry.
76
+ -- ===================================================================
77
+
78
+ create table u (id integer primary key, name text default 'unknown');
79
+ create view u_v as select id from u;
80
+ select is_insertable_into, is_updatable, is_deletable, effective_targets from view_info('u_v');
81
+ → [{"is_insertable_into":"YES","is_updatable":"YES","is_deletable":"YES","effective_targets":"[\"u\"]"}]
82
+
83
+ -- ===================================================================
84
+ -- Not-null-without-default base column not projected → not insertable.
85
+ -- (`extra` is not projected, has no default, and no predicate pin.)
86
+ -- ===================================================================
87
+
88
+ create table req (id integer primary key, name text, extra text);
89
+ create view req_v as select id, name from req;
90
+ select is_insertable_into, is_updatable, is_deletable, effective_targets from view_info('req_v');
91
+ → [{"is_insertable_into":"NO","is_updatable":"YES","is_deletable":"YES","effective_targets":"[\"req\"]"}]
92
+
93
+ -- ===================================================================
94
+ -- Correlated scalar subquery in the projection: the inner table is reached
95
+ -- only through a SCALAR child, never `getRelations()`, so it must NOT appear
96
+ -- in effective_targets nor rescue the outer not-null `req` via the whole-spine
97
+ -- defaultable walk (its base id is distinct and never an effective target).
98
+ -- Only the outer `subq_outer` is a target; `req` stays unrecoverable → NO.
99
+ -- ===================================================================
100
+ create table subq_outer (id integer primary key, req text not null);
101
+ create table subq_inner (k integer primary key, v text);
102
+ create view subq_v as
103
+ select id, (select v from subq_inner where k = id) as note from subq_outer;
104
+ select is_insertable_into, is_updatable, is_deletable, effective_targets from view_info('subq_v');
105
+ → [{"is_insertable_into":"NO","is_updatable":"YES","is_deletable":"YES","effective_targets":"[\"subq_outer\"]"}]
106
+
107
+ -- ===================================================================
108
+ -- Computed-only body: a non-invertible expression → wholly read-only.
109
+ -- ===================================================================
110
+
111
+ create view computed_v as select name || '!' as banner from t;
112
+ select is_insertable_into, is_updatable, is_deletable, effective_targets from view_info('computed_v');
113
+ → [{"is_insertable_into":"NO","is_updatable":"NO","is_deletable":"NO","effective_targets":"[]"}]
114
+
115
+ -- ===================================================================
116
+ -- VALUES body: no base-table lineage → wholly read-only.
117
+ -- ===================================================================
118
+
119
+ create view values_v as values (1, 2), (3, 4);
120
+ select is_insertable_into, is_updatable, is_deletable, effective_targets from view_info('values_v');
121
+ → [{"is_insertable_into":"NO","is_updatable":"NO","is_deletable":"NO","effective_targets":"[]"}]
122
+
123
+ -- ===================================================================
124
+ -- Aggregate body: aggregate output is read-only at the column level.
125
+ -- ===================================================================
126
+
127
+ create view agg_v as select count(*) as n from t;
128
+ select is_insertable_into, is_updatable, is_deletable, effective_targets from view_info('agg_v');
129
+ → [{"is_insertable_into":"NO","is_updatable":"NO","is_deletable":"NO","effective_targets":"[]"}]
130
+
131
+ -- ===================================================================
132
+ -- Recursive-CTE body: read-only; no recoverable base lineage.
133
+ -- ===================================================================
134
+
135
+ create view rec_v as
136
+ with recursive c(n) as (select 1 union all select n + 1 from c where n < 3)
137
+ select n from c;
138
+ select is_insertable_into, is_updatable, is_deletable, effective_targets from view_info('rec_v');
139
+ → [{"is_insertable_into":"NO","is_updatable":"NO","is_deletable":"NO","effective_targets":"[]"}]
140
+
141
+ -- ===================================================================
142
+ -- Multi-source key-preserving inner join: both base tables are effective
143
+ -- targets and the view is updatable; but the parent PK (pid) is hidden by
144
+ -- the projection → not deletable at every base, and the child's not-null
145
+ -- `pref` is unrecoverable → not insertable. (per-base rules)
146
+ -- ===================================================================
147
+
148
+ create table ms_parent (pid integer primary key, label text);
149
+ create table ms_child (cid integer primary key, pref integer, note text,
150
+ foreign key (pref) references ms_parent(pid));
151
+ create view ms_jv as
152
+ select c.cid as cid, c.note as note, p.label as label
153
+ from ms_child c join ms_parent p on p.pid = c.pref;
154
+ select is_insertable_into, is_updatable, is_deletable, effective_targets from view_info('ms_jv');
155
+ → [{"is_insertable_into":"NO","is_updatable":"YES","is_deletable":"NO","effective_targets":"[\"ms_child\",\"ms_parent\"]"}]
156
+
157
+ -- Surface agrees with propagate(): the two-table inner equi-join accepts a write
158
+ -- (the positive control for the Divergence 3 shape gate below — isDecomposableJoinBody
159
+ -- keeps this exact shape writable, unlike the cross / > 2-table shapes). No row
160
+ -- matches, so the routed base update is a clean no-op rather than an error.
161
+ update ms_jv set note = 'x' where cid = 999;
162
+
163
+ -- ===================================================================
164
+ -- Multi-source inner join exposing an INVERSE-profile column (`nv1 = c.nv + 1`):
165
+ -- still is_updatable='YES' (its `base`-with-`inverse` site is writable, like any
166
+ -- base site), effective_targets both bases. Same per-base shape as ms_jv: the
167
+ -- parent PK is hidden → not deletable at every base, and the child's not-null
168
+ -- `pref` is unrecoverable → not insertable (the inverse column is not insertable
169
+ -- through the multi-source envelope, but `pref` already forces NO here). The
170
+ -- multi-source UPDATE path consumes the inverse — see column_info goldens for the
171
+ -- per-column write. docs § Scalar Invertibility, § Inner Join.
172
+ -- ===================================================================
173
+
174
+ create table iv_parent (pid integer primary key, label text);
175
+ create table iv_child (cid integer primary key, pref integer, nv integer,
176
+ foreign key (pref) references iv_parent(pid));
177
+ create view iv_jv as
178
+ select c.cid as cid, c.nv + 1 as nv1, p.label as label
179
+ from iv_child c join iv_parent p on p.pid = c.pref;
180
+ select is_insertable_into, is_updatable, is_deletable, effective_targets from view_info('iv_jv');
181
+ → [{"is_insertable_into":"NO","is_updatable":"YES","is_deletable":"NO","effective_targets":"[\"iv_child\",\"iv_parent\"]"}]
182
+
183
+ -- ===================================================================
184
+ -- Divergence 1 — a view-declared insert default rescues insertability. `created`
185
+ -- is a not-null, no-declared-default base column projected away by the view; the
186
+ -- `with defaults (created = …)` clause recovers it → insertable. The default
187
+ -- provenance is never threaded onto the physical surface (consumed only in the
188
+ -- rewrite), so deriveViewInfo folds the view's declared defaults in directly.
189
+ -- Cross-checked by a real insert through the view — the dynamic truth the
190
+ -- surface now matches.
191
+ -- ===================================================================
192
+
193
+ create table dfi (id integer primary key, name text, created integer not null);
194
+ create view dfi_v as select id, name from dfi with defaults (created = 999);
195
+ select is_insertable_into, is_updatable, is_deletable, effective_targets
196
+ from view_info('dfi_v');
197
+ → [{"is_insertable_into":"YES","is_updatable":"YES","is_deletable":"YES","effective_targets":"[\"dfi\"]"}]
198
+
199
+ -- The omitted not-null column is supplied by the declared default at insert time.
200
+ insert into dfi_v (id, name) values (1, 'x');
201
+ select * from dfi order by id;
202
+ → [{"id":1,"name":"x","created":999}]
203
+
204
+ -- Negative control: same table+view shape WITHOUT a declared default → not
205
+ -- insertable (isolates the clause as the sole cause of the YES above).
206
+ create view dfi_v_nodefault as select id, name from dfi;
207
+ select is_insertable_into from view_info('dfi_v_nodefault');
208
+ → [{"is_insertable_into":"NO"}]
209
+
210
+ -- An unresolvable insert-default name (a typo) is silently skipped, NOT raised: a
211
+ -- read-only introspection surface stays conservative (the column simply does
212
+ -- not contribute insertability). The not-null `created` is still unrecovered → NO.
213
+ -- (At write time the same name is a hard sited error — see 93.4.)
214
+ create view dfi_v_typo as select id, name from dfi with defaults (nope = 0);
215
+ select is_insertable_into from view_info('dfi_v_typo');
216
+ → [{"is_insertable_into":"NO"}]
217
+
218
+ -- ===================================================================
219
+ -- Divergence 2 — outer-join bodies report PER-SIDE and agree with propagate().
220
+ -- A LEFT (or RIGHT) outer join is partially writable: the preserved side's columns are
221
+ -- base-updatable, the view is insertable (preserved-only / both-side routing) and
222
+ -- deletable (delete-to-preserved). The non-preserved (`null-extended`) side's columns are
223
+ -- now ALSO updatable (the matched-update / null-extended-insert materialization keyed off
224
+ -- the preserved anchor — `view-write-optional-member-transitions`), so the view-level
225
+ -- is_updatable stays YES. RIGHT is the exact mirror of LEFT (the right operand is the
226
+ -- preserved side) and the runtime now executes it (outer-join-right-full-runtime), so it
227
+ -- is re-admitted (view-write-right-join-readmit). FULL stays conservative all-`NO`: it has
228
+ -- no preserved side, hence no anchor to materialize off, so every write rejects.
229
+ -- ===================================================================
230
+
231
+ create table oj_a (aid integer primary key, av text);
232
+ create table oj_b (bid integer primary key, bv text);
233
+ insert into oj_a values (1, 'a1');
234
+
235
+ -- LEFT: oj_a preserved, oj_b non-preserved. aid/av updatable; the view is
236
+ -- insertable (preserved-only insert always works — oj_a's PK is projected) and
237
+ -- deletable (delete routes to oj_a, whose PK is exposed). Both bases are effective
238
+ -- targets (a both-side insert reaches oj_b).
239
+ create view oj_left as
240
+ select a.aid as aid, a.av as av, b.bv as bv
241
+ from oj_a a left join oj_b b on b.bid = a.aid;
242
+ select is_insertable_into, is_updatable, is_deletable, effective_targets
243
+ from view_info('oj_left');
244
+ → [{"is_insertable_into":"YES","is_updatable":"YES","is_deletable":"YES","effective_targets":"[\"oj_a\",\"oj_b\"]"}]
245
+
246
+ -- Surface agrees with propagate(): a preserved-side update is accepted, and a
247
+ -- non-preserved-side update is now accepted too — aid=1 has no oj_b match, so this
248
+ -- materializes oj_b(bid=1, bv='z') via the EC join key (bid = aid) and the row reads
249
+ -- back joined.
250
+ update oj_left set av = 'z' where aid = 1;
251
+ update oj_left set bv = 'z' where aid = 1;
252
+ select aid, av, bv from oj_left where aid = 1;
253
+ → [{"aid":1,"av":"z","bv":"z"}]
254
+
255
+ -- RIGHT: oj_b is preserved (the right operand of a `right` join), oj_a is non-preserved
256
+ -- (null-extended) — the exact mirror of oj_left above. bid/bv (oj_b) are base-updatable;
257
+ -- the preserved PK `bid` is projected, so the view is insertable (preserved-only /
258
+ -- both-side routing) and deletable (delete routes to oj_b). The non-preserved `av` (oj_a)
259
+ -- is updatable too (matched-update / null-extended-insert materialization keyed off the
260
+ -- preserved oj_b anchor). Both bases are effective targets (a both-side insert reaches
261
+ -- oj_a). The runtime now executes a RIGHT join (outer-join-right-full-runtime) and
262
+ -- write-through recognition admits it (view-write-right-join-readmit).
263
+ create view oj_right as
264
+ select a.av as av, b.bid as bid, b.bv as bv
265
+ from oj_a a right join oj_b b on b.bid = a.aid;
266
+ select is_insertable_into, is_updatable, is_deletable, effective_targets
267
+ from view_info('oj_right');
268
+ → [{"is_insertable_into":"YES","is_updatable":"YES","is_deletable":"YES","effective_targets":"[\"oj_a\",\"oj_b\"]"}]
269
+
270
+ -- Surface agrees with propagate(): both a preserved-side (oj_b) update and a
271
+ -- non-preserved-side (oj_a) update are accepted. Seed a preserved oj_b row whose bid has
272
+ -- no matching oj_a (bid=2; oj_a only has aid=1), so updating the preserved `bv` writes
273
+ -- oj_b directly, while updating the non-preserved `av` materializes oj_a(aid=2, av='zz')
274
+ -- via the EC join key (aid = bid) — the exact mirror of oj_left's `set bv` above.
275
+ insert into oj_b values (2, 'b2');
276
+ update oj_right set bv = 'zz' where bid = 2;
277
+ update oj_right set av = 'zz' where bid = 2;
278
+ select av, bid, bv from oj_right where bid = 2;
279
+ → [{"av":"zz","bid":2,"bv":"zz"}]
280
+
281
+ -- FULL: every side null-extended ⇒ no preserved anchor ⇒ conservative all-`NO`. FULL is
282
+ -- still gated (no preserved anchor); RIGHT is now admitted (view-write-right-join-readmit).
283
+ create view oj_full as
284
+ select a.aid as aid, a.av as av, b.bid as bid, b.bv as bv
285
+ from oj_a a full join oj_b b on b.bid = a.aid;
286
+ select is_insertable_into, is_updatable, is_deletable, effective_targets
287
+ from view_info('oj_full');
288
+ → [{"is_insertable_into":"NO","is_updatable":"NO","is_deletable":"NO","effective_targets":"[]"}]
289
+
290
+ -- Surface agrees with propagate(): a write through the full-outer view is deferred.
291
+ update oj_full set av = 'z' where aid = 1;
292
+ -- error: cannot write through view
293
+
294
+ -- ===================================================================
295
+ -- Divergence 3 — non-inner join bodies report conservative and agree with
296
+ -- propagate(). A cross join (and a comma/implicit join) never null-extends (only
297
+ -- LEFT/RIGHT/FULL do — deriveJoinUpdateLineage), so it carries strict-`base`
298
+ -- lineage and slips past the Divergence-2 outer-join gate above. Without the AST
299
+ -- shape gate (isJoinBody && !isDecomposableJoinBody) deriveViewInfo would resolve
300
+ -- its bases and over-report is_updatable='YES'. propagate() rejects a cross join
301
+ -- (collectInnerJoinSources requires an ON/USING predicate), so the surface must
302
+ -- report the conservative all-`NO`/`[]` row — cross-checked below against a real
303
+ -- (rejected) mutation.
304
+ --
305
+ -- n-way (≥2) inner equi-joins — composite-PK sides and self-joins included — are
306
+ -- now DECOMPOSABLE (isDecomposableJoinBody accepts them), so they report writable
307
+ -- and agree with propagate() accepting the write (covered after the cross join).
308
+ --
309
+ -- Comma / implicit join bodies are NOT tested here: a multi-source comma FROM
310
+ -- never produces a buildable view — with aliases (from a x, b y) it is a parse
311
+ -- error, and without aliases the select builder rejects multiple FROM sources —
312
+ -- so such a body is never introspected with base lineage; there is no buildable
313
+ -- case. The shape gate still covers it defensively (isDecomposableJoinBody
314
+ -- requires a single JOIN FROM), so it stays conservative if that ever becomes
315
+ -- plannable.
316
+ -- ===================================================================
317
+
318
+ create table xj_a (aid integer primary key, av text);
319
+ create table xj_b (bid integer primary key, bv text);
320
+ create table xj_c (cid integer primary key, cv text);
321
+
322
+ -- Cross join (two-table, no ON): strict-`base` lineage, but unwritable.
323
+ create view xj_cross as
324
+ select a.aid as aid, a.av as av, b.bv as bv
325
+ from xj_a a cross join xj_b b;
326
+ select is_insertable_into, is_updatable, is_deletable, effective_targets
327
+ from view_info('xj_cross');
328
+ → [{"is_insertable_into":"NO","is_updatable":"NO","is_deletable":"NO","effective_targets":"[]"}]
329
+
330
+ -- Surface agrees with propagate(): a write through the cross-join view is rejected.
331
+ update xj_cross set av = 'z' where aid = 1;
332
+ -- error: cannot write through view
333
+
334
+ -- Three-table inner join (> 2 base tables): now decomposable ⇒ updatable, with all
335
+ -- three bases in effective_targets. Not deletable (xj_b/xj_c PKs are not projected,
336
+ -- so a per-base row identity is not constructible from the view image) and not
337
+ -- insertable (their not-null PKs are unrecoverable). Agrees with propagate().
338
+ create view xj_three as
339
+ select a.aid as aid, a.av as av, b.bv as bv, c.cv as cv
340
+ from xj_a a join xj_b b on b.bid = a.aid join xj_c c on c.cid = a.aid;
341
+ select is_insertable_into, is_updatable, is_deletable, effective_targets
342
+ from view_info('xj_three');
343
+ → [{"is_insertable_into":"NO","is_updatable":"YES","is_deletable":"NO","effective_targets":"[\"xj_a\",\"xj_b\",\"xj_c\"]"}]
344
+
345
+ -- Surface agrees with propagate(): a write through the 3-table-join view is accepted
346
+ -- (no row matches the empty bases, so it is a clean no-op rather than an error).
347
+ update xj_three set av = 'z' where aid = 1;
348
+
349
+ -- Self-join (two alias-bound sites on one table): now decomposable ⇒ updatable. Both
350
+ -- aliases resolve to xj_a, so effective_targets collapses to the single base name.
351
+ -- Not deletable (alias b's PK `aid` is not exposed — only b.av is projected) and not
352
+ -- insertable (b's not-null PK is unrecoverable). Agrees with propagate() accepting.
353
+ create view xj_self as
354
+ select a.aid as aid, a.av as av, b.av as av2
355
+ from xj_a a join xj_a b on b.aid = a.aid;
356
+ select is_insertable_into, is_updatable, is_deletable, effective_targets
357
+ from view_info('xj_self');
358
+ → [{"is_insertable_into":"NO","is_updatable":"YES","is_deletable":"NO","effective_targets":"[\"xj_a\"]"}]
359
+
360
+ -- Surface agrees with propagate(): a write through the self-join view is accepted
361
+ -- (empty base ⇒ clean no-op).
362
+ update xj_self set av = 'z' where aid = 1;
363
+
364
+ -- ===================================================================
365
+ -- Name filter vs. full enumeration.
366
+ -- ===================================================================
367
+
368
+ -- A name filter returns exactly the one matching row.
369
+ select count(*) as c from view_info('ms_jv');
370
+ → [{"c":1}]
371
+
372
+ -- An unknown name filter returns nothing.
373
+ select count(*) as c from view_info('does_not_exist');
374
+ → [{"c":0}]
375
+
376
+ -- The 0-arg form enumerates every view (spot-check two distinct names).
377
+ select name from view_info() where name in ('v_identity', 'ms_jv') order by name;
378
+ → [{"name":"ms_jv"},{"name":"v_identity"}]